kubernetes快速入门5-Pod资源详谈

kubernetes快速入门5-Pod资源详谈

pod只是逻辑上的概念,可以把pod看成一个容器,容器内跑的是一个或多个容器实体(docker容器)。Pod资源spec.containers对象说明

pod.spec.containers <[]Object>

字段:
name    <string>    必选字段,表明容器名称
image   <string>    镜像地址
imagePullPolicy <string>  镜像拉取策略,Always, Never, IfNotPresent 其中之一,当镜像的tag为latest时,默认为Always
ports   <[]Object>   暴露端口,是说明性信息,并不代表容器是否真正暴露端口,只要容器监听某个端口,集群内就能访问相应的服务
    containerPort   <integer> 必选项,容器暴露的端口号
    name    <string>   起一个名称

command <[]string>  容器中执行的命令
args    <[]string>   容器中为执行命令传递的参数,如果要引用变量使用“$(VAR_NAM)”,使用“$$(VAR_NAM)”为变量逃逸

说明:镜像中可能会有CMD和ENTRYPOINT两个字段,镜像中的ENTRYPOINT相当于k8s中的command,镜像中的CMD相当于k8s中的args,如果定义资源清单时也定义了command和args字段,这4个字段混合使用会产生不同的场景。官方已给了详细的说明:https://kubernetes.io/zh/docs/tasks/inject-data-application/define-command-argument-container/

标签与标签选择器

官方文档参考: https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/labels/

标签是附加到 Kubernetes 对象(比如 Pods)上的键值对。标签旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 标签可以用于组织和选择对象。标签可以在创建时附加到对象,随后可以随时添加和修改。

标签可以在多个维度上进行定义,如

"release" : "stable", "release" : "canary"    # 以发布的版本为维度
"environment" : "dev", "environment" : "qa", "environment" : "production"  # 发环境为维度
"tier" : "frontend", "tier" : "backend", "tier" : "cache"  # 以层次为维度
"partition" : "customerA", "partition" : "customerB"  # 以分区为维度
"track" : "daily", "track" : "weekly"

标签语法和字符集

标签 是键值对。有效的标签键有两个段:可选的前缀和名称,用斜杠(/)分隔。名称段是必需的,必须小于等于 63 个字符,以字母数字字符([a-z0-9A-Z])开头和结尾,带有破折号(-),下划线(_),点( .)和之间的字母数字。

有效标签值必须为 63 个字符或更少,并且必须为空或以字母数字字符([a-z0-9A-Z])开头和结尾,中间可以包含破折号(-)、下划线(_)、点(.)和字母或数字。

标签相关命令

显示标签

在k8s中使用kubectl get来获取某种资源时,在最后加上--show-lables选项就能显示该种资源的标签信息,如

$ kubectl get pods --show-lables
$ kubectl get nodes --show-lables
过滤标签

-L, --label-columns=[] 显示某个资源指定标签的值,没有就为空

-l, --selector='' 过滤出指定的标签的资源

k8s@node01:~$ kubectl get pods --show-labels
NAME                                  READY   STATUS    RESTARTS   AGE     LABELS
myapp-dep-c988cf69-2dps2              1/1     Running   0          5h33m   app=myapp-dep,pod-template-hash=c988cf69
myapp-dep-c988cf69-hjm8j              1/1     Running   0          5h33m   app=myapp-dep,pod-template-hash=c988cf69
myapp-dep-c988cf69-j56hp              1/1     Running   0          5h33m   app=myapp-dep,pod-template-hash=c988cf69
mynginx-deployment-646959f957-jqq67   1/1     Running   0          5h33m   app=mynginx-deployment,pod-template-hash=646959f957
pod-demo                              2/2     Running   0          48s     app=myapp,tier=frontend

