首页 > 技术文章 > Kubernetes 学习6 Pod控制器应用进阶

Presley-lpc 2019-05-13 18:01 原文

一、资源配置清单

  1、自主式Pod资源

  2、资源的清单格式,大多数清单格式都遵循如下条件:

    a、一级字段:apiVersion(group/version),kind,metadata(name,namespace,labels,annotations....),spec,status(只读)

二、在spec中常用的定义资源的字段

  1、spec.containers <[]object>#列表对象

    a、 name <string> #容器名称

    b、 image <string>  #镜像名称 一般格式为 项目名称/用户名称/镜像名称:标签

    c、  imagePullPolicy <string>#镜像获取策略

    d、Always(总是到仓库中下载,无论本地有没有都要去仓库中下载),Never(本地有就用,本地没有也不下载),IfNotPreseat(如果本地存在则直接使用,如果本地不存在就去仓库下载)。如果镜像标签为latest则默认为Always,如果镜像标签不是latest则默认为IfNotPresent模式。一旦对象创建后就不能被更改。

    e、ports #暴露端口

    f、command #默认启动命令,如果要用到shell 需要手动指定,不指定的话默认运行默认启动命令,相当于docker中的entrypoint

    g、args #向entrypoint 传递参数。默认启动命令为  entrypoint 命令 + Cmd 命令,若指定了args那么就变成了entrypoint命令 + args命令 ,args相当于docker中的Cmd命令 

    h、command 和 args与镜像中的各标签对比如下

      

三、资源标签

  1、资源标签的键名和值必须小于等于63个字符。key 和 value 都需要小于等于63个字符。并且键名只能使用字母数字下划线点号连接线。并且只能以字母或者数字开头。

  2、通过命令查看标签

[root@k8smaster manifests]# kubectl get pods -o wide --show-labels
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
myapp-848b5b879b-5k4s4        1/1       Running   0          4d        10.244.2.14   k8snode2   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-bzblz        1/1       Running   0          4d        10.244.1.21   k8snode1   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-hzbf5        1/1       Running   0          4d        10.244.1.22   k8snode1   pod-template-hash=4046164356,run=myapp
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4    k8snode2   pod-template-hash=16151555,run=nginx-deploy
pod-demo                      2/2       Running   1          1h        10.244.1.23   k8snode1   app=myapp,tier=frontend

  3、显示拥有app标签的值

[root@k8smaster manifests]# kubectl get pods -o wide -L app
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE       APP
myapp-848b5b879b-5k4s4        1/1       Running   0          4d        10.244.2.14   k8snode2   
myapp-848b5b879b-bzblz        1/1       Running   0          4d        10.244.1.21   k8snode1   
myapp-848b5b879b-hzbf5        1/1       Running   0          4d        10.244.1.22   k8snode1   
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4    k8snode2   
pod-demo                      2/2       Running   0          4m        10.244.2.16   k8snode2   myapp

  4、显示拥有app标签的pod

[root@k8smaster manifests]# kubectl get pods -o wide -l app --show-labels
NAME       READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
pod-demo   2/2       Running   0          8m        10.244.2.16   k8snode2   app=myapp,tier=frontend

  5、给pod用命令打标签

[root@k8smaster manifests]# kubectl label pods pod-demo release=canary #金丝雀
pod/pod-demo labeled
[root@k8smaster manifests]# kubectl get pods -o wide -l app --show-labels
NAME       READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
pod-demo   2/2       Running   0          13m       10.244.2.16   k8snode2   app=myapp,release=canary,tier=frontend

  6、修改已有标签

[root@k8smaster manifests]# kubectl get pods -o wide -l app --show-labels
NAME       READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
pod-demo   2/2       Running   0          13m       10.244.2.16   k8snode2   app=myapp,release=canary,tier=frontend
[root@k8smaster manifests]# kubectl label pods pod-demo release=stable --overwrite
pod/pod-demo labeled
[root@k8smaster manifests]# kubectl get pods -o wide -l app --show-labels
NAME       READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
pod-demo   2/2       Running   0          15m       10.244.2.16   k8snode2   app=myapp,release=stable,tier=frontend

  7、k8s的标签选择器有两类

    a、等值关系标签选择器: = ,==,!=(不等于)

