01 引言
声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
由于在Kubernetes集群中配置的DNS服务 是一个名为 “kube-dns” 的Service, 所以容器应用都通过其ClusterIP地址(例如169.169.0.100)去执行服务名的DNS域名解析。这对于大规模集群可能引起以下两个问题:
- 集群
DNS
服务压力增大(这可以通过自动扩容缓解); - 由于
DNS
服务的IP
地址是Service
的ClusterIP
地址,所以会通过kube- proxy
设置的iptables规则进行转发,可能导致域名解析性能很差,原因是Netfilter
在做DNAT
转换时可能会引起conntrack
冲突,从而导致DNS
查询产生5s
的延时。
为了解决这两个问题,Kubernetes引入了Node本地DNS缓存(NodeLocal DNSCache
)来提高整个集群的DNS域名解析的性能,本文来讲解下。
02 Node本地DNS缓存
使用Node本地DNS缓存的好处如下:
- 在没有本地DNS缓存时,集群DNS服务的Pod很可能在其他节点上,跨主机访问会增加网络延时,使用Node本地DNS缓存可 显著减少跨主机查询的网络延时;
- 跳过iptables DNAT和连接跟踪将有助于 减少conntrack竞争,并避免UDP DNS记录填满conntrack表;
- 本地缓存到集群DNS服务的连接协议可以升级为TCP。TCP conntrack条目将在连接关闭时被删除;默认使用UDP时,conntrack条目只能等到超时时间过后才被删除,操作系统的默认超时时间(nf_conntrack_udp_timeout),为30s;
- 将DNS查询从UDP升级为TCP,将减少由于丢弃的UDP数据包和DNS超时而引起的尾部延迟(tail latency),UDP超时时间可能会长达30s(3次重试, 每次10s);
- 提供Node级别DNS解析请求的度量 (Metrics)和可见性 (visibility) 可以重新启用负缓存(Negative caching)功能,减少对集群DNS服务的查询数量。
2.1 工作流程
Node本地DNS缓存(NodeLocal DNSCache)的工作流程如图所示,客户端Pod首先会通过本地DNS缓存进行域名解析,当缓存中不存在域名时,会将请求转发到集群DS服务进行解析。
2.2 部署Node本地DNS缓存工具
配置文件nodelocaldns.yaml的内容如下,主要包括 ServiceAccount、Daemonset、ConfigMap和Service 几个资源对象。
2.2.1 资源对象配置
Service Account的定义如下:
apiVersion: v1
kind: ServiceAccount
metadata:
name: node-local-dns
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
Service的定义如下:
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: kube-dns
ConfigMap的定义如下:
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
bind169.254.20.10
forward.169.169.0.100{
force tcp
}
prometheus 9253
hea1th169.254.20.10:8081
}
in-addr.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10
forward . 169.169.0.100{
force tcp
}
prometheus 9253
}
ip6.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10
forward . 169.169.0.100{
force tcp
}
prometheus 9253
}
.:53 {
errors
cache 30
reload
loop
bind 169.254.20.10
forward . 169.169.0.100{
force tcp
}
prometheus 9253
}
ConfigMap Corefile的主要配置参数如下:
- bind 169.254.20.10 :node-local-dns需要绑定的本地IP地址,建议将其设置为
169.254.0.0/16
范围,确保不与集群内的其他IP冲突; - forward.169.169.0.100:在node-local-dns缓存中不存在域名记录时, 将转发到的上游DNS服务器IP设置为Kubernetes集群DNS服务(kube-dns)的IP,例如169.169.0.100;
- health169.254.20.10:8081:健康检查端口号设置与Daemonset的livenessProbe一致,需要注意,node-local-dns网络模式设置了 hostNetwork=true,这个端口号也会被直接绑定到宿主机上,需要确保不与宿主机的其他应用冲突。
DaemonSet的定义如下:
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:
maxUnavai1able: 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: k8s.gcr.io/k8s-dns-node-cache: 1.15.13
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: 8081
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
Daemonset node-local-dns的主要配置参数如下:
- args: ["-localip" , "169.254.20.10" , "-conf" , "/etc/Corefile" , "upstreamsvc" , "kube-dns-upstream"]:将-localip参数设置为node-local-dns绑定的本地IP地址,对其他参数无须修改;
- livenessProber中的健康检查端口号与ConfigMap中的一致;
另外,如果kube-proxy代理模式(-proxy-mode)使用的是ipvs模式,则还需要修改kubelet的启动参数-cluster-dns为node-local-dns绑定的本地IP地169.254.20.10。
2.2.2 部署
通过kubectl create命令创建node-local-dns服务:
kubectl create -f nodelocaldns.yaml
serviceaccount/node-local-dns created
service/kube-dns-upstream created
configmap/node-local-dns created
daemonset.apps/node-local-dns created
确认在每个Node上都运行了一个node-local-dns Pod:
在客户端Pod内对服务名的解析没有变化,仍然可以直接通过服务名访问其他服务,例如:
03 文末
本文主要讲解Node本地DNS缓存相关的概念,希望能帮助到大家,谢谢大家的阅读,本文完!