前言

  在当今云原生技术飞速发展的时代,Kubernetes(简称K8s)作为容器编排领域的翘楚,已成为企业构建、部署和管理容器化应用的首选平台。而在Kubernetes的众多核心概念中,Pod无疑是最为基础和关键的组成部分。它不仅是Kubernetes中最小的可部署单元,更是承载着应用程序及其依赖环境的基石。本文将深入剖析Pod的方方面面,从基础概念到进阶实践,带你全面了解Pod在Kubernetes世界中的重要作用和运作机制。

一、Pod基础概念

1. Pod的基本概念

  Pod是Kubernetes中的最小部署单元,它代表着集群中的一个运行进程。一个Pod可以包含一个或多个紧密耦合的容器,这些容器共享网络和存储资源。在Kubernetes中,Pod是管理容器的基础结构,其他如Deployment、StatefulSet、DaemonSet等控制器对象都围绕Pod进行扩展。
控制面

协议方向端口范围目的使用者
TCP入站6443Kubernetes API 服务器所有
TCP入站2379-2380etcd 服务器客户端 APIkube-apiserver、etcd
TCP入站10250kubelet API自身、控制面
TCP入站10259kube-scheduler自身
TCP入站10257kube-controller-manager自身

工作节点

协议方向端口范围目的使用者
TCP入站10250kubelet API自身、控制面
TCP入站10256kube-proxy自身、负载均衡器
TCP入站30000-32767NodePort Services所有
UDP入站30000-32767NodePort Services所有
  • NodePort Service 的默认端口范围。

  所有默认端口都可以重新配置。当使用自定义的端口时,你需要打开这些端口来代替这里提到的默认端口。
  一个常见的例子是 API 服务器的端口有时会配置为 443。或者你也可以使用默认端口,把 API 服务器放到一个监听 443 端口的负载均衡器后面,并且路由所有请求到 API 服务器的默认端口。
  尽管 etcd 的端口也列举在控制面的部分,但你也可以在外部自己托管 etcd 集群或者自定义端口。

2. Kubrenetes集群中Pod的使用方式

  在Kubernetes集群中,Pod主要有两种使用方式:

  • 单容器Pod:这是最常见的用法,一个Pod只包含一个容器。在这种情况下,Pod就相当于容器的封装,Kubernetes管理的是Pod,而不是容器。
apiVersion: v1
kind: Pod
metadata:
  name: single-container-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  • 多容器Pod:一个Pod可以包含多个容器,这些容器通常有共同的资源需求,如共享网络和存储,彼此间可以通过localhost进行通信。

​常见模式​:

  • ​Sidecar 模式​:比如日志收集容器 + 主业务容器。
  • Adapter 模式​:对主容器的输出进行格式转换等。
  • ​Ambassador 模式​:代理或访问外部服务。

用途​:容器之间需要频繁通信、共享资源,或者有辅助功能(如日志、监控代理等)。

apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: app
    image: my-app:latest
  - name: sidecar
    image: log-collector:latest

3. Pause容器(基础容器)

  在每个Pod中,都会有一个特殊的容器被称为Pause容器,它的主要职责是提供Pod的Linux命名空间基础。它使得Pod内的所有容器共享网络和存储资源。Pause容器运行时,它会创建一个Linux命名空间,其他容器将共享该命名空间来进行网络通信和存储操作。

4. Pod中的共享资源

  • 网络共享:每个Pod分配一个唯一的IP地址,Pod内的所有容器共享该IP和端口。它们能够通过localhost进行通信。与外界通信时,必须使用宿主机的端口映射。
    • 每个pod 分配一个独特IP地址。
    • pod 内部所有容器共享这个IP和端口 ,能通过localhost直接通信。
    • 与外界 通信时, 必须使用宿主机的端口映射。
  • 存储共享:Pod可以指定多个共享的Volume,这些Volume可以被Pod内的所有容器访问,确保容器重启后数据不会丢失。
    • Pod可以指定多个共享的Volume,所有容器都可以访问。
    • Volume可以用来持久化存储 ,确保容器重启后数据不会丢失。

二、Pod的类型与容器分类

1. Pod的类型

  • 自主式Pod:这种Pod不具备自我修复的能力。如果它所在的节点故障,Pod会被删除,且不会自动恢复。
  • 控制器管理的Pod:Kubernetes中通常通过控制器(如Deployment、StatefulSet)来管理Pod。控制器提供副本管理、滚动升级、自动修复等功能。

2. Pod容器的分类

  • 基础容器(infrastructure container):维护整个Pod网络和存储空间,每次创建Pod时,Kubernetes会自动启动一个基础容器(如Pause容器)。
  • 初始化容器(initcontainers):在应用程序容器启动之前运行完成,用于执行一些初始化任务,如安装工具、等待依赖服务等。
    • nit 容器总是运行到成功完成为止
      启动 —> 运行 —> 结束 —> 退出 (成功 再运行下一个INit)
    • 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成启动和退出
      如果 Pod 的 Init 容器失败,k8s 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的重启策略(restartPolicy)为 Never,它不会重新启动。
  • 应用容器(Maincontainer):主要运行应用程序的容器,它们可以并行启动,与初始化容器协同工作。
