Kubernetes DNS 高阶指南(转发别人 解析很详细)

时间:2021-05-03 09:44:37

转发地址:http://www.jintiankansha.me/t/Js1R84GGAl

DNS 是 Kubernetes 的核心功能之一,Kubernetes 通过 kube-dns 或  CoreDNS 作为集群的必备扩展来提供命名服务,通过 DNS 扩展,每一个 Service 都会产生一个独一无二的 FQDN(Fully Qualified Domain Name)名称。

在大多数使用场景下,我们并不会太关心 DNS 插件的内部运作细节,直接使用 Kubernetes 预设的 DNS 配置和策略就可以满足需求。然而随着使用场景越来越复杂,譬如跟 NFV(Network Function Virtualization)相关的场景,我们的应用(Pod)可能就会需要更加个性化的 DNS 配置。

接下来使用下面这张架构图来说明可能的使用场景:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

1. 为什么需要自定义 DNS

一般的使用场景下,我们的 Kubernetes 集群的使用方式就像图中紫色/粉红色(Pod3)区域一样,所有的 Pod 如果有任何要存取 DNS 的需求,都会透过集群内的的  k8s DNS 来处理对应的请求与回复。

然而在 NFV 的使用场景下,网络变成一个很重要的区域,整体的性能都取决于该应用的设计与集群的网络架构设计。这部分应用通常都会追求高输出或是低延迟,为了得到更好的性能,需要避免这些流量跟其他无关的流量使用相同的网络线路进行传输。

在这种情况下,通常就会把整个集群的网络设计成两种架构,分别是 Control Network 和  Data Network 这两个不同用途的网络架构。在 Kubernetes 中,Control Network 就类似于图中的  Cluster Network,负责整个集群之间的沟通。图中绿色/橘色(Pod1,Pod2)这两个区域就是所谓的 Data Network,其网卡本身也被独立出来,不会与本来的 Kubernetes 集群发生冲突,它们之间的流量通过独立的网络进行传输。

存在于独立出来的网络架构中的这些特殊的 Pod 基本上没法跟 Kubernetes 集群内的 DNS 互连,而且这些应用还有可能在外部有自己的 DNS Server,所以在这种场景下,我们希望这些应用(Pod1/Pod2)能够使用自定义的  DNS Server

2. 如何自定义 DNS

为了让用户更容易控制 Pod 中的 DNS 设置,Kubernetes v1.9 引入了一项新的 Alpha 特性(在 v1.10 中处于 Beta 阶段)。该特性在 v1.10 中被默认启用,在 v1.9 中如果想要启用此功能,集群管理员需要在 apiserver 和 kubelet 上启用 CustomPodDNS 特性,例如: “--feature-gates=CustomPodDNS=true,...”。启用了该特性之后,用户可以将 Pod 的 dnsPolicy 字段设置为  "None",并且可以在 Pod.Spec 中添加新的字段  dnsConfig

其中 dnsConfig 用来自定义 DNS 参数,而 dnsPolicy 用来给 Pod 选取预设的 DNS。接下来就看看可以通过哪些手段自定义 DNS。

dnsConfig

dnsConfig 可以让操作者延伸到 Pod 内部关于 DNS 的配置,这边需要特别注意的是,我使用的字眼是 延伸 而不是 配置,这是因为通过下一节的 dnsPolicy,每个 Pod 都会有一组预设的 DNS 配置。通过 dnsConfig 我们可以继续往上迭加相关的 DNS 参数到 Pod 之中。

目前总共支持三个参数,分别是:

  • nameservers

  • searches

  • options

这三个参数对应的就是大家熟悉的 /etc/resolv.conf 里面的三个参数,这里就不针对 DNS 进行详细解释了,不熟悉的朋友可以自行去 Google 学一下这些参数的意思。

在 Kubernetes 里面,这三个参数都包含在 dnsConfig 配置项中,而 dnsConfig 包含在 PodSpec 配置项中,因为 Pod 内所有的容器都共享相同的 Network Namespace,所以网络方面的配置都会共享。

这边提供一个简单的 yaml 示例:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

通过上述 yaml 创建 Pod 之后,通过下面的命令可以观察到容器中 DNS 配置文件中会出现额外的配置。

