Podman `--dns` 选项全解:自定义容器 DNS 服务器、`none` 特殊值、`/etc/resolv.conf` 生成机制与 aardvark-dns 转发原理
Podman `--dns` 选项全解:自定义容器 DNS 服务器、`none` 特殊值、`/etc/resolv.conf` 生成机制与 aardvark-dns 转发原理
📅 发布时间:2026/9/20 4:07:38👁 浏览次数:
容器运行时云原生CLI【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址https://gitcode.com/gh_mirrors/po/podman点击查看免费下载导读--dns*ipaddr*是 Podman 中用于为容器container、Pod、镜像构建build以及网络network设置自定义 DNS 服务器的核心网络选项。本文基于 Podman 仓库的官方选项文档 docs/source/markdown/options/dns.md 展开深入讲解该选项的语义、特殊值none的行为、/etc/resolv.conf的生成与绑定挂载过程并结合源码剖析在 netavark/aardvark-dns 环境下的实际转发链路。读完本文你将掌握--dns在podman run/create/build/network create等命令中的正确用法、与--dns-search、--dns-option的配合关系以及遇到宿主机 DNS 配置失效如127.0.0.1时的标准解决方案。说明docs/source/markdown/options/dns.md属于 Podman 的共享选项文件option file体系同一份内容会被同时注入到podman run、podman create、podman build、podman farm build、podman network create以及 Pod 相关命令podman-pod的文档中。因此下文所有命令行用法对上述命令均成立仅在 Quadlet 单元文件中对应不同的键名写法。一、选项语义覆盖传入容器的 DNS 配置根据 dns.md 的原始定义Set custom DNS servers. This option can be used to override the DNS configuration passed to the container.--dns*ipaddr*用于设置自定义 DNS 服务器其作用是覆盖 Podman 默认传递给容器的 DNS 配置。选项接受逗号分隔的多个 IP 地址例如# 为容器指定两组公共 DNS 服务器 podman run --dns8.8.8.8,8.8.4.4 --rm docker.io/library/alpine cat /etc/resolv.conf# 使用本地缓存 DNS podman run --dns192.168.1.1 --dns192.168.1.2 --rm docker.io/library/alpine cat /etc/resolv.conf1.1 何时必须使用--dns宿主机 DNS 失效场景文档中特别强调了一个典型场景——宿主机 DNS 配置对容器无效例如宿主机/etc/resolv.conf中写着127.0.0.1Typically this is necessary when the host DNS configuration is invalid for the container (e.g.,127.0.0.1). When this is the case, the--dnsflag is necessary for every run.当宿主机通过 systemd-resolved 等本地解析器监听127.0.0.53/127.0.0.1时这个回环地址在容器网络命名空间内并不指向宿主机上的解析器容器内的 DNS 解析会直接失败。此时需要在每次运行时都显式传入--dns指定一个容器可达的 DNS 服务器# 宿主机 resolv.conf 指向 127.0.0.x 时的标准做法 podman run --dns8.8.8.8 --rm docker.io/library/alpine nslookup example.com这一“每次运行都需要”的提示也从侧面解释了为什么 Podman 提供了默认值注入机制见下文“默认值与 containers.conf”一节可以在系统层面批量解决而不必每次手写标志。1.2 标志的底层定义从源码看--dns标志在 cmd/podman/common/netflags.go 中定义为一个StringSlice字符串切片类型标志dnsFlagName : dns netFlags.StringSlice( dnsFlagName, podmanConfig.ContainersConf.DNSServers(), Set custom DNS servers, ) _ cmd.RegisterFlagCompletionFunc(dnsFlagName, completion.AutocompleteNone)值得注意的两个实现细节该标志的默认值并非空而是取自podmanConfig.ContainersConf.DNSServers()即containers.conf中的dns_servers配置项该标志注册了AutocompleteNone完成函数意味着 CLI 不会对该参数做基于路径或命令的自动补全因为它是自由格式的 IP 地址。二、特殊值none完全禁用 resolv.conf 生成文档中定义了--dns最重要的特殊值The special valuenonecan be specified to disable creation of/etc/resolv.confin the container by Podman. The/etc/resolv.conffile in the image is then used without changes.即# 禁用 Podman 生成 resolv.conf直接使用镜像自带的版本 podman run --dnsnone --rm docker.io/library/alpine cat /etc/resolv.conf使用none后Podman不会在容器内创建并绑定挂载/etc/resolv.conf而是原样保留镜像中的/etc/resolv.conf。这在以下场景非常有用镜像内自带经过定制的 DNS 配置不希望被宿主机/网络后端覆盖容器运行在完全不依赖 DNS 的环境如仅使用 IP 直连的服务需要彻底复现镜像自带的解析行为。2.1none在源码中的处理路径--dnsnone的解析逻辑位于 cmd/podman/common/netflags.goif flags.Changed(dns) { servers, err : flags.GetStringSlice(dns) if err ! nil { return nil, err } for _, d : range servers { if d none { opts.UseImageResolvConf true if len(servers) 1 { return nil, fmt.Errorf(%s is not allowed to be specified with other DNS ip addresses, d) } break } dns : net.ParseIP(d) if dns nil { return nil, fmt.Errorf(%s is not an ip address, d) } opts.DNSServers append(opts.DNSServers, dns) } }该实现揭示了三个关键行为none与 IP 不能混用只要传入列表中出现none若同时还有其他 DNS 地址会直接报错none is not allowed to be specified with other DNS ip addresses。因此--dnsnone,8.8.8.8是非法的none设置的是内部标志而非 DNS 条目它把UseImageResolvConf置为true即“使用镜像自带的 resolv.conf”其余值必须是合法 IP非none的值都会经过net.ParseIP校验非法 IP 会被拒绝并提示is not an ip address。UseImageResolvConf标志定义于 libpod/container_config.go// UseImageResolvConf indicates that resolv.conf should not be // bind-mounted into the container UseImageResolvConf bool2.2none与其他 DNS 选项的互斥校验使用镜像自带 resolv.conf 时Podman 会拒绝同时配置其他 DNS 相关参数。校验位于 libpod/container_validate.go// Using image resolv.conf conflicts with various DNS settings. if c.config.UseImageResolvConf (len(c.config.DNSSearch) 0 || len(c.config.DNSServer) 0 || len(c.config.DNSOption) 0) { return fmt.Errorf(cannot configure DNS options if using images resolv.conf: %w, define.ErrInvalidArg) }而在 specgen 层客户端生成容器 spec 时也有等价校验见 pkg/specgen/container_validate.goif s.UseImageResolvConf ! nil *s.UseImageResolvConf { ... return exclusiveOptions(UseImageResolvConf, DNSServer) ... return exclusiveOptions(UseImageResolvConf, DNSSearch) ... return exclusiveOptions(UseImageResolvConf, DNSOption) }结论--dnsnone不能与--dns其他 IP、--dns-search、--dns-option同时使用否则 Podman 会以参数错误拒绝创建容器。三、/etc/resolv.conf的生成机制与绑定挂载3.1 挂载时机在 libpod/container_internal_common.go 中Podman 在容器启动流程里判断是否需要为容器创建 resolv.confif c.config.NetNsCtr ! (!c.config.UseImageResolvConf || !c.config.UseImageHosts) { ... } if !c.config.UseImageResolvConf { if err : c.createResolvConf(); err ! nil { ... } }即只要UseImageResolvConf为false未指定--dnsnonePodman 就会主动创建并绑定挂载 resolv.conf。createResolvConflibpod/container_internal_common.go的实现是在容器的 RunDir 下新建一个resolv.conf文件然后通过bindMountRootFile将其绑定挂载到容器内的/etc/resolv.conffunc (c *Container) createResolvConf() error { destPath : filepath.Join(c.state.RunDir, resolv.conf) f, err : os.Create(destPath) if err ! nil { return err } f.Close() return c.bindMountRootFile(destPath, resolvconf.DefaultResolvConf) }3.2 内容的组装优先级真正写入 resolv.conf 内容的函数是addResolvConflibpod/container_internal_common.go。其核心逻辑可归纳为以下优先级网络状态中的 nameserver 优先Podman 从每个已连接网络的netStatusStatusBlock中收集DNSServerIPs与DNSSearchDomains。在 netavark 网络后端下只要容器连接了启用了 DNS 的网络网络状态中就会携带 aardvark-dns 的 nameserverPodman 会优先写入网络返回的 nameserver源码注释明确引用了 netavark PR #452 与 podman issue #16172 的演进背景自定义--dns的兜底当网络状态中没有可用的 nameserver例如容器未连接任何启用 DNS 的网络时才会依次拼接containers.conf的dns_servers与命令行传入的DNSServer保留宿主机服务器的例外当既无网络 nameserver 也无自定义 DNS 时keepHostServers true将宿主机/etc/resolv.conf的 nameserver 写入对于 pasta 网络模式则使用 pasta 内置的 DNS 转发器addSpecialDNSsearch 域合并--dns-search与containers.conf的dns_searches会合并写入search行container_internal_common.gooptions 行--dns-option与containers.conf的dns_options合并写入options行container_internal_common.go。最终通过resolvconf.New(...)组装成完整的 resolv.conf 内容并写入绑定挂载目标路径。3.3 与--dns相关的姊妹选项--dns通常与以下两个选项配合使用均为同一套共享选项文件体系选项作用Quadlet 键文档--dns*ipaddr*设置自定义 DNS 服务器DNSdns.md--dns-search*domain*设置自定义 DNS 搜索域--dns-search.可移除搜索域DNSSearchdns-search.container.md--dns-option*option*设置自定义 DNS 选项如ndots:2、timeout:3DNSOptiondns-option.container.md需要注意两个限制见 dns-search.container.md 与 dns-option.container.md--dns-search与--dns-option在--networknone或--networkcontainer:*id*模式下无效--dns-search.用于显式移除搜索域避免容器继承宿主机搜索域。对应地podman build含podman farm build阶段使用 dns-search.image.md 与 dns-option.image.md 中的“during the build”语义版本。构建阶段同样禁止--networknone与 DNS 选项组合使用该校验在 cmd/podman/common/build.goif cmd.Flag(dns).Changed { return nil, errors.New(the --dns option cannot be used with --networknone) } if cmd.Flag(dns-option).Changed { return nil, errors.New(the --dns-option option cannot be used with --networknone) } if cmd.Flag(dns-search).Changed { return nil, errors.New(the --dns-search option cannot be used with --networknone) }四、aardvark-dns 环境下的转发行为文档中对“自定义 DNS 是否直接写入容器 resolv.conf”给出了重要说明Note thatipaddrmay be added directly to the containers/etc/resolv.conf. This is not guaranteed though. For example, passing a custom network whosedns_enabledis set totrueto--networkwill result in/etc/resolv.confonly referring to the aardvark-dns server. aardvark-dns then forwards to the suppliedipaddrfor all non-container name queries.翻译并展开解释行为不确定--dns传入的 IP可能被直接写进容器的/etc/resolv.conf但这不是保证行为典型反例当你通过--network连接一个dns_enabledtrue的自定义网络时容器内的/etc/resolv.conf只会指向 aardvark-dns 服务器通常是网络内的一个固定地址--dns提供的 IP不会直接出现在 resolv.conf 的nameserver行中转发机制此时 aardvark-dns 承担“DNS 代理”角色——对于非容器名称的查询即普通域名它会转发给--dns指定的 IP对于容器名称如同一 Pod/网络内其他容器的名字则直接在 Podman 网络内解析。这一设计让容器内 DNS 解析在“容器名解析aardvark-dns 直答”与“外部域名解析aardvark-dns 转发到上游”之间实现统一出口配合第三节介绍的“网络 nameserver 优先”策略libpod/container_internal_common.go从源码上印证了文档所述行为。4.1 网络创建时的 DNS 服务器在podman network create中同样存在 DNS 相关选项见 cmd/podman/networks/create.goflags.BoolVar(networkCreateOptions.DisableDNS, disable-dns, false, disable dns plugin) dnsserverFlagName : dns flags.StringSliceVar(networkCreateOptions.NetworkDNSServers, dnsserverFlagName, nil, DNS servers this network will use)# 创建一个启用了内置 DNS 插件、并将上游 DNS 指向公共服务器的网络 podman network create --dns8.8.8.8 --dns1.1.1.1 mynet创建的NetworkDNSServers会写入网络配置cmd/podman/networks/create.go后续连接该网络的容器即自动获得网络级 DNS 配置与文档中“自定义网络 dns_enabledtrue 时由 aardvark-dns 统一转发”的描述相互印证。五、默认值与 containers.conf一次配置、全部生效--dns标志的默认值来自containers.conf的dns_servers配置见第一节源码。与之对应的还有dns_searches与dns_options三者共同构成 Podman 的默认 DNS 策略# containers.conf节选 [containers] # 所有容器默认使用的 DNS 服务器 dns_servers [8.8.8.8] # 所有容器默认使用的 DNS 搜索域 # dns_searches [example.com] # 所有容器默认附加的 DNS 选项 # dns_options [ndots:2]设置后每次podman run都会自动带上这些 DNS 配置无需手写--dns——这正是文档所说“宿主机 DNS 配置无效时需要每次指定--dns”问题的系统性解法。命令行标志会叠加或覆盖默认值nameserver 部分在无网络 nameserver 时按“默认值在前、命令行值在后”的顺序合并见 libpod/container_internal_common.go。六、Quadlet 单元文件中的 DNS 配置在 Systemd Quadlet 单元文件中--dns对应键为DNS相关键定义于 pkg/systemd/quadlet/quadlet.goKeyDisableDNS DisableDNS KeyDNS DNS KeyDNSOption DNSOption KeyDNSSearch DNSSearch示例.container单元[Container] Imagedocker.io/library/nginx DNS8.8.8.8 DNSSearchexample.com DNSOptionndots:2DNS对应--dnsDNSSearch对应--dns-searchDNSOption对应--dns-option网络相关的DisableDNS对应podman network create --disable-dns。七、完整用法速查以下汇总--dns在不同命令下的标准用法# 1) 运行容器时指定 DNS podman run --dns8.8.8.8 --dns8.8.4.4 docker.io/library/alpine # 2) 创建容器时指定 DNS podman create --dns1.1.1.1 --name dns-test docker.io/library/alpine # 3) 构建镜像时指定 DNS仅构建阶段生效 podman build --dns8.8.8.8 -t myimage . # 4) 使用镜像自带 resolv.conf不生成/不挂载 podman run --dnsnone docker.io/library/alpine # 5) 创建自定义网络并指定上游 DNS podman network create --dns8.8.8.8 mynet # 6) 组合使用 search 域与 options podman run --dns8.8.8.8 --dns-searchexample.com --dns-optionndots:2 docker.io/library/alpine常见错误与规避错误用法结果--dnsnone,8.8.8.8报错none is not allowed to be specified with other DNS ip addresses--dnsabc非 IP报错abc is not an ip address--dnsnone --dns-searchexample.com报错cannot configure DNS options if using images resolv.confpodman build --dns8.8.8.8 --networknone报错the --dns option cannot be used with --networknone--networknone或--networkcontainer:id时使用--dns-option/--dns-search无效文档明确标注 Invalid八、总结与排查思路--dns是 Podman 网络栈中管理容器 DNS 的入口之一其核心机制可以归纳为三点覆盖能力用自定义 IP 覆盖宿主机传递的可能对容器无效的DNS 配置是解决127.0.0.1类宿主机 DNS 失效问题的标准手段none旁路--dnsnone通过UseImageResolvConf标志跳过 resolv.conf 的生成与绑定挂载直接使用镜像内配置且与--dns-search、--dns-option互斥后端协作在 netavark aardvark-dns 环境下--dns的 IP 不一定会直接出现在容器 resolv.conf 中而是由 aardvark-dns 统一代理转发容器名解析与外部域名解析共用同一出口。排查容器 DNS 问题时建议依次检查容器内cat /etc/resolv.conf实际内容 → 确认是否连接了dns_enabledtrue的网络决定 IP 是否直写→ 核对containers.conf默认值 → 确认是否误用--dnsnone。结合本文的源码路径netflags.go、container_internal_common.go、container_validate.go即可快速定位问题所在。赞分享容器运行时云原生CLI【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址https://gitcode.com/gh_mirrors/po/podman点击查看免费下载相关推荐Podman --dns-option 详解为容器自定义 /etc/resolv.conf 的 DNS 选项Podman dns option 详解为容器自定义 /etc/resolv.conf 的 DNS 选项 dns option 是 Podman 网络选项家族容器运行时云原生CLIPodman --dns-search 选项完全指南自定义容器 DNS 搜索域Podman dns search 选项完全指南自定义容器 DNS 搜索域 导读 本文围绕 Podman 容器与 Pod 的 dns search 网络选项展容器运行时云原生CLITechnitium DNS Server自定义DNS转发器列表功能解析Technitium DNS Server自定义DNS转发器列表功能解析 DNS服务器作为网络基础设施的核心组件其转发器配置的便捷性直接影响运维效率。Tech网络后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考