Kubernetes上Containerd部署的DIND容器网络与DNS配置求助
问题描述
业务需求是在Kubernetes上基于Containerd重写类似Github Actions/Nektos Act的应用,采用DIND(Docker-in-Docker)实现。目前已成功创建并启动DIND容器,代码如下:
container, err := cli.NewContainer(ctx, containerName, containerd.WithImage(image), containerd.WithNewSnapshot(containerName+"-snapshot", image), containerd.WithNewSpec( oci.WithImageConfig(image), oci.WithPrivileged, oci.WithEnv(containerEnv), oci.WithMounts(mnts), ), )
但容器内执行docker pull拉取私有仓库镜像时,出现DNS解析错误:
time="2024-08-01T12:44:17.563714641Z" level=warning msg="Error getting v2 registry: Get https://private-repo.local/v2/: dial tcp: lookup private-repo.local on [::1]:53: read udp [::1]:34343->[::1]:53: read: connection refused" time="2024-08-01T12:44:17.563756965Z" level=info msg="Attempting next endpoint for pull after error: Get https://private-repo.local/v2/: dial tcp: lookup private-repo.local on [::1]:53: read udp [::1]:34343->[::1]:53: read: connection refused" time="2024-08-01T12:44:17.563816052Z" level=error msg="Handler for POST /v1.40/images/create returned error: Get https://private-repo.local/v2/: dial tcp: lookup private-repo.local on [::1]:53: read udp [::1]:34343->[::1]:53: read: connection refused"
需解决两个问题:让DIND容器访问主机网络接口,以及配置指定DNS服务器。
解决方案
1. 让DIND容器访问主机网络
在创建容器的OCI Spec中添加主机网络命名空间配置,让容器直接复用主机的网络栈,即可访问主机网络接口:
container, err := cli.NewContainer(ctx, containerName, containerd.WithImage(image), containerd.WithNewSnapshot(containerName+"-snapshot", image), containerd.WithNewSpec( oci.WithImageConfig(image), oci.WithPrivileged, oci.WithEnv(containerEnv), oci.WithMounts(mnts), // 启用主机网络命名空间 oci.WithHostNamespace(oci.NetworkNamespace), ), )
注意:使用主机网络后,容器端口会直接占用主机端口,需避免端口冲突。Kubernetes环境中,还需确保对应Pod配置了hostNetwork: true权限。
2. 配置指定DNS服务器
如果不需要完全依赖主机网络,或需自定义DNS规则,可通过以下两种方式配置:
方式一:通过OCI Spec直接设置DNS
使用oci.WithDNSConfig指定DNS服务器和搜索域:
dnsConfig := &oci.DNSConfig{ Nameservers: []string{"192.168.1.1", "8.8.8.8"}, // 替换为你的目标DNS地址 Search: []string{"your-domain.local"}, // 可选:添加DNS搜索域 } container, err := cli.NewContainer(ctx, containerName, containerd.WithImage(image), containerd.WithNewSnapshot(containerName+"-snapshot", image), containerd.WithNewSpec( oci.WithImageConfig(image), oci.WithPrivileged, oci.WithEnv(containerEnv), oci.WithMounts(mnts), // 注入自定义DNS配置 oci.WithDNSConfig(dnsConfig), ), )
方式二:挂载主机resolv.conf到容器
将主机的/etc/resolv.conf挂载到容器内同路径,让容器直接使用主机DNS配置:
// 在现有挂载列表中添加resolv.conf绑定挂载 mnts = append(mnts, oci.Mount{ Type: "bind", Source: "/etc/resolv.conf", Destination: "/etc/resolv.conf", Options: []string{"rbind", "ro"}, // 只读挂载避免容器修改主机配置 }) container, err := cli.NewContainer(ctx, containerName, containerd.WithImage(image), containerd.WithNewSnapshot(containerName+"-snapshot", image), containerd.WithNewSpec( oci.WithImageConfig(image), oci.WithPrivileged, oci.WithEnv(containerEnv), oci.WithMounts(mnts), ), )
DIND专属额外配置
DIND容器内的Docker daemon会继承容器的DNS配置,若仍有解析问题,可通过环境变量强制指定Docker daemon的DNS:
// 向容器环境变量中添加Docker daemon参数 containerEnv = append(containerEnv, "DOCKER_OPTS=--dns=192.168.1.1 --dns=8.8.8.8")
内容的提问来源于stack exchange,提问作者skj_27
相关产品推荐
相关产品推荐

