[译] 深度剖析 K8S DNS 的 Service 与 Pod

栏目: 编程工具 · 发布时间: 6年前

内容简介:作者:Kirill Goltsman编辑:小君君(才云)

[译] 深度剖析 K8S DNS 的 Service 与 Pod

作者:Kirill Goltsman

编辑:小君君(才云)

众所周知,Kubernetes master 存储了所有 Service 的定义和更新。但是,要与后端 Pod 通信的客户端 Pod(通过 Service 实现负载均衡)也需要知道这些请求会发送到何处。这些 Pod 可以将网络信息存储在容器环境变量中,但从长远来看这是不可行的。如果网络详细信息和一组后端 Pod 在将来发生更改时,客户端 Pod 将无法与它们通信。

今天,我们就来一起看看 Kubernetes DNS 系统是如何解决这个问题的,然后通过一个实际用例加深对该 系统设计原理的理解。

Kube-DNS 和 CoreDNS 是两个已建立的 DNS 解决方案,用于定义 DNS 命名规则。它们还可以将 Pod、DNS 服务解析为其相应的集群 IP。 使用 DNS,Kubernetes 服务可以被 name 引用(该 name 对应于服务管理的任意数量的后端 Pod)。

DNS 的命名方案也遵循了可预测的模式,使各种服务的地址更容易被记住。服务不仅可以通过完全限定域名(FQDN)引用,还可以仅通过服务本身的 name 引用。

通过本文你将了解到:

  • Kubernetes DNS 如何运作;

  • Service DNS 记录;

  • Pod DNS 记录;

  • Pod 的主机名和子域字段;

  • 教程: 如何通过 DNS 命名解决服务问题;

  • 总结。

[译] 深度剖析 K8S DNS 的 Service 与 Pod

Kubernetes DNS 如何运作?

在 Kubernetes 中,你可以设置一个 DNS 系统,其中包含两个受到良好支持的附加组件:CoreDNS 和 Kube-DNS。CoreDNS 是一个较新的附加组件,从 Kubernetes v1.12 开始成为默认的 DNS 服务器。但,某些 Kubernetes 安装程序 工具 仍可将 Kube-DNS 安装为默认 DNS 系统。

这两个附加组件都可以在集群上 调度一个或多个 DNS Pod 以及具有静态 IP 的服务。为了实现互操作性,两者在 metadata.name 字段都被命名为 kube-dns 。当管理员或安装工具配置集群时, kubelet 会将 DNS 功能传递给每个带有 --cluster-dns=<dns-service-ip> 标识的容器。配置 kubelet 时,管理员还可以使用 --cluster-domain=<default-local-domain> 指定本地域名。

目前,Kubernetes DNS 加载项可以支持正向查找(A Record)、端口查找(SRV 记录)、反向 IP 地址查找(PTR 记录)以及一些其他选项。本文将继续讨论,在这些记录类型中 Pod 和 Service 的 Kubernetes 命名方案。

[译] 深度剖析 K8S DNS 的 Service 与 Pod

Service DNS 记录

通常,Kubernetes 服务支持 A Record、CNAME 和 SRV 记录。

A Record  

A Record 是用于将域或子域指向某个 IP 地址的 DNS 记录的最基本类型。记录包括域名、解析它的 IP 地址和以秒为单位的 TTL。TTL 代表生存时间,是 DNS 记录上的一种到期日期。每个 TTL 都会告诉 DNS 服务器,它应该在其缓存中保留给定记录多长时间。

Kubernetes 为“normal”和“headless”服务分配不同的 A Record name。“headless”服务与“ normal ”服务的不同之处在于它们未分配 ClusterIP 且不执行负载均衡。

