1 部署应用Pod

Kubernetes集群上自主运行的Pod对象在非计划内终止后,其生命周期即告结束,用户需要再次手动创建类似的Pod对象才能确保其容器中的依然可得。对于Pod数量众多的场景,尤其是对微服务业务来说,用户必将疲于应付此类需求。Kubernetes的工作负载(workload)类型的控制器能够自动确保由其管控的Pod对象按用户期望的方式运行,因此,Pod的创建和管理大多会通过这种类型的控制器来进行,包括DeploymentReplicasSetReplicationController等。

1)创建Deployment控制器对象

kubectl run命令可用于命令行直接创建Deployment控制器,并以 --image选项指定的镜像运行Pod中的容器,--dry-run选项可以用于命令的测试,但并不真正执行资源对象的创建过程。

  1. # 创建一个名字叫做nginx的deployment控制器,并指定pod镜像使用nginx:1.12版本,并暴露容器内的80端口,并指定副本数量为1个,并先通过--dry-run测试命令是否错误。
  2. [root@k8s-master ~]# kubectl run nginx --image=nginx:1.12 --port=80 --replicas=1 --dry-run=true
  3. [root@k8s-master ~]# kubectl run nginx --image=nginx:1.12 --port=80 --replicas=1
  4. deployment.apps/nginx created
  5. [root@k8s-master ~]# kubectl get pods #查看所有pod对象
  6. NAME READY STATUS RESTARTS AGE
  7. nginx-685cc95cd4-9z4f4 1/1 Running 0 89s
  8. ###参数说明:
  9. --image 指定需要使用到的镜像。
  10. --port 指定容器需要暴露的端口。
  11. --replicas 指定目标控制器对象要自动创建Pod对象的副本数量。

2)打印资源对象的相关信息

kubectl get 命令可用来获取各种资源对象的相关信息,它既能显示对象类型特有格式的简要信息,也能按照指定格式为YAMLJSON的详细信息,或者使用Go模板自定义要显示的属性及信息等。

  1. [root@k8s-master ~]# kubectl get deployment #查看所有deployment控制器对象
  2. NAME READY UP-TO-DATE AVAILABLE AGE
  3. nginx 1/1 1 1 66s
  4. ###字段说明:
  5. NAME 资源对象名称
  6. READY 期望由当前控制器管理的Pod对象副本数及当前已有的Pod对象副本数
  7. UP-TO-DATE 更新到最新版本定义的Pod对象的副本数量,在控制器的滚动更新模式下,表示已经完成版本更新的Pod对象的副本数量
  8. AVAILABLE 当前处于可用状态的Pod对象的副本数量,即可正常提供服务的副本数。
  9. AGE Pod的存在时长
  10. 说明:Deployment资源对象通过ReplicaSet控制器实例完成对Pod对象的控制,而非直接控制。另外,通过控制器创建的Pod对象都会被自动附加一个标签。格式为“run=<Controller_Name>”。
  11. [root@k8s-master ~]# kubectl get deployment -o wide #查看deployment控制器对象的详细信息
  12. NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
  13. nginx 1/1 1 1 69m nginx nginx:1.12 run=nginx
  14. [root@k8s-master ~]# kubectl get pods #查看pod资源
  15. NAME READY STATUS RESTARTS AGE
  16. nginx-685cc95cd4-9z4f4 1/1 Running 0 72m
  17. [root@k8s-master ~]# kubectl get pods -o wide
  18. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  19. nginx-685cc95cd4-9z4f4 1/1 Running 0 73m 10.244.1.12 k8s-node1 <none> <none>
  20. ###字段说明:
  21. NAME pode资源对象名称
  22. READY pod中容器进程初始化完成并能够正常提供服务时即为就绪状态,此字段用于记录处于就绪状态的容器数量
  23. STATUS pod的当前状态,其值有PendingRunningSucceededFailedUnknown等其中之一
  24. RESTARTS Pod重启的次数
  25. IP podIP地址,通常由网络插件自动分配
  26. NODE pod被分配的节点。

3)访问Pod对象

