【云原生】深入理解Pod的使用进行管理

深入理解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

bash 复制代码
# 使用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示例
bash 复制代码
[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、部署资源
bash 复制代码
[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、删除资源
bash 复制代码
[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。
bash 复制代码
# 写在/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的时候

  • 以下是一个示例
bash 复制代码
[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"]
bash 复制代码
[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
bash 复制代码
# 进入容器可以发现我们定义的postStart被执行了
[root@k8s-master ~]# kubectl exec -it nginx02 -- bash
root@nginx02:/# cat /start.txt 
postart
bash 复制代码
# 删除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来检测容器是否正常运行,并且对相应情况进行相应的补救措施。
bash 复制代码
# 该资源清单定义了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容器初始化,数据库连接上等等
bash 复制代码
# 该资源定义了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,它不会重启启动。
bash 复制代码
[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
相关推荐
SimonLiu00920 分钟前
清理HiNas(海纳斯) Docker日志并限制日志大小
java·docker·容器
高峰君主3 小时前
Docker容器持久化
docker·容器·eureka
能来帮帮蒟蒻吗3 小时前
Docker安装(Ubuntu22版)
笔记·学习·spring cloud·docker·容器
言之。7 小时前
别学了,打会王者吧
java·python·mysql·容器·spark·php·html5
秦始皇爱找茬11 小时前
docker部署Jenkins工具
docker·容器·jenkins
hoho不爱喝酒13 小时前
微服务Nacos组件的介绍、安装、使用
微服务·云原生·架构
樽酒ﻬق14 小时前
Kubernetes 常用运维命令整理
运维·容器·kubernetes
Golinie15 小时前
Docker底层原理浅析 | namespace+cgroups+文件系统
docker·容器·文件系统·cgroups·unionfs
樽酒ﻬق16 小时前
深度解析 Kubernetes 配置管理:如何安全使用 ConfigMap 和 Secret
安全·贪心算法·kubernetes
FreeBuf_16 小时前
新型恶意软件采用独特混淆技术劫持Docker镜像
运维·docker·容器