加粗样式## 一、环境准备

# 创建命名空间
[root@master30 ~ 19:13:38]# kubectl create ns pods

# 切换当前上下文到该命名空间
[root@master30 ~ 19:17:15]# kubectl config set-context --current --namespace pods


二、Pod 介绍

Pod 代表一个部署单元(deployment unit),即 Kubernetes 中一个应用程序的单个实例。

Kubernetes 通过定义 Pod 资源,在 Pod 里面运行容器。容器需要指定镜像,用来运行具体的服务。

核心概念

Pod 代表集群上正在运行的一个进程。一个 Pod 可以封装一个容器,也可以封装多个容器。

Pod 里的容器共享存储、网络等资源。可以把 Pod 看作虚拟机,每个容器相当于运行在虚拟机里的进程

类比理解

可以把 Pod 看成是一个 “豌豆荚” ,里面有很多 “豆子”(容器)。一个豌豆荚里的豆子吸收着共同的营养成分、肥料、水分等。Pod 和容器的关系也是一样,Pod 里面的容器共享 Pod 的网络、存储等。

单容器 Pod vs 多容器 Pod

类型 说明
单容器 Pod 将 Pod 看作是单个容器的包装器,Kubernetes 管理 Pod 而不是直接管理容器
多容器 Pod Pod 可以封装一个由多个共存容器组成的应用程序。Pod 中的容器会自动在集群中的同一物理机或虚拟机上运行

多容器 Pod 的特性

  • 共享资源和依赖项
  • 彼此通信
  • 协调何时以及如何终止
  • 将容器、网络资源和存储资源作为一个单一的可管理实体包装在一起

网络与存储共享

  • 每个 Pod 分配唯一的 IP 地址
  • Pod 中容器共享 netns,包括 IP 地址和端口
  • 多个容器之间使用 localhost 通信
  • 当 Pod 中容器与其他 Pod 通信时,使用共享的网络资源
  • Pod 可以使用多个 volume,Pod 中所有容器都可以访问这些卷

三、Pod 基本管理

1. 创建 Pod

方式一:空运行生成 YAML 文件
[root@master30 ~ 19:17:22]# kubectl run web \
  --image=hub.laoma.cloud/library/nginx \
  --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: web
  name: web
spec:
  containers:
  - image: hub.laoma.cloud/library/nginx
    name: web
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

方式二:直接创建 Pod

[root@master30 ~ 19:17:51]# kubectl run web --image=hub.laoma.cloud/library/nginx
pod/web created
查看 Pod 状态
[root@master30 ~ 19:18:30]# kubectl get pod
NAME   READY   STATUS              RESTARTS   AGE
web    0/1     ContainerCreating   0          36s

[root@master30 ~ 19:18:50]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          51s

# 查看详细信息(IP、节点等)
[root@master30 ~ 19:18:56]#  kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP               NODE
web    1/1     Running   0          67s   10.224.51.131    worker31.laoma.cloud
查看容器运行时
[root@master30 ~ 19:19:01]# ssh root@worker31
[root@worker31 ~ 19:19:40]# nerdctl ps --namespace k8s.io | grep web
[root@worker31 ~ 19:20:49]# nerdctl images --namespace k8s.io | grep nginx

2. 查看 Pod

# 以 YAML 格式查看 Pod
[root@master30 ~ 19:21:42]# kubectl get pod web -o yaml

# 查看 Pod 详细信息
[root@master30 ~ 19:21:44]# kubectl describe pod web

# 查看 Pod 标准输出(-f 动态查看)
[root@master30 ~ 19:21:59]# kubectl logs -f web

3. 编辑 Pod

[root@master30 ~ 19:22:14]# kubectl edit pod web

⚠️ 注意:并不是所有属性都可以编辑,例如 Pod 名称。如果非要编辑特定属性,可以先删除 Pod,然后修改 Pod 的 YAML 文件,重新创建。

4. Pod 中执行命令

# 查看主机名
[root@master30 ~ 19:23:15]# kubectl exec web -- hostname
web

# 查看当前目录
[root@master30 ~ 19:23:17]# kubectl exec web -- pwd
/