$ kubectl exec ubuntu-setting cat /etc/resolv.confnameserver 10.254.0.2nameserver 1.2.3.4search default.svc.cluster.local svc.cluster.local cluster.local ns1.svc.cluster.local my.dns.search.suffixoptions ndots:2 edns0

可以看到 nameserver 多了一个 1.2.3.4,而 search 则多了 ns1.svc.cluster.local my.dns.search.suffix 这两个自定义的值,最后 options 则增加了我们示例中指定的 ndots:2 edns0

dnsConfig 非常简单直观,如果你需要自定义 DNS 参数,就可以通过这个字段来指定。

dnsPolicy

前面提过,dnsConfig 提供的是延伸 Pod 内预设的 DNS 配置,而 dnsPolicy 就是决定 Pod 内预设的 DNS 配置有哪些。

目前总共有四个类型可以选择:

  • None

  • Default

  • ClusterFirst

  • ClusterFirstHostNet

接下来针对这四个类型分别介绍。

None

None 表示会清除 Pod 预设的 DNS 配置,当 dnsPolicy 设置成这个值之后,Kubernetes 不会为 Pod 预先载入任何自身逻辑判断得到的 DNS 配置。因此若要将 dnsPolicy 的值设为 None,为了避免 Pod 里面没有配置任何 DNS,最好再添加 dnsConfig 来描述自定义的 DNS 参数。

使用下面的示例来进行测试:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

通过上述 yaml 创建 Pod 之后,通过下面的命令可以观察容器中的 DNS 配置文件,可以观察到跟之前的 dnsConfig 的结果有一点差异,这里只有我们在 yaml 里配置的那些参数,而没有加入集群预设的 DNS 配置。

$ kubectl exec ubuntu-none cat /etc/resolv.confnameserver 1.2.3.4search ns1.svc.cluster.local my.dns.search.suffixoptions ndots:2 edns0

Default

Default 表示 Pod 里面的 DNS 配置继承了宿主机上的 DNS 配置。简单来说,就是该 Pod 的 DNS 配置会跟宿主机完全一致。

使用下面的示例来进行测试:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

首先,我们先观察 Node 上面的 DNS 配置:

$ cat /etc/resolv.conf# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTENnameserver 10.0.2.3

可以观察到,Node 上面的 DNS 配置得很简单,只有单纯的 10.0.2.3。 接下来我们观察该 Pod 内的 DNS 配置:

$ kubectl exec ubuntu-default cat /etc/resolv.confnameserver 10.0.2.3

可以看到这两个的 DNS 配置完全一致,该 Pod 内的 DNS 配置已经直接继承 Node 上面的配置了。

ClusterFirst

相对于上述的 Default,ClusterFirst 是完全相反的操作,它会预先把  kube-dns(或 CoreDNS)的信息当作预设参数写入到该 Pod 内的 DNS 配置。

ClusterFirst 是预设的行为,若没有在 Pod 內特別描述 PodPolicy, 则会将 dnsPolicy 预设为 ClusterFirst。

使用下面的示例来进行测试:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

通过上述 yaml 创建 Pod 之后,通过下面的命令观察容器中的 DNS 配置文件:

$ kubectl exec ubuntu-clusterfirst cat /etc/resolv.confnameserver 10.254.0.2search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5

可以看到这里使用的是 k8s DNS 的设置。

此外,ClusterFirst 还有一个冲突,如果你的 Pod 设置了 HostNetwork=true,则 ClusterFirst 就会被强制转换成 Default

HostNetwork

使用下面的示例来进行测试:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

通过上述 yaml 创建 Pod 之后,通过下面的命令观察容器中的 DNS 配置文件:

$ kubectl exec ubuntu-hostnetwork-policy-default cat /etc/resolv.confnameserver 10.0.2.3

可以观察到,Pod 里面的 DNS 配置直接继承了宿主机上的 DNS 配置。

这边稍微来解释一下这个设计上的原理以及流程:

  1. 因为设置了 HostNetwork=true , 会让该 Pod 与该节点共用相同的网路空间(网卡/路由等功能)。

  2. 预设的 k8s DNS 是使用 ClusterIP  的 kubernetes serivce. 这种情况下,只有属于 Cluster 內的 Pod  可以获取该 ClusterIP。

  3. 所以设置了 HostNetwork=true  的 Pod 就没有办法获取该 ClusterIP。

  4. 于是预设就会将对应的 DNS 配置改回 Default  的形式,从节点继承其 DNS 配置信息。

