深入理解Pod

一、介绍Pod

1.1、什么是Pod

  • Pod是kubernetes中的最小调度单元,k8s是通过定义一个Pod的资源,然后在Pod里面运行容器,容器需要指定一个镜像,这样就可以用来运行具体的服务。一个Pod封装一个容器(也可以封装多个容器),Pod里的容器共享存储、网络等。也就是说,应该把整个Pod看作虚拟机,然后每个容器相当于运行在虚拟机的进程。
    在这里插入图片描述

  • Pod是需要调度到k8s集群的工作节点来运行的,具体调度到哪个节点,是根据scheduler调度器实现的。
    在这里插入图片描述

  • Pod中可以同时运行多个容器。同一个Pod中的容器会自动的分配到同一个node上。同一个Pod中的容器共享资源、网络环境,它们总是被同时调度,在一个Pod中同时运行多个容器是一种比较高级的用法,只有当你的容器需要紧密配合协作的时候才考虑用这种模式。

1.2、Pod的特点

  • 容器共享网络命名空间:Pod中的容器共享相同的IP地址和端口范围,可以通过localhost相互通信。
  • 存储卷共享:Pod中的容器可以访问相同的存储卷,方便数据共享和通信。
  • 逻辑单元:Pod提供了一个逻辑独立、机密耦合的单元,容器在同一个Pod中可以方便进行通信和数据共享
  • 生命周期:Pod有自己的生命周期,当Pod中的所有容器都终止时,Pod才会终止

1.3、Pod的用途

  • 应用组合:将相互关联的应用容器组合到一个Pod中,以便它们可以直接通信。

  • 共享存储:多个容器可以访问相同的存储卷,实现数据共享

  • 单元部署:Pod作为一个单元进行部署,确保相关容器共同运行和调度。

  • 微服务:将微服务架构中的一组相关服务打包在一个Pod中,以简化部署和管理

1.4、Pod网络

  • Pod是有IP地址的,每个Pod都被分配唯一的IP地址(IP地址是靠网络插件calico、flannel、weave等分配的),Pod中的容器共享网络命名空间,包括IP地址和网络端口。Pod内部的容器可以使用localhost相互通信。Pod中的容器也可以通过网络插件calico与其他节点的Pod通信。

1.5、Pod存储

  • 创建Pod的时候可以指定挂载的存储卷。Pod中的所有容器都可以访问共享卷,允许这些容器共享数据。Pod只要挂载持久化数据卷,Pod重启之后数据还是会存在的。

1.6、Pod的工作方式

  • Pod的工作方式分为两种,一种是自主式Pod,一种是控制器管理的Pod,所谓的自主式Pod就是直接定义一个Pod资源,这种Pod一旦异常就推出了,使用控制器管理的Pod可以确保Pod始终维持在指定的副本数量。常见的管理Pod的控制器有:Replicaset、Deployment、Job、CronJob、Daemonset、Statefulset

二、创建Pod

2.1、命令行创建Pod

# 使用nginx镜像,创建一个叫nginx-test的Pod,使用--port指定容器内部应用程序监听的端口为80
[root@k8s-master ~]# kubectl run nginx-test --image=nginx --port=80
pod/nginx-test created


# 查看默认命名空间defalut中的所有Pod
[root@k8s-master ~]# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
nginx-test   1/1     Running   0          42s


# 使用-o wide可以可以查看到Pod更详细的信息,比如IP地址,Pod被分配所在的节点
[root@k8s-master ~]# kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE    IP              NODE         NOMINATED NODE   READINESS GATES
nginx-test   1/1     Running   0          107s   10.244.58.195   k8s-node02   <none>           <none>


# 使用--show-labels选项可以看到pod的标签
# LABELS字段为标签
# pod就是通过标签与service进行关联的
[root@k8s-master ~]# kubectl get pod --show-labels
NAME         READY   STATUS    RESTARTS   AGE     LABELS
nginx-test   1/1     Running   0          2m55s   run=nginx-test


# 使用-l选项后面跟标签,可以查询带有指定标签的pod
[root@k8s-master ~]# kubectl get pod -l run=nginx-test
NAME         READY   STATUS    RESTARTS   AGE
nginx-test   1/1     Running   0          5m15s


# 删除标签



