web service设置参数命名空间_深度剖析 K8S DNS 的 Service 与 Pod

c178f5fc14047f79c2ae8bfc8e5bcb67.png

作者: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 命名解决服务问题;

  • 总结。

2f2ea66edd9d0fc713d38acdc3cdc9ec.png

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=标识的容器。配置kubelet时,管理员还可以使用--cluster-domain= 指定本地域名。

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

7a8adef97e99598fe739d128796e9b0d.png

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 端口号和域名。

47665cb51e21c4a668738f756fbdcfee.png

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的条目。

c8abd27253a8c0de835614ee44d5b27e.png

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

9095fdbb8aa6cc6195157e596d8fcc88.png

教程:如何通过 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:
Annotations:
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:

看起来很正确!你可以看到该服务的 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 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 加载项。

7fb0bcc589f8f4b6cec7960f510d6d99.png

总结

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

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

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


4193dfdeeeef888861e3cda3ee194785.png

推荐阅读:

094e91b65e32ae38165c4835facb1ab5.png

fdfc03e36ee3d7bd47d9f0dea9713b90.png

c306de0c426c5469a03709e7a4e2fc94.png

9ce2e8f6decb83b77ce6b6fdd656975c.png

b1901aff2707e691fa3810258984ab76.png

326482d350fe1c73f7bba901c170b85c.png 在看点一下

写留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值