# 交互式执行命令
[root@master30 ~ 19:23:22]# kubectl exec -it web -- bash -c 'echo Hello World > htdocs/index.html'

# 查看用户信息
[root@master30 ~ 19:23:28]# kubectl exec web -- id
uid=0(root) gid=0(root) groups=0(root)

5. 拷贝文件到 Pod

[root@master30 ~ 19:23:33]# kubectl cp /etc/hosts web:/new-hosts
[root@master30 ~ 19:24:06]# kubectl exec web -- ls /new-hosts
/new-hosts

6. 删除 Pod

[root@master30 ~ 19:24:32]# kubectl delete pod web
pod "web" deleted

优雅删除时间:默认 terminationGracePeriodSeconds: 30

bash

[root@master30 ~ 19:28:47]# kubectl get pod web -o yaml | grep 'terminationGracePeriodSeconds'
terminationGracePeriodSeconds: 30

7. 使用 YAML 文件创建 Pod

创建 web.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
spec:
  containers:
  - image: hub.laoma.cloud/library/nginx
    name: web
# 方式一
[root@master30 ~ 19:28:49]# kubectl create -f web.yaml

# 方式二
[root@master30 ~]# kubectl apply -f web.yaml

四、综合实验:构建 WordPress

实验目标

  • 创建 Pod wordpress-db(MySQL 数据库)
  • 创建 Pod wordpress-app(WordPress 博客)

步骤

1. 创建数据库 Pod
[root@master30 ~ 19:29:08]#  kubectl run wordpress-db \
  --image=mysql \
  --image-pull-policy IfNotPresent \
  --env MYSQL_ROOT_PASSWORD=123
pod/wordpress-db created
2. 创建 WordPress Pod
[root@master30 ~ 19:29:33]#  kubectl run wordpress-app \
  --image=wordpress \
  --image-pull-policy IfNotPresent
pod/wordpress-app created
3. 端口转发(实现集群外访问)

bash

[root@master30 ~ 19:29:47]#  kubectl port-forward pod/wordpress-app --address 10.1.8.30 8080:80
# ⚠️ 该命令窗口不要关闭
4. 查看 Pod IP

[root@master30 ~ 19:29:57]# kubectl get pods -o wide | awk '{print $1" "$6}'
NAME               IP
wordpress-app      10.224.123.132
wordpress-db       10.224.19.5
5. 创建数据库

[root@master30 ~ 19:30:16]# mysql -uroot -p123 -h 10.224.19.5

mysql> create database wordpress;
mysql> create user wordpress identified by '123';
mysql> grant all privileges on wordpress.* to wordpress;
mysql> flush privileges;
mysql> exit
6. 访问 Web 页面

浏览器访问 http://10.1.8.30:8080,配置站点。


五、多容器 Pod

示例文件:pod-blog.yaml

apiVersion: v1
kind: Pod
metadata:
  name: bbs
  labels:
    run: bbs
spec:
  containers:
  - image: hub.laoma.cloud/library/mysql:latest
    imagePullPolicy: IfNotPresent
    name: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "123"
    - name: MYSQL_USER
      value: tom
    - name: MYSQL_PASSWORD
      value: "123"
    - name: MYSQL_DATABASE
      value: bbs
    ports:
    - containerPort: 3306
      name: mysql
      protocol: TCP

  - image: hub.laoma.cloud/library/wordpress:latest
    imagePullPolicy: IfNotPresent
    name: wordpress
    env:
    - name: WORDPRESS_DB_USER
      value: tom
    - name: WORDPRESS_DB_PASSWORD
      value: "123"
    - name: WORDPRESS_DB_NAME
      value: bbs
    - name: WORDPRESS_DB_HOST
      value: 127.0.0.1
    ports:
    - containerPort: 80
      name: wordpress
      protocol: TCP
    hostPort: 80

创建多容器 Pod

[root@master30 ~ 19:30:50]# kubectl apply -f pod-blog.yaml

查看 Pod

[root@master30 ~ 19:31:25]#  kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP               NODE
bbs    2/2     Running   0          10m   10.224.225.68    worker32.caojie.cloud

多容器 Pod 中执行命令(通过 -c 指定容器)

