k8s 服务注册与发现(三)CoreDNS
整个 CoreDNS 服务都建立在一个使用 Go 编写的 HTTP/2 Web 服务器上,CoreDNS 整个项目可以作为一个 Caddy 的教科书用法。CoreDNS 的大多数功能都是由插件来实现的,插件和服务本身都使用了 Caddy 提供的一些功能,所以项目本身也不是特别的复杂。
CoreDNS
作为一个加入 CNCF(Cloud Native Computing Foundation) 的服务 CoreDNS 的实现可以说的非常的简单。
介绍
整个 CoreDNS 服务都建立在一个使用 Go 编写的 HTTP/2 Web 服务器 Caddy · GitHub 上,CoreDNS 整个项目可以作为一个 Caddy 的教科书用法。
CoreDNS 的大多数功能都是由插件来实现的,插件和服务本身都使用了 Caddy 提供的一些功能,所以项目本身也不是特别的复杂。
部署 yaml
# __MACHINE_GENERATED_WARNING__
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
addonmanager.kubernetes.io/mode: Reconcile
name: system:coredns
rules:
- apiGroups:
- ""
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
addonmanager.kubernetes.io/mode: EnsureExists
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
- kind: ServiceAccount
name: coredns
namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
labels:
addonmanager.kubernetes.io/mode: EnsureExists
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes __DNS__DOMAIN__ in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/name: "CoreDNS"
spec:
# replicas: not specified here:
# 1. In order to make Addon Manager do not reconcile this replicas parameter.
# 2. Default is 1.
# 3. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
priorityClassName: system-cluster-critical
serviceAccountName: coredns
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values: ["kube-dns"]
topologyKey: kubernetes.io/hostname
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
nodeSelector:
kubernetes.io/os: linux
containers:
- name: coredns
image: registry.k8s.io/coredns/coredns:v1.9.3
imagePullPolicy: IfNotPresent
resources:
limits:
memory: __DNS__MEMORY__LIMIT__
requests:
cpu: 100m
memory: 70Mi
args: [ "-conf", "/etc/coredns/Corefile" ]
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- all
readOnlyRootFilesystem: true
dnsPolicy: Default
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
---
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/name: "CoreDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: __DNS__SERVER__
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
- name: metrics
port: 9153
protocol: TCP
说明: CoreDNS 服务在其 metadata.name
字段被命名为 kube-dns
。 这是为了能够与依靠传统 kube-dns
服务名称来解析集群内部地址的工作负载具有更好的互操作性。 使用 kube-dns
作为服务名称可以抽离共有名称之后运行的是哪个 DNS 提供程序这一实现细节。
如果你在使用 Deployment 运行 CoreDNS,则该 Deployment 通常会向外暴露为一个具有 静态 IP 地址 Kubernetes 服务。 kubelet 使用 --cluster-dns=<DNS 服务 IP>
标志将 DNS 解析器的信息传递给每个容器。
集群DNS域名解析原理
(注:以下内容需要一点阅读和一点理解)
ACK集群中kubelet的启动参数有--cluster-dns=<dns-service-ip>
、--cluster-domain=<default-local-domain>
,这两个参数分别被用来设置集群DNS服务器的IP地址和主域名后缀。
Pod内的DNS域名解析配置文件为/etc/resolv.conf,文件内容如下。
nameserver xx.xx.0.10
search kube-system.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
参数 | 描述 |
---|---|
nameserver | 定义DNS服务器的IP地址。 |
search | 设置域名的查找后缀规则,查找配置越多,说明域名解析查找匹配次数越多。ACK集群匹配有kube-system.svc.cluster.local 、svc.cluster.local 、cluster.local 3个后缀,最多进行8次查询才能得到正确解析结果(如果能的话),因为集群里面进行IPV4和IPV6查询各四次。 |
options | 定义域名解析配置文件选项,支持多个KV值。例如该参数设置成ndots:5 ,说明如果访问的域名字符串内的点字符数量超过ndots 值,则认为是完整域名,并被直接解析;如果不足ndots 值,则追加search段后缀再进行查询。 |
根据上述Pod内的配置,集群会将域名请求(集群内部定义的服务或是集群外部域名)查询发往集群DNS服务器获取结果。
集群dnsPolicy配置和场景说明
(这些前面都讲过了,之所以再讲,是因为前面没讲 dnsConfig 怎么写)
ACK支持通过dnsPolicy字段为每个Pod配置不同的DNS策略。目前ACK集群支持四种策略:
- ClusterFirst:通过CoreDNS来做域名解析,Pod内/etc/resolv.conf配置的DNS服务地址是集群DNS服务的kube-dns地址。该策略是集群工作负载的默认策略。
- None:忽略集群DNS策略,需要您提供dnsConfig字段来指定DNS配置信息。
- Default:Pod直接继承集群节点的域名解析配置。即在ACK集群直接使用ECS的/etc/resolv.conf文件
- ClusterFirstWithHostNet:强制在hostNetWork网络模式下使用ClusterFirst策略(默认使用Default策略)。
针对上述四种策略,本文列举四种场景分别介绍如何配置dnsPolicy。
-
场景一:使用ACK集群提供的CoreDNS来做域名解析
针对这种场景,可使用
dnsPolicy: ClusterFirst
策略。示例配置如下:apiVersion: v1 kind: Pod metadata: name: alpine namespace: default spec: containers: - image: alpine command: - sleep - "10000" imagePullPolicy: Always name: alpine dnsPolicy: ClusterFirst
-
场景二:Pod层面自定义DNS配置
当您需要给Deployment类型的工作负载指定DNS配置时,可使用
dnsPolicy: None
策略。示例配置如下:apiVersion: v1 kind: Pod metadata: name: alpine namespace: default spec: containers: - image: alpine command: - sleep - "10000" imagePullPolicy: Always name: alpine dnsPolicy: None dnsConfig: nameservers: ["169.254.xx.xx"] searches: - default.svc.cluster.local - svc.cluster.local - cluster.local options: - name: ndots value: "2"
其中,dnsConfig中的参数说明如下:
参数 描述 nameservers 将用作Pod的DNS服务器的IP地址列表。最多可以指定3个IP地址。当Pod的dnsPolicy设置为 None
时,列表必须至少包含一个IP地址,否则此属性是可选的。列出的DNS的IP列表将合并到基于dnsPolicy生成的域名解析文件的nameserver字段中,并删除重复的地址。searches Pod中主机名查找的DNS搜索域列表。此属性是可选的。指定后,提供的列表将合并到从所选DNS策略生成的基本搜索域名中,并删除重复的域名。Kubernetes最多允许6个搜索域。 options 可选的对象列表,其中每个对象可以具有name属性(必需)和value属性(可选)。此属性中的内容将合并到从指定的DNS策略生成的选项中,并删除重复的条目。 更多信息,请参见Kubernetes官网的DNS配置说明。
-
场景三:采用ECS的DNS配置
当您的应用Pod不需要访问集群内的其它服务,只需要通过DNS来做解析,也不希望DNS解析经过CoreDNS,可以采用
dnsPolicy: Default
策略。示例配置如下:apiVersion: v1 kind: Pod metadata: name: alpine namespace: default spec: containers: - image: alpine command: - sleep - "10000" imagePullPolicy: Always name: alpine dnsPolicy: Default
-
场景四:在HostNetwork网络模式下访问集群服务
如果您的应用Pod使用hostNetwork:true来配置网络,Pod中运行的应用程序可以直接看到宿主机的网络接口,其DNS策略默认为Default,不能访问集群内的服务。如果您希望在此网络模式下访问集群内服务,可使用
dnsPolicy: ClusterFirstWithHostNet
策略。示例配置如下:apiVersion: v1 kind: Pod metadata: name: alpine namespace: default spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet containers: - image: alpine command: - sleep - "10000" imagePullPolicy: Always name: alpine
CoreDNS配置说明
在命名空间kube-system下,ACK集群有一个CoreDNS配置项,CoreDNS会基于该配置项启用和配置插件。不同CoreDNS版本的配置项有略微差异,修改配置前请仔细阅读CoreDNS官方文档。以下是一个1.6.2版本CoreDNS默认采用的配置文件:
Corefile: |
.:53 {
errors
log
health {
lameduck 15s
}
ready
kubernetes {{.ClusterDomain}} in-addr.arpa ip6.arpa {
pods verified
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
说明 配置文件中ClusterDomain
代指集群创建过程中填写的集群本地域名,默认值为cluster.local
。
参数 | 描述 |
---|---|
errors | 错误信息到标准输出。 |
health | CoreDNS自身健康状态报告,默认监听端口8080,一般用来做健康检查。您可以通过http://localhost:8080/health 获取健康状态。 |
ready | CoreDNS插件状态报告,默认监听端口8181,一般用来做可读性检查。可以通过http://localhost:8181/ready 获取可读状态。当所有插件都运行后,ready状态为200。 |
kubernetes | CoreDNS Kubernetes插件,提供集群内服务解析能力。 |
prometheus | CoreDNS自身metrics数据接口。可以通过http://localhost:9153/metrics 获取prometheus格式的监控数据。 |
forward(或proxy) | 将域名查询请求转到预定义的DNS服务器。默认配置中,当域名不在Kubernetes域时,将请求转发到预定义的解析器(/etc/resolv.conf)中。默认使用宿主机的/etc/resolv.conf配置。 |
cache | DNS缓存。 |
loop | 环路检测,如果检测到环路,则停止CoreDNS。 |
reload | 允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,请等待两分钟以使更改生效。 |
loadbalance | 循环DNS负载均衡器,可以在答案中随机A、AAAA、MX记录的顺序。 |
CoreDNS的扩展配置
这块我还没研究。
针对以下不同场景,您可以扩展CoreDNS的配置:
-
场景一:开启日志服务
如果需将CoreDNS每次域名解析的日志打印出来,您可以开启Log插件,在Corefile里加上log。示例配置如下:
Corefile: | .:53 { errors log health { lameduck 15s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf { prefer_udp } cache 30 loop reload loadbalance }
-
场景二:特定域名使用自定义DNS服务器
如果example.com类型后缀的域名需要经过自建DNS服务器(IP为10.10.0.10)进行解析的话,您可为域名配置一个单独的服务块。示例配置如下:
example.com:53 { errors cache 30 forward . 10.10.0.10 }
完整配置如下:
Corefile: | .:53 { errors health { lameduck 15s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf { prefer_udp } cache 30 loop reload loadbalance } example.com:53 { errors cache 30 forward . 10.10.0.10 }
-
场景三:外部域名完全使用自建DNS服务器
如果您需要使用的自建DNS服务的域名没有统一的域名后缀,您可以选择所有集群外部域名都使用自建DNS服务器(此时需要您将自建的DNS服务不能解析的域名转发到阿里云DNS,禁止直接更改集群ECS上的/etc/resolv.conf文件)。例如,您自建的DNS服务器IP为10.10.0.10和10.10.0.20,可以更改forward参数进行配置。示例配置如下:
Corefile: | .:53 { errors health { lameduck 15s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . 10.10.0.10 10.10.0.20{ prefer_udp } cache 30 loop reload loadbalance }
-
场景四:自定义Hosts
如果您需要为特定域名指定hosts,如为www.example.com指定IP为127.0.0.1,可以使用Hosts插件来配置。示例配置如下:
Corefile: | .:53 { errors health { lameduck 15s } ready hosts { 127.0.0.1 www.example.com fallthrough } kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf { prefer_udp } cache 30 loop reload loadbalance }
注意 请配置fallthrough,否则会造成非定制Hosts域名解析失败。
-
场景五:集群外部访问集群内服务
如果您希望运行在集群ECS上的进程能够访问到集群内的服务,虽然可以通过将ECS的/etc/resolv.conf文件内
nameserver
配置为集群kube-dns的ClusterIP地址来达到目的,但不推荐您直接更改ECS的/etc/resolv.conf文件的方式来达到任何目的。内网场景下,您可以将集群内的服务通过内网SLB进行暴露,然后在云解析PrivateZone控制台通过添加A记录到该SLB的内网IP进行解析。具体操作,请参见添加解析记录。
-
场景六:统一域名访问服务或是在集群内对域名的做CNAME解析
您可以实现在公网、内网和集群内部通过统一域名foo.example.com访问您的服务,原理如下:
-
集群内的服务
foo.default.svc.cluster.local
通过公网SLB进行了暴露,且有域名foo.example.com
解析到该公网SLB的IP。 -
集群内服务
foo.default.svc.cluster.local
通过内网SLB进行了暴露,且通过云解析PrivateZone在VPC内网中将foo.example.com
解析到该内网SLB的IP。具体步骤,请参见上述场景四:自定义Hosts。 -
在集群内部,您可以通过Rewrite插件将
foo.example.com
CNAME到
foo.default.svc.cluster.local
。示例配置如下:
Corefile: | .:53 { errors health { lameduck 15s } ready rewrite stop { name regex foo.example.com foo.default.svc.cluster.local answer name foo.default.svc.cluster.local foo.example.com } kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf { prefer_udp } cache 30 loop reload loadbalance }
-
-
场景七:禁止CoreDNS对IPv6类型的AAAA记录查询返回
当业务容器不需要AAAA记录类型时,可以在CoreDNS中将AAAA记录类型拦截,返回域名不存在,以减少不必要的网络通信。示例配置如下:
Corefile: | .:53 { errors health { lameduck 15s } #新增以下一行Template插件,其它数据请保持不变。 template IN AAAA . }
-
场景八:开启ACK One多集群服务功能
说明 1.9.3及更高版本的CoreDNS支持ACK One多集群服务功能,如果您的CoreDNS组件版本低于1.9.3,请升级CoreDNS后再开启此功能。详细信息,请参见CoreDNS自动升级和CoreDNS手动升级。
-
执行如下命令,变更CoreDNS配置项。
kubectl edit configmap/coredns -n kube-system
-
在 kubernetes 字样上方增加一行 multicluster clusterset.local,表示开启multicluster多集群服务插件功能,并将多集群服务域名后缀设置为 clusterset.local。
Corefile: | .:53 { # 此处省略其它内容。 # 增加以下一行。 multicluster clusterset.local kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } # 此处省略其它内容。 }
-
修改完成后,按Esc键,输入:wq!并按Enter键,保存修改后的配置文件并退出编辑模式。
-
更多推荐
所有评论(0)