k8s@node01:~$ kubectl get pods -L tier,app
NAME                                  READY   STATUS    RESTARTS   AGE     TIER       APP
myapp-dep-c988cf69-2dps2              1/1     Running   0          5h36m              myapp-dep
myapp-dep-c988cf69-hjm8j              1/1     Running   0          5h36m              myapp-dep
myapp-dep-c988cf69-j56hp              1/1     Running   0          5h36m              myapp-dep
mynginx-deployment-646959f957-jqq67   1/1     Running   0          5h36m              mynginx-deployment
pod-demo                              2/2     Running   0          3m58s   frontend   myapp
k8s@node01:~$ kubectl get pods -l tier
NAME       READY   STATUS    RESTARTS   AGE
pod-demo   2/2     Running   0          4m12s
打标签
k8s@node01:~$ kubectl label pods pod-demo release=canary  # 给pod-demo这个pod对象打标签
pod/pod-demo labeled

k8s@node01:~$ kubectl get pod pod-demo --show-labels
NAME       READY   STATUS    RESTARTS   AGE     LABELS
pod-demo   2/2     Running   0          7m52s   app=myapp,release=canary,tier=frontend

# 对已有标签重新打标签需要加了“--overwrite”选项
k8s@node01:~$ kubectl label pods pod-demo release=stable --overwrite
pod/pod-demo labeled
k8s@node01:~$ kubectl get pod pod-demo --show-labels
NAME       READY   STATUS    RESTARTS   AGE   LABELS
pod-demo   2/2     Running   0          10m   app=myapp,release=stable,tier=frontend

标签选择器分类

基于等值关系的标签选择器

操作符: === 表示相等,!=表示不相等

k8s@node01:~$ kubectl get pods --show-labels
NAME                                  READY   STATUS    RESTARTS   AGE     LABELS
myapp-dep-c988cf69-2dps2              1/1     Running   0          5h52m   app=myapp-dep,pod-template-hash=c988cf69,release=canary
myapp-dep-c988cf69-hjm8j              1/1     Running   0          5h52m   app=myapp-dep,pod-template-hash=c988cf69
myapp-dep-c988cf69-j56hp              1/1     Running   0          5h52m   app=myapp-dep,pod-template-hash=c988cf69
mynginx-deployment-646959f957-jqq67   1/1     Running   0          5h52m   app=mynginx-deployment,pod-template-hash=646959f957,release=canary
pod-demo                              2/2     Running   0          19m     app=myapp,release=stable,tier=frontend

k8s@node01:~$ kubectl get pods -l release==canary --show-labels
NAME                                  READY   STATUS    RESTARTS   AGE     LABELS
myapp-dep-c988cf69-2dps2              1/1     Running   0          5h53m   app=myapp-dep,pod-template-hash=c988cf69,release=canary
mynginx-deployment-646959f957-jqq67   1/1     Running   0          5h53m   app=mynginx-deployment,pod-template-hash=646959f957,release=canary

k8s@node01:~$ kubectl get pods -l release=canary,app=myapp-dep --show-labels  # 多个条件
NAME                       READY   STATUS    RESTARTS   AGE     LABELS
myapp-dep-c988cf69-2dps2   1/1     Running   0          5h52m   app=myapp-dep,pod-template-hash=c988cf69,release=canary

k8s@node01:~$ kubectl get pods -l app!=myapp-dep --show-labels
NAME                                  READY   STATUS    RESTARTS   AGE     LABELS
mynginx-deployment-646959f957-jqq67   1/1     Running   0          5h53m   app=mynginx-deployment,pod-template-hash=646959f957,release=canary
pod-demo                              2/2     Running   0          20m     app=myapp,release=stable,tier=frontend
基于集合关系的标签选择器

操作符号: innotin

k8s@node01:~$ kubectl get pods -l "release in (canary, release, beta)" --show-labels
NAME                                  READY   STATUS    RESTARTS   AGE     LABELS
myapp-dep-c988cf69-2dps2              1/1     Running   0          5h59m   app=myapp-dep,pod-template-hash=c988cf69,release=canary
mynginx-deployment-646959f957-jqq67   1/1     Running   0          5h59m   app=mynginx-deployment,pod-template-hash=646959f957,release=canary

