Podman 容器基础

Administrator 11

Podman 容器基础


目录

  1. 软件包安装
  2. 容器 vs 镜像:只读镜像与可写容器
  3. 容器 vs 虚拟机
  4. Podman 是什么:与 Docker 的关系和区别
  5. 运行容器:拉取镜像与生命周期管理
  6. 端口映射(-p)与数据卷(-v)
  7. 容器日志与进入容器:logs / exec
  8. 构建镜像:Containerfile / Dockerfile
  9. rootless:非 root 运行容器的概念与意义
  10. 补充:镜像管理与容器网络
  11. 常见问题排查清单
  12. 总结与练习
  13. 参考资料

软件包安装

安装 Podman(Rocky / RHEL / CentOS)

Rocky 的 AppStream 自带 Podman,直接安装:

sudo dnf install -y podman

# 查看版本
podman --version

# 验证安装
podman info

安装依赖(rootless 需要)

rootless(非 root 运行)需要一些辅助组件,Rocky 通常会自动安装,也可显式确认:

sudo dnf install -y slirp4netns fuse-overlayfs
  • slirp4netns:rootless 容器的网络支持。
  • fuse-overlayfs:rootless 容器的存储驱动(可选,配合 vfs)。

Ubuntu / Debian 差异

sudo apt install -y podman

测试是否可用

# 拉取一个测试镜像并运行(无 root 也能跑,见第八章)
podman pull docker.io/library/hello-world
podman run hello-world

说明:Podman 无需守护进程,安装后即可用 podman 命令操作,普通用户(非 root)也能运行容器。


一、容器 vs 镜像:只读镜像与可写容器

这是理解容器的第一块基石。

1.1 镜像(Image):只读模板

  • 镜像是只读的模板:它包含运行一个应用所需的操作系统基础、运行时、依赖、代码等,被打包成一层层只读的"镜像层(layers)"。
  • 镜像是不可变的,多个容器可以共用同一个镜像
  • 类比:镜像是"光盘"或"安装模板"。

1.2 容器(Container):可写运行实例

  • 容器是镜像的一个可写运行实例podman run 基于镜像启动一个容器,容器在镜像之上加了一层可写层(writable layer)
  • 对容器做的修改(新建文件、改配置)都写在这层,不影响底层镜像
  • 容器被删除后,这层可写层也随之消失(除非用数据卷保存,见第五章)。
  • 类比:容器是"正在运行、可写"的一个实例。

1.3 一句话记住

镜像 = 只读模板(不可变)
容器 = 从镜像创建的可写运行实例
podman run 镜像   -->  启动一个容器

参考:docs.podman.io - Introduction


二、容器 vs 虚拟机

2.1 核心区别:共享内核 vs 独立内核

  • 虚拟机(VM):每个虚拟机里都有一个完整的操作系统(自己的内核 + 用户空间),通过**虚拟化层(Hypervisor)**跑在物理机上,相互完全隔离。
  • 容器:多个容器共享宿主机的一个内核,每个容器只是内核上隔离出来的用户空间(应用 + 依赖),没有自己的内核。
虚拟机:  [App][App]        [App][App]
         [Guest OS][Guest OS]  <- 每个有自己的内核
         [    Hypervisor    ]
         [   物理机/宿主机  ]

容器:    [App][App][App][App]
         [   共享的宿主机内核   ]
         [       宿主机        ]

2.2 对比表

对比项 虚拟机 容器
内核 每个有自己的内核 共享宿主机内核
启动速度 慢(秒~分钟级) 快(毫秒~秒级)
资源占用 重(完整 OS) 轻(只含应用)
隔离性 强(完全隔离) 较弱(共享内核)
系统支持 可跑任意 OS(Windows/Linux) 通常 Linux(共享宿主内核)
场景 需要强隔离、跑异构 OS 轻量、快速部署、微服务

2.3 理解要点

  • 容器更轻、更快,但隔离性不如虚拟机(毕竟共享内核)。
  • 容器里的进程其实还是跑在宿主机内核上,只是被 namespace 等机制隔离了"视角"。
  • 对安全性要求极高、或需要跑不同内核的场景,选虚拟机;追求轻量和部署效率,选容器。

