目标
- 了解 Kubernetes 中的服务
- 了解标签和选择器与服务的关系
- 使用服务将应用程序暴露在 Kubernetes 集群之外
Kubernetes 服务概述
Kubernetes Pod 是短暂的。Pod 具有 生命周期。当工作节点死亡时,在该节点上运行的 Pod 也会丢失。然后,ReplicaSet 可以通过创建新的 Pod 来动态地将集群驱动回所需状态,以保持应用程序运行。例如,考虑一个具有 3 个副本的图像处理后端。这些副本是可互换的;前端系统不应该关心后端副本,甚至不应该关心 Pod 是否丢失和重新创建。也就是说,Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址,即使是同一节点上的 Pod 也是如此,因此需要一种方法来自动协调 Pod 之间的更改,以便您的应用程序继续运行。
Kubernetes 中的服务是一种抽象,它定义了一组逻辑 Pod 以及访问它们的策略。服务使依赖 Pod 之间的松散耦合成为可能。服务使用 YAML 或 JSON 定义,就像所有 Kubernetes 对象清单一样。服务所针对的 Pod 集通常由 _标签选择器_ 确定(有关您可能想要在规范中不包含 _选择器_ 的原因,请参见下文)。
虽然每个 Pod 都有一个唯一的 IP 地址,但这些 IP 不会在没有服务的情况下暴露在集群之外。服务允许您的应用程序接收流量。服务可以通过在规范中指定 _类型_ 来以不同的方式暴露spec服务
- _ClusterIP_(默认) - 在集群中的内部 IP 上暴露服务。此类型使服务只能从集群内部访问。
- _NodePort_ - 使用 NAT 在集群中每个选定节点的相同端口上暴露服务。使服务可以使用 _<NodeIP>:<NodePort>_ 从集群外部访问。ClusterIP 的超集。
- _LoadBalancer_ - 在当前云中创建外部负载均衡器(如果支持)并将固定外部 IP 分配给服务。NodePort 的超集。
- _ExternalName_ - 通过返回具有其值的 _CNAME_ 记录,将服务映射到 _externalName_ 字段的内容(例如 _foo.bar.example.com_)。不设置任何类型的代理。此类型需要 _kube-dns_ 的 v1.7 或更高版本,或 CoreDNS 版本 0.0.8 或更高版本。
有关不同类型服务的更多信息,请参阅 使用源 IP 教程。另请参阅 使用服务连接应用程序。
此外,请注意,服务中有一些用例涉及在规范中不定义 _选择器_。在没有 _选择器_ 的情况下创建的服务也不会创建相应的 Endpoints 对象。这允许用户手动将服务映射到特定端点。另一个可能没有选择器的原因是您严格使用 _type: ExternalName_。
总结
- 将 Pod 暴露给外部流量
- 跨多个 Pod 负载均衡流量
- 使用标签
Kubernetes 服务是一种抽象层,它定义了一组逻辑 Pod,并为这些 Pod 提供外部流量暴露、负载均衡和服务发现。
服务和标签
服务跨一组 Pod 路由流量。服务是允许 Pod 在 Kubernetes 中死亡和复制而不会影响您的应用程序的抽象。依赖 Pod 之间的发现和路由(例如应用程序中的前端和后端组件)由 Kubernetes 服务处理。
服务使用 标签和选择器 来匹配一组 Pod,标签和选择器是一种分组原语,允许对 Kubernetes 中的对象进行逻辑操作。标签是附加到对象的键值对,可以以多种方式使用
- 为开发、测试和生产指定对象
- 嵌入版本标签
- 使用标签对对象进行分类
标签可以在创建时或之后附加到对象。它们可以随时修改。现在让我们使用服务公开我们的应用程序并应用一些标签。
步骤 1:创建新服务
让我们验证我们的应用程序是否正在运行。我们将使用 _kubectl get_ 命令并查找现有的 Pod
kubectl get pods
如果没有任何 Pod 正在运行,则意味着来自先前教程的对象已清理。在这种情况下,请返回并从 使用 kubectl 创建部署 教程中重新创建部署。请等待几秒钟,然后再次列出 Pod。看到一个 Pod 正在运行后,您可以继续。
接下来,让我们列出集群中的当前服务
kubectl get services
我们有一个名为kubernetes的服务,它是 minikube 启动集群时默认创建的。要创建新服务并将其暴露给外部流量,我们将使用 expose 命令,并将 NodePort 作为参数。
kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
让我们再次运行 _get services_ 子命令
kubectl get services
现在我们有一个名为 kubernetes-bootcamp 的正在运行的服务。在这里,我们看到服务收到了一个唯一的集群 IP、一个内部端口和一个外部 IP(节点的 IP)。
要找出外部打开的端口(对于type: NodePort服务),我们将运行 _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 隧道。这是因为 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
我们从服务器获得响应。服务已暴露。
步骤 2:使用标签
部署自动为我们的 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 "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:删除服务
要删除服务,可以使用 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。
准备就绪后,请继续 运行应用程序的多个实例。