K8s 使用资源清单创建资源 (二)

标签选选择器是 K8s 中的一个重要的组成部分,用于不同的 Pod 控制器控制此类标签的 Pod,用于 Service 进行后端的关联等,所以对 Pod 标签的操作显得尤为的种要。同时在基本的 Pod 配置清单中, Containers 部分的配置包含了镜像的拉取规则,当 Docker 和 配置清单都配置有要执行的命令时,到底执行那一部分的命令?Pod 有生命周期,当然我们也可以在容器启动和销毁之前做一些操作。包括容器的重启策略等。从这些知识点中可以看,K8s 在保证已经存活,并且达到用户理想的状态其实做了很多的工作,在了解之后的原理之后就会觉得很有意思。

镜像拉取规则

Pod.spec.containers 字段中,spec.containers 类型为<[] object>,格式如下。

- name <String>
  image <String>
  imagePullPolicy <String>, 支持的值有 Always(总是拉取, 默认值),Never(从不拉取),IfNotPresent(如果存在则不拉取)。默认是 Always,但是如果镜像是 latest 版本,那么也是总是拉取的,除非手动指定 imagePullPolicy

命令优先级

在 Docker 中,命令的执行有 cmd 和 entrypoint。如果只有 cmd 那么就执行 cmd 的内容,如果同时存在 entrypoint 和 cmd,那么会将 cmd 的值作为参数传入 entrypoint 中执行。

而在 K8s 中,没有了 cmd 和 entrypoint,而是有 command 和 args。command 相当于 docker 中的 entrypoint,args 相当于 docker 中的 cmd。

那么什么时候使用容器的命令,什么时候使用 k8s 资源清单中的命令就显得及其的重要了,具体可以分为以下四种情况:

  1. 如果没有提供 command 和 args,那么就默认使用 docker 镜像中的 cmd 和 entrypoint。
  2. 如果提供了 command 但是没有 args,那么就只运行 command,镜像中的 entrypoint 和 cmd 都被忽略。
  3. 如果提供了 args 但是没有 command,那么就使用镜像中的 entrypoint,args 将作为 entrypoint 的参数,镜像中的 cmd 将被忽略。
  4. 如果 command 和 args 都提供了,那么镜像中的 entrypoint 和 args 都将被忽略。


更多信息,可见 https://k8smeetup.github.io/docs/tasks/inject-data-application/define-command-argument-container/

标签操作

一个资源应用可能有多个标签,而一个标签也可以分布在不同的资源上。标签的灵活使用可以将资源从不同角度进行分组,从而实现不同的管理。标签的名称和值的长度为最大36个字符。

查看 Pod 显示标签

kubectl get pods --show-labels
NAME                            READY   STATUS    RESTARTS   AGE    LABELS
nginx-deploy-5c9b546997-nv2xp   1/1     Running   0          4h7m   pod-template-hash=5c9b546997,run=nginx-deploy

Pod 标签过滤

查看包含 app 的标签。显示结果新增一列,新增的一列为过滤的标签名称,下面显示过滤匹配的结果。-L 后面可跟多个标签,多个过滤的时候使用 “,” 进行分割。

kubectl get pods -L app
[[email protected] rexyan]# kubectl get pods -L app
NAME                            READY   STATUS    RESTARTS   AGE     APP
nginx-deploy-5c9b546997-nv2xp   1/1     Running   0          4h10m   
pod-demo                        2/2     Running   0          15s     myapp

表示只显示包含的 app 的标签,其余的不显示。后面也可跟多个标签,多个过滤的时候使用 “,” 进行分割。

kubectl get pods -l app
NAME       READY   STATUS    RESTARTS   AGE
pod-demo   2/2     Running   0          4m57s

Pod 新增标签

为 pod-demo 新增一个 release=canary 的标签。命令格式为 kubectl label + 资源类型 + 资源名称 + 标签值

kubectl label pods pod-demo release=canary
[[email protected] rexyan]# kubectl get pods --show-labels
NAME                            READY   STATUS    RESTARTS   AGE     LABELS
nginx-deploy-5c9b546997-nv2 xp   1/1     Running   0          4h21m   pod-template-hash=5c9b546997,run=nginx-deploy
pod-demo                        2/2     Running   0          10m     app=myapp,author=rexyan,release=canary

Pod修改标签

将上面的 release=canary 改为 release=stable,需要在刚才新增的命令上加上 –overwrite 选项。

