简介
在之前的实验中,你已经了解到 Pod 会不断创建和销毁。如果一个 Pod 出现故障,由新的 Pod 替代它,新 Pod 会获得完全不同的 IP 地址。想象一下:你每次挂断电话后,朋友的电话号码都会改变!
Kubernetes 使用 Service 解决这个问题。
即使后端 Pod 发生变化,Service 也能为工作负载提供稳定的网络身份。将 Pod 生命周期与 Service 端点分离,是 Kubernetes 网络机制中的基本理念。
这是 Kubernetes 网络中最重要的思维模型之一:Pod 应该可以被替换,但客户端仍然需要一个可靠的地址。Service 位于不断变化的 Pod 前面,通过稳定的名称和虚拟 IP 对外提供访问入口,从而解决了这一矛盾。
在本实验中,你将:
- 创建一个 Service,为应用提供稳定的地址。
- 了解 Service 如何知道应该将请求发送给哪些 Pod(使用 Selector)。
- 使用一种名为 NodePort 的 Service 类型从集群外部访问应用。
创建 Service YAML
在此步骤中,你将为 Service 创建配置文件。我们将使用一种名为 NodePort 的特定类型。
NodePort Service 会在集群中的每个 Node(服务器)上开放一个指定端口。这就像在房屋上打开一扇特定的门,让外部世界可以进入。
NodePort 易于理解,因为它会直接映射到每个节点上的端口,但在生产环境中通常不是对外部流量的最终设计方案。在较大的环境中,NodePort 通常位于云负载均衡器或 ingress 层之后。在本实验中使用 NodePort,是因为它能让初学者清楚地看到网络请求的路径。
在项目目录中创建名为 service.yaml 的文件:
nano service.yaml
粘贴以下内容。注意 selector 部分——我们暂时故意将其设置为 app: unknown,以便展示它的工作方式。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
ports:
- port: 80 ## The port the Service exposes internally
targetPort: 80 ## The port the container is listening on
nodePort: 30008 ## The static door we are opening to the outside
selector:
app: unknown ## This needs to match your Pod's label
保存并退出(Ctrl+X、Y、Enter)。
此文件定义了一个名为 my-service 的 Service。它会监听端口 30008(即 nodePort)。所有到达此端口的流量都会被转发到带有 app: unknown 标签的 Pod(当前不存在这样的 Pod!)。
修正选择器
Service 使用 Selector 查找应该接收流量的 Pod。它的作用类似于邮寄地址标签。如果信封上的地址(Service Selector)与房屋上的地址(Pod Label)不匹配,邮件就无法送达。
标签和选择器不仅用于 Service,还会出现在 Kubernetes 的各个部分中。它们是该平台的核心分组机制之一。Kubernetes 资源通常不会写死具体的 Pod 名称,而是通过匹配标签来查找相关对象。这样,即使 Pod 被重新创建,系统仍然保持灵活。
在 Setup 步骤中,我们已经为你自动启动了一个 Web 应用。现在找出它的「地址标签」。
运行以下命令,查看正在运行的 Pod 的标签:
kubectl get pods --show-labels
你应该会看到类似这样的内容:web-app-xxxxx ... app=web-app
标签是 app=web-app。但是,我们的 Service 查找的是 app: unknown。现在修正这个配置。
编辑 service.yaml 文件:
nano service.yaml
将 selector 部分修改为与你的 Pod 标签匹配:
selector:
app: web-app
保存并退出。现在,Service 已经准确知道应该将流量发送到哪里。
应用并验证
现在地址已经正确,接下来启用 Service。
应用此清单后,Kubernetes 会创建 Service 对象,并设置内部网络规则,使到达 Service 的请求可以转发到匹配的 Pod 端点。需要注意的是,Service 本身不会运行你的应用。它是位于应用 Pod 前面的网络抽象层。
将配置应用到集群:
kubectl apply -f service.yaml
你应该会看到:service/my-service created。
确认 Service 已启动并正在运行,查看指定 Service:
kubectl get svc my-service
你将看到:
- NAME:my-service
- TYPE:NodePort
- **PORT(S)**:80:30008/TCP
这表示你的「电话号码」已经启用,并正在端口 30008 上等待请求。
访问应用
现在到了验证结果的时候。我们能否从「外部」(你的终端)访问应用?
应用已经暴露在 Kubernetes Node 的 30008 端口上。
这里涉及三个端口,初学者经常会混淆它们。nodePort 是节点上对外开放的端口,port 是 Service 抽象层暴露的端口,targetPort 是容器内部实际提供应用服务的端口。区分这三个端口的作用,可以避免后续产生混淆。
首先,获取 Minikube 节点的 IP 地址:
minikube ip
假设结果是 192.168.49.2。应用的完整地址就是 http://192.168.49.2:30008。
我们可以使用 curl 访问这个地址,验证应用是否响应:
curl http://$(minikube ip):30008
你应该会看到「Welcome to nginx!」页面的 HTML 代码。
这说明请求完整地经过了以下路径:
- 你访问了 Node 的外部端口(
30008)。 - Service 接收了请求。
- 它检查了自己的 Selector(
app: web-app)。 - 它将请求转发给了带有该标签的某个 Pod。
- Pod 返回了网页。
总结
在本实验中,你使用 Service 解决了 Pod IP 地址不断变化的问题。
你已经成功完成以下操作:
- 创建了一个 NodePort Service(
service.yaml),为应用打开访问入口。 - 配置了 Selector,告诉 Service 应该管理哪些 Pod。
- 使用稳定地址从外部访问了正在运行的应用。
Service 是连接 Kubernetes 应用各部分的纽带,使系统的不同部分能够可靠地相互通信。


