Kubernetes集群核心概念 Pod

Posted 123坤

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes集群核心概念 Pod相关的知识,希望对你有一定的参考价值。

Kubernetes集群核心概念 Pod

一、工作负载(workloads)

参考链接:https://kubernetes.io/zh/docs/concepts/workloads/

工作负载(workload)是在kubernetes集群中运行的应用程序。无论你的工作负载是单一服务还是多个一同工作的服务构成,在kubernetes中都可以使用pod来运行它。

workloads分为pod与controllers

  • pod通过控制器实现应用的运行,如何伸缩,升级等
  • controllers 在集群中管理pod
  • pod与控制器之间通过label-selector相关联,是唯一的关联方式

在pod的YAML里指定pod标签

定义标签
  labels: 
	app: nginx

在控制器的YAML里指定标签选择器匹配标签

通过标签选择器选择对应的pod
  selector:
    matchLabels:
      app: nginx

二、pod介绍

2.1 pod定义与分类

参考链接: https://kubernetes.io/zh/docs/concepts/workloads/pods/

2.1.1 Pod定义

  • Pod(豌豆荚) 是Kubernetes集群管理(创建、部署)与调度的最小计算单元,表示处于运行状态的一组容器。
  • Pod不是进程,而是容器运行的环境。
  • 一个Pod可以封装一个容器或多个容器(主容器或sidecar边车容器)
  • 一个pod内的多个容器之间共享部分命名空间,例如:Net Namespace,UTS Namespace,IPC Namespace及存储资源
  • 用户pod默认会被调度运行在node节点之上(不运行在master节点上,但也有例外情况)
  • pod内的IP不是固定的,集群外不能直接访问pod

2.1.2 Pod分类

  • 静态Pod 也称之为“无控制器管理的自主式pod”,直接由特定节点上的 kubelet 守护进程管理, 不需要API 服务器看到它们,尽管大多数 Pod 都是通过控制面(例如,Deployment) 来管理的,对于静态 Pod 而言,kubelet 直接监控每个 Pod,并在其失效时重启。
  • 控制器管理的pod 控制器可以控制pod的副本数,扩容与缩减,版本更新与回滚等

2.2 查看pod方法

pod是一种计算资源,可以通过kubectl get pod来查看

[root@k8s-master01 ~]# kubectl get pod		# pod或pods都可以,不指定namespace,默认是名为default的namespace
[root@k8s-master01 ~]# kubectl get pod -n kube-system

2.3 pod的YAML资源清单格式

先看一个yaml格式的pod定义文件解释

# yaml格式的pod定义文件完整内容:
apiVersion: v1         #必选,api版本号,例如v1
kind: Pod       	   #必选,Pod
metadata:       	   #必选,元数据
  name: string         #必选,Pod名称
  namespace: string    #Pod所属的命名空间,默认在default的namespace
  labels:     		   # 自定义标签
    name: string       #自定义标签名字
  annotations:         #自定义注释列表
    name: string
spec:                  #必选,Pod中容器的详细定义(期望)
  containers:          #必选,Pod中容器列表
  - name: string       #必选,容器名称
    image: string      #必选,容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]  #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string  #容器的工作目录
    volumeMounts:      #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:             #需要暴露的端口库号列表
    - name: string     #端口号名称
      containerPort: int   #容器需要监听的端口号
      hostPort: int        #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string     #端口协议,支持TCP和UDP,默认TCP
    env:               #容器运行前需设置的环境变量列表
    - name: string     #环境变量名称
      value: string    #环境变量的值
    resources:         #资源限制和请求的设置
      limits:          #资源限制的设置
        cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:        #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string #内存清求,容器启动的初始可用数量
    livenessProbe:     #对Pod内的容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:            #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:         #对Pod内的容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:        #对Pod内的容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0       #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0        #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure] # Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  # 设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:      #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork: false     #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:               #在该pod上定义共享存储卷列表
    - name: string         #共享存储卷名称 (volumes类型有很多种)
      emptyDir:          #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string       #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:              #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:           #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

YAML格式查找帮助方法回顾

