使用 Service 暴露你的应用程序

了解 Kubernetes 中的 Service。理解标签和选择器与 Service 的关系。将应用程序暴露到 Kubernetes 集群外部。

目标

  • 了解 Kubernetes 中的 Service
  • 理解标签和选择器与 Service 的关系
  • 使用 Service 将应用程序暴露到 Kubernetes 集群外部

Kubernetes Service 概述

Kubernetes Pod 是有生命周期的。Pod 具有生命周期。当工作节点宕机时,在该节点上运行的 Pod 也会丢失。副本集可能会通过创建新的 Pod 来动态地将集群恢复到所需状态,以保持应用程序运行。另一个例子是具有 3 个副本的图像处理后端。这些副本是可以互换的;前端系统不应该关心后端副本,甚至不应该关心 Pod 是否丢失并重新创建。也就是说,Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址,即使是同一节点上的 Pod 也是如此,因此需要一种自动协调 Pod 之间变化的方法,以便应用程序能够继续运行。

Kubernetes 中的 Service 是一种抽象,它定义了一组逻辑 Pod 以及访问它们的策略。Service 实现了依赖 Pod 之间的松散耦合。与所有 Kubernetes 对象清单一样,Service 是使用 YAML 或 JSON 定义的。Service 定位的 Pod 集通常由*标签选择器*确定(请参阅下文,了解为什么你可能希望 Service 的规约中不包含 `selector`)。

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

  • *ClusterIP*(默认)- 在集群的内部 IP 上暴露 Service。此类型使 Service 只能在集群内访问。
  • *NodePort* - 使用 NAT 在集群中每个选定节点的同一端口上暴露 Service。使用 `<NodeIP>:<NodePort>` 使 Service 可以从集群外部访问。ClusterIP 的超集。
  • *LoadBalancer* - 在当前云中(如果支持)创建一个外部负载均衡器,并为 Service 分配一个固定的外部 IP。NodePort 的超集。
  • *ExternalName* - 通过返回一个值为 `externalName` 字段内容(例如 `foo.bar.example.com`)的 `CNAME` 记录,将 Service 映射到该字段的内容。不设置任何类型的代理。此类型需要 v1.7 或更高版本的 `kube-dns` 或 CoreDNS 0.0.8 或更高版本。

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

此外,请注意,Service 的某些用例涉及不在规约中定义 `selector`。没有 `selector` 创建的 Service 也不会创建相应的端点对象。这允许用户手动将 Service 映射到特定端点。可能没有选择器的另一个原因是你严格使用 `type: ExternalName`。

总结

  • 将 Pod 暴露给外部流量
  • 在多个 Pod 之间进行负载均衡
  • 使用标签

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


Service 和标签

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

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

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


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

步骤 1:创建新 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

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

要找出外部打开了哪个端口(对于type: NodePortService),我们将运行 `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"

我们将从服务器获得响应。服务已暴露。

步骤 2:使用标签

Deployment 会自动为我们的 Pod 创建一个标签。使用 describe deployment 子命令,您可以看到该标签的名称(即*键*)

kubectl describe deployment

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

kubectl get pods -l app=kubernetes-bootcamp

您可以使用相同的命令列出现有的服务

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 "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:删除服务

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

kubectl delete service -l app=kubernetes-bootcamp

确认服务已消失

kubectl get services

这确认我们的服务已被移除。要确认路由不再暴露,您可以curl先前暴露的 IP 和端口

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

这证明应用程序不再可以从集群外部访问。您可以使用curl从 pod 内部

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

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

准备好后,请继续阅读 运行您的应用的多个实例