“Normal”服务都分配了一个 DNS A Record 作为表单 your-svc.your-namespace.svc.cluster.local 的 name(根域名可以在 kubelet 设置中更改)。此 name 解析为服务的集群 IP。“Headless”服务还为表单 your-svc.your-namespace.svc.cluster.local 的 name 分配一个 DNS A Record。但是,与“normal”服务相反,此 name 解析的是,为服务选择的一组 Pod IP。DNS 不会自动将此设置解析为特定的 IP,因此客户端应该负责好集合中进行的负载均衡或循环选择。

CNAME  

CNAME 记录用于将域或子域指向另一个主机名。为此,CNAME 使用现有的 A Record 作为其值。反过来,A Record 会解析为指定的 IP 地址。此外,在 Kubernetes 中,CNAME 记录可用于联合服务的跨集群服务发现。在整个场景中会有一个跨多个 Kubernetes 集群的公共服务。所有 Pod 都可以发现这项服务(无论这些 Pod 在哪个集群上)。这是一种跨集群服务发现方法。

SRV 记录  

SRV 记录是通过描述某些服务协议和地址来促进服务发现的。

SRV 记录通常定义一个符号名称和作为域名一部分的传输协议(如,TCP),并定义给定服务的优先级、权重、端口和目标(请参阅下面的示例)。

_sip._tcp.example.com.   3600 IN    SRV 10       70     5060 srvrecord.example.com.
_sip._tcp.example.com.   3600 IN    SRV 10       20     5060 srvrecord2.ex

在上面的示例中, _sip 是服务的符号名称, _tcp 是服务的使用传输协议。记录内容代表的意思是:两个记录都定义了 10 的优先级。另外,第一个记录的权重为 70,第二个记录的权重为 20。优先级和权重通常用于建议指定使用某些服务器。 记录中的最后两个值定义了要连接的端口和主机名,以便与服务通信

SRV 记录是为“normal”或“headless”服务的部分指定端口创建的。SRV 记录采用 _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local 的形式 。对于常规服务,它被解析的端口号和域名是: my-svc.my-namespace.svc.cluster.local 。在 “headless” 服务的情况下,此 name 解析为多个 answer,每个 answer 都支持服务。

每个 answer 都包含 auto-generated-name.my-svc.my-namespace.svc.cluster.local 表单的 Pod 端口号和域名。

[译] 深度剖析 K8S DNS 的 Service 与 Pod

Pod DNS 记录

A Record  

如果启用了 DNS,Pod 将以 pod-ip-address.my-namespace.pod.cluster.local 的形式被分配为一个 DNS 记录。例如,在 default 命名空间中 IP 为 172.12.3.4 、DNS 名称为 cluster.local 的 Pod  将有一个形式 172-12-3-4.default.pod.cluster.local 的条目。

[译] 深度剖析 K8S DNS 的 Service 与 Pod

Pod 的主机名和子域字段

Pod 的默认主机名由 Pod 的 metadata.name 值定义。然而,用户可以通过在可选的 hostname 字段中指定一个新值来更改默认主机名。用户还可以在 subdomain 字段中自定义子域名。例如,在命名空间 my-namespace 中,将 hostname 设置为 custom-host ,将 subdomain 设置为 custom-subdomain 的 Pod 将具有完全限定的域名 (FQDN) custom-host.custom-subdomain.my-namespace.svc.cluster.local

[译] 深度剖析 K8S DNS 的 Service 与 Pod

教程:如何通过 DNS 命名解决服务问题

接下来,本文将演示如何通过 DNS 命名解决服务问题,检查 DNS 解析并在发生 DNS 问题时对其进行调试。要完成下面的示例, 你需要满足以下先决条件:

  • 一个正在运行的 Kubernetes 集群;

  • 安装与配置 kubectl 命令行工具。

首先,你需要使用三个 Python HTTP 服务器创建一个部署,该服务器会在端口 80 上侦听连接并返回包含 Pod 主机名的自定义问候语。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test-pod
  template:
    metadata:
      labels:
        app: test-pod
    spec:
      containers:
      - name: python-http-server
        image: python:2.7
        command: ["/bin/bash"]
        args: ["-c", "echo \" Hello from $(hostname)\" > index.html; python -m SimpleHTTPServer 80"]
        ports:
        - name: http
          containerPort: 80

