OFFSET偏移
← 文章目录OFFSET / FIELD NOTESNO. 122

Pod 体系与 Kubernetes 清单

组织共享网络的本地容器,并检查 Kubernetes 清单导入导出的范围。

所在专题Podman 容器工作流 ↗
约 11 分钟阅读开始阅读

Podman 的 Pod 让本地容器共享指定命名空间,并为 Kubernetes 清单工作流提供一种组织方式。


什么是 Pod?(零基础版)#

从一个场景理解

想象你部署一个网站,需要三个东西:Web 服务器 + 后台 API + 数据库。

Docker 方式(各自独立):

容器 A (nginx)     独立网络地址(示意)
容器 B (api)       独立网络地址(示意)
容器 C (postgres)  独立网络地址(示意)

独立网络命名空间常通过桥接网络和容器 DNS 通信;实际开销取决于网络实现和工作负载,不能据此认定单机数据库必须与 API 放进同一 Pod。

Pod 方式(住同一个"房间"):

┌──────── Pod 共享网络 ────────┐
│  localhost                  │
│  容器 A (nginx)              │  ← 通过 localhost:3000 访问 API
│  容器 B (api)                │  ← 通过 localhost:5432 访问 DB
│  容器 C (postgres)           │
└──────────────────────────────┘

Pod 的核心特性:同一个 Pod 内的容器共享网络——它们可以用 localhost 互相通信,不需要暴露端口到外部。

Pod 和 Kubernetes 的关系

Kubernetes 中,Pod 是最小的调度单位——你永远无法直接运行一个容器,你必须把它放在一个 Pod 里。Podman 把 Pod 概念带到了本地开发环境,让你在单机上也能享受相同的组织方式。


Pod 基本操作#

创建一个空 Pod

# 创建 Pod 并暴露端口
podman pod create --name mypod -p 127.0.0.1:8080:80
#                └───────┘ └────────┘
#               Pod 名称    把 Pod 的 80 端口映射到宿主机 8080

# 查看所有 Pod
podman pod ps
# 输出类似:
# POD ID     NAME   STATUS  CREATED  INFRA ID   # OF CONTAINERS
# abc123...  mypod  Running 2s ago   def456...  1
# 注意:刚创建的 Pod 已经有 1 个容器——这就是 infra 容器

Infra 容器是什么?

默认创建 Pod 时,Podman 创建一个 infra 容器。它的作用类似 Pod 的"房东"——持有共享的网络、IPC 等名字空间。其他容器加入 Pod 时,"住进"这个房东的房子里。

# 查看 infra 容器(podman pod ps 中 INFRA ID 对应的容器)
podman ps --pod
# infra 容器名字类似 abc123-infra,状态为 Running

# 当前默认由 Podman 创建本地轻量 infra 镜像;可用 --infra-image 覆盖

向 Pod 中添加容器

# 创建 Pod
podman pod create --name webapp -p 127.0.0.1:8080:80

# 向 Pod 中添加 nginx 容器
podman run -d --pod webapp --name web docker.io/library/nginx:alpine
#              └───────┘ └──────┘
#           加入 webapp Pod  容器名

# 添加 API 容器(同一 Pod 内可用 localhost 访问 nginx)
podman run -d --pod webapp --name api myapi:latest

# 添加数据库容器
podman run -d --pod webapp --name db \
  --env-file /path/to/private/postgres.env \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16-alpine

关键:现在 api 容器可以通过 localhost:80 访问 web,web 可以通过 localhost:3000 访问 api,都在共享网络命名空间;服务需监听相应端口,端口不能冲突。

管理 Pod

# 查看 Pod 内所有容器
podman pod ps --ctr-names

# 查看 Pod 详情
podman pod inspect webapp

# 停止整个 Pod(停掉里面所有容器)
podman pod stop webapp

# 启动整个 Pod
podman pod start webapp

# 重启整个 Pod
podman pod restart webapp

# 暂停/恢复 Pod
podman pod pause webapp
podman pod unpause webapp

# 删除 Pod(和里面所有容器)
podman pod rm -f webapp

Podman ↔ Kubernetes 双向转换#

这是 Podman 独特的杀手能力。

从 Pod 生成 Kubernetes YAML

# 生成 K8s YAML
podman kube generate webapp > webapp.yaml

# 产出后检查镜像、环境变量、卷、hostPath、标签和网络字段
# 迁移集群前调整清单;经授权部署时才运行 kubectl apply -f webapp.yaml

