K8s核心组件Pod:基础篇

在Kubernetes(简称K8s)的生态体系中,Pod是最基础也是最核心的部署单元。对于刚接触K8s的开发者来说,理解Pod的本质、意义及相关策略,是掌握容器编排技术的关键一步。本文将从Pod的基本概念出发,逐步拆解其存在价值、实现机制,并详细解析镜像拉取策略与容器重启策略,帮你构建对Pod的完整认知。

一、Pod的基本概念:容器的"最小集合"

Pod是K8s中最小的可部署、可调度的计算单元,它并非容器本身,而是一个容器组------可以包含一个或多个紧密关联的容器。这些容器共享Pod的网络命名空间(如IP地址、端口)、存储资源(如EmptyDir、PVC挂载的目录)以及运行时信息,就像被封装在同一个"逻辑主机"内协同工作。

1.1 Pod 的使用场景

**单一进程应用:**最常见的用法,一个 Pod 用于运行一个容器。

**多进程协作:**多个容器在同一个 Pod 内共享网络和存储资源,适用于紧密耦合的服务。

1.2 Pod 的类型

自主式 Pod: 这种 Pod 不具备自我修复的能力。如果它所在的节点故障,Pod 会被删除,且不会自动恢复。

**控制器管理的 Pod:**Kubernetes 中通常通过控制器(如 Deployment、StatefulSet)来管理 Pod。控制器提供副本管 理、滚动升级、自动修复等功能。

1.3 Kubrenetes集群中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 可以包含多个容器,这些容器通常有共同的资源需求,如共享网络和存储,彼此间可以 通过 l ocalhost 进行通信。

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: app
    image: my-app:latest    mysql
  - name: sidecar   
    image: log-collector:latestfilbeat

1.4 Pod 中的共享资源

网络共享: 每个 Pod 分配一个唯一的 IP 地址,Pod 内的所有容器共享该 IP 和端口。它们能够通过 localhost 进行通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的 端口映射)

① 每个pod 分配一个独特IP地址

② pod 内部所有容器共享这个IP和端口 ,能通过 localhost直接通信

③ 与外界 通信时, 必须使用宿主机的端口映射

存储共享: Pod 可以指定多个共享的 Volume,这些 Volume 可以被 Pod 内的所有容器访问,确保容器重启 后数据不会丢失。

① Pod可以指定多个共享的Volume,所有容器都可以访问

② Volume可以用来持久化存储 ,确保容器重启后数据不会丢失

二、Pod的存在意义:为何不直接调度容器?

很多人会疑惑:既然Pod的核心是容器,为何K8s不直接调度容器,而是引入Pod这一层抽象?其实,Pod的设计是为了解决"紧密关联容器的协同问题",其存在意义主要体现在三个方面:

  1. 解决"紧耦合容器"的协同部署问题:有些应用组件必须紧密配合才能工作,例如,一个Web应用容器需要与一个专用的日志收集容器共享日志目录------Web容器写入日志,日志容器实时收集日志并上传。如果直接调度两个独立容器,无法保证它们被部署到同一节点,且难以实现目录共享。而Pod将它们封装在一起,确保协同部署和资源共享。

  2. 简化容器间的通信机制:同一Pod内的容器共享网络命名空间,容器之间可以通过localhost直接通信,无需通过网络路由。例如,主容器运行的应用监听8080端口,辅助容器可以直接通过http://localhost:8080访问该应用,通信延迟极低,且无需配置复杂的网络策略。

  3. 统一管理资源与生命周期:Pod作为一个整体,能够统一申请和管理CPU、内存等资源,避免单个容器资源分配混乱。同时,Pod的生命周期(如启动、停止、重启)会同步影响其内部所有容器,确保容器间的生命周期协同------例如,当主容器异常退出时,辅助容器也会随之终止,避免资源泄漏。

三、Pod的实现机制:基于Namespace和Cgroups的封装

Pod的本质是K8s对Linux容器技术的封装和抽象,其实现依赖于Linux的两大核心技术:Namespace(命名空间)和Cgroups(控制组)。K8s通过这两项技术,为Pod内的容器构建了"隔离且共享"的运行环境。

