背景
K3s集群内集成了CoreDNS作为kube-dns,默认IP为10.43.0.10。当Pod的dns类型为ClusterFirst
/ClusterFirstWithHostNet
时,在容器内可以通过<service名>.<namespace名>.svc.cluster.local
域名访问集群内的service(后面几段可以省略),而不再需要使用cluster ip或node port。
笔者的K3s集群有跨省份的多个节点,节点之间通过tailscale虚拟局域网通信。tailscale使用UDP协议传输数据,而运营商对跨省的UDP流量往往会采取QoS限流策略。
笔者观察到的现象是,当K3s的CoreDNS实例部署在省份A时,那么处于省份B的部分Pod在解析集群内service域名时,容易出现解析速度慢、甚至解析失败的情况,这点很是让笔者头疼。
和AI探讨方案后,AI提出可以使用K8s的NodeLocal DNSCache
(以下简称localdns)来建立本地DNS缓存,保证域名解析的稳定性。但默认的localdns配置并不兼容K3s,笔者经过一番摸索得出了兼容k3s集群的localdns配置,用本文作为记录。
localdns配置
K8s默认的localdns配置可在Github上查看。内容较多,但对于K3s场景来说只需要有两个关键配置。
ConfigMap配置
localdns使用的也是CoreDNS,所以在ConfigMap里编写Corefile即可。主体逻辑如下:
- 监听169.254.20.10:53,处理发来的DNS请求,并开启日志/缓存等功能
- 如果请求域名是
cluster.local.
结尾,则转发到K3s自身的CoreDNS10.43.0.10
- 否则将请求转发到公共DNS
119.29.29.29
1 2 3 4 5 6 7 8 9
| apiVersion: v1 kind: ConfigMap metadata: name: node-local-dns namespace: kube-system labels: addonmanager.kubernetes.io/mode: Reconcile data: Corefile: ".:53 {\n bind 169.254.20.10\n\n\tforward cluster.local. 10.43.0.10 {\n force_tcp\n }\n forward . 119.29.29.29\n\n reload\n log\n loop\n errors\n cache 30\n prometheus :9253\n}"
|
DaemonSet配置
要在每台机器上部署一个localdns实例,使用如下DaemonSet配置即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| apiVersion: apps/v1 kind: DaemonSet metadata: name: node-local-dns namespace: kube-system labels: k8s-app: node-local-dns kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile spec: updateStrategy: rollingUpdate: maxUnavailable: 10% selector: matchLabels: k8s-app: node-local-dns template: metadata: labels: k8s-app: node-local-dns annotations: prometheus.io/port: "9253" prometheus.io/scrape: "true" spec: priorityClassName: system-node-critical serviceAccountName: node-local-dns hostNetwork: true dnsPolicy: Default tolerations: - key: "CriticalAddonsOnly" operator: "Exists" - effect: "NoExecute" operator: "Exists" - effect: "NoSchedule" operator: "Exists" containers: - name: node-cache image: registry.k8s.io/dns/k8s-dns-node-cache:1.26.4 resources: requests: cpu: 25m memory: 5Mi args: [ "-localip", "169.254.20.10", "-conf", "/etc/Corefile" ] securityContext: capabilities: add: - NET_ADMIN ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP - containerPort: 9253 name: metrics protocol: TCP volumeMounts: - mountPath: /run/xtables.lock name: xtables-lock readOnly: false - name: config-volume mountPath: /etc/coredns volumes: - name: xtables-lock hostPath: path: /run/xtables.lock type: FileOrCreate - name: config-volume configMap: name: node-local-dns items: - key: Corefile path: Corefile.base
|
确认部署状态
可通过kubectl get pods -n kube-system
命令确认localdns部署状态
1 2 3 4 5 6 7
| NAME READY STATUS RESTARTS AGE ...省略 node-local-dns-56v44 1/1 Running 0 45s node-local-dns-7tnrs 1/1 Running 0 41s node-local-dns-j74kr 1/1 Running 0 45s node-local-dns-pk9kt 1/1 Running 0 45s node-local-dns-vghvz 1/1 Running 0 45s
|
K3s配置
修改文件/etc/rancher/k3s/config.yaml
,在kubelet配置中设置cluster-dns
:
1 2 3
| kubelet-arg: - "--cluster-dns=169.254.20.10"
|
然后重启K3s服务
1 2 3
| sudo systemctl daemon-reload sudo systemctl restart k3s sudo systemctl restart k3s-agent
|
接下来创建的Pod,当dns类型为ClusterFirst
/ClusterFirstWithHostNet
时,就会使用本地的localdns解析service域名,而不是默认的10.43.0.10
。