# 查看Pod日志
# 不指定命令空间默认在default下查看pod日志
[root@k8s-master ~]# kubectl logs nginx-test


# 进入Pod容器(如果一个pod中有多个容器,默认会进入第一个容器内,除非指定容器)
[root@k8s-master ~]# kubectl exec -it nginx-test -- bash


# 删除一个叫nginx-test的pod
[root@k8s-master ~]# kubectl delete pod nginx-test
pod "nginx-test" deleted


# 使用-n选项可以查询指定命名空间的Pod
# 查看kube-system命名空间中的所有Pod
[root@k8s-master ~]# kubectl get pod -n kube-system


# 使用--all-namespaces可以查询所有命名空间的Pod
# --all-namespaces也可以简写为-A
[root@k8s-master ~]# kubectl get pod -A
NAMESPACE     NAME                                      READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-858fbfbc9-l8tpp   1/1     Running   1          4d7h
kube-system   calico-node-k6qbl                         1/1     Running   1          4d7h
kube-system   calico-node-q969p                         1/1     Running   1          4d7h
kube-system   calico-node-sv48g                         1/1     Running   1          4d7h
kube-system   coredns-7ff77c879f-lnl72                  1/1     Running   1          4d7h
kube-system   coredns-7ff77c879f-nfx7g                  1/1     Running   1          4d7h
kube-system   etcd-k8s-master                           1/1     Running   1          4d7h
kube-system   kube-apiserver-k8s-master                 1/1     Running   1          4d7h
kube-system   kube-controller-manager-k8s-master        1/1     Running   1          4d7h
kube-system   kube-proxy-2c282                          1/1     Running   1          4d7h
kube-system   kube-proxy-6n6pn                          1/1     Running   1          4d7h
kube-system   kube-proxy-zhm2m                          1/1     Running   1          4d7h
kube-system   kube-scheduler-k8s-master                 1/1     Running   1          4d7h

2.2、资源清单创建Pod

  • 在kubernetes中大多数都是使用资源清单来进行创建,通常情况下是yaml格式的。以下是一个创建Pod的yaml示例
[root@k8s-master ~]# cat nginx_pod.yaml 
# 定义Kubernetes API版本
apiVersion: v1

# 指定Kubernetes资源类型(本次为pod)
kind: Pod

# Pod的元数据,包括名称、命名空间和标签
metadata:
  name: nginx      # Pod的名字为nginx
  namespace: default   # 在default命名空间中创建这个Pod
  labels: 
    app: nginx   # 标签应用为nginx的标签

# Pod的规格,包括容器及配置
spec:
  restartPolicy: Never   # 设置重启策略
  # Pod中的容器列表
  containers:
  - name: nginx   # 容器名称
    ports: 
    - containerPort: 80  # 从容器中暴露的端口
    image: nginx:latest   # 用于容器的Docker镜像
    imagePullPolicy: IfNotPresent   # 容器镜像拉取策略
2.2.1、镜像拉取策略

Kubernetes中的容器镜像拉取策略(imagePullPolicy)有以下三种:

  • Always(总是)

表示Kubernetes将始终尝试从指定的镜像仓库拉取容器镜像。即使节点上已经存在相同版本的镜像,也会尝试拉取最新的版本。

  • IfNotPresent(如果不存在则拉取)

这是默认的策略,它表示如果节点上不存在指定的容器镜像版本,那么就拉取该镜像。如果本地已经存在,则不再拉取。

  • Never(从不拉取)

表示Kubernetes不会尝试拉取指定的容器镜像。他要求节点上必须存在所需版本的镜像,否则启动容器会失败

如果省略imagePullPolicy字段,镜像的名称没有带标签,或是标签是:latest则策略为Always,否则为IfNotPresent。

2.2.2、Pod重启策略
  • Pod重启策略有以下3种,Pod的重启策略定义了在容器退出时Kubernetes应该采取的操作。这对于确保应用程序的高可用性非常重要,使用restartPolicy字段进行配置

Always:在任何情况下,只要容器不在运行状态,就自动重启容器(默认策略)

OnFailure:只在容器异常才自动重启容器

Never:从来不重启容器

