Information in this document may be out of date

This document has an older update date than the original, so the information it contains may be out of date. If you're able to read English, see the English version for the most up-to-date information: Using a Service to Expose Your App

使用 Service 暴露你的应用

了解 Kubernetes 中的 Service。 理解标签和选择算符如何关联到 Service。 在 Kubernetes 集群外暴露应用。

目标

  • 了解 Kubernetes 中的 Service
  • 了解标签(Label)和选择算符(Selector)如何与 Service 关联
  • 在 Kubernetes 集群外用 Service 暴露应用

Kubernetes Service 总览

Kubernetes Pod 是转瞬即逝的。 Pod 拥有 生命周期。 当一个工作节点挂掉后, 在节点上运行的 Pod 也会消亡。 ReplicaSet 会自动地通过创建新的 Pod 驱动集群回到目标状态,以保证应用正常运行。 换一个例子,考虑一个具有 3 个副本的用作图像处理的后端程序。 这些副本是可替换的。前端系统不应该关心后端副本,即使某个 Pod 丢失或被重新创建。 此外,Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址,即使是在同一个 Node 上的 Pod 也是如此, 因此需要一种方法来自动协调 Pod 之间的变化,以便应用保持运行。

Kubernetes 中的服务(Service)是一种抽象概念,它定义了 Pod 的逻辑集和访问 Pod 的协议。 Service 使从属 Pod 之间的松耦合成为可能。 和所有 Kubernetes 对象清单一样, Service 用 YAML 或者 JSON 来定义。 Service 下的一组 Pod 通常由一个 标签选择算符 来标记 (请参阅下面的说明为什么你可能想要一个 spec 中不包含 selector 的 Service)。

尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service,这些 IP 不会被公开到集群外部。 Service 允许你的应用接收流量。 通过设置 Service 的 spec 中的 type,你可以用不同的方式公开 Service:

  • ClusterIP(默认)- 在集群的内部 IP 上公开 Service。这种类型使得 Service 只能从集群内访问。
  • NodePort - 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service 。使用<NodeIP>:<NodePort> 从集群外部访问 Service。是 ClusterIP 的超集。
  • LoadBalancer - 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。
  • ExternalName - 将 Service 映射到 externalName 字段的内容(例如 foo.bar.example.com),通过返回带有该名称的 CNAME 记录实现。不设置任何类型的代理。这种类型需要 kube-dns 的 v1.7 或更高版本,或者 CoreDNS 的 0.8 或更高版本。

关于不同 Service 类型的更多信息可以在使用源 IP 教程找到。 也请参阅 使用 Service 连接到应用

另外,需要注意的是有一些 Service 的用例不需要在 spec 中定义 selector。 一个创建时未设置 selector 的 Service 也不会创建相应的 Endpoint 对象。 这允许用户手动将 Service 映射到特定的端点。 没有 selector 的另一种可能是你在严格使用 type: ExternalName 服务。

总结

  • 将 Pod 暴露给外部通信
  • 跨多个 Pod 的负载均衡
  • 使用标签(Label)

Kubernetes 的 Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露、负载平衡和服务发现。


Service 和 Label

Service 为一组 Pod 提供流量路由。Service 是一种抽象,允许 Kubernetes 中的 Pod 死亡和复制,而不会影响应用。 在依赖的 Pod(如应用中的前端和后端组件)之间进行发现和路由是由 Kubernetes Service 处理的。

Service 通过标签和选择算符来匹配一组 Pod, 它们是允许对 Kubernetes 中的对象进行逻辑操作的一种分组原语。 标签是附加在对象上的键/值对,可以以多种方式使用:

  • 指定用于开发、测试和生产的对象
  • 嵌入版本标记
  • 使用标记将对象分类


标签可以在对象创建时或之后附加到对象上。它们可以随时被修改。现在使用 Service 发布我们的应用并添加一些标签。


第一步:创建新 Service

让我们来验证我们的应用正在运行。我们将使用 kubectl get 命令并查找现有的 Pod:

kubectl get pods

如果没有 Pod 正在运行,则意味着之前教程中的对象已被清理。这时, 请返回并参考 使用 kubectl 创建 Deployment 教程重新创建 Deployment。 请等待几秒钟,然后再次列举 Pod。一旦看到一个 Pod 正在运行,你就可以继续了。

接下来,让我们列举当前集群中的 Service:

kubectl get services

我们有一个名为 kubernetes 的 Service ,它在 minikube 启动集群时默认创建。 要创建一个新的 Service 然后暴露给外部流量,我们将使用 expose 命令,并将 NodePort 作为参数。

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

让我们再次运行 get services 子命令:

kubectl get services

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

要得到外部打开的端口号(对于 type: NodePort 的服务),我们需要运行 describe service 子命令:

kubectl describe services/kubernetes-bootcamp

创建一个名为 NODE_PORT 的环境变量,它的值为所分配的 Node 端口:

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

现在我们可以使用 curl、Node 的 IP 地址和对外暴露的端口,来测试应用是否已经被公开到了集群外部:

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

然后我们就会收到服务器的响应。Service 已经被暴露。

第二步:使用标签

Deployment 自动给我们的 Pod 创建了一个标签。通过 describe deployment 子命令你可以看到那个标签的名称(对应 key):

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 pods 命令检查它:

kubectl describe pods "$POD_NAME"

我们可以看到现在标签已经被附加到我们的 Pod 上。我们可以通过新的标签来查询 Pod 列表:

kubectl get pods -l version=v1

我们看到了对应的 Pod。

第三步:删除一个 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 http://localhost:8080

这里我们看到应用是运行状态。这是因为 Deployment 正在管理应用。 要关闭应用,你还需要删除 Deployment。

准备好之后,继续学习运行应用的多个实例

最后修改 December 09, 2023 at 9:18 PM PST: [zh-cn] sync tutorials/* (0f9e2f2569)