10: 服务发现深入探讨
在本章中,你将了解服务发现、它为何重要,以及它在 Kubernetes 中的实现方式。你还将学习一些故障排查技巧。
如果你了解 Kubernetes Service,本章将让你收获最大。如果你还不了解,应该先阅读第 7 章。
我将本章分为以下几个部分:
- 场景设定
- 服务注册表
- 服务注册
- 服务发现
- 服务发现与命名空间
- 服务发现故障排查
关于术语
“service”一词有诸多不同含义,因此当指代 Kubernetes API 中的 Service 资源时,我将首字母大写(Service)。
场景设定
在像 Kubernetes 这样的繁忙平台上查找资源很困难,而服务发现使其变得简单。
大多数 Kubernetes 集群运行着成百上千个微服务应用。其中大部分应用位于自己的 Service 之后,并拥有各自可靠的名称和 IP。当一个应用与另一个应用通信时,它实际上是与其他应用的 Service 通信。在本章剩余部分,每当提到一个应用需要找到或与其他应用通信时,我们指的即是它需要找到或与另一个应用前面的 Service 通信。
图 10.1 展示了 app-a 通过其 Service 与 app-b 通信。
图 10.1 - 应用通过 Service 连接
应用需要具备两个条件才能向其他应用发送请求:
- 一种知道其他应用名称(其 Service 的名称)的方式。
- 一种将名称转换为 IP 地址的方式。
开发人员负责步骤 1——确保应用知道它们所消费的其他应用和微服务的名称。Kubernetes 负责步骤 2——将名称转换为 IP 地址。
图 10.2 是整体流程的高层次视图,包含四个主要步骤:
- 步骤 1:开发人员配置 app-a 与 app-b 通信。
- 步骤 2:app-a 向 Kubernetes 询问 app-b 的 IP 地址。
- 步骤 3:Kubernetes 返回 IP 地址。
- 步骤 4:app-a 向 app-b 的 IP 地址发送请求。
图 10.2
步骤 1 是唯一的手动步骤。Kubernetes 自动处理步骤 2、3 和 4。
我们来更仔细地看看。
服务注册表
服务注册表的工作是维护一个 Service 名称及其关联 IP 地址的列表。
每个 Kubernetes 集群都有一个内置的集群 DNS,用作其服务注册表。它是一个 Kubernetes 原生应用,在每个 Kubernetes 集群的控制平面上以两个或多个 Pod 的形式运行,这些 Pod 由一个 Deployment 管理,并由其自己的 Service 作为前端。该 Deployment 通常称为 coredns 或 kube-dns,而 Service 始终称为 kube-dns。
图 10.3 展示了 Kubernetes 服务注册表架构。它还展示了一个 Service 注册其名称和 IP,以及两个容器使用它进行服务发现。稍后你将发现,Kubernetes 使服务注册和服务发现自动进行。
图 10.3 - 集群 DNS 架构
以下命令显示了组成集群 DNS(服务注册表)的 Pod、Deployment 和 Service。它们与图 10.3 中的内容一致,你可以在自己的集群上运行这些命令。
此命令列出运行集群 DNS 的 Pod。它们通常使用 registry.k8s.io/coredns/coredns 镜像,但某些其他集群使用不同的镜像,并可能将 Pod 和 Deployment 称为 kube-dns 而不是 coredns。
$ kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-76f75df574-d6nn5 1/1 Running 0 13d
coredns-76f75df574-n7qzk 1/1 Running 0 13d下一个命令显示管理 Pod 的 Deployment。它确保始终运行正确数量的集群 DNS Pod。
$ kubectl get deploy -n kube-system -l k8s-app=kube-dns
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 13d最后一个命令显示集群 DNS Pod 前面的 Service。它始终称为 kube-dns,但在每个集群上获得不同的 IP。稍后你将发现,Kubernetes 会自动配置每个容器使用此 IP 进行服务发现。
$ kubectl get svc -n kube-system -l k8s-app=kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP总之,每个 Kubernetes 集群都运行着一个内部集群 DNS 服务,用作其服务注册表。它将每个 Service 的名称和 IP 映射起来,并在控制平面上以一组 Pod 的形式运行,由 Deployment 管理,并由一个 Service 作为前端。
接下来,让我们把重点转向服务注册。
服务注册
关于 Kubernetes 上的服务注册,最重要的一点是:它是自动的!
从高层次来看,你开发应用并将其放到 Service 后面,以获得可靠的名称和 IP。Kubernetes 会自动将这些 Service 名称和 IP 注册到服务注册表中。从现在开始,我们将服务注册表称为集群 DNS。
服务注册有三个步骤:
- 为 Service 赋予一个名称。
- 为 Service 分配一个 IP。
- 将名称和 IP 注册到集群 DNS。
开发人员负责第一点,Kubernetes 负责第二点和第三点。
考虑一个快速示例。
你正在开发一个新的 Web 应用,其他应用将使用名称 valkyrie-web 连接到它。为此,你将应用部署在一个名为 valkyrie-web 的 Kubernetes Service 之后。Kubernetes 确保 Service 名称唯一,并自动为其分配一个 IP 地址(ClusterIP)。它还将名称和 IP 注册到集群 DNS 中。
注册过程是自动的,因为集群 DNS 是一个 Kubernetes 原生应用,它会监视 API 服务器以获取新的 Service。每当它看到一个新的 Service,就会自动注册其名称和 IP。这意味着你的应用程序不需要任何服务注册逻辑——你将它们放在一个 Service 之后,集群 DNS 完成其余所有工作。
图 10.4 总结了服务注册流程,并补充了第 7 章中的一些细节。
图 10.4 - 服务注册流程
让我们逐步解析该图。
你部署了一个新应用,该应用由一个 YAML 文件定义,描述了一个 Deployment 和一个 Service。你将其提交给 Kubernetes,在那里它经过身份验证和授权。Kubernetes 为该 Service 分配一个 ClusterIP,并将其配置持久化到集群存储中。集群 DNS 观察到新 Service,并注册相应的 DNS A 记录和 SRV 记录。创建关联的 EndpointSlice 对象,以保存与 Service 标签选择器匹配的健康 Pod IP 列表。每个集群节点上的 kube-proxy 进程观察到这些新对象,并创建本地路由规则(IPVS),以便发往 Service ClusterIP 的请求被路由到 Pod。
总之,每个应用都位于一个 Service 之后,以获得可靠的名称和 IP。集群 DNS 监视 API 服务器以获取新的 Service 对象,并自动注册其名称和 IP。
服务发现
应用通过名称与其他应用通信。然而,它们需要将这些名称转换为 IP 地址,这就是服务发现发挥作用的地方。
假设你有一个集群,其中包含两个应用:enterprise 和 cerritos。enterprise 应用位于一个名为 ent 的 ClusterIP Service 之后,而 cerritos 应用位于一个名为 cer 的 Service 之后。Kubernetes 自动为这两个 Service 分配了 ClusterIP,集群 DNS 也自动注册了它们。目前情况如下:
| 应用 | Service 名称 | ClusterIP |
|---|---|---|
| Enterprise | ent | … |
10: 服务发现深入探讨
| App | Service name | ClusterIP |
|---|---|---|
| Enterprise | ent | 192.168.201.240 |
| Cerritos | cer | 192.168.200.217 |
图 10.5
如果任一应用想要连接到另一个应用,它需要知道对方的名字以及如何将该名字转换为 IP。
开发者负责在应用程序中编写代码以包含它们所消费的应用的名称,但 Kubernetes 提供了将名称转换为 IP 的机制。
考虑一个快速示例,图 10.5 中的企业应用需要向 cerritos 应用发送请求。为此,企业应用开发者需要将其配置为 cerritos 应用前面的 Service 的名称。假设他们这样做了,企业应用将向 cer 发送请求。然而,它需要一种将 cer 转换为 IP 地址的方法。幸运的是,Kubernetes 将每个容器配置为向集群 DNS 请求名称到 IP 的转换。这意味着企业应用容器会将 cer 名称发送给集群 DNS,集群 DNS 将返回 ClusterIP。然后应用向该 IP 发送请求。
如前所述,Kubernetes 将每个容器配置为使用集群 DNS 进行服务发现。它通过自动配置每个容器的 /etc/resolv.conf 文件(写入集群 DNS Service 的 IP 地址)来实现这一点。它还会添加搜索域,用于追加到非限定名称后面。
非限定名称是短名称,例如 ent。追加一个搜索域会将其转换为完全限定域名(FQDN),例如 ent.default.svc.cluster.local。
以下摘录自一个容器的 /etc/resolv.conf 文件,该容器配置为将服务发现请求(DNS 查询)发送到位于 10.96.0.10 的集群 DNS。它还列出了三个搜索域,用于追加到非限定名称后面。
$ cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10 <<---- ClusterIP of internal clus
options ndots:5以下命令证明前一个 /etc/resolv.conf 文件中的 nameserver IP 与集群 DNS(kube-dns Service)的 IP 地址相匹配。
$ kubectl get svc -n kube-system -l k8s-app=kube-dns
NAME TYPE CLUSTER-IP PORT(S) AG
kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 1现在你已经了解了基础知识,我们来看一下图 10.5 中的企业应用如何向 cerritos 应用发送请求。
首先,企业应用需要知道 cerritos 应用前面的 cer Service 的名称。这是企业应用开发者的工作。假设它知道这个名称,它会向 cer 发送请求。应用容器的网络栈自动将名称发送给集群 DNS,询问关联的 IP。集群 DNS 返回 cer Service 的 ClusterIP,请求被发送到该 IP。然而,ClusterIP 是虚拟 IP,需要额外的魔法来确保请求最终到达 cerritos Pod。
ClusterIP 路由
ClusterIP 位于一个称为服务网络的特殊网络上,并且没有通往该网络的路由!这意味着每个容器都会将 ClusterIP 流量发送到其默认网关。
术语:默认网关
默认网关是系统在不知道将网络流量发送到哪里时发送流量的地方。默认网关随后将流量转发到另一个设备,期望下一个设备知道将其发送到哪里。
容器的默认网关将流量发送到它运行所在的节点。节点也没有通往服务网络的路由,因此它将流量发送到自己的默认网关。这导致节点的内核处理该流量,而魔法就在此处发生……
每个 Kubernetes 节点上运行着一个称为 kube-proxy 的系统服务,它实现了一个控制器,监视 API Server 以获取新的 Service 和 EndpointSlice 对象。每当它看到这些对象时,它会在内核中创建规则,以拦截 ClusterIP 流量并将其转发到各个 Pod IP。
这意味着,每当节点的内核处理针对某个 ClusterIP 的流量时,它都会将其重定向到与 Service 的标签选择器匹配的健康 Pod 的 IP。
服务发现总结
让我们借助图 10.6 中的流程图快速总结服务发现过程。
图 10.6
企业应用向 cer Service 发送请求。容器通过将名称发送到其 /etc/resolv.conf 文件中配置的集群 DNS IP 地址,将名称转换为 IP 地址。集群 DNS 返回 Service 的 ClusterIP,然后容器将流量发送到该 IP 地址。但是,ClusterIP 位于服务网络上,而容器没有通往该网络的路由。因此,它将其发送到默认网关,默认网关将其转发到容器运行所在的节点。节点也没有路由,因此将其发送到自己的默认网关。这导致节点的内核处理该请求,并将其重定向到与 Service 的标签选择器匹配的 Pod 的 IP 地址。
服务发现与命名空间
每个 Kubernetes 对象在集群地址空间中都有一个名称,你可以使用命名空间(Namespace)来划分地址空间。
集群地址空间是一个 DNS 域,通常称为集群域。在大多数集群上,它是 cluster.local,并且对象名称在域内必须是唯一的。例如,你只能在 default 命名空间中拥有一个名为 cer 的 Service,它的名称将是 cer.default.svc.cluster.local。
像这样的长名称称为完全限定域名(FQDN),格式为 <object-name>.<namespace>.svc.cluster.local。
你可以使用命名空间来划分集群域下方的地址空间。例如,如果你的集群有两个命名空间 dev 和 prod,地址空间将如下划分:
dev:<service-name>.dev.svc.cluster.localprod:<service-name>.prod.svc.cluster.local
对象名称在命名空间内必须是唯一的,但在不同命名空间之间不必唯一。作为快速示例,图 10.7 显示了一个集群被划分为两个命名空间 dev 和 prod。两个命名空间都有相同的 cer Service 实例。这使得命名空间成为在同一个集群上运行并行开发和生产配置的一种选择。
图 10.7 - 不同命名空间中的相同配置
应用可以使用短名称(如 ent 和 cer)连接到本地命名空间中的 Service,但必须使用完全限定域名才能连接到远程命名空间中的 Service。
让我们通过一个快速示例来实践。
服务发现示例
以下 YAML 来自本书 GitHub 仓库中 service-discovery 文件夹下的 sd-example.yml 文件。它部署了图 10.8 中的配置。
该文件定义了两个命名空间、两个 Deployment、两个 Service 以及一个独立的跳板 Pod。Deployment 和 Service 具有相同的名称,因为它们位于不同的命名空间。跳板 Pod 仅部署到 dev 命名空间。书中对 YAML 进行了截断。
图 10.8
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Namespace
metadata:
name: prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: enterprise
namespace: dev
spec:
replicas: 2
template:
spec:
containers:
- image: nigelpoulton/k8sbook:text-dev
name: enterprise-ctr
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: enterprise
namespace: prod
spec:
replicas: 2
template:
spec:
containers:
- image: nigelpoulton/k8sbook:text-prod
name: enterprise-ctr
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: ent
namespace: dev
spec:
selector:
app: enterprise
ports:
- port: 8080
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
name: ent
namespace: prod
spec:
selector:
app: enterprise
ports:
- port: 8080
type: ClusterIP
---
apiVersion: v1
kind: Pod
metadata:
name: jump
namespace: dev
spec:
terminationGracePeriodSeconds: 5
containers:
- name: jump
image: ubuntu
tty: true
stdin: true运行以下命令来部署所有内容。你需要在 service-discovery 目录中执行该命令。
$ kubectl apply -f sd-example.yml
namespace/dev created
namespace/prod created
deployment.apps/enterprise created
deployment.apps/enterprise created
service/ent created
service/ent created
pod/jump-pod created检查 Kubernetes 是否正确部署了所有内容。我已裁剪输出以适应页面,并且只显示部分对象。
$ kubectl get all --namespace dev
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/enterprise 2/2 2 2 51s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
service/ent ClusterIP 10.96.138.186 <none> 8080/TCP
<Snip>
$ kubectl get all --namespace prod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/enterprise 2/2 2 2 1m24
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
service/ent ClusterIP 10.96.147.32 <none> 8080/TCP
<snip>你有了两个命名空间 dev 和 prod,每个命名空间都有一个企业应用实例和一个 ent Service 实例。dev 命名空间还有一个名为 jump 的独立 Pod。
让我们看看服务发现如何在命名空间内部以及跨命名空间工作。
你将执行以下所有操作:
- 登录到
dev命名空间中的jumpPod。 - 检查其
/etc/resolv.conf文件。 - 连接到本地
dev命名空间中的entService。 - 连接到远程
prod命名空间中的entService。
每个命名空间中的应用版本会返回不同的消息,以便你确认连接到了正确的版本。
打开一个交互式 exec 会话到 jump Pod 的容器。你的终端提示符会改变,示你已附加到容器。
$ kubectl exec -it jump --namespace dev -- bash
root@jump:/#检查容器 /etc/resolv.conf 文件的内容。它应该包含集群 kube-dns Service 的 IP 地址以及 dev 命名空间的搜索域(dev.svc.cluster.local)。
# cat /etc/resolv.conf
search dev.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5安装 curl 工具。
# apt-get update && apt-get install curl -y
<snip>运行以下 curl 命令以连接到端口 8080 上的 ent Service。这将连接到本地 dev 命名空间中的实例。
# curl ent:8080
Hello from the DEV Namespace!
Hostname: enterprise-76fc64bd9-lvzsnHello from the DEV Namespace! 响应证明连接到达了 dev 命名空间中的实例。
容器自动将 dev.svc.cluster.local 追加到名称后面,并将查询发送到其 /etc/resolv.conf 文件中指定的集群 DNS。集群 DNS 返回本地 dev 命名空间中 ent Service 的 ClusterIP,应用将流量发送到该 IP 地址。在流量到达节点默认网关的途中,流量触发了节点内核中的陷阱,导致内核将其重定向到托管该应用的 Pod。
再次运行 curl 命令,但这次附加 prod 命名空间的域名。这将导致集群 DNS 返回 prod 命名空间中 Service 的 ClusterIP。
# curl ent.prod.svc.cluster.local:8080
Hello from the PROD Namespace!
Hostname: enterprise-b5468cd4d-gfm7k这次响应显示来自 PROD 命名空间,证明连接跨越了命名空间边界。
跨命名空间服务发现
要从一个命名空间连接到另一个命名空间中的 Service,必须使用完全限定域名(FQDN)格式:
<service-name>.<namespace>.svc.cluster.local。本地命名空间允许使用短名称。
你还可以通过以下命令验证跳板 Pod 的 DNS 解析功能:
# nslookup ent
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: ent.dev.svc.cluster.local
Address: 10.96.138.186nslookup 返回了本地命名空间中的 Service 的 FQDN 和 ClusterIP。
检查 prod 命名空间中的 ent Service:
# nslookup ent.prod.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: ent.prod.svc.cluster.local
Address: 10.96.147.32每个命名空间中的 Service 都有不同的 ClusterIP,并且 DNS 解析正确。
服务发现故障排查
如果应用无法通过服务名称连接,可以遵循以下排查步骤:
- 验证 Service 存在:使用
kubectl get svc --namespace <namespace>确认 Service 对象已创建。 - 检查 /etc/resolv.conf:确认容器内的 nameserver 指向正确的集群 DNS IP(通常是
10.96.0.10),并且搜索域包含正确的命名空间。 - 使用诊断 Pod 测试 DNS 解析:部署一个临时 Pod(如
busybox或ubuntu),并使用nslookup或dig测试名称能否解析为 IP。 - 检查 EndpointSlice:使用
kubectl get endpointslices确认 Service 背后有匹配的 Pod 端点。如果没有端点,检查 Pod 是否正常运行以及标签选择器是否匹配。 - 检查 kube-proxy 规则:在节点上使用
iptables -L -t nat | grep <ClusterIP>或ipvsadm -L -n(取决于 kube-proxy 模式)查看是否有正确的 NAT 规则。 - 检查网络策略:确认命名空间或集群中的网络策略未阻止流量。
- 查看 kube-dns Pod 日志:
kubectl logs -n kube-system -l k8s-app=kube-dns可以显示 DNS 查询失败的信息。
常见问题
- 名称超时:通常是因为集群 DNS Pod 未运行或网络连接问题。
- 解析到错误 IP:检查
/etc/resolv.conf中的搜索域顺序,确保本地命名空间优先。- 连接被拒绝:确认 Pod 的端口已正确暴露,且 Service 的目标端口与 Pod 容器端口匹配。
总结
Kubernetes 服务发现基于集群 DNS 和 kube-proxy 实现。每个容器的 /etc/resolv.conf 指向集群 DNS,集群 DNS 将 Service 名称解析为 ClusterIP。由于 ClusterIP 是虚拟 IP,节点内核通过 kube-proxy 创建的规则重定向流量到健康的 Pod IP。命名空间允许对象名称复用,并支持在同一集群内隔离开发和生产环境。跨命名空间通信需要使用 FQDN。故障排查时应从 DNS、端点、kube-proxy 规则和网络策略入手。
10: 服务发现深入探讨
再次执行 curl 命令,但这次追加 prod 命名空间的域名。这将使集群 DNS 返回 prod 命名空间中服务的 ClusterIP。
# curl ent.prod.svc.cluster.local:8080
Hello from the PROD Namespace!
Hostname: enterprise-5cfcd578d7-nvzlp这一次,响应来自 prod 命名空间中的一个 Pod。
测试证明,Kubernetes 会自动将短名称解析到本地命名空间,并且你需要指定 FQDN 才能跨命名空间连接。
输入 exit 以从 jump Pod 断开终端连接。
服务发现故障排查
Kubernetes 使服务注册和服务发现自动化。然而,幕后发生了很多事情,了解如何检查和重启这些组件是很有帮助的。
如前所述,Kubernetes 使用集群 DNS 作为其内置的服务注册表。它作为一个或多个托管 Pod 运行,并附带一个提供稳定端点的 Service 对象。重要的组件包括:
- Pods:由
corednsDeployment 管理 - Service:一个名为
kube-dns的 ClusterIP Service,监听 53 端口(TCP/UDP) - EndpointSlice 对象:名称以
kube-dns为前缀
所有这些对象都位于 kube-system 命名空间中,并带有标签 k8s-app=kube-dns,以帮助你找到它们。
检查 coredns Deployment 及其 Pod 是否正在运行。
$ kubectl get deploy -n kube-system -l k8s-app=kube-dns
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 14d
$ kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-76f75df574-6q7k7 1/1 Running 0 14d
coredns-76f75df574-krnr7 1/1 Running 0 14d检查每个 coredns Pod 的日志。以下输出是正常工作的 DNS Pod 的典型输出。你需要使用自己环境中的 Pod 名称。
$ kubectl logs coredns-76f75df574-n7qzk -n kube-system
.:53
[INFO] plugin/reload: Running configuration SHA512 = 591cf328cccc
CoreDNS-1.11.1
linux/arm64, go1.20.7, ae2bbc2现在检查 Service 和 EndpointSlice 对象。输出应显示服务已启动,ClusterIP 字段中有 IP 地址,并监听 53 端口(TCP/UDP)。
kube-dns Service 的 ClusterIP 地址必须与集群中所有容器的 /etc/resolv.conf 文件中的 IP 地址匹配。如果不匹配,容器会将 DNS 请求发送到错误的位置。
$ kubectl get svc kube-dns -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,关联的 kube-dns EndpointSlice 对象也应处于正常状态,并包含监听 53 端口的 coredns Pod 的 IP 地址。
$ kubectl get endpointslice -n kube-system -l k8s-app=kube-dns
NAME ADDRESSTYPE PORTS ENDPOINTS
kube-dns-jb72g IPv4 9153,53,53 10.244.1.9,10.244.1.14一旦验证了基本的 DNS 组件已启动并正常工作,你就可以执行更详细、更深入的故障排查。以下是一些简单的提示。
启动一个故障排查 Pod,其中包含你喜欢的网络工具(ping、traceroute、curl、dig、nslookup 等)。registry.k8s.io/e2e-test-images/jessie-dnsutils 镜像是一个常用的选择,如果你没有自己的自定义镜像。你可以访问 explore.ggcr.dev 浏览 registry.k8s.io/e2e-test-images 仓库以获取更新版本。
以下命令启动一个名为 dnsutils 的新独立 Pod,并将连接你的终端。它基于刚才提到的镜像,可能需要几秒钟才能启动。
$ kubectl run -it dnsutils \
--image registry.k8s.io/e2e-test-images/jessie-dnsutils:1.7测试集群 DNS 是否正常工作的常用方法是使用 nslookup 解析 kubernetes Service。该服务在每个集群上运行,并将 API 服务器暴露给所有 Pod。查询应返回名称 kubernetes.default.svc.cluster.local 及其 IP 地址。
# nslookup kubernetes
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1前两行应显示集群 DNS 的 IP 地址。最后两行应显示 kubernetes Service 的 FQDN 及其 ClusterIP。你可以通过运行 kubectl get svc kubernetes 来验证 kubernetes Service 的 ClusterIP。
DNS 故障
诸如
nslookup: can't resolve kubernetes之类的错误表明 DNS 无法正常工作。一种可能的解决方法是删除corednsPod。这将导致corednsDeployment 重新创建它们。
以下命令删除 DNS Pod。如果你仍然登录到 dnsutils Pod,则需要先输入 exit 断开连接,然后再运行该命令。
$ kubectl delete pod -n kube-system -l k8s-app=kube-dns
pod "coredns-76f75df574-d6nn5" deleted
pod "coredns-76f75df574-n7qzk" deleted运行 kubectl get pods -n kube-system -l k8s-app=kube-dns 验证它们已重启,然后再次测试 DNS。
清理
运行以下命令进行清理。
$ kubectl delete pod dnsutils
$ kubectl delete -f sd-example.yml本章总结
在本章中,你学习了 Kubernetes 使用内部集群 DNS 进行服务注册和服务发现。这是一个 Kubernetes 原生的应用程序,它监视 API 服务器中新创建的 Service 对象,并自动注册它们的
[Images 位置参考]
- [Image 2158 on Page 284]
- [Image 2161 on Page 286]
- [Image 2163 on Page 287]
- [Image 2171 on Page 291]
- [Image 2174 on Page 293]
- [Image 2179 on Page 297]
- [Image 2182 on Page 299]
- [Image 2184 on Page 300]