容器服务 从 kube-dns 切换到 CoreDNS

低版本的 kube-dns 存在一些潜在问题,例如1. 依赖库 miekg/dns 存在 bug,导致 kube-dns 在处理 /etc/resolv.conf 中的某些特定 option 时会发生 panic。

相关产品
容器服务 产品页,含版本规格、价格与购买入口。

2. 依赖库 client-go 的版本较低,不支持 周期性刷新 token 的功能,导致 kube-dns 在访问 kube-apiserver 时无法进行鉴权。因此,我们建议你将集群中的 kube-dns 切换到 CoreDNS。

这篇档提供了一种尽可能平滑、对业务无感知的方式,来完成将集群中的 kube-dns 切换到 CoreDNS 的过程。

一、前置说明

·集群 Kubernetes 版本不低于1.12。

·在切换到 CoreDNS 之前,请根据集群的 Kubernetes 版本选择最适合的 CoreDNS 版本。详情请参见 选择最佳 CoreDNS 版本。

·如果集群的 kube-proxy 正在使用 IPVS 模式,在 kube-dns 缩容阶段,由于 IPVS UDP 会话超时,可能会导致 DNS 解析失败的概率性问题。为了缩短解析失败的持续时间,使切换过程尽可能平滑,请配置 IPVS UDP 会话保持的超时时间。由于 kube-dns 不具备像 CoreDNS 一样的优雅退出的能力,针对 kube-dns 切换到 CoreDNS 的场景,建议将超时时间配置为5秒,配置方法详情请参见 配置会话保持。完成配置后,请等待5分钟后再继续进行后续步骤。

注意:说明:

注意:关于 ipvs udp 会话超时问题,TencentOS 3.1 中0009.23及以上的内核合并了社区 expire_nodest_conn 特性,能快速删除已有连接,减少解析超时的持续时间,用户无需再配置 ipvs UDP 会话保持超时时间。具体特性请参见 ipvs: queue delayed work to expire no destination connections if expire_nodest_conn=1。

二、准备 CoreDNS 资源文件

基于以下 CoreDNS 资源模板,根据集群 Kubernetes 版本以及 CoreDNS 版本处理 # 标注的内容后,将其保存到 switch2coredns.yaml 文件:

apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: labels: addonmanager.kubernetes.io/mode: Reconcile kubernetes.io/bootstrapping: rbac-defaults name: system:corednsrules: – apiGroups: – '*' resources: – endpoints – services – pods – namespaces verbs: – list – watch # 如果集群 k8s 版本大于等于 1.20,则需要增加对 endpointslice 的权限,反之则不需要,从此开始 – apiGroups: – discovery.k8s.io resources: – endpointslices verbs: – list – watch # 到此结束—apiVersion: v1kind: ServiceAccountmetadata: labels: addonmanager.kubernetes.io/mode: Reconcile kubernetes.io/cluster-service: "true" name: coredns namespace: kube-system—apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" labels: addonmanager.kubernetes.io/mode: EnsureExists kubernetes.io/bootstrapping: rbac-defaults name: system:corednsroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:corednssubjects: – kind: ServiceAccount name: coredns namespace: kube-system—apiVersion: v1data: Corefile: |2- .:53 { template ANY HINFO . { rcode NXDOMAIN } errors health { lameduck 30s } ready kubernetes cluster.local. in-addr.arpa ip6.arpa { pods insecure # 如果 CoreDNS 版本小于 v1.7.0,则需要 upstream 选项,反之则不需要,CoreDNS 版本确定参见这篇档前置说明 upstream fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf { prefer_udp } cache 30 reload loadbalance }kind: ConfigMapmetadata: labels: addonmanager.kubernetes.io/mode: EnsureExists name: coredns namespace: kube-system—apiVersion: apps/v1kind: Deploymentmetadata: labels: addonmanager.kubernetes.io/mode: Reconcile k8s-app: kube-dns kubernetes.io/cluster-service: "true" kubernetes.io/name: CoreDNS name: coredns namespace: kube-systemspec: # 副本数先设置成0,后面的步骤会调整 replicas: 0 selector: matchLabels: k8s-app: kube-dns strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 type: RollingUpdate template: metadata: annotations: seccomp.security.alpha.kubernetes.io/pod: docker/default labels: k8s-app: kube-dns name: coredns namespace: kube-system spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: – labelSelector: matchExpressions: – key: k8s-app operator: In values: – kube-dns topologyKey: kubernetes.io/hostname containers: – args: – -conf – /etc/coredns/Corefile # 集群所在地域不同,{HOST} 也不同,可直接采用当前 kube-dns 镜像所使用的域名替换这里的 {HOST},比如香港地域域名为:hkccr.ccs.tencentyun.com # 使用要切换到的 CoreDNS 版本来替换 {VERSION},CoreDNS 版本确定参见这篇档前置说明 image: {HOST}/tkeimages/coredns:{VERSION} name: coredns livenessProbe: failureThreshold: 5 httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 ports: – containerPort: 53 name: dns protocol: UDP – containerPort: 53 name: dns-tcp protocol: TCP – containerPort: 9153 name: metrics protocol: TCP readinessProbe: failureThreshold: 5 httpGet: path: /ready port: 8181 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 resources: limits: memory: 170M requests: cpu: 100m memory: 30M securityContext: allowPrivilegeEscalation: false capabilities: add: – NET_BIND_SERVICE drop: – all readOnlyRootFilesystem: true volumeMounts: – mountPath: /etc/coredns name: config-volume readOnly: true dnsPolicy: Default serviceAccountName: coredns tolerations: – effect: NoSchedule key: node-role.kubernetes.io/master – key: CriticalAddonsOnly operator: Exists volumes: – configMap: items: – key: Corefile path: Corefile name: coredns optional: true name: config-volume