[root@k8s-master1 ~]# kubectl explain namespace
[root@k8s-master1 ~]# kubectl explain pod
[root@k8s-master1 ~]# kubectl explain pod.spec
[root@k8s-master1 ~]# kubectl explain pod.spec.containers

三、pod创建与验证

3.1 命令创建pod(v1.18变化)

  • k8s之前版本中, kubectl run命令用于创建deployment控制器
  • 在v1.18版本中, kubectl run命令改为创建pod

3.1.1 创建一个名为pod-nginx的pod

[root@k8s-master01 ~]# kubectl run nginx1 --image=nginx:1.15-alpine
pod/nginx1 created

3.1.2 验证

[root@k8s-master01 ~]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
nginx1           1/1     Running   0          41s

3.2 YAML创建pod

3.2.1 准备yaml文件

[root@k8s-master01 ~]# vim pod1.yml
apiVersion: v1					# api版本
kind: Pod						# 资源类型为Pod
metadata:						
  name: pod-stress				# 自定义pod的名称
spec:
  containers:					# 定义pod里包含的容器
  - name: c1					# 自定义pod中的容器名
    image: polinux/stress		# 启动容器的镜像名
    command: ["stress"]			# 自定义启动容器时要执行的命令(类似dockerfile里的CMD)
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"] # 自定义启动容器执行命令的参数
# polinux/stress这个镜像用于压力测试,在启动容器时传命令与参数就是相当于分配容器运行时需要的压力

2, 通过yaml文件创建pod

[root@k8s-master01 ~]# kubectl apply -f pod1.yml
pod/pod-stress created

3.2.2 查看pod信息

查看pod信息

[root@k8s-master01 ~]# kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
pod-stress    1/1     Running   0          45s

查看pod详细信息

[root@k8s-master01 ~]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
pod-stress   1/1     Running   0          71s   10.244.194.72   k8s-worker02   <none>           <none>

描述pod详细信息

[root@k8s-master01 ~]# kubectl describe pod pod-stress 
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  102s  default-scheduler  Successfully assigned default/pod-stress to k8s-worker1
  Normal  Pulling    102s  kubelet            Pulling image "polinux/stress"
  Normal  Pulled     83s   kubelet            Successfully pulled image "polinux/stress" in 18.944533343s
  Normal  Created    83s   kubelet            Created container c1
  Normal  Started    82s   kubelet            Started container c1

3.3 删除pod

3.3.1 单个pod删除

方法1:

[root@k8s-master01 ~]# kubectl delete pod pod-stress
pod "pod-stress" deleted

方法2:

[root@k8s-master01 ~]# kubectl delete -f pod1.yml

3.3.2 多个pod删除

方法1: 后接多个pod名

[root@k8s-master01 ~]# kubectl delete pod pod名1 pod名2 pod名3 ......

方法2: 通过awk截取要删除的pod名称,然后管道给xargs

[root@k8s-master01 ~]# kubectl get pods |awk 'NR>1 print $1' |xargs kubectl  delete pod

方法3: 如果要删除的pod都在同一个非default的命名空间,则可直接删除命名空间

[root@k8s-master01 ~]# kubectl delete ns xxxx

3.4 镜像拉取策略

由imagePullPolicy参数控制

  • Always : 不管本地有没有镜像,都要从仓库中下载镜像
  • Never : 从来不从仓库下载镜像, 只用本地镜像,本地没有就算了
  • IfNotPresent: 如果本地存在就直接使用, 不存在才从仓库下载

默认的策略是:

  • 当镜像标签版本是latest,默认策略就是Always
  • 如果指定特定版本默认拉取策略就是IfNotPresent。
  1. 将上面的pod删除再创建,使用下面命令查看信息
[root@k8s-master01 ~]# kubectl apply -f pod1.yml
[root@k8s-master01 ~]# kubectl delete -f pod1.yml
[root@k8s-master01 ~]# kubectl describe pod pod-stress
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  102s  default-scheduler  Successfully assigned default/pod-stress to k8s-worker1
  Normal  Pulling    102s  kubelet            Pulling image "polinux/stress"
  Normal  Pulled     83s   kubelet            Successfully pulled image "polinux/stress" in 18.944533343s
  Normal  Created    83s   kubelet            Created container c1
  Normal  Started    82s   kubelet            Started container c1

