使用 Service 公开你的应用程序

目标

  • 了解 Kubernetes 中的 Service。
  • 理解标签(Label)和选择器(Selector)如何与 Service 相关联。
  • 将应用程序公开到 Kubernetes 集群之外。

开始之前

本教程中的 Shell 命令使用 POSIX Shell 语法,大多数 Linux 和 macOS 系统上的默认 Shell(例如 bash、zsh 或 sh)都支持该语法。Windows 用户必须使用支持 POSIX 的 Shell(如 Windows Subsystem for Linux (WSL)Git Bash)才能按原样运行这些命令。使用 export$() 和类似结构的命令兼容 PowerShell 或 Windows 命令提示符。

Kubernetes Service 概述

Kubernetes Pod 是脆弱的,具有自己的 生命周期。当工作节点崩溃时,在该节点上运行的 Pod 也会随之丢失。此时,ReplicaSet 可能会动态地将集群恢复到期望状态,通过创建新的 Pod 来保持应用运行。以一个具有 3 个副本的图像处理后端为例:这些副本是可互换的,前端系统不应关心后端副本,甚至不关心某个 Pod 是否丢失并被重新创建。话虽如此,Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址(即使是同一节点上的 Pod 也是如此),因此需要一种自动协调 Pod 间变动的方法,以确保应用程序持续正常运行。

Kubernetes 中的 Service 是一种抽象,定义了一组逻辑上的 Pod 以及访问它们的策略。Service 实现了依赖 Pod 之间的松耦合。像所有 Kubernetes 对象清单一样,Service 使用 YAML 或 JSON 定义。Service 目标 Pod 的集合通常由“标签选择器(Label Selector)”决定(下文会说明为什么有时需要在定义中不包含 selector)。

尽管每个 Pod 都有一个唯一的 IP 地址,但如果没有 Service,这些 IP 不会暴露在集群外部。Service 允许应用程序接收流量。可以通过在 Service 的 spec 中指定 type 来以不同方式暴露 Service。

  • ClusterIP(默认)- 在集群内部 IP 上公开 Service。这种类型使 Service 只能从集群内部访问。

  • NodePort - 使用 NAT 在集群中每个已选节点的相同端口上公开 Service。通过 NodeIP:NodePort 使 Service 可从集群外部访问。它是 ClusterIP 的超集。

  • LoadBalancer - 在当前云服务中创建一个外部负载均衡器(如果支持),并为 Service 分配一个固定的外部 IP。它是 NodePort 的超集。

  • ExternalName - 通过返回包含其值的 CNAME 记录,将 Service 映射到 externalName 字段的内容(例如 foo.bar.example.com)。不会设置任何代理。此类型需要 v1.7 或更高版本的 kube-dns,或 CoreDNS 0.0.8 或更高版本。

有关不同 Service 类型的更多信息,请参阅 使用源 IP 教程。另请参阅 使用 Service 连接应用程序

此外,请注意有些 Service 的使用场景涉及在 spec 中不定义 selector。在没有 selector 的情况下创建的 Service 也不会创建对应的 Endpoints 对象。这允许用户手动将 Service 映射到特定的端点。没有选择器的另一个原因是您严格使用 type: ExternalName

服务(Service)与标签(Label)

Service 在一组 Pod 之间路由流量。它们是 Kubernetes 中的一种抽象,允许 Pod 在不影响应用程序的情况下销毁和复制。依赖 Pod(例如应用程序中的前端和后端组件)之间的发现和路由由 Kubernetes Service 处理。

Service 使用 标签和选择器(Labels and Selectors) 来匹配一组 Pod,这是一种允许对 Kubernetes 中的对象进行逻辑操作的分组原语。标签是附加到对象的键/值对,可以以多种方式使用。

  • 为开发、测试和生产环境指定对象。
  • 嵌入版本标签。
  • 使用标签对对象进行分类。