生成的 YAML 示例(简化):

apiVersion: v1
kind: Pod
metadata:
  name: webapp
spec:
  containers:
    - name: web
      image: docker.io/library/nginx:alpine
      ports:
        - containerPort: 80
    - name: db
      image: docker.io/library/postgres:16-alpine
      env:
        - name: POSTGRES_PASSWORD
          value: NON_SECRET_EXAMPLE_REPLACE_BEFORE_USE

从 Kubernetes YAML 运行本地容器

# 手头有个 K8s YAML,想本地跑起来看看
podman kube play webapp.yaml

# 本地解释支持的 Kubernetes 对象/字段,不是完整 Kubernetes 控制平面
# Podman 会解析 YAML,在本地创建对应的 Pod 和容器

生成 systemd 服务文件

# 为当前运行的 Pod 生成 systemd unit file
podman generate systemd --files --name webapp --pod-prefix myapp
# --files 输出到当前目录;--name 使用资源名;webapp 是位置参数;--pod-prefix 控制前缀

# 但官方现在更推荐用 Quadlet(见下一篇)

实战示例:WordPress + MySQL in a Pod#

# 1. 创建 Pod
podman pod create --name wordpress -p 127.0.0.1:8080:80

# 2. 启动 MariaDB(WordPress 的数据库)
podman run -d \
  --pod wordpress \
  --name wp-db \
  --env-file /path/to/private/mariadb.env \
  -e MYSQL_DATABASE=wordpress \
  -e MYSQL_USER=wpuser \
  -v wp-db:/var/lib/mysql \
  docker.io/library/mariadb:11

# 3. 启动 WordPress
podman run -d \
  --pod wordpress \
  --name wp-app \
  -e WORDPRESS_DB_HOST=127.0.0.1 \
  -e WORDPRESS_DB_USER=wpuser \
  --env-file /path/to/private/wordpress.env \
  -e WORDPRESS_DB_NAME=wordpress \
  docker.io/library/wordpress:latest

# 4. 打开 http://localhost:8080,WordPress 安装界面就绪

# 5. 生成 K8s YAML 存档
podman kube generate wordpress > wordpress-k8s.yaml

对比 Docker Compose:Compose 的 depends_on 控制依赖,不决定寻址方式;同一网络中通常通过服务名解析。Pod 可用 localhost,但仍经过网络栈,并非零开销。MariaDB 初始化与 WordPress 启动仍需就绪重试。


Pod 的存储共享#

同一 Pod 内的容器可以共享卷,但需要显式挂载同一路径:

podman run -d --pod mypod --name container-a -v shared:/data app-a:latest
podman run -d --pod mypod --name container-b -v shared:/data app-b:latest
# container-a 和 container-b 都能读写 shared 卷里的文件


示例 env 文件存放在仓库外且权限受限,分别提供匹配的数据库口令等必需值;所有展示字符串为无效演示值。导出的 kube 清单可能包含明文环境变量,不能直接当作安全存档上传。podman play kube 是 podman kube play 的别名,generate kube 为旧入口;命令更名不等于功能变为完整 Kubernetes。Pod 共享哪些 namespace 可配置;共享网络不自动共享文件系统和卷。podman generate systemd 已弃用,保留只为识别旧工作流,新服务采用 Quadlet。

参考与延伸

  1. Podman 官方 run 手册 ↗
  2. Podman 官方总览与 rootless ↗
  3. Pod 创建与 infra ↗
  4. kube play 范围 ↗
  5. kube generate ↗
  6. 旧 systemd 生成命令 ↗

根据技术笔记重新整理,示例使用通用名称。

沿专题继续阅读

Podman 容器工作流

  1. 01Podman 基础原理
  2. 02Podman 基本使用指南
  3. 03Rootless 容器,文件权限到底算谁的?
  4. 04Rootless 配置:映射、ICMP 与注册表
  5. 05Pod 体系与 Kubernetes 清单
  6. 06Quadlet 如何把容器声明变成服务?
  7. 07Quadlet 的 Pod 与多服务配置
  8. 08Compose provider 与 Docker 工具互操作
  9. 09NixOS 上的 Podman 管理
  10. 10Podman 高级运维与调优
  11. 11Docker 与 Podman:架构、兼容与共存
CONTINUE READING / 下一篇Quadlet 的 Pod 与多服务配置

补充 Pod、数据库、API 和代理资源的完整依赖模板。