k8s@node01:~$ kubectl get pods -l "release notin (canary, release, beta)" --show-labels
NAME                       READY   STATUS    RESTARTS   AGE     LABELS
myapp-dep-c988cf69-hjm8j   1/1     Running   0          5h59m   app=myapp-dep,pod-template-hash=c988cf69
myapp-dep-c988cf69-j56hp   1/1     Running   0          5h59m   app=myapp-dep,pod-template-hash=c988cf69
pod-demo                   2/2     Running   0          27m     app=myapp,release=stable,tier=frontend

k8s@node01:~$ kubectl get pods -l "release" --show-labels  # 显示有 release 标签的资源
NAME                                  READY   STATUS    RESTARTS   AGE    LABELS
myapp-dep-c988cf69-2dps2              1/1     Running   0          6h3m   app=myapp-dep,pod-template-hash=c988cf69,release=canary
mynginx-deployment-646959f957-jqq67   1/1     Running   0          6h3m   app=mynginx-deployment,pod-template-hash=646959f957,release=canary
pod-demo                              2/2     Running   0          31m    app=myapp,release=stable,tier=frontend

k8s@node01:~$ kubectl get pods -l !"release" --show-labels  # 不支持显示没有 release 标签的资源
-su: !"release": event not found

资源清单定义标签选择器

许多资源支持内嵌字段定义其使用的标签选择器

matchLable: 直接给定键值

mathExpressions: 基于给定的表达式来定义使用的标签选择器,格式为 {key: "KEY", operator: "OPERATOR", values: [VAL1, VAL2, ...]},表示 KEY这个键基于 [VAL1, VAL2, ...]这些值做 OPERATOR 比较。operator常用操作符号一般为In,NotIn,values必须为非空列表,Exists, NotExists,values必须为空列表。

pod的节点标签选择器

pods.spec下有字段nodeSelector &lt;map[string]string&gt;,表示pod运行节点的倾向性,比如k8s集群内的工作节点配置不相同,一些节点有ssd磁盘,有些节点有比较大的内存或多颗cpu,这样可以针对各个节点的特点打上标签,然后在定义pod时使用节点选择器让pod更有倾向运行在打有相应标签的节点上。

pods.spec下有字段nodeName &lt;string&gt;,表示让pod运行在指定的节点上

元数据annotations字段

pod.annotations 定义pod的注解信息。

annotations &lt;map[string]string&gt; 与label不同的地方在于它不能用于挑选资源对象,仅用于为对象提供元数据

综合以上,对pods-demo.yaml文件进行修改

k8s@node01:~/my_manifests$ cat pods-demo.yaml
apiVersion: v1
kind: Pod
metadata:
        name: pod-demo
        namespace: default
        labels:
                app: myapp
                tier: frontend
        annotations:
                abc.com/created-by: "cluster admin"
spec:
        containers:
                - name: app
                  image: ikubernetes/myapp:v1
                  imagePullPolicy: IfNotPresent
                  ports:
                  - name: http
                    containerPort: 80
                - name: bbox
                  image: busybox:latest
                  imagePullPolicy: IfNotPresent
                  command:
                  - "/bin/sh"
                  - "-c"
                  - "sleep 3600"
        nodeName: node03

pod生命周期

pod创建过程

1. 通过kubectl向apiserver发送创建Pod资源的请求
2. apiserver把请求创建资源的目标状态保存在etcd中,apiserver请求scheduler进行调度,并把调度的结果(调度在哪个节点上)保存在pod信息相关etcd中
3. apiserver通知目标工作节点的kubelet有新的资源创建请求,并拿到相应的资源清单,根据清单在当前节点创建资源,并把相应的创建的状态信息发送回apiserver

pod状态:

Pending: 挂起状态,调度未完成
Running: 正常运行状态
Failed: 运行失败
Succeeded: 成功
Unknown: 工作节点kubelet出现故障,apiserver无法获取状态信息