# 在 wordpress 容器中执行命令
[root@master30 ~ 19:31:41]# kubectl exec bbs -c wordpress -- hostname
bbs

# 拷贝文件到指定容器
[root@master30 ~ 19:32:10]# kubectl cp /etc/hosts bbs:/new-hosts -c wordpress

[root@master30 ~ 19:32:14]# kubectl exec bbs -c wordpress -- ls /new-hosts
/new-hosts

# 进入 MySQL 容器
[root@master30 ~ 19:32:20]#  kubectl exec -it bbs -c mysql -- mysql -utom -p123

访问

使用所在宿主机的 80 端口访问:http://10.1.8.32/


六、Pod 关键属性

查看 Pod 资源结构

[root@master30 ~ 19:32:25]# kubectl explain pod | grep '^ [a-zA-Z]'
apiVersion
kind
metadata
spec
status

1. pod.metadata

[root@master30 ~ 19:33:12]# kubectl explain pod.metadata | grep '^ [a-zA-Z]'
annotations
clusterName
creationTimestamp
deletionGracePeriodSeconds
deletionTimestamp
finalizers <[]string>
generateName
generation
labels
managedFields <[]Object>
name
namespace
ownerReferences <[]Object>
resourceVersion
selfLink
uid

重点关注labelsnamenamespacedeletionGracePeriodSeconds

2. pod.spec

[root@master30 ~ 19:33:30]#  kubectl explain pod.spec | grep '^ [a-zA-Z]'
activeDeadlineSeconds
affinity
automountServiceAccountToken
containers <[]Object> -required-
dnsConfig
dnsPolicy
enableServiceLinks
ephemeralContainers <[]Object>
hostAliases <[]Object>
hostIPC
hostNetwork
hostPID
hostname
imagePullSecrets <[]Object>
initContainers <[]Object>
nodeName
nodeSelector
overhead
preemptionPolicy
priority
priorityClassName
readinessGates <[]Object>
restartPolicy
runtimeClassName
schedulerName
securityContext
serviceAccount
serviceAccountName
setHostnameAsFQDN
shareProcessNamespace
subdomain
terminationGracePeriodSeconds
tolerations <[]Object>
topologySpreadConstraints <[]Object>
volumes <[]Object>

重点关注containersnodeNamevolumes

3. pod.spec.containers

[root@master30 ~ 19:33:54]# kubectl explain pod.spec.containers | grep '^ [a-zA-Z]'
args <[]string>
command <[]string>
env <[]Object>
envFrom <[]Object>
image
imagePullPolicy
lifecycle
livenessProbe
name -required-
ports <[]Object>
readinessProbe
resources
securityContext
startupProbe
stdin
stdinOnce
terminationMessagePath
terminationMessagePolicy
tty
volumeDevices <[]Object>
volumeMounts <[]Object>
workingDir

重点关注commandenvimageimagePullPolicyvolumeMounts

4. imagePullPolicy

策略 说明
Always 总是从仓库下载镜像
Never 只使用本地镜像,不下载
IfNotPresent 优先使用本地镜像,如果没有才从仓库下载镜像

七、Pod 生命周期与状态

生命周期

  • Pod 的生命周期取决于 Pod 中所有容器的生命周期
  • 容器的生命周期取决于容器中进程的生命周期

常见 Pod 状态

状态 说明
ContainerCreating 正在创建
Running 正在运行
Completed 运行完成
Error / RunContainerError 运行错误
CrashLoopBackOff 反复重启(崩溃循环)
ErrImagePull 获取镜像错误
ImagePullBackOff 重新获取镜像
Terminating 正在终止(删除中)

实验1:单容器 Pod 状态验证

监控命令

watch -n 1 kubectl get pod

示例1 - 正常完成

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']

状态变化ContainerCreatingRunningCompleted

示例2 - 命令错误

command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

状态变化ContainerCreatingError

实验2:多容器 Pod 状态验证

示例1 - 两个容器都正常

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Never
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']

状态变化ContainerCreatingRunningNotReady(其中一个先完成)→ Completed(两个都完成)

示例2 - 一个容器错误

# busybox1 命令错误,busybox2 正常

状态变化ContainerCreatingError


八、重启策略(restartPolicy)

restartPolicy 针对 Pod 中所有容器生效。