这里部署的是pod是运行的为nginx程序,所以我们可以访问是否ok,在kubernetes集群中的任意一个节点上都可以直接访问PodIP地址。

  1. [root@k8s-master ~]# kubectl get pods -o wide #查看pod详细信息
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. nginx-685cc95cd4-9z4f4 1/1 Running 0 88m 10.244.1.12 k8s-node1 <none> <none>
  4. [root@k8s-master ~]# curl 10.244.1.12 #kubernetes集群的master节点上访问
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <title>Welcome to nginx!</title>
  9. <style>
  10. body {
  11. width: 35em;
  12. margin: 0 auto;
  13. font-family: Tahoma, Verdana, Arial, sans-serif;
  14. }
  15. </style>
  16. </head>
  17. <body>
  18. <h1>Welcome to nginx!</h1>
  19. <p>If you see this page, the nginx web server is successfully installed and
  20. working. Further configuration is required.</p>
  21. <p>For online documentation and support please refer to
  22. <a href="http://nginx.org/">nginx.org</a>.<br/>
  23. Commercial support is available at
  24. <a href="http://nginx.com/">nginx.com</a>.</p>
  25. <p><em>Thank you for using nginx.</em></p>
  26. </body>
  27. </html>
  28. [root@k8s-node2 ~]# curl 10.244.1.12 #kubernetes集群的node节点上访问
  29. <!DOCTYPE html>
  30. <html>
  31. <head>
  32. <title>Welcome to nginx!</title>
  33. <style>
  34. body {
  35. width: 35em;
  36. margin: 0 auto;
  37. font-family: Tahoma, Verdana, Arial, sans-serif;
  38. }
  39. </style>
  40. </head>
  41. <body>
  42. <h1>Welcome to nginx!</h1>
  43. <p>If you see this page, the nginx web server is successfully installed and
  44. working. Further configuration is required.</p>
  45. <p>For online documentation and support please refer to
  46. <a href="http://nginx.org/">nginx.org</a>.<br/>
  47. Commercial support is available at
  48. <a href="http://nginx.com/">nginx.com</a>.</p>
  49. <p><em>Thank you for using nginx.</em></p>
  50. </body>
  51. </html>

上面访问是基于一个pod的情况下,但是,当这个pod由于某种原因意外挂掉了,或者所在的节点挂掉了,那么deployment控制器会立即创建一个新的pod,这时候再去访问这个IP就访问不到了,而我们不可能每次去到节点上看到IP再进行访问。测试如下:

  1. [root@k8s-master ~]# kubectl get pods -o wide
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. nginx-685cc95cd4-9z4f4 1/1 Running 0 99m 10.244.1.12 k8s-node1 <none> <none>
  4. [root@k8s-master ~]# kubectl delete pods nginx-685cc95cd4-9z4f4 #删除上面的pod
  5. pod "nginx-685cc95cd4-9z4f4" deleted
  6. [root@k8s-master ~]# kubectl get pods -o wide #可以看出,当上面pod刚删除,接着deployment控制器又马上创建了一个新的pod,且这次分配在k8s-node2节点上了。
  7. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  8. nginx-685cc95cd4-z5z9p 1/1 Running 0 89s 10.244.2.14 k8s-node2 <none> <none>
  9. [root@k8s-master ~]# curl 10.244.1.12 #访问之前的pod,可以看到已经不能访问
  10. curl: (7) Failed connect to 10.244.1.12:80; 没有到主机的路由
  11. [root@k8s-master ~]#
  12. [root@k8s-master ~]# curl 10.244.2.14 #访问新的pod,可以正常访问
  13. <!DOCTYPE html>
  14. <html>
  15. <head>
  16. <title>Welcome to nginx!</title>
  17. <style>
  18. body {
  19. width: 35em;
  20. margin: 0 auto;
  21. font-family: Tahoma, Verdana, Arial, sans-serif;
  22. }
  23. </style>
  24. </head>
  25. <body>
  26. <h1>Welcome to nginx!</h1>
  27. <p>If you see this page, the nginx web server is successfully installed and
  28. working. Further configuration is required.</p>
  29. <p>For online documentation and support please refer to
  30. <a href="http://nginx.org/">nginx.org</a>.<br/>
  31. Commercial support is available at
  32. <a href="http://nginx.com/">nginx.com</a>.</p>
  33. <p><em>Thank you for using nginx.</em></p>
  34. </body>
  35. </html>

2 部署Service对象