具体实现逻辑如下:

  1. 创建"基础设施容器"(Infra Container):当K8s创建一个Pod时,会首先创建一个特殊的基础设施容器(通常是pause容器)。这个容器体积极小(仅几MB),不执行任何业务逻辑,其核心作用是"占坑"并创建Pod的网络命名空间和挂载点。

  2. 业务容器加入Pod的命名空间:基础设施容器创建完成后,Pod内的主容器和辅助容器会以"加入现有命名空间"的方式启动------它们不再创建自己的网络命名空间和挂载点,而是直接复用基础设施容器的资源。这就使得所有容器共享同一个IP地址、端口范围和存储目录,实现了Pod内的资源共享。

  3. 通过Cgroups实现资源限制:K8s会为Pod整体分配CPU、内存等资源,并通过Cgroups技术将资源限制应用到Pod层面。Pod内的每个容器可以在Pod的资源配额内,进一步设置自身的资源限制(如request和limit),确保容器间的资源隔离,避免单个容器过度占用资源影响其他容器。

简单来说,Pod的实现逻辑可以概括为:"用基础设施容器构建共享环境,用业务容器执行核心功能,用Namespace实现资源共享,用Cgroups实现资源隔离"。

四、Pod容器的分类

4.1 基础容器(infrastructure container)

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

复制代码
维护整个 Pod 网络和存储空间
node 节点中操作
启动一个Pod时,k8s会自动启动一个基础容器
cat /opt/kubernetes/cfg/kubelet
......
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"

每次创建 Pod 时候就会创建,运行的每一个Pod都有一个 pause-amd64 的基础容器自动会运行,对于用户
是透明的
docker ps -a
registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0    

4.2初始化容器(initcontainers)

4.2.1 Init容器启动过程

Init容器必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供 了一种简单的阻塞或延迟应用容器的启动的方法。

Init 容器与普通的容器非常像,除了以下两点:

**1、**Init 容器总是运行到成功完成为止

启动 --》运行 --》 结束 --》 退出 成功 再运行下一个init

**2、**每个 Init 容器都必须在下一个 Init 容器启动之前成功完成启动和退出 如果 Pod 的 Init 容器失败,k8s 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的重启策略(restartPolicy)为 Never,它不会重新启动。

4.2.2 Init 的容器作用

因为init容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:

1、Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。例如,没有必要仅 为了在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具而去FROM 一个镜像来生成一 个新的镜像。

独立使用的工具

2、Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。

3、应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。

4、Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权 限,而应用容器不能够访问。

5、由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用 容器的启动, 直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。

4.3 应用容器(Maincontainer)

复制代码
官网示例:
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: 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; do echo waiting for 
myservice; sleep 2; done;']
  - name: init-mydb 
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 
2; done;']

这个例子是定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动, 第二个等待 
mydb 启动。 一旦这两个 Init容器都启动完成,Pod 将启动 spec 中的应用容器。

先去查看  找不到错误信息 
kubectl describe pod myapp-pod

使用logs查看  指定好  init r容器名称
kubectl logs myapp-pod -c init-myservice

vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

kubectl create -f myservice.yaml
kubectl get svc
kubectl get pods -n kube-system
kubectl get pods

vim mydb.yaml
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377

kubectl create -f mydb.yaml

kubectl get pods

4.4 pod init初始化

在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容 器启动之前成功退出。

如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行 重试。然而,如果Pod的restartPolicy设置为Always,Init容器失败时会使用RestartPolicy策略。

在所有的Init容器没有成功之前,Pod将不会变成Ready状态。Init容器的端口将不会在Service中进 行聚集。正在初始化中的Pod处于Pending状态,但应该会将Initializing状态设置为true。

如果Pod重启,所有Init容器必须重新执行。

对Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效。更改Init容器的image 字段,等价于重启该Pod。