#官网示例:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app.kubernetes.io/name: MyApp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
#后加
---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377
#启动
kubectl apply -f myapp.yaml
#查询
kubectl get -f myapp.yaml
#查看更多详细信息
kubectl describe -f myapp.yaml
#查询初始化容器日志
kubectl logs myapp-pod -c init-myservice
kubectl logs myapp-pod -c init-mydb
#添加service 信息并执行service.yaml 可以看到容器成功运行
kubectl get -f service.yaml

三、Pod的实现机制与镜像策略

1. Pod的实现机制

  Pod的实现依赖于Kubernetes的底层机制,包括调度、网络和存储管理等。Kubernetes通过调度器将Pod分配到合适的节点上,并通过网络插件为Pod提供网络连接,通过存储插件为Pod提供持久化存储。

2. 镜像拉取策略

  Pod中的容器需要通过指定镜像来启动,镜像拉取策略有以下几种:

  • IfNotPresent(默认):如果本地已有镜像,不会拉取新的镜像,仅在本地缺失时拉取。
  • Always:每次启动Pod时都会拉取镜像。
  • Never:不拉取镜像,仅使用本地镜像。
imagePullPolicy: Always

  如果你省略了 imagePullPolicy 字段,并且你为容器镜像指定了摘要, 那么 imagePullPolicy 会自动设置为 IfNotPresent。
  如果你省略了 imagePullPolicy 字段,并且容器镜像的标签是 :latest, imagePullPolicy 会自动设置为 Always。
  如果你省略了 imagePullPolicy 字段,并且没有指定容器镜像的标签, imagePullPolicy 会自动设置为 Always。
  如果你省略了 imagePullPolicy 字段,并且为容器镜像指定了非 :latest 的标签, imagePullPolicy 就会自动设置为 IfNotPresent。

3. Pod的重启策略

  Pod的重启策略定义了容器退出后Kubernetes如何处理容器的重启。主要有以下三种策略:

  • Always:无论容器的退出状态如何,都会重新启动。
  • OnFailure:只有容器非正常退出(即退出码非0)时,才会重启容器。
  • Never:容器退出后不会重启。
restartPolicy: Always

四、Pod的进阶实践

1. Pod资源限制

  在Kubernetes中,为了合理管理集群中的资源,容器的CPU和内存资源都可以设置请求值(requests)和限制值(limits)。这些设置确保了容器的资源分配和限制,避免资源争用和过度使用。

  • 请求(request):当容器启动时,Kubernetes会根据容器的资源请求来决定容器应该调度到哪个节点上。这个值表示容器在运行时最少需要的资源。
  • 限制(limit):容器在运行时可以使用的最大资源量。如果容器超过了这个限制,Kubernetes会采取措施来控制容器的资源使用,防止过度消耗。
spec.containers.resources.requests.cpu		#定义创建容器时预分配的CPU资源
spec.containers.resources.requests.memory		#定义创建容器时预分配的内存资源
spec.containers.resources.limits.cpu			#定义 cpu 的资源上限 
spec.containers.resources.limits.memory		#定义内存的资源上限
#官方示例
---
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

2. 健康检查:探针(Probe)

  探针是由kubelet对容器执行的定期诊断,主要包括以下三种规则:

  • livenessProbe:判断容器是否正在运行。如果探测失败,则kubelet会杀死容器,并且容器将根据restartPolicy来设置Pod状态。
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/busybox:1.27.2
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • readinessProbe:判断容器是否准备好接受请求。如果探测失败,端点控制器将从与Pod匹配的所有service的endpoints中剔除删除该Pod的IP地址。
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: readiness
  name: readiness-exec
spec:
  containers:
  - name: readiness
    image: registry.k8s.io/busybox:1.27.2
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
    readinessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