2.2.3、部署资源
[root@k8s-master ~]# kubectl apply -f nginx_pod.yaml 
pod/nginx created
[root@k8s-master ~]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          5s
2.2.4、删除资源
[root@k8s-master ~]# kubectl delete pod nginx
pod "nginx" deleted
[root@k8s-master ~]# kubectl get pod
No resources found in default namespace.

三、静态Pod

3.1、静态Pod的介绍

  • 在Kubernetes集群中除了我们经常使用到的普通的Pod外,还有一种特殊的Pod,叫做Static Pod,就是我们说的静态Pod,静态Pod有什么特殊的地方呢?

  • 静态Pod直接由特定节点上的kubelet进程来管理,不通过master节点上的apiserver。无法与我们常用的控制器 Deployment或者DaemonSet进行关联,它由kubelet进程自己来监控,当Pod崩溃时重启该Pod,kubelet也无法对它们进行健康检查。静态Pod始终绑定在某一个kubelet,并且始终运行在同一个节点上。kubelet会自动为每个静态Pod在kubernetes的apiserver上创建一个镜像Pod,因此我们可以在apiserver中查询到该Pod,但是不能通过apiserver进行控制(例如不能删除)。

  • 创建静态Pod有两种方式:配置文件和HTTP两种方式,在这里我们主要讲解配置文件创建的方式。

3.2、创建镜像Pod

  • 配置文件就是放在特定目录下的标准的JSON或YAML格式的Pod定义文件。用于kube --pod-manifest-path=来启动kubelet进程,kubelet定期的去扫描这个目录,根据这个目录下出现或消失的YAML/JSON文件来创建或者删除静态Pod。
# 写在/etc/kubernetes/manifests/即可
[root@k8s-master ~]# cat > /etc/kubernetes/manifests/static-nginx.yaml << EOF
apiVersion: "v1"
kind: Pod
metadata:
  name: nginx01
  namespace: default
  labels: 
    app: nginx
spec:
  containers:
  - name: nginx
    ports: 
    - containerPort: 80
    image: nginx:latest
  imagePullPolicy: IfNotPresent
EOF

[root@k8s-master ~]# kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
nginx01-k8s-master   1/1     Running   0          53s


# 删除pod后pod依然存在
[root@k8s-master ~]# kubectl delete pod nginx01-k8s-master
pod "nginx01-k8s-master" deleted
[root@k8s-master ~]# kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
nginx01-k8s-master   1/1     Running   0          27s


# 只有删除yaml资源文件才能删除
[root@k8s-master ~]# rm -rf /etc/kubernetes/manifests/static-nginx.yaml 
[root@k8s-master ~]# kubectl get pod
No resources found in default namespace.

四、Pod Hook

4.1、Pod Hook介绍

​ 我们都知道Pod是Kubernetes群集中的最小单元,而Pod是有容器组成的,所以在谈论Pod的生命周期的时候我们可以先来讨论下容器的生命周期。

实际上Kubernetes为我们的容器提供了生命周期钩子,就是我们说的Pod Hook,Pod Hook是由kubelet发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。我们可以同时为Pod中的所有容器都配置Hook。

Kubernetes为我们提供了两种钩子函数:

  • PostStart:这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOIN之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起,容器将不能达到running状态。
  • PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的,所以它必须在删除容器的调用发出之前完成。主要用于优化关闭应用程序、通知其他系统等。如果钩子在执行期间挂起,Pod阶段将停留在running状态且永不会达到failed状态

​ 如果PostStart或者PreStop钩子失败,它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的,比如在停止容器之前预先保存状态。

​ 另外我们有两种方式来实现上面的钩子函数:

Exec:用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器

HTTP:对容器上的特定的端点执行HTTP请求

4.2、Pod Hook的时候

  • 以下是一个示例
[root@k8s-master ~]# cat nginx_hook.yaml 
apiVersion: "v1"
kind: Pod
metadata:
  name: nginx02
  labels:
    app: nginx
spec:
  restartPolicy: Always
  containers:
  - name: test-nginx01
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    lifecycle:
      postStart: 
        exec: 
          # 启动容器立即执行的命令
          command: ["sh","-c","echo 'postart' >> /start.txt"]
      preStop:
        exec:
          # 关闭容器立即执行的命令
          command: ["sh","-c","echo 'prestop' >> /stop.html; sleep 100"]

