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

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

内容简介:作者: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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

REST实战

REST实战

Jim Webber、Savas Parastatidis、Ian Robinson / 李锟、俞黎敏、马钧、崔毅 / 东南大学出版社 / 2011-10 / 78.00元

为何典型的企业项目无法像你为web所开发的项目那样运行得如此平滑?对于建造分布式和企业级的应用来说,rest架构风格真的提供了一个可行的替代选择吗? 在这本富有洞察力的书中,三位soa专家对于rest进行了讲求实际的解释,并且通过将web的指导原理应用到普通的企业计算问题中,向你展示了如何开发简单的、优雅的分布式超媒体系统。你将会学习到很多技术,并且随着一家典型的公司从最初的小企业逐渐成长为......一起来看看 《REST实战》 这本书的介绍吧!

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具