目标
- 了解 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 不会在没有服务的情况下暴露在集群外部。服务允许您的应用程序接收流量。服务可以通过在规范中指定类型 来以不同的方式暴露规范服务
- 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 教程。另请参见 使用服务连接应用程序。
此外,请注意,服务中有一些用例涉及在规范中不定义选择器。在没有
选择器 的情况下创建的服务也不会创建相应的端点对象。这允许用户将服务手动映射到特定的端点。没有选择器的另一个可能原因是您严格使用
类型: 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)。
要找出外部打开的端口(用于类型: 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 "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。
准备就绪后,请继续了解 运行您的应用的多个实例。