Init容器具有应用容器的所有字段。除了readinessProbe,因为Init容器无法定义不同于完成 (completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行。

在Pod中的每个app和Init容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出 错误

五、配置的核心部分

5.1 Pod镜像拉取策略

Pod内的容器运行依赖于镜像,镜像拉取策略(ImagePullPolicy)定义了K8s在创建容器时,从镜像仓库拉取镜像的规则。K8s支持三种镜像拉取策略,开发者需根据实际场景选择合适的策略:

  1. Always(默认,针对latest标签):每次创建容器时,都会强制从镜像仓库拉取最新的镜像。这种策略的优势是能确保使用的镜像始终是最新版本,适合开发环境或需要频繁更新镜像的场景。但缺点是每次启动都会触发拉取操作,增加启动时间,且依赖镜像仓库的可用性。

  2. IfNotPresent:只有当节点本地不存在该镜像时,才从镜像仓库拉取。如果本地已存在该镜像(无论版本是否最新),则直接使用本地镜像。这种策略平衡了更新需求和启动效率,适合生产环境中镜像版本相对稳定的场景,能减少网络开销和启动时间。

  3. Never:从不从镜像仓库拉取镜像,仅使用节点本地已存在的镜像。如果本地没有该镜像,则创建容器失败。这种策略适合离线环境(无法访问外部镜像仓库)或需要严格控制镜像版本的场景,能避免意外拉取未知版本的镜像导致应用异常。

注意:当镜像标签为"latest"时,K8s默认使用Always策略;如果镜像指定了具体版本号(如nginx:1.24),则默认使用IfNotPresent策略。

5.2 pod重启策略

Pod重启策略(RestartPolicy)定义了当Pod内的容器异常退出(非正常终止)时,K8s是否以及如何重启该容器。重启策略作用于Pod内的所有容器,常见的异常场景包括:容器进程崩溃、资源耗尽被OOM杀死、健康检查失败等。K8s支持三种重启策略:

  1. Always(默认):只要容器异常退出,就会自动重启容器。这种策略适合核心业务容器,确保应用的高可用性------例如,运行数据库、Web服务的容器,需要在异常时快速恢复。需要注意的是,K8s会通过"退避策略"控制重启频率(重启间隔逐渐增加,最大间隔为5分钟),避免无限循环重启。

  2. OnFailure:仅当容器以非零退出码(表示异常退出)时,才重启容器;如果容器以零退出码正常终止,则不重启。这种策略适合一次性任务或批处理任务------例如,数据迁移脚本容器,正常执行完成后无需重启,但若执行失败则需要重试。

  3. Never:无论容器是正常退出还是异常退出,都不会重启容器。这种策略适合临时测试容器或不需要自动恢复的场景------例如,临时调试用的容器,退出后无需继续运行。

    restartPolicy: Always

#注意:K8S 中不支持重启 Pod 资源,只有删除重建

复制代码
kubectl edit deployment nginx-deployment
......
restartPolicy: Always

案例:

复制代码
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
  - name: busybox
    image: busybox
    args:- /bin/sh
    - -c
    - sleep 30; exit 3

kubectl apply -f pod3.yaml
//查看Pod状态,等容器启动后30秒后执行exit退出进程进入error状态,就会重启次数加1
kubectl get pods

NAME                 READY              STATUS         RESTARTS      AGE
foo                   1/1              Running            1          50s


vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
  - name: busybox
    image: busybox
    args:- /bin/sh
    - -c
    - sleep 30; exit 3
  restartPolicy: Never

#注意:跟container同一个级别
kubectl apply -f pod3.yaml
//容器进入error状态不会进行重启
kubectl get pods -w

总结:Pod是K8s生态的"基石"

Pod作为K8s的最小部署单元,其核心价值在于解决了紧密关联容器的协同部署、通信和资源共享问题。通过Namespace和Cgroups技术,Pod实现了"共享环境+隔离资源"的平衡;而镜像拉取策略和容器重启策略,则为Pod的稳定运行提供了保障。

理解Pod的本质和相关机制,是后续学习Deployment、StatefulSet等更高层控制器的基础。在实际应用中,开发者需根据业务场景合理设计Pod的容器组合、选择合适的镜像拉取策略和重启策略,才能充分发挥K8s的编排优势。

相关推荐
鲨莎分不晴9 小时前
Docker 网络深度解析:打破容器的“孤岛效应”
网络·docker·容器
nix.gnehc10 小时前
Serverless
云原生·serverless
拔剑纵狂歌10 小时前
helm-cli安装资源时序报错问题问题
后端·docker·云原生·容器·golang·kubernetes·腾讯云
techzhi10 小时前
Docker & Docker Compose 安装方案
docker·容器·eureka
weixin_4481199410 小时前
如何装docker
java·云原生·eureka
喵叔哟10 小时前
19.服务集成与通信
后端·docker·容器·服务发现
没有bug.的程序员11 小时前
Service Mesh 下的流量治理:灰度、熔断、限流的深度实践与代价剖析
网络·云原生·限流·熔断·灰度发布·流量治理·servicemesh
Ice星空11 小时前
Docker 镜像创建和管理以及 buildx 交叉编译
运维·docker·容器
Cyber4K11 小时前
【Kubernetes专项】Docker 容器部署及基本用法
运维·docker·云原生·容器