$ kubectl explain pod.spec.dnsPolicy KIND: Pod VERSION: v1
FIELD: dnsPolicy <string>
DESCRIPTION: Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. Possible enum values: - `"ClusterFirst"` indicates that the pod should use cluster DNS first unless hostNetwork is true, if it is available, then fall back on the default (as determined by kubelet) DNS settings. - `"ClusterFirstWithHostNet"` indicates that the pod should use cluster DNS first, if it is available, then fall back on the default (as determined by kubelet) DNS settings. - `"Default"` indicates that the pod should use the default (as determined by kubelet) DNS settings. - `"None"` indicates that the pod should use empty DNS settings. DNS parameters such as nameservers and search paths should be defined via DNSConfig.
默认 pod 就是 ClusterFirst 会使用 kubelet 配置的 clusterDNS 也就是 coredns 的 svc IP
// kubernetes/pkg/kubelet/network/dns/dns.go // GetPodDNS returns DNS settings for the pod. func(c *Configurer) GetPodDNS(pod *v1.Pod) (*runtimeapi.DNSConfig, error) { dnsConfig, err := c.getHostDNSConfig(c.ResolverConfig) if err != nil { returnnil, err }
dnsType, err := getPodDNSType(pod) if err != nil { klog.ErrorS(err, "Failed to get DNS type for pod. Falling back to DNSClusterFirst policy.", "pod", klog.KObj(pod)) dnsType = podDNSCluster } switch dnsType { case podDNSNone: // DNSNone should use empty DNS settings as the base. dnsConfig = &runtimeapi.DNSConfig{} case podDNSCluster: iflen(c.clusterDNS) != 0 { // For a pod with DNSClusterFirst policy, the cluster DNS server is // the only nameserver configured for the pod. The cluster DNS server // itself will forward queries to other nameservers that is configured // to use, in case the cluster DNS server cannot resolve the DNS query // itself. dnsConfig.Servers = []string{} for _, ip := range c.clusterDNS { dnsConfig.Servers = append(dnsConfig.Servers, ip.String()) } dnsConfig.Searches = c.generateSearchesForDNSClusterFirst(dnsConfig.Searches, pod) dnsConfig.Options = defaultDNSOptions break } // clusterDNS is not known. Pod with ClusterDNSFirst Policy cannot be created. nodeErrorMsg := fmt.Sprintf("kubelet does not have ClusterDNS IP configured and cannot create Pod using %q policy. Falling back to %q policy.", v1.DNSClusterFirst, v1.DNSDefault) c.recorder.Eventf(c.nodeRef, v1.EventTypeWarning, "MissingClusterDNS", nodeErrorMsg) c.recorder.Eventf(pod, v1.EventTypeWarning, "MissingClusterDNS", "pod: %q. %s", format.Pod(pod), nodeErrorMsg) // Fallback to DNSDefault. fallthrough case podDNSHost: // When the kubelet --resolv-conf flag is set to the empty string, use // DNS settings that override the docker default (which is to use // /etc/resolv.conf) and effectively disable DNS lookups. According to // the bind documentation, the behavior of the DNS client library when // "nameservers" are not specified is to "use the nameserver on the // local machine". A nameserver setting of localhost is equivalent to // this documented behavior. if c.ResolverConfig == "" { for _, nodeIP := range c.nodeIPs { if utilnet.IsIPv6(nodeIP) { dnsConfig.Servers = append(dnsConfig.Servers, "::1") } else { dnsConfig.Servers = append(dnsConfig.Servers, "127.0.0.1") } } iflen(dnsConfig.Servers) == 0 { dnsConfig.Servers = append(dnsConfig.Servers, "127.0.0.1") } dnsConfig.Searches = []string{"."} } }
var ( // Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"} defaultIPv6Dns = []string{"nameserver 2001:4860:4860::8888", "nameserver 2001:4860:4860::8844"} ...
// FilterResolvDNS cleans up the config in resolvConf. It has two main jobs: // 1. It looks for localhost (127.*|::1) entries in the provided // resolv.conf, removing local nameserver entries, and, if the resulting // cleaned config has no defined nameservers left, adds default DNS entries // 2. Given the caller provides the enable/disable state of IPv6, the filter // code will remove all IPv6 nameservers if it is not enabled for containers funcFilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) { cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{}) // if IPv6 is not enabled, also clean out any IPv6 address nameserver if !ipv6Enabled { cleanedResolvConf = nsIPv6Regexp.ReplaceAll(cleanedResolvConf, []byte{}) } // if the resulting resolvConf has no more nameservers defined, add appropriate // default DNS servers for IPv4 and (optionally) IPv6 iflen(GetNameservers(cleanedResolvConf, IP)) == 0 { log.G(context.TODO()).Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: %v", defaultIPv4Dns) dns := defaultIPv4Dns if ipv6Enabled { log.G(context.TODO()).Infof("IPv6 enabled; Adding default IPv6 external servers: %v", defaultIPv6Dns) dns = append(dns, defaultIPv6Dns...) } cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...) } return &File{Content: cleanedResolvConf, Hash: hashData(cleanedResolvConf)}, nil }
所以 /etc/resolv.conf 为空,docker 创建容器会追加谷歌 DNS,开头由来章节的日志就是本地复现的日志,避免手段就主要是利用 kubelet 在 case 后的逻辑判断:
1 2 3
if pod.Spec.DNSConfig != nil { dnsConfig = appendDNSConfig(dnsConfig, pod.Spec.DNSConfig) }