使用 Service 公开你的应用程序
目标
- 了解 Kubernetes 中的 Service。
- 了解标签和选择器与 Service 的关系。
- 将应用程序暴露到 Kubernetes 集群外部。
Kubernetes Service 概述
Kubernetes Pod 是短暂的。Pod 具有 生命周期。当工作节点死亡时,在节点上运行的 Pod 也会丢失。一个 ReplicaSet 可能会动态地将集群恢复到所需状态,通过创建新的 Pod 来保持应用程序的运行。例如,考虑一个具有 3 个副本的图像处理后端。这些副本是可互换的;前端系统不应关心后端副本,甚至 Pod 是否丢失并被重新创建。也就是说,Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址,即使在同一个节点上的 Pod 也是如此,因此需要一种自动协调 Pod 更改的方法,以便您的应用程序继续运行。
Kubernetes 中的 Service 是一种抽象,它定义了一组 Pod 的逻辑集合以及访问它们的方式策略。Service 实现了 Pod 之间的松耦合。Service 使用 YAML 或 JSON 定义,就像所有 Kubernetes 对象清单一样。Service 针对的 Pod 集合通常由一个标签选择器确定(请参阅下方为什么您可能需要一个没有在 spec 中包含 selector 的 Service)。
虽然每个 Pod 都有一个唯一的 IP 地址,但这些 IP 地址在没有 Service 的情况下无法暴露到集群外部。Service 允许您的应用程序接收流量。可以通过在 Service 的 spec 中指定一个 type 来以不同的方式暴露 Service
ClusterIP (默认) - 在集群中的内部 IP 上暴露 Service。这种类型使 Service 只能从集群内部访问。
NodePort - 使用 NAT 在集群中每个选定的节点上的相同端口上暴露 Service。使用
NodeIP:NodePort可以从集群外部访问 Service。ClusterIP 的超集。LoadBalancer - 在当前云中创建一个外部负载均衡器(如果受支持),并为 Service 分配一个固定的外部 IP。NodePort 的超集。
ExternalName - 将 Service 映射到
externalName字段的内容(例如foo.bar.example.com),通过返回一个包含其值的CNAME记录。不设置任何类型的代理。此类型需要 v1.7 或更高版本的kube-dns,或 CoreDNS 版本 0.0.8 或更高版本。
有关不同类型的 Service 的更多信息,请参阅 使用源 IP 教程。另请参阅 使用 Service 连接应用程序。
此外,请注意,在 Service 中有一些不定义 selector 的用例。创建没有 selector 的 Service 也不会创建相应的 Endpoints 对象。这允许用户手动将 Service 映射到特定的端点。另一个可能没有选择器的情况是您严格使用 type: ExternalName。
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
为了将部署暴露给外部流量,我们将使用带有 --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。
接下来
- 教程 运行应用程序的多个实例。
- 了解更多关于 Service 的信息。