简单来说,一个Service对象可视作通过其标签选择器过滤出的一组Pod对象,并能够为此组Pod对象监听的套接字提供端口代理及调度服务。就好比上面做的测试,如果没有Service,那么每次都得去访问pod对象自己的地址等。且那还只是创建了一个pod对象,如果是多个。那么该如何是好?故使用Service解决此问题。

1)创建Service对象(将Service端口代理至Pod端口示例)

"kubectl expose"命令可用于创建Service对象以将应用程序“暴露”(expose)于网络中。

  1. #方法一
  2. [root@k8s-master ~]# kubectl expose deployment nginx --name=nginx-svc --port=80 --target-port=80 --protocol=TCP #为deployment的nginx创建service,取名叫nginx-svc,并通过service的80端口转发至容器的80端口上。
  3. service/nginx-svc exposed
  4. #方法二
  5. [root@k8s-master ~]# kubectl expose deployment/nginx --name=nginx-svc --port=80 --target-port=80 --protocol=TCP
  6. service/nginx-svc exposed
  7. ###参数说明:
  8. --name 指定service对象的名称
  9. --port 指定service对象的端口
  10. --target-port 指定pod对象容器的端口
  11. --protocol 指定协议
  12. [root@k8s-master ~]# kubectl get svc #查看service对象。或者kubectl get service
  13. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  14. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25h
  15. nginx-svc ClusterIP 10.109.54.136 <none> 80/TCP 41s

这时候可以在kubernetes集群上所有节点上直接访问nginx-svccluster-ip及可访问到名为deployment控制器下nginxpod。并且,集群中的别的新建的pod都可以直接访问这个IP或者这个service名称即可访问到名为deployment控制器下nginxpod。示例:

  1. # master节点上通过ServiceIP进行访问
  2. [root@k8s-master ~]# curl 10.109.54.136
  3. <!DOCTYPE html>
  4. <html>
  5. <head>
  6. <title>Welcome to nginx!</title>
  7. <style>
  8. body {
  9. width: 35em;
  10. margin: 0 auto;
  11. font-family: Tahoma, Verdana, Arial, sans-serif;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <h1>Welcome to nginx!</h1>
  17. <p>If you see this page, the nginx web server is successfully installed and
  18. working. Further configuration is required.</p>
  19. <p>For online documentation and support please refer to
  20. <a href="http://nginx.org/">nginx.org</a>.<br/>
  21. Commercial support is available at
  22. <a href="http://nginx.com/">nginx.com</a>.</p>
  23. <p><em>Thank you for using nginx.</em></p>
  24. </body>
  25. </html>
  26. #新建一个客户端pod进行访问,这里这个客户端使用busybox镜像,且pod副本数量为1个,-it表示进入终端模式。--restart=Never,表示从不重启。
  27. [root@k8s-master ~]# kubectl run client --image=busybox --replicas=1 -it --restart=Never
  28. If you don't see a command prompt, try pressing enter.
  29. / # wget -O - -q 10.109.54.136 #访问上面创建的(service)nginx-svc的IP
  30. <!DOCTYPE html>
  31. <html>
  32. <head>
  33. <title>Welcome to nginx!</title>
  34. ......
  35. / #
  36. / # wget -O - -q nginx-svc #访问上面创建的(service)名称nginx-svc
  37. <!DOCTYPE html>
  38. <html>
  39. <head>
  40. <title>Welcome to nginx!</title>

2)创建Service对象(将创建的Pod对象使用“NodePort”类型的服务暴露到集群外部)

  1. [root@k8s-master ~]# kubectl run mynginx --image=nginx:1.12 --port=80 --replicas=2 #创建一个deployments控制器并使用nginx镜像作为容器运行的应用。
  2. [root@k8s-master ~]# kubectl get pods #查看创建的pod
  3. NAME READY STATUS RESTARTS AGE
  4. client 1/1 Running 0 15h
  5. mynginx-68676f64-28fm7 1/1 Running 0 24s
  6. mynginx-68676f64-9q8dj 1/1 Running 0 24s
  7. nginx-685cc95cd4-z5z9p 1/1 Running 0 16h
  8. [root@k8s-master ~]#
  9. [root@k8s-master ~]# kubectl expose deployments/mynginx --type="NodePort" --port=80 --name=mynginx-svc #创建一个service对象,并将mynginx创建的pod对象使用NodePort类型暴露到集群外部。
  10. service/mynginx-svc exposed
  11. [root@k8s-master ~]#
  12. [root@k8s-master ~]# kubectl get svc #查看service
  13. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  14. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 41h
  15. mynginx-svc NodePort 10.111.89.58 <none> 80:30884/TCP 10s
  16. nginx-svc ClusterIP 10.109.54.136 <none> 80/TCP 15h
  17. ###字段说明:
  18. PORT(S) 这里的mynginx-svc对象可以看出,集群中各工作节点会捕获发往本地的目标端口为30884的流量,并将其代理至当前service对象的80端口。于是集群外部的用户可以使用当前集群中任一节点的此端口来请求Service对象上的服务。
  19. [root@k8s-master ~]#
  20. [root@k8s-master ~]# netstat -nlutp |grep 30884 #查看master节点上是否有监听上面的30884端口
  21. tcp6 0 0 :::30884 :::* LISTEN 7340/kube-proxy
  22. [root@k8s-node1 ~]#
  23. [root@k8s-node1 ~]# netstat -nlutp |grep 30884 #查看node节点是否有监听上面的30884端口
  24. tcp6 0 0 :::30884 :::* LISTEN 2537/kube-proxy