标签可以在创建对象时附加,也可以在之后附加。它们可以随时修改。现在让我们使用 Service 公开我们的应用程序并应用一些标签。

第 1 步:创建新的 Service

让我们验证应用程序是否正在运行。我们将使用 kubectl get 命令查看现有的 Pod。

kubectl get pods

如果没有正在运行的 Pod,说明之前教程中的对象已被清理。在这种情况下,请返回并从 使用 kubectl 创建 Deployment 教程中重新创建 Deployment。请稍等几秒钟并再次列出 Pod。看到有一个 Pod 在运行后即可继续。

接下来,让我们列出集群中当前的 Service。

kubectl get services

要将 Deployment 暴露给外部流量,我们将使用带有 --type=NodePort 选项的 kubectl expose 命令。

kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

现在我们有了一个名为 kubernetes-bootcamp 的运行中的 Service。在这里,我们看到该 Service 接收了一个唯一的集群 IP、一个内部端口和一个外部 IP(节点的 IP)。

要找出外部打开了什么端口(对于 type: NodePort 的 Service),我们将运行 describe service 子命令。

kubectl describe services/kubernetes-bootcamp

创建一个名为 NODE_PORT 的环境变量,其值为已分配的节点端口。

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo "NODE_PORT=$NODE_PORT"

现在我们可以使用 curl、节点的 IP 地址和外部暴露的端口,测试该应用程序是否在集群外部被成功公开。

curl http://"$(minikube ip):$NODE_PORT"

说明

如果您使用 Docker Desktop 作为容器驱动运行 minikube,则需要使用 minikube tunnel。这是因为 Docker Desktop 内的容器与您的主机计算机是隔离的。

在单独的终端窗口中,执行:

minikube service kubernetes-bootcamp --url

输出如下所示

http://127.0.0.1:51082
!  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

然后使用给定的 URL 访问该应用程序。

curl 127.0.0.1:51082

我们从服务器收到了响应。Service 已被成功公开。

第 2 步:使用标签

Deployment 自动为我们的 Pod 创建了一个标签。通过 describe deployment 子命令,您可以查看该标签的名称()。

kubectl describe deployment

让我们使用此标签来查询我们的 Pod 列表。我们将使用 kubectl get pods 命令,并将 -l 作为参数,后跟标签的值。

kubectl get pods -l app=kubernetes-bootcamp

您可以使用相同的方法列出现有的 Service。

kubectl get services -l app=kubernetes-bootcamp

获取 Pod 的名称并将其存储在 POD_NAME 环境变量中。

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
echo "Name of the Pod: $POD_NAME"

要应用新标签,我们使用 label 子命令,后跟对象类型、对象名称和新标签。

kubectl label pods "$POD_NAME" version=v1

这将为我们的 Pod 应用一个新标签(我们将应用程序版本固定到 Pod 上),我们可以使用 describe pod 命令进行检查。

kubectl describe pods "$POD_NAME"

我们在这里看到标签现在已附加到我们的 Pod 上。现在可以使用新标签查询 Pod 列表。

kubectl get pods -l version=v1

我们看到了该 Pod。

第 3 步:删除 Service

要删除 Service,可以使用 delete service 子命令。标签在这里也可以使用。

kubectl delete service -l app=kubernetes-bootcamp

确认 Service 已被删除。

kubectl get services

这确认了我们的 Service 已被移除。要确认路由不再被公开,您可以 curl 之前暴露的 IP 和端口。

curl http://"$(minikube ip):$NODE_PORT"

这证明应用程序无法再从集群外部访问。您可以通过在 Pod 内部执行 curl 来确认应用程序仍在运行。

kubectl exec -ti $POD_NAME -- curl https://:8080

我们看到应用程序正在运行。这是因为 Deployment 正在管理该应用程序。要关闭应用程序,您还需要删除 Deployment。

接下来


最后修改时间:2026 年 3 月 12 日 下午 3:33 PST:明确先决条件中的 POSIX shell 措辞 (5d98744874)