[root@k8s-master ~]# kubectl apply -f nginx_hook.yaml 
pod/nginx02 created
[root@k8s-master ~]# kubectl get pod nginx02
NAME      READY   STATUS    RESTARTS   AGE
nginx02   1/1     Running   0          27s
# 进入容器可以发现我们定义的postStart被执行了
[root@k8s-master ~]# kubectl exec -it nginx02 -- bash
root@nginx02:/# cat /start.txt 
postart
# 删除Pod,然后迅速的去打开一个终端进行验证,容器被关闭的时候是否执行了相应的命令
[root@k8s-master ~]# kubectl delete pod nginx02
pod "nginx02" deleted


# 在打开一个终端,发现删除pod的时候定义的preStop被执行了
[root@k8s-master ~]# kubectl exec -it nginx02 -- bash
root@nginx02:/# cat /stop.html 
prestop

五、Pod健康检查

在kubernetes集群当中,我们可以通过配置liveness probe(存活探针)和readiness probe(可读性探针)来影响容器的生存周期。

目前LivenessProbe和ReadinessProbe两种探针都支持下面三种探测方式:

  • ExecAction:在容器中执行指定的命令,如果执行成功,退出代码为0则探测成功
  • TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够简历TCP连接,则表明容器健康。
  • HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果相应的状态码大于等于200且小于400,则认为容器健康

探针探测结果有以下值:

  • Success:表示通过检测
  • Failure:表示未通过检测
  • Unknown:表示检测没有正常运行

Pod探针相关的属性:探针(Probe)有许多可选字段,可以用来更加精确的控制Liveness和Readiness两种探针的行为

  • initialDelaySeconds:Pod启动后首次进行检查的等待时间,单位“秒”
  • periodSeconds:检查的间隔时间,默认为10s,单位“秒”
  • timeoutSeconds:探针执行检测请求后,等待相应的超时时间,默认为1s,单位“秒”
  • successThreshold:连续失败的重试次数,重试一定次数后将认为失败,在热爱的iness探针中,Pod会被标记为未就绪,默认为3,最小值为1

5.1、livenessProbe:存活性探测

  • 许多应用程序经过长时间运行,最终过渡到无法运行的状态,除了重启,无法恢复。通常情况下,K8S会发现应用程序已经终止,然后重启应用程序Pod。有时应用程序可能因为某些原因(后端服务故障等)导致暂时无法对外提供服务,但应用软件没有终止,导致K8S无法隔离有故障的Pod,调用者可能会访问到有故障的Pod,导致业务不稳定。K8S提供livenessProbe来检测容器是否正常运行,并且对相应情况进行相应的补救措施。
# 该资源清单定义了livenessProbe,启动后10秒在进行检查,每3秒检测一次
# 检测失败就会重启Pod
[root@master ~]# cat nginx_livenessProbe.yaml 
apiVersion: "v1"
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  restartPolicy: Always
  containers:
  - name: test-nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    # 容器内指定的命令
    args:
    - /bin/sh
    - -c
    # 创建一个文件等待30秒后删除,然后等待600秒(十分钟)
    - touch /tmp/healthy;sleep 30;rm -rf /tmp/healthy;sleep 600
    # 存活性探测
    livenessProbe:
    # 启动容器后等待10秒
      initialDelaySeconds: 10
    # 每3秒进行一次探测
      periodSeconds: 3
     # 执行的命令
      exec: 
        command: 
        - cat
        - /tmp/healthy


# 部署资源
[root@master ~]# kubectl apply -f nginx_livenessProbe.yaml 
pod/nginx created


# 检测失败就会重启Pod,可以查看RESTARTl了解重启次数
[root@master ~]# kubectl get pod
NAME    READY   STATUS    RESTARTS      AGE
nginx   1/1     Running   5 (28s ago)   6m37s

5.2、readinessProbe:就绪性探测

  • 在没有配置readinessProbe的资源对象中,pod中的容器启动完成后,就认为pod中的应用程序可以对外提供服务,该pod就会加入相应的service,对外提供服务。但有时一些应用程序启动后,需要较长时间的加载才能对外服务,如果这时对外提供服务,执行结果必然无法达到预期的效果,影响用户体验。比如使用tomcat应用程序来说,并不是简单地说tomcat启动成功就可以对外提供服务的,还需要等待spring容器初始化,数据库连接上等等