说明: 可以看到第二行信息还是pulling image下载镜像

  1. 修改YAML
[root@k8s-master01 ~]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress
  namespace: default
spec:
  containers:
  - name: c1
    image: polinux/stress
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    imagePullPolicy: IfNotPresent					#  增加了这一句
  1. 再次删除再创建
[root@k8s-master01 ~]# kubectl describe pod pod-stress
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  17s   default-scheduler  Successfully assigned default/pod-stress to k8s-worker1
  Normal  Pulled     17s   kubelet            Container image "polinux/stress" already present on machine
  Normal  Created    17s   kubelet            Created container c1
  Normal  Started    17s   kubelet            Started container c1

说明: 第二行信息是说镜像已经存在,直接使用了

3.5 pod的标签

  • 为pod设置label,用于控制器通过label与pod关联
  • 语法与前面学的node标签几乎一致

3.5.1 通过命令管理Pod标签

  1. 查看pod的标签
[root@k8s-master01 ~]# kubectl get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE   LABELS
pod-stress     1/1    Running   0          7m25s   <none>
  1. 打标签,再查看
[root@k8s-master01 ~]# kubectl label pod pod-stress region=huanai zone=A env=test bussiness=game
pod/pod-stress labeled
[root@k8s-master01 ~]# kubectl get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE     LABELS
pod-stress    1/1     Running   0          8m54s   bussiness=game,env=test,region=huanai,zone=A
  1. 通过等值关系标签查询
[root@k8s-master01 ~]# kubectl get pods -l zone=A
NAME         READY   STATUS    RESTARTS   AGE
pod-stress   1/1     Running   0          9m22s
  1. 通过集合关系标签查询
[root@k8s-master01 ~]# kubectl get pods -l "zone in (A,B,C)"
NAME         READY   STATUS    RESTARTS   AGE
pod-stress   1/1     Running   0          9m55s
  1. 删除标签后再验证
[root@k8s-master01 ~]# kubectl label pod pod-stress region- zone- env- bussiness-
pod/pod-stress labeled
[root@k8s-master01 ~]# kubectl get pods --show-labels
NAME          READY   STATUS    RESTARTS   AGE   LABELS
pod-stress    1/1     Running   0          16m     <none>

小结:

  • pod的label与node的label操作方式几乎相同
  • node的label用于pod调度到指定label的node节点
  • pod的label用于controller关联控制的pod

3.5.2 通过YAML创建Pod时添加标签

  1. 修改yaml
[root@k8s-master01 ~]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress
  namespace: default
  labels:
    env: dev
    app: nginx				# 直接在原来的yaml里加上多个标签
spec:
  containers:
  - name: c1
    image: polinux/stress
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
    imagePullPolicy: IfNotPresent
  1. 直接apply应用
[root@k8s-master01 ~]# kubectl apply -f pod1.yaml
pod/pod-stress1 configured			  # 这里是configured,表示修改了
  1. 验证
[root@k8s-master01 ~]# kubectl get pods --show-labels
NAME          READY   STATUS             RESTARTS   AGE     LABELS
pod-stress   1/1     Running            0          3m5s    app=nginx,env=dev		# 标签有了

3.6 pod资源限制

准备2个不同限制方式的创建pod的yaml文件

[root@k8s-master01 ~]# vim pod2.yml
apiVersion: v1
kind: Namespace
metadata:
  name: namespace1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress2
  namespace: namespace1
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]				    # 启动容器时执行的命令
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]  # 产生1个进程分配150M内存1秒后释放
[root@k8s-master01 ~]# vim pod3.yml
apiVersion: v1
kind: Namespace
metadata:
  name: namespace1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress3
  namespace: namespace1
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "150Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
[root@k8s-master01 ~]# kubectl apply -f pod2.yml
namespace/namespace1 created
pod/pod-stress2 created
[root@k8s-master01 ~]# kubectl apply -f pod3.yml
namespace/namespace1 unchanged
pod/pod-stress3 created
[root@k8s-master01 ~]# kubectl get namespace  |grep namespace1
namespace1        Active   1m28s
[root@k8s-master1 ~]# kubectl get pod -n namespace1
NAME          READY   STATUS      RESTARTS   AGE
pod-stress2   1/1     Running     0          2m2s
pod-stress3   0/1     OOMKilled   4          115s
查看会发现pod-stress3这个pod状态变为OOMKilled,因为它是内存不足所以显示Container被杀死