一句话:虚拟机是"搬来一台电脑",容器是"在一个电脑里划出一个个隔离的小隔间"。


三、Podman 是什么:与 Docker 的关系和区别

3.1 Podman 是什么

Podman 是一个开源的 Linux 容器管理工具,由 Red Hat 主导开发,兼容 Docker 的命令行(很多命令直接 dockerpodman 就能用),遵循 OCI(Open Container Initiative) 标准。

3.2 Podman 与 Docker 的核心区别

对比项 Docker Podman
架构 **守护进程(daemon)**模式:dockerd 常驻后台 无守护进程(daemonless):直接由 podman 命令管理
root 权限 传统上需要 root 运行 Docker 支持 rootless(普通用户可直接运行)
容器管理 Docker 守护进程统一管理 无中心守护进程,更轻量
兼容性 事实标准、生态庞大 兼容 Docker CLI,可 alias docker=podman
镜像格式 OCI OCI(通用)

3.3 最关键的两点差异

① 无守护进程(daemonless)

  • Docker 需要一个常驻的 dockerd 守护进程来管理容器;它挂了,所有容器管理命令就失效。
  • Podman 没有守护进程podman 命令直接调用 OCI 运行时(runc/crun)干活,更简单、更安全、更好排查。

② rootless(无 root 也能用)

  • Docker 传统上要求 root 权限(守护进程以 root 跑)。
  • Podman 支持普通用户直接运行容器(rootless),安全性更好——即使容器被攻破,也只是普通用户权限(见第八章)。

3.4 兼容 Docker 命令

# 大部分 docker 命令可以直接换成 podman
alias docker=podman     # 临时别名
podman ps               # 等价 docker ps
podman run -d nginx     # 等价 docker run -d nginx

参考:podman.io - 官方首页、Rocky Linux - Podman guide


四、运行容器:拉取镜像与生命周期管理

4.1 拉取镜像(podman pull)

镜像默认从 registry(镜像仓库) 拉取,默认是 Docker Hub(docker.io)。也可以指定 quay.io 等仓库。

podman pull nginx                 # 拉取 nginx 镜像
podman pull docker.io/library/nginx   # 显式指定仓库
podman pull quay.io/podman/hello  # 从 quay.io 拉取

4.2 查看本地镜像(podman images)

podman images      # 列出本地所有镜像
podman images nginx   # 只看 nginx

4.3 运行容器(podman run)

# 前台运行并直接看输出
podman run nginx

# 后台运行(-d)并命名(--name),映射端口(-p)
podman run -d --name web -p 8080:80 nginx

# 交互式进入容器(-it),如运行一个 Ubuntu 容器
podman run -it --name shell ubuntu /bin/bash
  • -d:后台(detached)运行。
  • --name:给容器起名,方便管理。
  • -p 8080:80:端口映射,把宿主机 8080 映射到容器 80(见第五章)。
  • -it:交互式终端。

4.4 查看容器(podman ps)

podman ps          # 查看正在运行的容器
podman ps -a       # 查看所有容器(含已停止的)

4.5 停止、启动、删除(stop / start / rm)

podman stop web        # 停止容器
podman start web       # 启动已停止的容器
podman restart web     # 重启
podman rm web          # 删除容器(先停止)
podman rm -f web       # 强制删除
podman rmi nginx       # 删除镜像(先删依赖它的容器)

参考:docs.podman.io - podman-runpodman-pull


五、端口映射(-p)与数据卷(-v)

5.1 端口映射(-p):让外部访问容器

容器默认有自己的网络命名空间,外部(宿主机或其他机器)访问不到容器内监听的服务。用 -p 把宿主机端口映射到容器端口:

# 把宿主机 8080 端口映射到容器 80 端口
podman run -d --name web -p 8080:80 nginx

# 访问测试:宿主机上
curl http://127.0.0.1:8080
  • 语法:-p 宿主机端口:容器端口
  • 也可以指定 IP:-p 127.0.0.1:8080:80(只允许本机访问)。
  • 多个端口:-p 8080:80 -p 443:443

为什么需要映射:容器和宿主机是隔离的网络空间,-p 相当于开了一个"桥",让宿主机端口上的流量进入容器。

5.2 数据卷(-v):持久化数据