kubectl label pods pod-demo release=stable --overwrite
[[email protected] rexyan]# kubectl get pods --show-labels
NAME                            READY   STATUS    RESTARTS   AGE     LABELS
nginx-deploy-5c9b546997-nv2xp   1/1     Running   0          4h23m   pod-template-hash=5c9b546997,run=nginx-deploy
pod-demo                        2/2     Running   0          13m     app=myapp,author=rexyan,release=stable

Node 查看标签

 kubectl get node --show-labels
izrj94q5l72imm6kxm11qvz   Ready    master   4h57m   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qvz,kubernetes.io/os=linux,node-role.kubernetes.io/master=
izrj94q5l72imm6kxm11qwz   Ready    <none>   4h50m   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qwz,kubernetes.io/os=linux
izrj94q5l72imm6kxm11qxz   Ready    <none>   4h51m   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qxz,kubernetes.io/os=linux

Node 新增标签

kubectl label nodes izrj94q5l72imm6kxm11qxz type=test
kubectl get node --show-labels
NAME                      STATUS   ROLES    AGE     VERSION   LABELS
izrj94q5l72imm6kxm11qvz   Ready    master   5h10m   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qvz,kubernetes.io/os=linux,node-role.kubernetes.io/master=,type=master
izrj94q5l72imm6kxm11qwz   Ready    <none>   5h3m    v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qwz,kubernetes.io/os=linux
izrj94q5l72imm6kxm11qxz   Ready    <none>   5h4m    v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qxz,kubernetes.io/os=linux,type=test

指定 Pod 调度节点

nodelSelecter

Node 有标签,那我们就可以将一个 Pod 指定调度在哪一个节点上运行。在 Pod.spec 下有 nodelSelecter 字段,nodelSelecter 代表的意思是节点标签选择器。我们为之前的 pod-demo 设置 ports 和 nodeSelector,示例如下:

apiVersion: v1
kind: Pod
metadata: 
  name: pod-demo
  namespace: default
  labels: 
    app: myapp
    author: rexyan
spec:
  containers: 
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
    - containerPort: 80
  - name: busybox
    image: busybox 
    command:
    - "/bin/sh"
    - "-c"
    - "sleep 3600"
  nodeSelector:
    type: test

示例会将 pod 调度到 type=test 的 节点上。

kubectl delete -f pod-demo.yaml 
kubectl create -f pod-demo.yaml 
kubectl get pods -o wide 
NAME                            READY   STATUS    RESTARTS   AGE    IP           NODE                      NOMINATED NODE   READINESS GATES
nginx-deploy-5c9b546997-nv2xp   1/1     Running   0          5h7m   10.244.1.2   izrj94q5l72imm6kxm11qxz   <none>           <none>
pod-demo                        2/2     Running   0          19s    10.244.1.3   izrj94q5l72imm6kxm11qxz   <none>           <none>

可以看到两个容器均调度到了 izrj945l72imm6kxm11qxz 的节点上,而这个节点就是被打上 type=test 标签的节点。

查看 pod 的详细信息中的 default-scheduler 字段也可以看到调度的结果

kubectl describe pods pod-demo
......
Events:
  Type    Reason     Age    From                              Message
  ----    ------     ----   ----                              -------
  Normal  Scheduled  3m35s  default-scheduler                 Successfully assigned default/pod-demo to izrj94q5l72imm6kxm11qxz
  Normal  Pulling    3m35s  kubelet, izrj94q5l72imm6kxm11qxz  Pulling image "ikubernetes/myapp:v1"
  Normal  Pulled     3m32s  kubelet, izrj94q5l72imm6kxm11qxz  Successfully pulled image "ikubernetes/myapp:v1"
  Normal  Created    3m32s  kubelet, izrj94q5l72imm6kxm11qxz  Created container myapp
  Normal  Started    3m32s  kubelet, izrj94q5l72imm6kxm11qxz  Started container myapp
  Normal  Pulling    3m32s  kubelet, izrj94q5l72imm6kxm11qxz  Pulling image "busybox"
  Normal  Pulled     3m30s  kubelet, izrj94q5l72imm6kxm11qxz  Successfully pulled image "busybox"
  Normal  Created    3m30s  kubelet, izrj94q5l72imm6kxm11qxz  Created container busybox
  Normal  Started    3m30s  kubelet, izrj94q5l72imm6kxm11qxz  Started container busybox

nodeName

使用 nodeName,可以直接将一个 Pod 指定运行在某个 node 上,根据 node 名称。

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

  1. matchLabels:表示直接给定键值就能进行选择
  2. matchExpressions:表示要基于给定的表达式来进行选择

标签选择器

等值关系

可以使用 = ,== 或者 !=

kubectl get pods -l author=rexyan
kubectl get pods -l author==rexyan,app=test  # author==rexyan且app=test
kubectl get pods -l author!=rexyan  # author不等于rexyan