Pod生命周期中的重要行为:

  1. 初始化容器,在创建Pod时需要先做容器的初始化操作

  2. 容器探测

    探测有两种类型:
    liveness probe 存活性探测,用于探测容器是否处于存活状态
    readiness probe 就绪性探测,用于探测容器中的程序是否能够正常提供服务
    
    每种探测类型都支持3种探针:
    1. ExecAction, 执行自定义的命令
    2. TCPSockerAction, 向指定的tcp端口发请求
    3. HTTPGetAction, 向指定的http服务发请求

pod的重启策略

pod.spec下有字段restartPolicy

restartPolicy   <string>

One of Always, OnFailure, Never. Default to Always. More info:
     https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy

Always: 总是重启,其内部实现延时重启策略,如:第一次异常立刻重启,第二次重启就得等30秒,第三次重启就得等更长的时间,最多等待300秒重启
OnFailure:状态为错误时重启
Never:不管是什么原因永不重启

pod终止过程

kubectl delete -f FILE命令向apiserver发送任务,apiserver通知目标工作节点的kubelet对相应pod资源进行终止操作,先向pod中的容器发送terminal(15)信号,并有一个默认30秒的宽限期,如果能正常终止就终止pod,再如宽限期过后pod还无法终止,则再发送 kill(9)信号强制终止。

livenessProbe探测

使用kubectl explain pod.spec.containers.livenessProbe查看容器的存活性探测的帮助信息

livenessProbe <Object>

FIELDS:
    exec    <Object>   exec类型探针
    httpGet <Object>  http类型探针
    tcpSocket   <Object>  tcp类型探针
    failureThreshold    <integer>   探测几次才判断为失败,默认为3次
    periodSeconds   <integer>    每一次探测间隔时长,默认为10s
    successThreshold    <integer>  判断为成功的次数,默认为1次
    timeoutSeconds  <integer>  每一次探测的超时时间,默认为1s
    initialDelaySeconds <integer>  容器启动后开始做探测等待时长,无默认值

exec探针

k8s@node01:~/my_manifests$ cat liveness-exec.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec-pod
  namespace: default
spec:
  containers:
  - name: liveness-exec-container
    image: busybox:latest
    imagePullPolicy: IfNotPresent  # 镜像tag为latest时镜像拉取策略都为Always
    command: ["/bin/sh", "-c", "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 3600"]
    livenessProbe:
      exec:
        command: ["test", "-e", "/tmp/healthy"]
      initialDelaySeconds: 1
      periodSeconds: 3

# 应用yaml
k8s@node01:~/my_manifests$ kubectl create -f liveness-exec.yaml
pod/liveness-exec-pod created

# 容器启动后等待1秒开始进行探测,前30秒探测为正常
k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE 
liveness-exec-pod                     1/1     Running   0          21s 

# /tmp/healthy文件被删除后,探测失败,经过3个周期探测失败后,pod的默认restartPolicy为Always,容器会重启
k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS        RESTARTS   AGE
liveness-exec-pod                     1/1     Running       2          2m42s

# 当容器被重启次数过多时,状态为 CrashLoopBackOff
k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS             RESTARTS   AGE
liveness-exec-pod                     0/1     CrashLoopBackOff   5          7m16s

httpGet探针

k8s@node01:~/my_manifests$ cat liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-httpget-pod
  namespace: default
spec:
  containers:
  - name: liveness-httpget-container
    image: ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: myapp-http
      containerPort: 80
    livenessProbe:
      httpGet:
        port: myapp-http  # 可引用暴露端口的名称
        path: /
        scheme: HTTP # 可省略,默认使用HTTP
      initialDelaySeconds: 1
      periodSeconds: 3

k8s@node01:~/my_manifests$ kubectl create -f liveness-httpget.yaml
pod/liveness-httpget-pod created

# pod处于Running状态,正常
k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
liveness-httpget-pod                  1/1     Running   0          2m36s