这种情况下,就会有人想要问,如果我刻意想要这样设置不行吗?

原先的设计中,是没有办法刻意处理的,原因是当 Pod yaml 配置文件被发送出去后,在发现没有设定  dnsPolicy 的情况下,会自动帮你把该 dnsPolicy 补上 ClusterFirst 的数值。

然后最后面的程序处理逻辑中,其实並没有办法分別下列两种情况:

  1. HostNetwork:我希望走 Host DNS

  2. HostNetwork & dnsPolicy=ClusterFirst:我希望走 ClusterIP DNS

上述两种情况对于后端的程序来看都长得一样,完全没有办法分辨,我们可以直接从 Kubernetes 源码 来阅读一下其运作流程:

func getPodDNSType(pod *v1.Pod) (podDNSType, error) {    dnsPolicy := pod.Spec.DNSPolicy    switch dnsPolicy {    case v1.DNSNone:        if utilfeature.DefaultFeatureGate.Enabled(features.CustomPodDNS) {            return podDNSNone, nil        }        // This should not happen as kube-apiserver should have rejected        // setting dnsPolicy to DNSNone when feature gate is disabled.        return podDNSCluster, fmt.Errorf(fmt.Sprintf("invalid DNSPolicy=%v: custom pod DNS is disabled", dnsPolicy))    case v1.DNSClusterFirstWithHostNet:        return podDNSCluster, nil    case v1.DNSClusterFirst:        if !kubecontainer.IsHostNetworkPod(pod) {            return podDNSCluster, nil        }        // Fallback to DNSDefault for pod on hostnetowrk.        fallthrough    case v1.DNSDefault:        return podDNSHost, nil    }    // This should not happen as kube-apiserver should have rejected    // invalid dnsPolicy.    return podDNSCluster, fmt.Errorf(fmt.Sprintf("invalid DNSPolicy=%v", dnsPolicy))}

这边可以看到一旦是 DNSClusterFirst 的情况下,若设置了 HostNetwork, 最后就会直节回传 podDNSHost 节点的 DNS 设定回去。

为了解决上述的问题,所以引进了一个新的类型 ClusterFirstHostNet

ClusterFirstWithHostNet

ClusterFirstWithHostNet 用途非常简单,我希望满足使用 HostNetwork 同时使用 k8s DNS 作为我 Pod 预设 DNS 的配置。

根据上面的源码也可以观察到:


case v1.DNSClusterFirstWithHostNet:    return podDNSCluster, nil

只要將 dnsPolicy 设置为 ClusterFirstWithHostNet, 就会一律返回 k8s DNS 的 clusterIP 这种形式。

使用下面的示例来进行测试:

Kubernetes DNS 高阶指南(转发别人 解析很详细)

通过上述 yaml 创建 Pod 之后,通过下面的命令观察该 Pod 的状态:

$ kubectl exec ubuntu-hostnetwork-policy cat /etc/resolv.confnameserver 10.254.0.2search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5

可以发现这时候的 DNS 就会配置成 k8s DNS 的 ClusterIP 了。

Kubernetes DNS 高阶指南(转发别人 解析很详细)的更多相关文章

  1. React 精要面试题讲解(五) 高阶组件真解

    说明与目录 在学习本章内容之前,最好是具备react中'插槽(children)'及'组合与继承' 这两点的知识积累. 详情请参照React 精要面试题讲解(四) 组合与继承不得不说的秘密. 哦不好意 ...

  2. React组件重构:嵌套+继承 与 高阶组件

    前言 在最近做的一个react项目中,遇到了一个比较典型的需要重构的场景:提取两个组件*同的部分. 最开始通过使用嵌套组件和继承的方式完成了这次重构. 但是后来又用高阶组件重新写了一遍,发现更好一点 ...

  3. Kotlin——高级篇(二):高阶函数详解与标准的高阶函数使用

    在上面一个章节中,详细的讲解了Kotlin中关于Lambda表达式的语法以及运用,如果还您对其还不甚理解,请参见Kotlin--高级篇(一):Lambda表达式详解.在这篇文章中,多次提到了Kotli ...

  4. php对象和数组的相互转换(还是可以去找没有没php的高阶课程看看看)(要不别人分析一下重点要点,要不自己来,不然 效果真的不好)

    php对象和数组的相互转换(还是可以去找没有没php的高阶课程看看看)(要不别人分析一下重点要点,要不自己来,不然 效果真的不好) 一.总结 都是自己实现的函数 算法: 1.先判断类型,gettype ...

  5. 《JS权威指南学习总结--8.8.2高阶函数》

    内容要点: 所谓高阶函数(higher-order function)就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 例1: //这个高阶函数返回一个新的函数,这个新函数将它的实 ...

  6. vue源码cached高阶函数解析

    1.源代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...

  7. DNS的主从,转发与负载功能

    接着原来<DNS原理与应用>的文章,本章内容主要通过实现DNS的主从,转发,及基于域名解析不同的ip实现后端服务负载均衡的效果.最后再实现DNS的高级功能:类似CDN原理实现基于IP实现区 ...

  8. 高阶组件(Higher-Order Components)

    有时候人们很喜欢造一些名字很吓人的名词,让人一听这个名词就觉得自己不可能学会,从而让人望而却步.但是其实这些名词背后所代表的东西其实很简单. 我不能说高阶组件就是这么一个东西.但是它是一个概念上很简单 ...

  9. 《React后台管理系统实战 :一》:目录结构、引入antd、引入路由、写login页面、使用antd的form登录组件、form前台验证、高阶函数&sol;组件

    实战 上接,笔记:https://blog.csdn.net/u010132177/article/details/104150177 https://gitee.com/pasaulis/react ...

随机推荐

  1. VS2012创建UML项目

    1.选择建模工具 2.添加新建项 3.添加UML图或用例图 4.打开工具箱添加

  2. DOM系列---DOM操作表格

    DOM在操作生成HTML上,还是比较简明的.不过,由于浏览器总是存在兼容和陷阱,导致最终的操作就不是那么简单方便了.本篇章主要了解一下DOM操作表格. 一.操作表格 <table>标签是H ...

  3. 一个ListBox的例子

    1.向ListBox中放入其他控件 XAML: <Window x:Class="ItemsControls.MainWindow" xmlns="http://s ...

  4. Spring配置事务 http&colon;&sol;&sol;www&period;cnblogs&period;com&sol;leiOOlei&sol;p&sol;3725911&period;html

    http://www.cnblogs.com/leiOOlei/p/3725911.html JNDI方式配置数据源: <?xml version="1.0" encodin ...

  5. ArcGIS Runtime SDK for Android 10&period;2&period;5新开发平台安装配置指南

    ArcGIS Runtime SDK for Android 10.2.5版本在年前发布,其中一个重大的变化是:新版本使用了新的开发环境,在10.2.5版本中Esri使用了官方提供的新的Android ...

  6. sqlplus handbook

    1.直接敲sqlplus并回车就是启动SQL*PLUS,输入user及password将使用户登陆到缺省的数据库. 请输入用户名: 2.sqlplus user/password@SERVICE_NA ...

  7. linux基础命令整理

    1  显示当前工作目录                pwd 2  查看目录下的所有内容          ls        ls   -l   以列方式查看        ls  -a  显示所有 ...

  8. kafka集群扩容后的topic分区迁移

    https://www.cnblogs.com/honeybee/p/5691921.html kafka集群扩容后,新的broker上面不会数据进入这些节点,也就是说,这些节点是空闲的:它只有在创建 ...

  9. Docker容器技术-Docker架构

    一.Docker系统架构 1.Docker基础架构 1)Docker守护进程 负责容器的创建.运行和监控,以及镜像的构建和存储. docker daemon 2)Docker客户端 通过HTTP与Do ...

  10. &lbrack;bzoj&rsqb; 1043 下落的圆盘 &vert;&vert; 圆上的&OpenCurlyDoubleQuote;线段覆盖”

    原题 n个圆盘,求下落后能看到的总周长. 红色即为所求 借鉴于黄学长的博客 对于每下落的一个圆盘,处理他后面的圆盘会挡住哪些区域,然后把一整个圆(2\(/pi\))当做一整个区间,每个被覆盖的部分都可 ...