创建部署:

kubectl create -f deployment.yml 
deployment.extensions "test-deployment" created

接下来,创建一个服务来发现部署的 Pod 并在它们之间分发客户端请求。以下是分配 ClusterIP 的“normal”服务清单。

kind: Service
apiVersion: v1
metadata:
  name: test-service
spec:
  selector:
    app: test-pod
  ports:
  - protocol: TCP
    port: 4000
    targetPort: http

请注意,服务的 spec.selector 字段应该与部署创建的Pod的 spec.template.metadata.labels 相匹配。

kubectl create -f service.yml
service "test-service" created

最后,创建一个客户端 Pod,curl 将通过其 name 来提供服务。这样管理员就不需要知道服务端点的 IP,而是依赖于 Kubernetes Pod 的短暂性。

apiVersion: v1
kind: Pod
metadata:
  name: client-pod
spec:
  containers:
  - name: curl
    image: appropriate/curl
    command: ["/bin/sh"]
    args: ["-c","curl test-service:4000 "]

请注意,本实验使用的是服务名称,而不是部署创建的 ClusterIP 或 Pod 的 IP。你可以使用服务的 DNS 名称(“tut-service”),因为本实验设置的 Kubernetes 集群是使用 Kube-DNS 附加组件来监视 Kubernetes API 以获取新服务并为每个服务创建 DNS 记录。如果在集群中启用了 Kube-DNS,则所有 Pod 都可以自动执行服务的名称解析。但是,你也可以继续使用你的服务 ClusterIP。

kubectl create -f client.yml
pod "client-pod" created

创建客户端 Pod 后,检查日志。现在,你验证服务的名称已解析为正确的后端 Pod:

上面的响应表明 Kube-DNS 已正确解析服务的 ClusterIP 服务名称,并且服务已成功将客户端请求转发到以循环方式选择的随机后端 Pod。反过来,选定的 Pod 会返回其自定义问候语,你就可以在上面的响应中看到结果。

使用 nslookup 检查 DNS 解析  

现在,查找 A Record 定义的 FQDN,验证 DNS 是否正常工作。为此,你需要将 shell 添加到正在运行的 Pod 中,并在其中使用 nslookup 命令。

首先,找到在部署中创建的 Pod:

kubectl get pods -l app=test-pod
NAME                               READY     STATUS    RESTARTS   AGE
test-deployment-84dc998fc5-772gj   1/1       Running   0          1m
test-deployment-84dc998fc5-fh5pf   1/1       Running   0          1m
test-deployment-84dc998fc5-pkmsc   1/1       Running   0          1m

选择其中一个 Pod 并使用下面的命令获取 shell(使用你的唯一 Pod name):

kubectl exec -ti test-deployment-84dc998fc5-772gj -- /bin/bash

下一步,你需要在 BusyBox 包中安装 nslookup 命令:

apt-get update
apt-get install busybox

安装 BusyBox 后,请检查服务的 DNS:

busybox nslookup test-service.default.svc.cluster.local
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name:      test-service.default.svc.cluster.local
Address 1: 10.109.90.121 test-service.default.svc.cluster.local

在上面的命令中,本实验使用了服务 A Record 的命名方案。现在,你可以通过验证 DNS 查找 DNS 服务的解析是否为正确的 IP(A Record)。

kubectl describe svc test-service
Name:              test-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=test-pod
Type:              ClusterIP
IP:                10.109.90.121
Port:              <unset>  4000/TCP
TargetPort:        http/TCP
Endpoints:         172.17.0.11:80,172.17.0.15:80,172.17.0.19:80
Session Affinity:  None
Events:            <none>

看起来很正确!你可以看到该服务的 ClusterIP 是 10.109.90.121 (与 DNS 查找解析的 IP 相同)。

调试 DNS  