在这里插入图片描述
在这里插入图片描述

  • startupProbe:判断容器内的应用程序是否已启动,主要针对于不能确定具体启动时间的应用。
    探针支持三种检查方法:exectcpSockethttpGet。每种方法都有其特定的应用场景和优势。
    • exec(执行命令)
      概念:exec方式是通过在容器内部 ​执行一个命令,然后根据该命令的 ​退出状态码​ 来判断容器是否健康。
      场景:适用于无法通过 HTTP 或 TCP 判断健康状态的场景,比如需要执行一些自定义脚本或命令来检测应用内部状态。
      • 如果命令 ​退出码为 0,表示探测成功,容器健康。
      • 如果命令 ​退出码非 0,表示探测失败,容器不健康。
    • tcpSocket(TCP 套接字)
      概念:tcpSocket方式是尝试在容器的指定 ​IP 和端口​ 上 ​建立 TCP 连接。
      场景:适用于检测某个 ​TCP 端口是否处于监听状态,比如数据库服务、自定义 TCP 服务,但不提供 HTTP 接口的情况。
      • 如果 ​连接成功建立,则认为探测成功,容器健康。
      • 如果 ​连接失败(比如端口未监听、拒绝连接等)​,则认为探测失败,容器不健康。
    • httpGet(HTTP GET 请求)
      概念:httpGet方式是向容器内的指定 ​IP、端口、路径​ 发送一个 ​HTTP GET 请求,然后根据返回的 ​HTTP 状态码​ 判断健康状态。
      场景:适用于有 ​HTTP/HTTPS 接口​ 的 Web 服务,比如 RESTful API 服务,可以通过访问某个健康检查接口来判断服务是否正常。
      • 如果返回的 HTTP 状态码在 ​200~399 范围内,则认为探测成功,容器健康。
      • 如果返回其他状态码(如 404、500 等),则认为探测失败,容器不健康。
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: soscscs/myapp:v1
    lifecycle:   #此为关键字段
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler >> /var/log/nginx/message"]      
      preStop:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the poststop handler >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  initContainers:
  - name: init-myservice
    image: soscscs/myapp:v1
    command: ["/bin/sh", "-c", "echo 'Hello initContainers'   >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  volumes:
  - name: message-log
    hostPath:
      path: /data/volumes/nginx/log/
      type: DirectoryOrCreate

在这里插入图片描述
在这里插入图片描述

  • initialDelaySeconds:容器启动后要等待多少秒后才启动启动、存活和就绪探针。 如果定义了启动探针,则存活探针和就绪探针的延迟将在启动探针已成功之后才开始计算。 如果 periodSeconds 的值大于 initialDelaySeconds,则 initialDelaySeconds 将被忽略。默认是 0 秒,最小值是 0。
  • periodSeconds:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。 当容器未就绪时,ReadinessProbe 可能会在除配置的 periodSeconds 间隔以外的时间执行。这是为了让 Pod 更快地达到可用状态。
  • timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。
  • successThreshold:探针在失败后,被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1。
  • failureThreshold:探针连续失败了 failureThreshold 次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。 默认值为 3,最小值为 1。 对于启动探针或存活探针而言,如果至少有 failureThreshold 个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。 kubelet 遵循该容器的 terminationGracePeriodSeconds 设置。 对于失败的就绪探针,kubelet 继续运行检查失败的容器,并继续运行更多探针; 因为检查失败,kubelet 将 Pod 的 Ready 状况设置为 false。
  • terminationGracePeriodSeconds:为 kubelet 配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长。 默认值是继承 Pod 级别的 terminationGracePeriodSeconds 值(如果不设置则为 30 秒),最小值为 1。

五、Pod的状态与生命周期

1. Pod的状态

  Pod在其生命周期中可能会经历多种状态,包括:

  • Pending:Pod已经被系统认可了,但是内部的container还没有创建出来。
  • Running:Pod已经与node绑定了,而且pod中所有的container已经创建出来,至少有一个容器在运行中。
  • Succeeded:表明pod中的所有container已经成功的terminated了,而且不会再被拉起了。
  • Failed:pod中的所有容器都被terminated,至少一个container是非正常终止的。
  • Unknown:由于某些原因pod的状态获取不到,有可能是由于通信问题。
创建 Pod
    ↓
Pending (调度中 / 镜像拉取中 / 容器创建中)
    ↓
Running (容器运行中)
    ↓         ↘
Succeeded  Failed (容器退出,可能重启)
    ↓
(终止 / 被删除)

  如果 Pod 中的容器退出,Kubernetes 根据 ​restartPolicy​(如 Always、OnFailure、Never)决定是否重启容器。
  Pod 本身一般不被直接重启,而是通过控制器(如 Deployment、StatefulSet)来重建新的 Pod。

2. Container生命周期

容器的生命周期包括:

  • Waiting:启动到运行中间的一个等待状态。
  • Running:运行状态。
  • Terminated:终止状态。

六、结语

  通过对Kubernetes Pod的深入解析,我们从基础概念到进阶实践,全面了解了Pod在Kubernetes集群中的重要性和运作机制。Pod作为Kubernetes中最小的可部署单元,不仅是应用程序的载体,更是实现高可用性、弹性伸缩和自动化管理的关键。掌握Pod的相关知识和技能,对于每一位Kubernetes开发者和运维人员来说,都是至关重要的。
  在实际应用中,合理配置Pod的资源限制、健康检查和重启策略,能够有效提升应用的稳定性和可靠性。同时,理解Pod的生命周期和状态变化,有助于我们更好地监控和调试应用,确保系统的平稳运行。
  希望本文能够为你在Kubernetes的学习和实践中提供有价值的参考。随着技术的不断演进,Kubernetes和Pod的功能也在不断完善,持续关注和学习最新的技术动态,将帮助我们在云原生领域走得更远。让我们一起在Kubernetes的世界中探索更多的可能性,构建更加高效和可靠的云原生应用!

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