# 连接至pod中的容器,手动删除主页文件
k8s@node01:~/my_manifests$ kubectl exec -it liveness-httpget-pod -- /bin/sh
/ # rm -f /usr/share/nginx/html/
50x.html    index.html
/ # rm -f /usr/share/nginx/html/index.html
/ # command terminated with exit code 137   # 主机文件被删除后,httpget探测失败,容器被重启,退出容器连接

# pod被重启1次
k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
liveness-httpget-pod                  1/1     Running   1          4m33s

tcpSocket探针

k8s@node01:~/my_manifests$ cat liveness-tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-tcpsokcet-pod
  namespace: default
spec:
  containers:
  - name: liveness-tcpsokcet-container
    image: ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: myapp-http
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: myapp-http  # 可引用暴露端口的名称
      initialDelaySeconds: 1
      periodSeconds: 3

readingProbe探测

为什么要做就绪性探测?

service是对外提供访问的固定端点,对其下的pods会进行负载调度,如果一个pod下运行了两个容器,现在因负载太大需要扩容为3个容器,第3个容器被创建成功后就立刻会被pod所关联进来进行调度,而容器内运行的程序可能需要一定的时间才能接受请求服务,而此时会有一部分流量被service分配到未就绪的第3个容器上,请求到该容器上的请求就会出问题,所以需要做就绪性探测,只有探测正常后service才分配流量到新的容器上。

readinessProbe探测同样支持exec, httpGet, tcpSocket三种探针进行探针,定义格式也一样。

k8s@node01:~/my_manifests$ cat readiness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget-pod
  namespace: default
spec:
  containers:
  - name: readiness-httpget-container
    image: ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: myapp-http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: myapp-http  # 可引用暴露端口的名称
        path: /
        scheme: HTTP # 可省略,默认使用HTTP
      initialDelaySeconds: 1
      periodSeconds: 3

k8s@node01:~/my_manifests$ kubectl create -f readiness-httpget.yaml
pod/readiness-httpget-pod created

k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
readiness-httpget-pod                 1/1     Running   0          11s

# 连接到Pod删除主页
k8s@node01:~/my_manifests$ kubectl exec -it readiness-httpget-pod -- /bin/sh
/ # mv /usr/share/nginx/html/index.html /tmp/
/ #

# 删除主页后,REAY中就绪为0,容器主进程仍然在运行,容器不会被重启;如果再把主页还原,就绪状态就恢复
# k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
readiness-httpget-pod                 0/1     Running   0          2m7s

lifecycle-生命周期勾子

pod中的容器在被启动后(postStart)可以立刻执行一些操作,当该操作执行成功后才接着做接下来的流程;pod中的容器在结束前preStop也可以先执行一此收尾操作,收尾操作完成后才结束pod的生命周期。

k8s@node01:~/my_manifests$ kubectl explain pod.spec.containers.lifecycle
说明:
RESOURCE: lifecycle <Object>
FIELDS:
   postStart    <Object>
   preStop  <Object>

postStartpreStop都支持exec, httpGet和tcpSocket三种类型的探针。

k8s@node01:~/my_manifests$ cat lifecycle-poststart.yaml
apiVersion: v1
kind: Pod
metadata:
  name: lifecycele-poststart-pod
  namespace: default
spec:
  containers:
  - name: busybox-container
    image: busybox:latest
    command: ["/bin/sh", "-c", "sleep 3600"]
    lifecycle:
      postStart:
        exec:
          command: ['/bin/sh', "-c", "mkdir /tmp/lifecycle"]

k8s@node01:~/my_manifests$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
lifecycele-poststart-pod              1/1     Running   0          10s

# 检查 /tmp/lifecycle 目录是否存在
k8s@node01:~/my_manifests$ kubectl exec -it lifecycele-poststart-pod -- ls /tmp
lifecycle

注意:

postStart中执行的操作与容器的command中执行的程序不要有强依赖性,如:容器的command运行httpd服务,并把家目录指向postStart中创建的一个目录,这样容器运行httpd命令时会出错,也就是容器是先执行自己的command中的命令,再运行postStart中定义的操作。

猜你喜欢

转载自blog.51cto.com/zhaochj/2532541