集合关系

可以使用 KEY in (VALUE1, VALUE2) 或者 notin 或者 !KEY

kubectl get pods -l "author in (rexyan, yanrunsha, runsha.yan)"
kubectl get pods -l "author notin (rexyan, yanrunsha, runsha.yan)"

Pod 注解

annotations 是 Pod 的注解。与 lable 不同的地方在于,他不能用于挑选资源对象,仅用于为对象提供 “元数据”

修改 pod-demo.yaml, 内容如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    author: rexyan
  annotations:
    rexyan.me/create-by: "rexyan"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
  - name: busybox
    image: busybox
    command:
    - "/bin/sh"
    - "-c"
    - "sleep 3600"
  nodeSelector:
    type: test            

将 pod 删除,并且重新创建

kubectl delete -f pod-demo.yaml 
kubectl create -f pod-demo.yaml

可以使用 describe 查看资源的注解

kubectl describe pods pod-demo
Name:               pod-demo
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               izrj94q5l72imm6kxm11qxz/172.20.245.188
Start Time:         Sat, 18 May 2019 22:27:11 +0800
Labels:             app=myapp
                    author=rexyan
Annotations:        rexyan.me/create-by: rexyan
Status:             Running
IP:                 10.244.1.4
Containers:
  myapp:
    Container ID:   docker://0f3a448bb2c66d26c060ebf0fb65941265dc8b2cf9cb837fed88641e5478df0f
    Image:          ikubernetes/myapp:v1
    Image ID:       docker-pullable://docker.io/ikubernetes/[email protected]:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 18 May 2019 22:27:12 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-8dmfd (ro)
  busybox:
    Container ID:  docker://89e2a12051d98435c427f091b4753a2900455641b397a5396f59b16426561c06
    Image:         busybox
    Image ID:      docker-pullable://docker.io/[email protected]:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/sh
      -c
      sleep 3600
    State:          Running
      Started:      Sat, 18 May 2019 22:27:13 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-8dmfd (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-8dmfd:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-8dmfd
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  type=test
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From                              Message
  ----    ------     ----  ----                              -------
  Normal  Scheduled  18s   default-scheduler                 Successfully assigned default/pod-demo to izrj94q5l72imm6kxm11qxz
  Normal  Pulled     17s   kubelet, izrj94q5l72imm6kxm11qxz  Container image "ikubernetes/myapp:v1" already present on machine
  Normal  Created    17s   kubelet, izrj94q5l72imm6kxm11qxz  Created container myapp
  Normal  Started    17s   kubelet, izrj94q5l72imm6kxm11qxz  Started container myapp
  Normal  Pulling    17s   kubelet, izrj94q5l72imm6kxm11qxz  Pulling image "busybox"
  Normal  Pulled     16s   kubelet, izrj94q5l72imm6kxm11qxz  Successfully pulled image "busybox"
  Normal  Created    16s   kubelet, izrj94q5l72imm6kxm11qxz  Created container busybox
  Normal  Started    16s   kubelet, izrj94q5l72imm6kxm11qxz  Started container busybox

Pod 的生命周期

状态:Pending,Running,Failed,Succeeded,Unknow……

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

初始化容器
容器探测:
    liveness(用来判定容器是否正常)
    readiness(用来判定容器中的服务是否正常)

容器重启策略

restartPolicy 用于定义容器的充气策略。支持以下几种。

Always(默认),OnFailure(失败后才重启),Never(从不重启)

进入容器和日志查看

查看容器日志和进入容器分别使用kubectl logskubectl exec 命令。当 Pod 中只有一个容器的时候,我们可以不使用 -c 参数指定进入哪一个容器,但是如果 Pod 中有多个容器的时候,就需要使用-c 来指定具体的容器。


 上一篇
K8s 应用存活和容器启动结束钩子 K8s 应用存活和容器启动结束钩子
Pod 正常里面的 Docker 服务不一定正常。Docker 服务正常,Docker 里面的服务不一定正常。所以如何正确的监测这些状态,成为了应用健康很重要的关键。 livenessProbe, 用来判定容器是否正常。readinessP
2019-05-19
下一篇 
K8s 使用资源清单创建资源 K8s 使用资源清单创建资源
以命令的方式创建资源,命令很多,且很容易忘记。K8s 支持以配置清单(文件)的方式来创建,使用中支持 json 格式和 yaml 格式的方式创建资源清单,但是 yaml 有更好的可读性,所以我们都使用 yaml 进行资源清单的配置,在执行
2019-05-18
  目录