客户端访问kubernetes集群的30884端口
master.png
node.png

3)Service资源对象的描述

“kuberctl describe services”命令用于打印Service对象的详细信息,它通常包括Service对象的Cluster IP,关联Pod对象使用的标签选择器及关联到的Pod资源的端点等。示例

  1. [root@k8s-master ~]# kubectl describe service mynginx-svc
  2. Name: mynginx-svc
  3. Namespace: default
  4. Labels: run=mynginx
  5. Annotations: <none>
  6. Selector: run=mynginx
  7. Type: NodePort
  8. IP: 10.111.89.58
  9. Port: <unset> 80/TCP
  10. TargetPort: 80/TCP
  11. NodePort: <unset> 30884/TCP
  12. Endpoints: 10.244.1.14:80,10.244.2.15:80
  13. Session Affinity: None
  14. External Traffic Policy: Cluster
  15. Events: <none>
  16. ###字段说明:
  17. Selector 当前Service对象使用的标签选择器,用于选择关联的Pod对象
  18. Type Service的类型,其值可以是ClusterIPNodePortLoadBalancer等其中之一
  19. IP 当前Service对象的ClusterIP
  20. Port 暴露的端口,即当前Service用于接收并响应的端口
  21. TargetPort 容器中的用于暴露的目标端口,由Service Port路由请求至此端口
  22. NodePort 当前ServiceNodePort,它是否存在有效值与Type字段中的类型相关
  23. Endpoints 后端端点,即被当前ServiceSelector挑中的所有PodIP及其端口
  24. Session Affinity 是否启用会话粘性
  25. External Traffic Policy 外部流量的调度策略

3 扩容和缩容

所谓的“伸缩(Scaling)”就是指改变特定控制器上Pod副本数量的操作,“扩容(scaling up)”即为增加副本数量,而“缩容(scaling down)”则指缩减副本数量。不过,不论是扩容还是缩容,其数量都需要由用户明确给出。

Service对象内建的负载均衡机制可在其后端副本数量不止一个时自动进行流量分发,它还会自动监控关联到的Pod的健康状态,以确保将请求流量分发至可用的后端Pod对象。若某Deployment控制器管理包含多个Pod实例,则必要时用户还可以为其使用“滚动更新”机制将其容器镜像升级到新的版本或变更那些支持动态修改的Pod属性。

使用kubect run命令创建Deployment对象时,“--replicas=”选项能够指定由该对象创建或管理的Pod对象副本的数量,且其数量支持运行时进行修改,并立即生效。“kubectl scale”命令就是专用于变动控制器应用规模的命令,它支持对Deployment资源对象的扩容和缩容操作。

上面示例中创建的Deployment对象nginx仅创建了一个Pod对象,其所能够承载的访问请求数量即受限于这单个Pod对象的服务容量。请求流量上升到接近或超出其容量之前,可以通过kubernetes的“扩容机制”来扩招Pod的副本数量,从而提升其服务容量。