三、迁移配置

如果你在当前集群中对 kube-dns 进行了一些自定义配置,例如自定义上游等,那么你需要将这些配置等效地迁移到 CoreDNS。请参考以下示例完成迁移:

四、kube-dns 自定义配置

apiVersion: v1data: federations: | {"foo" : "foo.feddomain.com"} stubDomains: | {"abc.com" : ["1.2.3.4"], "my.cluster.local" : ["2.3.4.5"]} upstreamNameservers: | ["8.8.8.8", "8.8.4.4"]kind: ConfigMapmetadata: name: kube-dns namespace: kube-system

五、迁移到 CoreDNS 的相应配置

根据 CoreDNS 版本处理 # 标注的内容后,将你的自定义配置写入上一步准备好的 switch2coredns.yaml 文件:

apiVersion: v1data: Corefile: |2- .:53 { kubernetes cluster.local. in-addr.arpa ip6.arpa { pods insecure # 如果 CoreDNS 版本小于 v1.7.0,则需要 upstream 选项,反之则不需要,CoreDNS 版本确定参见这篇档前置说明 upstream 8.8.8.8 8.8.4.4 fallthrough in-addr.arpa ip6.arpa } federation cluster.local { foo foo.feddomain.com } forward . 8.8.8.8 8.8.4.4 } abc.com:53 { forward . 1.2.3.4 } my.cluster.local:53 { forward . 2.3.4.5 }kind: ConfigMapmetadata: labels: addonmanager.kubernetes.io/mode: EnsureExists name: coredns namespace: kube-system

六、部署 CoreDNS

将上述 switch2coredns.yaml 完善后,执行以下命令部署 CoreDNS:

注意:此时 CoreDNS Deployment 的副本数为0,不会实际部署 Pod。

kubectl apply -f switch2coredns.yaml

七、执行切换

切换的总体思路为:逐步扩容 CoreDNS,缩容 kube-dns,直到所有 kube-dns 副本都被 CoreDNS 副本替代。执行切换的步骤如下:

注意:由于 kube-dns 和 CoreDNS 副本之间配置了 Pod 反亲和,因此如果集群资源有限,例如节点数不大于2,可以考虑先缩容 kube-dns,再扩容 CoreDNS,类似于原地腾挪,但这种方案在缩容时会带来服务容量的降低。

1. 扩容一个 CoreDNS 副本:

kubectl scale deployment coredns -n kube-system –replicas=1

2. 等待该 CoreDNS Pod 正常运行并变为 Ready 状态。如果长时间无法 Ready,请执行以下命令查看 CoreDNS Pod 的日志以诊断问题。

kubectl logs $(COREDNS_POD_NAME) -n kube-system

3. 等待 CoreDNS Pod Ready 后,进入一个业务 Pod 或创建一个测试 Pod(包含 nslookup 工具),将 nameserver 指向该 CoreDNS Pod 的 IP 地址,并测试系统域名、业务域名(注意命名空间)、外部域名等的解析是否正常。

nslookup kubernetes.default $(COREDNS_POD_IP)nslookup $(业务域名) $(COREDNS_POD_IP)nslookup www.baidu.com $(COREDNS_POD_IP)

4. 检查该 CoreDNS Pod 是否已添加到 kube-dns Service 的后端列表。

kubectl get endpoints kube-dns -n kube-system -o jsonpath='{.subsets[*].addresses[*].ip}{"\\n"}' | grep $(COREDNS_POD_IP)

5. 缩容一个 kube-dns 副本,假设 kube-dns 原先副本数为 N:

kubectl scale deployment kube-dns -n kube-system –replicas=N-1

6. 确认业务侧没有频繁的 DNS 解析报错,通过监控系统(如果具备)确认 DNS 服务整体 QPS 水平稳定,持续观察5分钟。

7. 重复执行步骤1-6,每扩容一个 CoreDNS Pod 就缩容一个 kube-dns pod,直到 CoreDNS 副本数达到原先 kube-dns 副本数,而 kube-dns 副本数变为0,即完成整体切换。

8. 切换完成后,观察业务持续72小时无问题,再清理 kube-dns 相关资源:

kubectl delete deployment kube-dns -n kube-systemkubectl delete cm kube-dns -n kube-systemkubectl delete serviceaccount kube-dns -n kube-system

八、回滚

如在切换过程中遇到不符合预期的行为,你可以通过扩容 kube-dns Deployment 到原来的副本数,缩容 CoreDNS Deployment 到0副本的方式实现回滚。

赞 (0)
上一篇 4天前
下一篇 4天前