策略 说明
Always 除了 Running 状态,其他状态总是重启(默认值)
OnFailure 失败了才重启
Never 从不重启

⚠️ 注意:更改 Pod 重启策略,直接 apply 会报错,需要删除重建。

实验1:单容器重启策略验证

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Always    # 可替换为 OnFailure / Never
  containers:
  - name: busybox
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']

验证 OnFailure

restartPolicy: OnFailure
command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

验证 Never

restartPolicy: Never
command: ['sh', '-c', 'echoxxx Hello Kubernetes! && sleep 5']

实验2:多容器重启策略验证

结论:只要有一个容器满足重启策略条件,就会重启整个 Pod。

示例1 - 所有容器正常

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  restartPolicy: Always    # 可替换为 OnFailure / Never
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 5']

使用 Always 重启策略时,当容器 busybox1 状态为 Completed 时,容器 busybox2 还未创建成功,此时会根据重启策略重启 Pod。使用 OnFailure/Never 则不会出现这种情况。

示例2 - 一个容器错误

# busybox1 正常,busybox2 命令错误
  • AlwaysOnFailure:总是会重启 Pod
  • Never:不会重启 Pod

九、Init Containers(初始化容器)

基本概念

一个 Pod 可以有多个运行应用程序的容器,也可以有一个或多个 initContainers

  • initContainers 中容器状态必须是 Completecontainers 容器才能运行
  • 如果 Pod 的 initContainers 失败,Kubernetes 根据 restartPolicy 重启 Pod,直到 initContainers 状态为 Complete
  • 如果有多个 initContainers,按顺序创建和执行
  • 所有 init 全部成功执行完成后,才开始执行 Pod 中常规容器

使用场景

  1. 等待某个服务创建成功

    for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
    
  2. 等待固定时间后再运行 app 容器

    sleep 60
    
  3. Clone git repository into a volume

示例1:等待 Service 就绪

创建 Service

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

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

创建 Pod

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  initContainers:
  - name: init-myservice
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done; sleep 3;']
  - name: init-mydb
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done; sleep 3;']
  containers:
  - name: myapp-container
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']

操作顺序:先创建 2 个 Service,再创建 Pod,观察 Pod 状态变化。

示例2:Init 容器写入文件

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  volumes:
  - name: workdir
    emptyDir: {}
  containers:
  - name: myapp-container
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  initContainers:
  - name: init-poda
    image: hub.laoma.cloud/library/busybox
    command: ['sh', '-c', 'touch /work-dir/aa.txt && sleep 10']
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"

查看文件

[root@worker31 ~ 19:06:15]# kubectl exec myapp-pod -c myapp-container -- ls /xx

状态变化Init:0/1PodInitializingRunning

测试 Init 容器失败

command: ['sh', '-c', 'touchxx /work-dir/aa.txt']

状态变化Init:0/1Init:ErrorInit:CrashLoopBackOff(循环)


十、静态 Pod(Static Pod)

问题引入

正常情况下,Pod 由 Master 节点统一管理。那么 Master 上的 kube-apiserver、kube-scheduler、kube-controller-manager 等 Pod 又是由谁来管理的呢?

答案:kubelet 服务。

Master 节点上组件以 静态 Pod 方式运行,由本地 kubelet 进行管理。

静态 Pod 的特点

  • 不能通过 API Server 进行管理
  • 无法与 ReplicationController、Deployment 或 DaemonSet 进行关联
  • kubelet 无法对其健康检查

kubelet 配置分析

查看 kubelet 服务状态:

[root@worker31 ~ 19:36:50]# systemctl status kubelet.service

查看 kubelet 启动参数:

[root@worker31 ~ 19:37:37]#  cat /usr/lib/systemd/system/kubelet.service

查看 Drop-In 配置文件:

[root@master30 ~ 19:37:43]# cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf

staticPodPath 配置

[root@master30 ~ 19:38:26]]# grep staticPodPath /var/lib/kubelet/config.yaml
staticPodPath: /etc/kubernetes/manifests

kubelet 会定期扫描该目录中的 Pod 文件,并根据目录中文件变动创建和删除 Pod。

查看该目录下的静态 Pod 文件:

[root@master30 ~ 19:39:28]# ls -1 /etc/kubernetes/manifests
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml

⚠️ 注意:不要修改 staticPodPath 参数配置,否则需要将集群组件 4 个 YAML 文件也要复制过去。

也可以通过参数 --pod-manifest-path 设置,该目录下所有 Pod 也是静态 Pod:

[root@master30 ~ 19:39:46]# kubelet --help | grep pod-manifest-path
--pod-manifest-path string

十一、思考题

1. Kubernetes 中 Pod 和 Container 的区别?

容器:运行时概念,真正跑应用的进程环境。

Pod:Kubernetes 独有的概念,是 K8s 中最小调度、管理、自愈单元,是容器的 “外壳 + 运行环境”

特性 容器 Pod
K8s 最小调度单位 ❌ 不是 ✅ 是
独立 IP ✅ 有 ✅ 有
独立存储 ✅ 有 ✅ 有
多容器支持 ❌ 不支持 ✅ 天然支持
网络/存储共享 ❌ 不能 ✅ 内部容器可共享
生命周期管理 ❌ 弱 ✅ 完整(重启、自愈)
属于谁 运行时(Docker/containerd) Kubernetes

2. Kubernetes 为什么直接管理 Pod 而不是容器?

原因一:容器太"原子",不适合直接调度

K8s 需要一个能直接被调度、能独立运行、有完整身份的对象——Pod。

  • 容器:只是一个进程/运行环境(Docker/containerd)
  • Pod:是容器的封装 + 网络/存储/配置/生命周期的统一抽象
  • K8s 调度、扩缩容、自愈、服务发现、监控……全都以 Pod 为单位

原因二:Pod 支持"多容器协同"(最关键设计)

很多场景必须多个容器一起跑、共享资源:

  • 业务容器 + Sidecar(日志、监控、代理)
  • 业务容器 + InitContainer(初始化)
  • 业务容器 + 网络/安全代理容器

它们需要:

  • 共享 Network Namespace(同一个 IP、端口空间)
  • 共享 Volume
  • 一起调度到同一台机器

Pod 提供统一的生命周期与自愈。

原因三:解耦底层容器运行时

Pod 屏蔽了底层实现:

  • Docker
  • containerd
  • cri-o
  • 其他 CRI 运行时

K8s 只跟 Pod/CRI 打交道,不绑定某一种容器技术。

3. 解释 Pod 中 Pause 容器的作用

在 Kubernetes 里,每个 Pod 都会自动创建一个 pause 容器(也叫 infra 容器),它是 Pod 里第一个启动、最后退出的容器。

pause 容器就是为了 “占坑” ,把 Pod 的网络和命名空间先 hold 住。

三大核心作用

① 创建并持有 Pod 的 Linux Namespace

Pod 里所有容器要共享:

  • Network namespace(同一个 IP、端口)
  • PID namespace(可选)
  • IPC namespace

这些共享空间必须由一个 “永远不死” 的容器来持有,否则共享空间会消失。这个容器就是 pause。

② 让 Pod 生命周期独立于业务容器

  • 业务容器挂了 → 重启
  • pause 容器不挂 → Pod 就不会消失
  • 网络、IP、存储挂载都能保持不变

如果没有 pause:业务容器一退出,整个 Pod 的网络就没了,重启也没用。

③ 实现多容器共享网络

nginx、业务容器、sidecar 都加入 pause 的 network namespace:

  • 共享同一个 IP
  • 可以用 127.0.0.1 互相访问
  • 端口不能冲突
形象比喻
  • pause = 房东
  • Pod = 房子
  • 业务容器 = 租客

房东(pause)先占好房子(网络/命名空间),租客(业务容器)才能住进来。租客换了一波又一波,房子一直都在。

Pod 内部结构
Pod
├── pause 容器(infra)—— 永远第一个启动
│   持有:网络命名空间、IP、IPC
└── 业务容器 1、2、3... 都加入 pause 的命名空间
精炼总结

pause 容器 = Pod 的基石

  • 只负责 holding namespace
  • 保证 Pod 网络、IP、生命周期稳定

十二、环境清理

[root@master30 ~]# kubectl delete ns pods
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