扩容示例

  1. [root@k8s-master ~]# kubectl get pods -l run=nginx #查看标签run=nginx的pod
  2. NAME READY STATUS RESTARTS AGE
  3. nginx-685cc95cd4-z5z9p 1/1 Running 0 17h
  4. [root@k8s-master ~]#
  5. [root@k8s-master ~]# kubectl scale deployments/nginx --replicas=3 #将其扩容到3个
  6. deployment.extensions/nginx scaled
  7. [root@k8s-master ~]#
  8. [root@k8s-master ~]# kubectl get pods -l run=nginx #再次查看
  9. NAME READY STATUS RESTARTS AGE
  10. nginx-685cc95cd4-f2cwb 1/1 Running 0 5s
  11. nginx-685cc95cd4-pz9dk 1/1 Running 0 5s
  12. nginx-685cc95cd4-z5z9p 1/1 Running 0 17h
  13. [root@k8s-master ~]#
  14. [root@k8s-master ~]# kubectl describe deployments/nginx #查看Deployment对象nginx详细信息
  15. Name: nginx
  16. Namespace: default
  17. CreationTimestamp: Thu, 29 Aug 2019 15:29:31 +0800
  18. Labels: run=nginx
  19. Annotations: deployment.kubernetes.io/revision: 1
  20. Selector: run=nginx
  21. Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
  22. StrategyType: RollingUpdate
  23. ...
  24. #由nginx自动创建的pod资源全部拥有同一个标签选择器“run=nginx”,因此,前面创建的Service资源对象nginx-svc的后端端点也已经通过标签选择器自动扩展到了这3个Pod对象相关的端点
  25. [root@k8s-master ~]# kubectl describe service/nginx-svc
  26. Name: nginx-svc
  27. Namespace: default
  28. Labels: run=nginx
  29. Annotations: <none>
  30. Selector: run=nginx
  31. Type: ClusterIP
  32. IP: 10.109.54.136
  33. Port: <unset> 80/TCP
  34. TargetPort: 80/TCP
  35. Endpoints: 10.244.1.15:80,10.244.2.14:80,10.244.2.16:80
  36. Session Affinity: None
  37. Events: <none>

缩容示例

缩容的方式和扩容相似,只不过是将Pod副本的数量调至比原来小的数字即可。例如将nginxpod副本缩减至2个

  1. [root@k8s-master ~]# kubectl scale deployments/nginx --replicas=2
  2. deployment.extensions/nginx scaled
  3. [root@k8s-master ~]#
  4. [root@k8s-master ~]# kubectl get pods -l run=nginx
  5. NAME READY STATUS RESTARTS AGE
  6. nginx-685cc95cd4-pz9dk 1/1 Running 0 10m
  7. nginx-685cc95cd4-z5z9p 1/1 Running 0 17h

4 删除对象

有一些不再有价值的活动对象可使用“kubectl delete”命令予以删除,需要删除Service对象nginx-svc时,即可使用下面命令完成:

  1. [root@k8s-master ~]# kubectl get services #查看当前所有的service对象
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 43h
  4. mynginx-svc NodePort 10.111.89.58 <none> 80:30884/TCP 96m
  5. nginx-svc ClusterIP 10.109.54.136 <none> 80/TCP 17h
  6. [root@k8s-master ~]# kubectl delete service nginx-svc #删除service对象nginx-svc

有时候要清空某一类型下的所有对象,只需要将上面的命令对象的名称缓存“--all”选项便能实现。例如,删除默认名称空间中所有的Deployment控制器的命令如下:

  1. [root@k8s-master ~]# kubectl delete deployment --all
  2. deployment.extensions "mynginx" deleted

注意:受控于控制器的Pod对象在删除后会被重建,删除此类对象需要直接删除其控制器对象。不过,删除控制器时若不想删除其Pod对象,可在删除命令上使用“--cascade=false“选项。

虽然直接命令式管理的相关功能强大且适合用于操纵Kubernetes资源对象,但其明显的缺点是缺乏操作行为以及待运行对象的可信源。另外,直接命令式管理资源对象存在较大的局限性,它们在设置资源对象属性方面提供的配置能力相当有限,而且还有不少资源并不支持命令操作进行创建,例如,用户无法创建带有多个容器的Pod对象,也无法为Pod对象创建存储卷。因此,管理资源对象更有效的方式是基于保存有对象配置信息的配置清单来进行。