说明: 一旦pod中的容器挂了,容器会有重启策略, 如下:

  • Always:表示容器挂了总是重启,这是默认策略

  • OnFailures:表容器状态为错误时才重启,也就是容器正常终止时才重启

  • Never:表示容器挂了不予重启

  • 对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启… 依次类推

测试完后删除

[root@k8s-master01 ~]# kubectl delete ns namespace1

3.7 pod包含多个容器

  1. 准备yml文件
[root@k8s-master01 ~]# vim pod4.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-stress4
spec:
  containers:
  - name: c1
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
  - name: c2
    image: polinux/stress
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
  1. 应用yml文件创建pod
[root@k8s-master01 ~]# kubectl apply -f pod4.yml
pod/pod-stress4 created
  1. 查看pod在哪个节点
[root@k8s-master01 ~]# kubectl get pods  -o wide
NAME          READY   STATUS    RESTARTS   AGE     IP               NODE          NOMINATED NODE   READINESS GATES
pod-stress4   2/2     Running   0          70s     10.244.159.136   k8s-master01   <none>           <none>
可以看到有2个容器,运行在k8s-master01节点
  1. 在k8s-master01上验证,确实产生了2个容器
[root@k8s-master1 ~]# docker ps -a |grep stress
d7827a963f9d        df58d15b053d              "stress --vm 1 --vm-…"   2 hours ago         Up 2 hours                                      k8s_c2_pod-stress4_default_a534bce1-3ffe-45f5-8128-34657e289b44_0
ae8e8f8d095b        df58d15b053d              "stress --vm 1 --vm-…"   2 hours ago         Up 2 hours                                      k8s_c1_pod-stress4_default_a534bce1-3ffe-45f5-8128-34657e289b44_0
e66461900426        easzlab/pause-amd64:3.2   "/pause"                 2 hours ago         Up 2 hours                                      k8s_POD_pod-stress4_default_a534bce1-3ffe-45f5-8128-34657e289b44_0

3.8 对pod里的容器进行操作

3.8.1 命令帮助

[root@k8s-master01 ~]# kubectl exec -h

3.8.2 不用交互直接执行命令

格式为: kubectl exec pod名 -c 容器名 -- 命令

注意:

  • -c 容器名为可选项,如果是1个pod中1个容器,则不用指定;
  • 如果是1个pod中多个容器,不指定默认为第1个。
[root@k8s-master01 ~]# kubectl exec pod-stress4 -c c2  -- touch /111
[root@k8s-master01 ~]# kubectl exec pod-stress4 -c c2  -- ls /111
/111

不指定容器名,则默认为pod里的第1个容器

[root@k8s-master01 ~]# kubectl exec  pod-stress4  -- touch /222
Defaulting container name to c1.
Use 'kubectl describe pod/pod-stress4 -n default' to see all of the containers in this pod.

3.8.3 和容器交互操作

和docker exec几乎一样

[root@k8s-master01 ~]# kubectl exec -it pod-stress4 -c c1 -- /bin/bash
bash-5.0# touch /333
bash-5.0# ls
222    bin    etc    lib    mnt    proc   run    srv    tmp    var
333    dev    home   media  opt    root   sbin   sys    usr
bash-5.0# exit
exit	   

3.9 验证pod中多个容器网络共享

  1. 编写YAML
[root@k8s-master01 ~]# vim pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx2
spec:
  containers:
  - name: c1
    image: nginx:1.15-alpine
  - name: c2
    image: nginx:1.15-alpine
  1. 应用YAML
[root@k8s-master01 ~]# kubectl apply -f pod-nginx.yaml
pod/nginx2 created

3, 查看pod信息与状态