容器删除后,容器内的数据(写在可写层)会丢失。用数据卷把宿主机目录或命名卷挂载进容器,数据就能持久保存、也能在多个容器间共享:

# 把宿主机目录 /data 挂载到容器的 /app/data
podman run -d --name app -v /data:/app/data myimage

# 使用命名卷(podman 管理):
podman run -d --name app -v myvolume:/app/data myimage

# 查看卷
podman volume ls
  • 语法:-v 宿主机目录:容器目录-v 卷名:容器目录
  • 挂载后,容器写 /app/data 就是在写宿主机 /data,数据不随容器删除而丢。
  • 权限:宿主机目录的属主/权限会影响到容器内访问(结合前面权限模块理解)。

参考:docs.podman.io - podman-run(-p / -v 选项)


六、容器日志与进入容器:logs / exec

6.1 查看容器日志(podman logs)

排查容器问题时,先看日志:

podman logs web              # 查看容器标准输出/错误日志
podman logs -f web           # 实时跟踪(-f = follow)
podman logs --tail 50 web    # 只看最后 50 行
  • 前台运行的应用日志,logs 能直接看到。
  • 应用把日志写到文件而非标准输出时,logs 看不到,需用 exec 进容器看。

6.2 进入容器(podman exec)

运行中的容器里执行命令:

# 进入容器打开一个交互式 shell
podman exec -it web /bin/bash

# 在容器里执行单条命令(不进交互)
podman exec web ls /usr/share/nginx/html

# 以 root 身份进入(容器默认用户可能不是 root)
podman exec -it -u root web /bin/bash
  • -it:交互式终端。
  • -u root:指定以 root 用户执行。
  • 容器里可能没有 bash,可改用 shpodman exec -it web sh

6.3 查看容器状态细节

podman inspect web    # 查看容器的详细信息(IP、端口、挂载、环境变量等)
podman stats           # 查看容器资源占用

参考:docs.podman.io - podman-logspodman-exec


七、构建镜像:Containerfile / Dockerfile

7.1 什么是 Containerfile / Dockerfile

Containerfile(旧称 Dockerfile) 是一个文本文件,用指令描述"如何从基础镜像一步步构建出新的镜像"。Podman 的 podman build 用它来构建镜像。

7.2 常用指令

指令 作用 示例
FROM 指定基础镜像 FROM nginx:latest
RUN 在构建时执行命令 RUN apt install -y curl
COPY 把宿主机文件拷进镜像 COPY index.html /usr/share/nginx/html/
CMD 容器启动时执行的命令 CMD ["nginx", "-g", "daemon off;"]
EXPOSE 声明容器对外端口(文档性) EXPOSE 80
WORKDIR 设置工作目录 WORKDIR /app

7.3 一个完整的构建示例

准备一个带自定义页面的 nginx 镜像:

# 准备一个静态页面
mkdir -p ~/myweb && cd ~/myweb
echo "<h1>Hello Podman Build</h1>" > index.html

# 创建 Containerfile
cat > Containerfile <<'EOF'
FROM nginx:latest
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
EOF

# 构建镜像
podman build -t myweb:latest .

# 运行构建出的镜像
podman run -d --name myweb -p 8080:80 myweb
curl http://127.0.0.1:8080/
  • podman build -t 镜像名:标签 .. 表示构建上下文(当前目录),-t 指定镜像名和标签。
  • 构建时会从 FROM 的基础镜像逐层执行指令,生成新的镜像层。

7.4 Dockerfile 也通用

  • Podman 兼容 Docker 的镜像构建,ContainerfileDockerfile 都能用(Podman 两者都认,优先 Containerfile)。
  • 已有的 Dockerfile 可以直接用 podman build 构建,无需改动。

参考:Rocky Linux - Podman guide(Containerfile 部分)、docs.podman.io - podman-build


八、rootless:非 root 运行容器的概念与意义

8.1 什么是 rootless

  • rootless普通用户(非 root)也能直接运行容器,不需要 sudo,也不需要 root 权限的守护进程。
  • Docker 传统上需要 root 权限;Podman 天生支持 rootless,这是它与 Docker 最本质的区别之一。

