使用服务公开你的应用程序
目标
- 了解 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 与所有 Kubernetes 对象清单一样,使用 YAML 或 JSON 定义。Service 所指向的 Pod 集合通常由_标签选择器_决定(有关为何需要在不包含 selector
的情况下创建 Service,请参阅下文)。
尽管每个 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
)。不设置任何类型的代理。此类型需要kube-dns
v1.7 或更高版本,或者 CoreDNS 0.0.8 或更高版本。
有关不同类型的 Service 的更多信息,请参阅使用源 IP 教程。另请参阅使用 Service 连接应用程序。
此外,请注意,Service 有些用例不涉及在 spec 中定义 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
为了将 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。
下一步
- 教程运行应用程序的多个实例。
- 了解有关Service的更多信息。