[root@k8smaster manifests]# kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
myapp-848b5b879b-5k4s4        1/1       Running   0          4d
myapp-848b5b879b-bzblz        1/1       Running   0          4d
myapp-848b5b879b-hzbf5        1/1       Running   0          4d
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d
pod-demo                      2/2       Running   0          22m
[root@k8smaster manifests]# kubectl label pods nginx-deploy-5b595999-d9lv5 release=canary  
pod/nginx-deploy-5b595999-d9lv5 labeled
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l release  #查看包含release标签的pod
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4    k8snode2   pod-template-hash=16151555,release=canary,run=nginx-deploy
pod-demo                      2/2       Running   0          24m       10.244.2.16   k8snode2   app=myapp,release=stable,tier=frontend
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l release=canary  #查看包含release=canary标签的pod
NAME                          READY     STATUS    RESTARTS   AGE       IP           NODE       LABELS
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4   k8snode2   pod-template-hash=16151555,release=canary,run=nginx-deploy
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l release,app  #查看既包含release又包含app标签的pod
NAME       READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
pod-demo   2/2       Running   0          24m       10.244.2.16   k8snode2   app=myapp,release=stable,tier=frontend
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l release=stable,app=myapp #查看release=stable和app=myapp的pod
NAME       READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
pod-demo   2/2       Running   0          25m       10.244.2.16   k8snode2   app=myapp,release=stable,tier=frontend
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l release!=stable,app!=myapp #查看release不等于stable和app不等于myapp的pod
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
myapp-848b5b879b-5k4s4        1/1       Running   0          4d        10.244.2.14   k8snode2   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-bzblz        1/1       Running   0          4d        10.244.1.21   k8snode1   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-hzbf5        1/1       Running   0          4d        10.244.1.22   k8snode1   pod-template-hash=4046164356,run=myapp
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4    k8snode2   pod-template-hash=16151555,release=canary,run=nginx-deploy
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l release!=stable #查看release不等于stable的pod
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
myapp-848b5b879b-5k4s4        1/1       Running   0          4d        10.244.2.14   k8snode2   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-bzblz        1/1       Running   0          4d        10.244.1.21   k8snode1   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-hzbf5        1/1       Running   0          4d        10.244.1.22   k8snode1   pod-template-hash=4046164356,run=myapp
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4    k8snode2   pod-template-hash=16151555,release=canary,run=nginx-deploy

    b、集合关系的标签选择器

      KEY in {VALUE1,VALUE2,...}

      KEY notin {VALUE1,VALUE2...}

      KEY #存在此键

      !KEY #不存在此键

[root@k8smaster manifests]# kubectl get pods -o wide --show-labels 
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
myapp-848b5b879b-5k4s4        1/1       Running   0          4d        10.244.2.14   k8snode2   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-bzblz        1/1       Running   0          4d        10.244.1.21   k8snode1   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-hzbf5        1/1       Running   0          4d        10.244.1.22   k8snode1   pod-template-hash=4046164356,run=myapp
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4    k8snode2   pod-template-hash=16151555,release=canary,run=nginx-deploy
pod-demo                      2/2       Running   0          39m       10.244.2.16   k8snode2   app=myapp,release=stable,tier=frontend

