本期文章是K8s系列第5篇,主要是实战使用Service暴露应用。通过本期文章:我们将学习了解 Kubernetes 中的 Service,学习标签(Label) 和 标签选择器(Label Selector) 对象如何与 Service 关联,最后在 Kubernetes 集群外用 Service 暴露应用。
在前期的文章中,已经介绍了一些云原生入门的知识及简单实战,感兴趣的同学可以去我的云原生专栏中学习,任意门:云原生学习专栏
本期的学习目标是:
Kubernetes Pod 实际上是拥有生命周期的。 当一个工作 Node 挂掉后, 在 Node 上运行的 Pod 也会消亡。 ReplicaSet 会自动地通过创建新的 Pod 驱动集群回到目标状态,以此可以保证应用程序正常运行。
换一个例子来说明,目前有一个具有3个副本数的用作图像处理的后端程序。这些副本是可替换的,前端系统不应该关心后端副本,即使 Pod 丢失或重新创建。
这也就是说,Kubernetes 集群中的每个 Pod (即使是在同一个 Node 上的 Pod )都有一个唯一的 IP 地址,因此需要一种方法自动协调 Pod 之间的变更,以便应用程序保持运行。
Kubernetes 中的服务(Service)是一种抽象概念,它定义了 Pod 的逻辑集和访问 Pod 的协议。Service 使从属 Pod 之间的松耦合成为可能。 和其他 Kubernetes 对象一样, Service 用 YAML (更推荐) 或者 JSON 来定义. Service 下的一组 Pod 通常由 LabelSelector 来标记。
尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service ,这些 IP 不会暴露在集群外部。Service 允许你的应用程序接收流量。Service 也可以用在 ServiceSpec 标记type的方式暴露。
Service 通过一组 Pod 路由通信。Service 是一种抽象,它允许 Pod 死亡并在 Kubernetes 中复制,而不会影响应用程序。在依赖的 Pod (如应用程序中的前端和后端组件)之间进行发现和路由是由Kubernetes Service 处理的。
Service 匹配一组 Pod 是使用 标签(Label)和选择器(Selector), 它们是允许对 Kubernetes 中的对象进行逻辑操作的一种分组原语。标签(Label)是附加在对象上的键/值对,可以以多种方式使用,如:
接下来,我们将实战如何使用kubectl expose命令在集群外公开Kubernetes应用程序。我们还将学习如何使用kubectl label命令查看并将标签应用到对象。
实战使用的环境是在线终端是预先配置好的Linux环境,可以作为常规控制台使用(可以输入命令)
让我们验证一下应用程序是否正在运行。我们将使用kubectl get命令并查找现有的Pods:、
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-fb5c67579-pgxxl 1/1 Running 0 51s
$
我们有一个名为kubernetes的服务,它是在minikube启动集群时默认创建的。为了创建一个新服务并将其公开给外部通信,我们将使用expose命令,将NodePort作为参数(minikube还不支持LoadBalancer选项)。
kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
接下来,让我们列出集群中当前的服务:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7m37s
kubernetes-bootcamp NodePort 10.110.52.119 <none> 8080:30349/TCP 97s
现在有一个服务叫做kubernetes-bootcamp。这里我们看到服务接收了一个唯一的集群IP、一个内部端口和一个外部IP(节点的IP)。
要找出外部打开了哪些端口(通过NodePort选项),我们将运行如下的describe service命令:
$ kubectl describe services/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
Labels: app=kubernetes-bootcamp
Annotations: <none>
Selector: app=kubernetes-bootcamp
Type: NodePort
IP Families: <none>
IP: 10.110.52.119
IPs: 10.110.52.119
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 30349/TCP
Endpoints: 172.18.0.6:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
创建一个名为NODE_PORT的环境变量,分配节点端口的值:
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=30349
现在我们可以使用curl、节点的IP和外部暴露的端口来测试应用程序是否暴露在集群外:
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-fb5c67579-pgxxl | v=1
部署自动为Pod创建了一个标签。使用description部署命令,我们可以看到标签的名称:
kubectl describe deployment
让我们使用这个标签来查询Pods列表。我们将使用kubectl get pods命令,参数是-l,后面是标签值:
$ kubectl get pods -l app=kubernetes-bootcamp
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-fb5c67579-pgxxl 1/1 Running 0 15m
我们也可以这样做来列出现有的服务:
$ kubectl get services -l app=kubernetes-bootcamp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-bootcamp NodePort 10.110.52.119 <none> 8080:30349/TCP 10m
获取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
Name of the Pod: kubernetes-bootcamp-fb5c67579-pgxxl
接下来要应用一个新标签,我们使用label命令,后面跟着对象类型、对象名称和新标签:
$ kubectl label pods $POD_NAME version=v1
pod/kubernetes-bootcamp-fb5c67579-pgxxl labeled
这将为我们的Pod应用一个新标签(我们把应用版本钉在了Pod上),我们可以用describe Pod命令来检查它:
kubectl describe pods $POD_NAME
我们在这里看到标签现在连接到我们的Pod。现在我们可以使用新标签查询:
$ kubectl get pods -l version=v1
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-fb5c67579-pgxxl 1/1 Running 0 18m
需要删除服务,使用delete service命令。标签也可以在这里使用:
$ kubectl delete service -l app=kubernetes-bootcamp
service "kubernetes-bootcamp" deleted
确认服务已消失:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 20m
这证实了我们的服务已被删除。为了确认路由没有暴露,我们可以查询之前暴露的IP和端口:
$ curl $(minikube ip):$NODE_PORT
curl: (7) Failed to connect to 10.0.0.12 port 30349: Connection refused
这证明了应用程序从集群外部无法再访问。我们可以确认应用程序仍在运行,并在pod内卷起:
$ kubectl exec -ti $POD_NAME -- curl localhost:8080
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-fb5c67579-pgxxl | v=1
我们在这里看到,应用程序启动了。这是因为部署正在管理应用程序。如果要关闭应用程序,还需要删除Deployment。