8.2 rootless 是怎么实现的

  • 用户命名空间(user namespace):把容器内的 root(UID 0)映射到宿主机的一个普通用户,容器里以为是 root,其实只是普通用户权限。
  • 网络用 slirp4netns(用户态网络),存储用 fuse-overlayfs 或 vfs。

8.3 为什么要用 rootless(意义)

  • 更安全:容器即使被攻破,攻击者得到的也只是普通用户权限,无法直接破坏宿主机(不像 root 容器那样是 root)。
  • 无需提权:普通用户随手就能跑容器,适合开发、CI 等场景。
  • 更符合最小权限原则:不把整个主机的 root 交给容器。

8.4 rootless 的限制(要知道)

  • 默认无法绑定 <1024 的特权端口(如 80),因为绑定特权端口需要 root(呼应权限模块)。可用 8080 等高位端口,或用 sysctl net.ipv4.ip_unprivileged_port_start 调整。
  • 性能可能略低于 root 模式(用户态网络/存储开销)。
  • 某些需要内核级权限的容器功能受限。
# rootless 示例:普通用户直接运行容器
podman run -d --name test -p 8080:80 nginx
podman ps

# 尝试绑定 80 会失败(非 root 无法绑定特权端口)
podman run -d --name test80 -p 80:80 nginx
# 会报错:Error: ... bind: permission denied

参考:podman.io - Rootless 教程


九、补充:镜像管理与容器网络

9.1 镜像管理

podman images           # 列出本地镜像
podman rmi 镜像名        # 删除镜像
podman search nginx     # 在仓库中搜索镜像
podman pull 镜像名       # 拉取镜像
podman image inspect 镜像名  # 查看镜像详情

9.2 容器网络

  • Podman 默认创建一个 bridge 网络,容器接入后可互相通信(通过容器名/IP)。
  • 外部访问容器要靠 -p 端口映射(见第五章)。
podman network ls          # 查看网络
podman inspect 容器名 | grep -i ipaddress   # 查看容器 IP
podman network create mynet    # 创建自定义网络
  • 同一网络内的容器可以用容器名互相访问(如后端容器访问数据库容器)。

参考:docs.podman.io - podman-network


十、常见问题排查清单

  1. podman: command not found → 没安装,sudo dnf install -y podman
  2. 拉取镜像超时/失败 → 网络问题或仓库不可达;确认能访问 docker.io/quay.io,必要时换镜像源。
  3. 端口映射不生效 → 确认 -p 宿主机端口:容器端口 写对;宿主机的防火墙是否放行了宿主机端口(呼应防火墙模块)。
  4. rootless 绑定 80 失败 → 非 root 无法绑定 <1024 端口,改用高位端口或 root 运行。
  5. podman exec 进不去 → 容器是否在运行(podman ps);容器里没有 bash 时改用 sh
  6. 容器数据一删就没了 → 没用数据卷 -v,容器可写层随容器删除而丢。
  7. container ... already exists → 容器名冲突,换个 --name 或先删旧容器。
  8. podman rmi 删除失败 → 先删除依赖该镜像的容器(podman rm -f)。

十一、总结与练习

11.1 核心速查

需求 命令
安装 sudo dnf install -y podman
拉取镜像 podman pull nginx
运行容器 podman run -d --name web -p 8080:80 nginx
查看运行容器 podman ps
查看所有容器 podman ps -a
停止/删除 podman stop web / podman rm web
看日志 podman logs -f web
进入容器 podman exec -it web /bin/bash
构建镜像 podman build -t myimage .
查看镜像 podman images

11.2 动手练习建议

# 1. 安装并拉一个镜像
sudo dnf install -y podman
podman pull nginx

# 2. 运行 nginx 并映射端口、验证访问
podman run -d --name web -p 8080:80 nginx
curl http://127.0.0.1:8080

# 3. 练习生命周期:ps / stop / start / logs / exec / rm
podman logs -f web
podman exec -it web sh
podman stop web && podman rm web

# 4. 用 Containerfile 构建自己的镜像(见第七章)

# 5. 体会 rootless:用普通用户跑容器,并尝试绑定 80 看报错

提示:练习在虚拟机进行。用普通用户(非 root)跑容器,能更直观地体会 rootless 的意义。


参考资料