目录
一、NodeLocal DNS是什么?
二、为什么使用NodeLocal DNS?
三、工作原理
四、安装NodeLocal DNS
五、在应用中使用NodeLocal DNSCache
六、验证
NodeLocal DNSCache
通过在集群节点上运行一个 DaemonSet 来提高 clusterDNS 性能和可靠性。处于 ClusterFirst
的 DNS 模式下的 Pod 可以连接到 kube-dns
的 serviceIP 进行 DNS 查询。通过 kube-proxy
组件添加的 iptables
规则将其转换为 CoreDNS
端点。通过在每个集群节点上运行 DNS 缓存,NodeLocal DNSCache 可以缩短 DNS 查找的延迟时间、使 DNS 查找时间更加一致,以及减少发送到 kube-dns 的 DNS 查询次数。
借助这种新架构,Pod 将可以访问在同一节点上运行的 DNS 缓存代理,从而避免 iptables DNAT 规则和连接跟踪。 本地缓存代理将查询 kube-dns 服务以获取集群主机名的缓存缺失(默认为 "cluster.local
" 后缀)。
nf_conntrack_udp_timeout
是 30 秒)。避免IPVS缺陷导致的DNS概率性解析超时问题
默认解析使用UDP,UDP默认返回报文长度为512字节,大于512字节后就会将包丢弃,升级为TCP协议可以解决这个问题。TCP可以进行数据包的切片可以完整的得到返回的response
架构图
获取文件将文件保存为nodelocaldns.yamlkubernetes/nodelocaldns.yaml at master · kubernetes/kubernetes · GitHub Production-Grade Container Scheduling and Management - kubernetes/nodelocaldns.yaml at master · kubernetes/kuberneteshttps://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
health [__PILLAR__LOCAL__DNS__]:8080
"。获取coredns的IP
kubedns=`kubectl get svc coredns -n kube-system -o jsonpath={.spec.clusterIP}`
# 表示集群域,默认就是 cluster.local
domain=cluster.local
# 表示 DNSCache 本地的 IP,默认为169.254.20.10
localdns=169.254.20.10
的默认值是 "cluster.local"。
是 NodeLocal DNSCache 选择的本地侦听 IP 地址。
如果 kube-proxy 运行在 IPTABLES 模式:
sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml
node-local-dns Pod 会设置 __PILLAR__CLUSTER__DNS__
和 __PILLAR__UPSTREAM__SERVERS__
。 在此模式下, node-local-dns Pod 会同时侦听 kube-dns 服务的 IP 地址和
的地址,以便 Pod 可以使用其中任何一个 IP 地址来查询 DNS 记录。
如果 kube-proxy 运行在 IPVS 模式:
sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/,__PILLAR__DNS__SERVER__//g; s/__PILLAR__CLUSTER__DNS__/$kubedns/g" nodelocaldns.yaml
在此模式下,node-local-dns Pod 只会侦听
的地址。 node-local-dns 接口不能绑定 kube-dns 的集群 IP 地址,因为 IPVS 负载均衡使用的接口已经占用了该地址。 node-local-dns Pod 会设置 __PILLAR__UPSTREAM__SERVERS__
4. 将NodeLocalDNS 部署到集群
1. 如果是线上集群,推荐不要直接apply 文件,采用灰度的方式部署。我们可以在yaml中增加配置如下
spec:
nodeSelector:
nodelocaldns: "true"
2. 挑选集群的一些机器打上nodelocaldns=true的标签
for i in `cat 1.txt`; do kubectl label node $i nodelocaldns=true;done
3. apply 文件
kubectl apply -f nodelocaldns.yaml
4. 这个时候我们需要进入到pod内验证服务是否有异常 (这些打了标签的node 上面的pod)
验证方式:
1) pod内是否可以解析外网域名(前提条件 node节点可以访问域名)
2) pod内解析内网域名
2) pod内解析集群service name
如果都没有问题,说明部署NodeLocalDNS后并没有影响我们集群现有的服务
5. 将yaml中NodeSelect 配置注释,重新apply
kubectl apply -f nodelocaldns.yaml
6. 查看kube-system 命名空间下的node-local-dns pod
kubectl get pod -n kube-system | grep node-local
自此NodeLocalDNS就部署完成了,但是还没有应用到它
为了能使应用原本请求CoreDNS的流量改为由DNS缓存DaemonSet代理,需要使Pod内部的中nameservers配置成169.254.20.10和kube-dns对应的IP地址,您有以下几种方式可以选择:
第一种方式:
需要集群具备adminssion webhook功能,或者可以使用第三方的一些插件完成部署
adminssion webhook:基于Admission Webhook机制拦截Pod创建的请求,自动注入使用DNS缓存的Pod DNSConfig信息。
第二种方式:
由于我用了原生的部署方式,在我们生产环境我采用了是第二种应用方式
背景:我们的每一个服务都是通过helm 模板渲染生成一个chart, 我们gitlab代码仓库会管理一个helm 模板,所以我只要修改helm 模板,服务重新发布即可使用NodeLocal DNSCache了。你也可以手动修改yaml文件具体方式看你们当前环境是怎么部署的服务了。下面是我的配置
{{-if eq .Values.cluster "offline" }}
dnsPolicy: None
dnsConfig:
nameservers: ["169.254.20.10","10.11.128.10"]
searches:
- yidian-prod.svc.cluster.local
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
- yidian.com
- yidian-inc.com
options:
- name: ndots
value: "3"
- name: attempts
value: "2"
- name: timeout
value: "1"
{{- end }}
第三种方式:
不建议使用尤其是生产环境禁止使用
如果是二进制部署的集群,需要修改/etc/systemd/system/kubelet.service.d/10-kubeadm.conf 文件中的--cluster-dns=xxx.xxx.xxx.xxx参数。
查看kbuelet启动依赖的配置文件
ps -elf | grep kubelet | grep cluster-dns
systemctl status kubelet
如果是kubeadm部署的集群,修改/var/lib/kubelet/config.yaml文件中的clusterDNS参数
上面说到由于我们是使用的第二种方式,需要重新发布才可以生效。下图是发布后pod内部的状况,可以看到我们的pod内有两行nameserver信息第一行为NodeLocalDNS的IP,第二行是coreDNS的IP。
验证方式:
1) pod内是否可以解析外网域名(前提条件 node节点可以访问域名)
2) pod内解析内网域名
2) pod内解析集群service name
下面是我的nodelocaldns.yaml,也可以使用我的yaml,需要注意的是对应的那些变量要做变更,一定要改coredns的ip
apiVersion: v1
kind: ServiceAccount
metadata:
name: node-local-dns
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: v1
kind: Service
metadata:
name: kube-dns-upstream
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/name: "KubeDNSUpstream"
spec:
ports:
- name: dns
port: 53
protocol: UDP
targetPort: 53
- name: dns-tcp
port: 53
protocol: TCP
targetPort: 53
selector:
k8s-app: coredns
---
apiVersion: v1
kind: ConfigMap
metadata:
name: node-local-dns
namespace: kube-system
labels:
addonmanager.kubernetes.io/mode: Reconcile
data:
Corefile: |
cluster.local:53 {
errors
cache {
success 9984 30
denial 9984 5
}
reload
loop
bind 169.254.20.10 __PILLAR__DNS__SERVER__
forward . 10.11.128.10 {
force_tcp
}
prometheus :9253
health 169.254.20.10:8080
}
in-addr.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10 __PILLAR__DNS__SERVER__
forward . 10.11.128.10 {
force_tcp
}
prometheus :9253
}
ip6.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10 __PILLAR__DNS__SERVER__
forward . 10.11.128.10 {
force_tcp
}
prometheus :9253
}
.:53 {
errors
cache 30
reload
loop
bind 169.254.20.10 __PILLAR__DNS__SERVER__
forward . __PILLAR__UPSTREAM__SERVERS__ {
force_tcp
}
prometheus :9253
}
---
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 # Don't use cluster DNS.
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
- effect: "NoExecute"
operator: "Exists"
- effect: "NoSchedule"
operator: "Exists"
containers:
- name: node-cache
image: hub.kce.ksyun.com/ksyun/k8s-dns-node-cache:1.22.8
resources:
requests:
cpu: 25m
memory: 5Mi
args: [ "-localip", "169.254.20.10", "-conf", "/etc/Corefile", "-upstreamsvc", "kube-dns-upstream" ]
securityContext:
privileged: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9253
name: metrics
protocol: TCP
livenessProbe:
httpGet:
host: 169.254.20.10
path: /health
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
volumeMounts:
- mountPath: /run/xtables.lock
name: xtables-lock
readOnly: false
- name: config-volume
mountPath: /etc/coredns
- name: kube-dns-config
mountPath: /etc/kube-dns
volumes:
- name: xtables-lock
hostPath:
path: /run/xtables.lock
type: FileOrCreate
- name: kube-dns-config
configMap:
name: coredns
optional: true
- name: config-volume
configMap:
name: node-local-dns
items:
- key: Corefile
path: Corefile.base
---
# A headless service is a service with a service IP but instead of load-balancing it will return the IPs of our associated Pods.
# We use this to expose metrics to Prometheus.
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/port: "9253"
prometheus.io/scrape: "true"
labels:
k8s-app: node-local-dns
name: node-local-dns
namespace: kube-system
spec:
clusterIP: None
ports:
- name: metrics
port: 9253
targetPort: 9253
selector:
k8s-app: node-local-dns
参考文献:
在 Kubernetes 集群中使用 NodeLocal DNSCache | Kubernetes
使用NodeLocal DNSCache - 容器服务 ACK - 阿里云