[root@k8s-master01 ~]# kubectl describe pod nginx2
......
......
Events:
  Type    Reason     Age              From               Message
  ----    ------     ----             ----               -------
  Normal  Scheduled  25s              default-scheduler  Successfully assigned default/nginx2 to k8s-worker1
  Normal  Pulling    24s              kubelet            Pulling image "nginx:1.15-alpine"
  Normal  Pulled     5s               kubelet            Successfully pulled image "nginx:1.15-alpine" in 18.928009025s
  Normal  Created    5s               kubelet            Created container c1
  Normal  Started    5s               kubelet            Started container c1
  Normal  Pulled     2s (x2 over 5s)  kubelet            Container image "nginx:1.15-alpine" already present on machine
  Normal  Created    2s (x2 over 5s)  kubelet            Created container c2
  Normal  Started    2s (x2 over 5s)  kubelet            Started container c2
[root@k8s-master01 ~]# kubectl get pods |grep nginx2
nginx2   1/2     CrashLoopBackOff   3          2m40s

有一个启动不了,因为一个pod中两个容器是共用网络的,所以不能两个都占用80端口

通过查找k8s-worker01上面的容器,然后docker logs查看,得到如下的报错,说明是端口被占用

[root@k8s-worker01 ~]# docker logs k8s_c2_nginx2_default_51fd8e81-1c4b-4557-9498-9b25ed8a4c99_4
2022/12/21 14:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2022/12/21 14:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2022/12/21 14:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2022/12/21 14:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2022/12/21 14:29:12 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
2022/12/21 14:29:12 [emerg] 1#1: still could not bind()
nginx: [emerg] still could not bind()

四、pod调度

4.1 pod调度流程

Step1
通过kubectl命令应用资源清单文件(yaml格式)向api server 发起一个create pod 请求
Step2
api server接收到pod创建请求后,生成一个包含创建信息资源清单文件
Step3
apiserver 将资源清单文件中信息写入etcd数据库
Step4
Scheduler启动后会一直watch API Server,获取 podSpec.NodeName为空的Pod,即判断pod.spec.Node == null? 若为null,表示这个Pod请求是新的,需要创建,因此先进行调度计算(共计2步:1、过滤不满足条件的,2、选择优先级高的),找到合适的node,然后将信息在etcd数据库中更新分配结果:pod.spec.Node = nodeA (设置一个具体的节点)
Step5
kubelet 通过watch etcd数据库(即不停地看etcd中的记录),发现有新的Node出现,如果这条记录中的Node与所在节点编号相同,即这个Pod由scheduler分配给自己,则调用node中的Container Runtime,进而创建container,并将创建后的结果返回到给api server用于更新etcd数据库中数据状态。

4.2 调度约束方法

我们为了实现容器主机资源平衡使用, 可以使用约束把pod调度到指定的node节点

  • nodeName 用于将pod调度到指定的node名称上
  • nodeSelector 用于将pod调度到匹配Label的node上

4.2.1 nodeName

  1. 编写YAML文件
[root@k8s-master01 ~]# vim pod-nodename.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
spec:
  nodeName: k8s-worker02                    # 通过nodeName调度到k8s-worker02节点
  containers:
  - name: nginx
    image: nginx:1.15-alpine
  1. 应用YAML文件创建pod
[root@k8s-master01 ~]# kubectl apply -f pod-nodename.yml
pod/pod-nodename created
  1. 验证
[root@k8s-master01 ~]# kubectl describe pod pod-nodename |tail -6
Events:
  Type    Reason   Age    From     Message
  ----    ------   ----   ----     -------
  Normal  Pulled   2m47s  kubelet  Container image "nginx:1.15-alpine" already present on machine
  Normal  Created  2m47s  kubelet  Created container nginx
  Normal  Started  2m47s  kubelet  Started container nginx
倒数第3行没有使用scheduler,而是直接给运行了,说明nodeName约束生效

4.2.2 nodeSelector

  1. 为k8s-worker02打标签
[root@k8s-master01 ~]# kubectl label nodes k8s-worker02 bussiness=game
node/k8s-worker02 labeled
  1. 编写YAML文件