[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l "release in (canary,beta,alpha)"
NAME                          READY     STATUS    RESTARTS   AGE       IP           NODE       LABELS
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        10.244.2.4   k8snode2   pod-template-hash=16151555,release=canary,run=nginx-deploy
[root@k8smaster manifests]# kubectl get pods -o wide --show-labels -l "release notin (canary,beta,alpha)"
NAME                     READY     STATUS    RESTARTS   AGE       IP            NODE       LABELS
myapp-848b5b879b-5k4s4   1/1       Running   0          4d        10.244.2.14   k8snode2   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-bzblz   1/1       Running   0          4d        10.244.1.21   k8snode1   pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-hzbf5   1/1       Running   0          4d        10.244.1.22   k8snode1   pod-template-hash=4046164356,run=myapp
pod-demo                 2/2       Running   0          41m       10.244.2.16   k8snode2   app=myapp,release=stable,tier=frontend

  8、有很多类型的资源都要基于标签选择器关联其它资源,比如pod控制器和service实现标签关联时通过另外两个字段来嵌套。deployment和service等资源通常支持使用matchLabels定义怎么使用标签选择器。许多资源支持内嵌字段matchLabels或matchExpressions来定义其使用的标签选择器

    a、matchLabels  :直接给定键值来进行选择

    b、matchExpressions:基于给定的表达式来定义使用标签选择器,{key:"KEY",operator:"OPERATOR",values:[VAL1,VAL2,...]} #意思是某个键基于某个值基于operator中的操作符(条件判断)作比较

      常见的操作符为:In,NotIn:values字段值必须为非空列表;

              Exists,NotExists:使用后面这两种操作符时,values字段值必须为空列表;

  9、很多字段都可以打标签,给列表打标签

[root@k8smaster ~]# kubectl get nodes --show-labels
NAME        STATUS    ROLES     AGE       VERSION   LABELS
k8smaster   Ready     master    5d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8smaster,node-role.kubernetes.io/master=
k8snode1    Ready     <none>    4d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8snode1
k8snode2    Ready     <none>    4d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8snode2
[root@k8smaster ~]# kubectl label nodes k8snode1 disktype=ssd
node/k8snode1 labeled
[root@k8smaster ~]# kubectl get nodes --show-labels
NAME        STATUS    ROLES     AGE       VERSION   LABELS
k8smaster   Ready     master    5d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8smaster,node-role.kubernetes.io/master=
k8snode1    Ready     <none>    4d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=k8snode1
k8snode2    Ready     <none>    4d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8snode2

  10、在定义pod的时候有nodeSelector <map[string]string> #节点标签选择器,定义pod运行在哪个节点。如果两个节点都有该标签那么会按照调度算法来调度pod,如果只有一个节点有那么只会被调度到该节点。还有nodeName <string>,表示运行在某具体节点上

[root@k8smaster manifests]# cat pod-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels: #也可以在此处写上{app:myapp,tier:frontend}代替下面两行
    app: myapp #应用层级标签
    tier: frontend #架构层级标签,在分层架构中属于frontend层
spec:
  containers: #是一个列表,具体定义方式如下
  - name: myapp
    image: ikubernetes/myapp:v1
    ports: #不暴露端口其实也可以被访问,目的是为了说明启动的端口有哪些
    - name: http #service 中可以通过名称来引用端口
      containerPort: 80
    - name: https
      containerPort: 443
  - name: busybox
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    command: #也可以写成中括号形式,比如可以在此处写上["/bin/sh","-c","sleep 3600"]
    - "/bin/sh"
    - "-c"
    - "sleep 3600"
  nodeSelector:
    disktype: ssd #定义pod只运行在拥有disktype标签并且其值为ssd的节点上
[root@k8smaster manifests]# kubectl get nodes --show-labels
NAME        STATUS    ROLES     AGE       VERSION   LABELS
k8smaster   Ready     master    5d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8smaster,node-role.kubernetes.io/master=
k8snode1    Ready     <none>    4d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=k8snode1
k8snode2    Ready     <none>    4d        v1.11.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8snode2
[root@k8smaster manifests]# kubectl get pods --show-labels
NAME                          READY     STATUS    RESTARTS   AGE       LABELS
myapp-848b5b879b-5k4s4        1/1       Running   0          4d        pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-bzblz        1/1       Running   0          4d        pod-template-hash=4046164356,run=myapp
myapp-848b5b879b-hzbf5        1/1       Running   0          4d        pod-template-hash=4046164356,run=myapp
nginx-deploy-5b595999-d9lv5   1/1       Running   0          4d        pod-template-hash=16151555,release=canary,run=nginx-deploy
pod-demo                      2/2       Running   0          2m        app=myapp,tier=frontend

  11、annotations:除了标签之外,资源还可以使用注解。与资源标签很相像,他们都是属于键值,但是其与labels区别在于,其不能作为标签选择器的挑选机制。因此其不能用于挑选资源对象,仅用于为对象提供“元数据”。

[root@k8smaster manifests]# cat pod-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels: #也可以在此处写上{app:myapp,tier:frontend}代替下面两行
    app: myapp #应用层级标签
    tier: frontend #架构层级标签,在分层架构中属于frontend层
  annotations:
    wohaoshuai.com/created-by: "cluster admin"
spec:
  containers: #是一个列表,具体定义方式如下
  - name: myapp
    image: ikubernetes/myapp:v1
    ports: #不暴露端口其实也可以被访问,目的是为了说明启动的端口有哪些
    - name: http #service 中可以通过名称来引用端口
      containerPort: 80
    - name: https
      containerPort: 443
  - name: busybox
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    command: #也可以写成中括号形式,比如可以在此处写上["/bin/sh","-c","sleep 3600"]
    - "/bin/sh"
    - "-c"
    - "sleep 3600"
  nodeSelector:
    disktype: ssd #定义pod只运行在拥有disktype标签并且其值为ssd的节点上
[root@k8smaster manifests]# kubectl describe pod pod-demo 
Name:               pod-demo
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               k8snode1/192.168.10.11
Start Time:         Tue, 14 May 2019 09:30:08 +0800
Labels:             app=myapp
                    tier=frontend
Annotations:        wohaoshuai.com/created-by=cluster admin
...

四、pod的生命周期

  1、pod的生命周期由如下几个阶段组成。

    a、一个pod里面可以有多个容器,一个容器为一个进程,但是只会有一个主容器,首先是初始化其它容器,当所有初始化容器完成后主容器就可以开始启动了

    b、主容器启动时也需要自己把应用程序环境初始化,然后启动后会执行post start操作,结束前也会有一个pre stop操作,无论是启动后还是结束前都可以放一个钩子勾住一些命令执行一下作为启动前的预设和结束后的清理,这个在很多命令中都有,比如awk的begin和end

    c、在整个主容器执行过程中还可以做两类操作。在k8s中,支持两类对pod中容器的检测

      1)、liveness probe:存活状态检测,检测主进程是否处于存活状态,若为Running状态表示容器存活。

      2)、readiness probe:就绪性状态检测

      无论是哪种检测,都支持三种行为

        执行自定义命令

        向指定的TCP套接字发请求

        直接向对方发应用层的GET请求指定方法向指定URL发请求。(http服务发请求)

      

 

  2、常见的pod状态

    a、Pending(调度尚未完成) :挂起,表示我们请求创建pod时条件不能满足,调度没完成,没有任何节点能满足调度条件,比如刚刚设置了nodeSelector 中 disktype 为ssd 的pod,如果没有标签为ssd的节点。

    b、Running :运行状态

    c、Failed:失败

    d、Succeeded :成功 

    e、Unknow:未知状态,所谓一个pod处于什么状态,是我们api server和运行在这个节点的kubelet组件通信来获取其状态信息,若kubelet故障了此时api server就无法获得信息然后处于未知状态。

  3、创建pod时的过程

    当用户创建pod时,请求提交给api server,然后api server先将其请求的目标状态保存在etcd中,然后api server接下来会请求scheduler 进行调度,如果调度成功那么会将调度结果保存在etcd的pod资源的状态信息中,比如调度到哪个节点上了,一旦保存在etcd中并完成更新后,随后目标节点上kubelet通过api server中的状态编号拿到此前用户所提交的创建的清单,然后根据清单在当前节点上创建并启动此pod,然后再将创建结果状态发回给api server,然后api server再次保存在etcd中。 

  4、pod 的restartPolicy <string>字段,默认为Always

    a、Always 总是重启,反复重启机制是这样的:第一次重启是立即完成的,第二次重启需要10秒,第三次重启需要20秒,第四次重启等40秒,再重启等80秒,再重启等160秒,再重启等300秒,后面每次重启都是等300秒

    b、OnFallure 状态为错误时才重启

    c、Never 从不重启

  5、在提交或删除pod时,是不会一上来就kill掉的,当删除pod时,其会向pod中的每一个容器发送终止信号 15,这个终止会给其一个宽限期,默认为30秒,若宽限期到了还没有终止那么会直接发送 强行终止信号 9 。

五、总结pod生命周期

  从创建开始到最终结束之间要经历的事情包含了:初始化容器进行初始化,然后启动主容器和其它辅助容器,主容器启动后可以做启动后钩子(post start),以及结束之前可以做结束之前的钩子(pre stop),而整个过程中会周期性的每隔3,5,10,30秒和两分钟做一次liveness probe以及readiness probe探测,一旦发生故障,比如liveness probe出错了那么就要受控于restartPolicy来决定他是否被重启,一旦我们删除一个pod那么我们要正常平滑终止pod,终止的时候先发送-15信号,当宽限期过后还没有终止的话会直接发送-9信号。

推荐阅读