如果 nslookup 命令由于某种原因失败,你会有几个调试和故障排除的方案。但是,你应该如何得知 DNS 查找失败呢?如果 DNS 失败,你通常会得到如下响应:

kubectl exec -ti busybox -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10
nslookup: can't resolve 'kubernetes.default'

如果出现此错误,你需要做的第一件事是检查 DNS 配置是否正确。

查看容器中的 resolv.conf 文件:

kubectl exec test-deployment-84dc998fc5-772gj cat /etc/resolv.conf

验证是否正确设置了搜索路径和名称服务器,如下例所示(请注意,搜索路径可能因不同的云提供商而异):

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

如果是 /etc/resolve.conf 的所有条目都是正确的,你需要检查 kube-dns / coredns 插件是否已启用。在 Minikube 上,运行:

minikube addons list
- addon-manager: enabled
- coredns: disabled
- dashboard: enabled
- default-storageclass: enabled
- efk: disabled
- freshpod: disabled
- heapster: disabled
- ingress: disabled
- kube-dns: enabled
- metrics-server: enabled
- registry: disabled
- registry-creds: disabled
- storage-provisioner: enabled

如你所见,本实验启用了 kube-dns 。如果你的 DNS 加载项未运行,你可以尝试使用以下命令启用它:

minikube addons enable kube-dns
kube-dns was successfully enabled

或者,你可以检查 kubedns / coredns Pod 是否正在运行:

kubectl get pods --namespace=kube-system
NAME                                    READY     STATUS    RESTARTS   AGE
....
kube-dns-86f4d74b45-2qkfd               3/3       Running   232        133d
kube-proxy-b2frq                        1/1       Running   0          15m
...

如果 Pod 正在运行,则全局 DNS 服务可能存在问题。

检查一下:

$ kubectl get svc --namespace=kube-system
NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
kube-dns               ClusterIP   10.96.0.10       <none>        53/UDP,53

你可能还需要检查是否公开了 DNS 端点:

kubectl get ep kube-dns --namespace=kube-system
NAME       ENDPOINTS                     AGE
kube-dns   172.17.0.5:53,172.17.0.5:53   133d

这些调试操作通常会指示 DNS 配置的问题,或者它只是向你显示应在集群配置中启用的 DNS 加载项。

[译] 深度剖析 K8S DNS 的 Service 与 Pod

总结

总而言之,Kubernetes 通过其内置的 DNS 附件实现高效的服务发现: Kube-DNS 或 CoreDNS。

Kubernetes DNS 系统会将域和子域名分配给 Pod、端口和服务,这使得它们可以被 Kubernetes 集群中的其他组件发现。

基于 DNS 的服务发现是非常强大,因为用户不需要将 IP 和端口等网络参数硬编码到应用程序中。 当服务管理一组 Pod 时,你就可以使用服务的 DNS 轻松访问它们了。

[译] 深度剖析 K8S DNS 的 Service 与 Pod

推荐阅读:

[译] 深度剖析 K8S DNS 的 Service 与 Pod

[译] 深度剖析 K8S DNS 的 Service 与 Pod

[译] 深度剖析 K8S DNS 的 Service 与 Pod

[译] 深度剖析 K8S DNS 的 Service 与 Pod

[译] 深度剖析 K8S DNS 的 Service 与 Pod

在看点一下

写留言


以上所述就是小编给大家介绍的《[译] 深度剖析 K8S DNS 的 Service 与 Pod》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Microsoft Windows程序设计

Microsoft Windows程序设计

佩措尔德 / 章立民 / 华中科技 / 2004-1 / 118.00元

Charles Petzold是全球最权威且知名的Windows程序设计专家,他将其最畅销Programming Microsoft Windows with C#一书加以改写,使之能完全适用于Visual Basic.NET的开发人员。这位畅销书的作家示范了如何使用Visual Basic.NET将Windows Forms的功能发挥到极致(Windows Forms是新一代的Windows程序......一起来看看 《Microsoft Windows程序设计》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具