[root@k8s-master01 ~]# vim pod-nodeselector.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselect
spec:
  nodeSelector:                         # nodeSelector节点选择器
    bussiness: game                     # 指定调度到标签为bussiness=game的节点
  containers:
  - name: nginx
    image: nginx:1.15-alpine
  1. 应用YAML文件创建pod
[root@k8s-master01 ~]# kubectl apply -f pod-nodeselector.yml
pod/pod-nodeselect created
  1. 验证
[root@k8s-master01 ~]# kubectl describe pod pod-nodeselect |tail -6
 Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  20s   default-scheduler  Successfully assigned default/pod-nodeselect to k8s-worker1
  Normal  Pulled     19s   kubelet            Container image "nginx:1.15-alpine" already present on machine
  Normal  Created    19s   kubelet            Created container nginx
  Normal  Started    19s   kubelet            Started container nginx
仍然经过了scheduler,但确实分配到了 k8s-worker02上

五、pod的生命周期

5.1 Pod生命周期

  • 有些pod(比如运行httpd服务),正常情况下会一直运行中,但如果手动删除它,此pod会终止
  • 也有些pod(比如执行计算任务),任务计算完后就会自动终止

上面两种场景中,pod从创建到终止的过程就是pod的生命周期。

5.1.1 容器启动

  1. pod中的容器在创建前,有初始化容器(init container)来进行初始化环境

  2. 初化完后,主容器(main container)开始启动

  3. 主容器启动后,有一个post start的操作(启动后的触发型操作,或者叫启动后钩子)

  4. post start后,就开始做健康检查

    • 第一个健康检查叫存活状态检查(liveness probe ),用来检查主容器存活状态的

    • 第二个健康检查叫准备就绪检查(readiness probe),用来检查主容器是否启动就绪

5.1.2 容器终止

  1. 可以在容器终止前设置pre stop操作(终止前的触发型操作,或者叫终止前钩子)
  2. 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止
  3. 终止容器后还可能会重启容器(视容器重启策略而定)。

5.1.3 回顾容器重启策略

  • Always:表示容器挂了总是重启,这是默认策略
  • OnFailures:表示容器状态为错误时才重启,也就是容器正常终止时不重启
  • Never:表示容器挂了不予重启
  • 对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启… 依次类推

5.2 HealthCheck健康检查

当Pod启动时,容器可能会因为某种错误(服务未启动或端口不正确)而无法访问等。

5.2.1 Health Check方式

kubelet 拥有两个检测器,它们分别对应不同的触发器(根据触发器的结构执行进一步的动作)

方式说明
Liveness Probe(存活状态探测)指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success
readiness Probe(就绪型探测)指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。注:检查后不健康,将容器设置为Notready;如果使用service来访问,流量不会转发给此种状态的pod
startup Probe指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success

5.2.2 Probe探测方式

方式说明
Exec执行命令
HTTPGethttp请求某一个URL路径
TCPtcp连接某一个端口
gRPC使用 gRPC 执行一个远程过程调用。 目标应该实现 gRPC健康检查。 如果响应的状态是 “SERVING”,则认为诊断成功。 gRPC 探针是一个 alpha 特性,只有在你启用了 “GRPCContainerProbe” 特性门控时才能使用。

5.2.3 liveness-exec案例

  1. 准备YAML文件
[root@k8s-master01 ~]# vim pod-liveness-exec.yml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  containers:
  - name: liveness
    image: busybox
    imagePullPolicy: IfNotPresent
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5 				# pod启动延迟5秒后探测
      periodSeconds: 5 						# 每5秒探测1次
  1. 应用YAML文件
[root@k8s-master01 ~]# kubectl apply -f pod-liveness-exec.yml
  1. 通过下面的命令观察
[root@k8s-master01 ~]# kubectl describe pod liveness-exec
......
Events:
  Type     Reason     Age   From               Message
  ----     --Docker&Kubernetes ❀ Kubernetes集群Pod控制器分类简述

Docker&Kubernetes ❀ Kubernetes集群Pod控制器分类简述

第144天学习打卡( Kubernetes DaemonSet k8s集群组件 k8s的核心概念)

理解Kubernetes的NodePort、LoadBalancer和Ingress

Kubernetes三大核心概念

Kubernetes三大核心概念