# 该资源定义了readinessProbe,启动后20秒在进行检查
# 每隔5秒检测一次80端口的/index.heml页面,设置10秒超时,检测失败,该pod就不能提供服务
[root@master ~]# cat nginx_readinessProbe.yaml 
apiVersion: "v1"
kind: Pod
metadata:
  name: nginx01
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    # 指定80端口命令
    - name: server
      containerPort: 80
    # 指定81端口名称
    - name: management
      containerPort: 81
    # 可读性探针探测
    readinessProbe:
    # 启动后等待20秒
      initialDelaySeconds: 20 
    # 每间隔5秒进行一次探测
      periodSeconds: 5
    # 执行探测请求后,等待响应的超时时间
      timeoutSeconds: 10
    # 向80端口发送HTTP访问请求
      httpGet:
        scheme: HTTP
        port: 80
        path: /index.html


# 部署资源
[root@master ~]# kubectl apply -f nginx_readinessProbe.yaml 
pod/nginx01 created


# 把pod的index.heml页面删除发现pod的就绪状态就变了
# 就绪的字段为“READY”如果为0表示未就绪
[root@master ~]# kubectl exec -it nginx01 -- rm -rf /usr/share/nginx/html/index.heml
[root@master ~]# kubectl get pod nginx01
NAME      READY   STATUS    RESTARTS   AGE
nginx01   0/1     Running   0          5m1s

5.3、两种探针的区别

ReadinessProbe和livenessProbe可以使用相同的探测方式,只是对Pod的处置方式不同:

  • readinessProbe:当检测失败后,将pod的IP:Port从对应的EngPoint列表中删除。
  • livenessProbe:当检测失败后,将杀死容器并根据Pod的重启策略决定做出对应的措施

六、初始化容器

  • Pod里面可以有一个或者多个容器,部署应用的容器可以称为主容器,在创建Pod时候,Pod中可以有一个或多个先于主容器启动init容器,这个init容器就可以成为初始化容器,初始化容器一旦执行完,它从启动开始到初始代码执行完就退出了,它不会一直存在,所以在主容器启动之前执行初始化,初始化容器可以有多个,多个初始化是要串行执行的,先执行初始化容器1,再执行初始化容器2等,等初始化容器执行完初始化就推出了,然后再执行主容器,主容器一退出,pod就结束了,主容器退出的时间就是pod的结束点,他俩时间轴是一致的。
  • init容器就是做初始化工作的容器。可以有一个或多个,如果多个按照定义的顺序依次执行,只有所有的初始化容器执行完后,主容器才能启动。由于一个Pod里的存储卷是共享的,所以init Container里产生的数据可以被主容器使用到,init Container可以在多种K8S资源里被使用到,如Deployment、DaemonSet、StatefulSet、Job等,但都是在Pod启动时,在主容器启动前指定,做初始化工作。

init容器与普通的容器区别是:

  • init容器不支持Readiness,因为它们必须在pod就绪之前运行完成。
  • 每个init容器必须运行成功,下一个才能运行。
  • 如果Pod的init容器失败,Kubernetes会不断地重启该Pod,直到init容器成功为止,然而,如果Pod对应的restartPolicy值为Never,它不会重启启动。
[root@master ~]# cat nginx_init.yaml 
apiVersion: "v1"
kind: Pod
metadata:
  name: nginx02
  labels:
    app: nginx
spec:
  containers:
  - name: test-nginx
    ports:
    - containerPort: 80
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: webdata
      mountPath: /usr/share/nginx/html
  initContainers:
  - name: init-heml
    image: busybox:1.28
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: webdata
      mountPath: /opt
    command: ["sh","-c","echo 'init' > /opt/index.html"]
  volumes:
  - name: webdata
    emptyDir: {}


# 部署资源
[root@master ~]# kubectl apply -f nginx_init.yaml 
pod/nginx02 created
 
 
# 启动的时候先启动初始化启动
[root@master ~]# kubectl get pod
nginx02   0/1     Init:0/1           0                5s
[root@master ~]# kubectl get pod
nginx02   1/1     Running   0                65s


# 查看容器里面index.html文件的内容就是初始化容器写的
[root@master ~]# kubectl exec -it nginx02 -c test-nginx -- cat /usr/share/nginx/html/index.html
init

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部