Podman 容器基础
Podman 容器基础
目录
- 软件包安装
- 容器 vs 镜像:只读镜像与可写容器
- 容器 vs 虚拟机
- Podman 是什么:与 Docker 的关系和区别
- 运行容器:拉取镜像与生命周期管理
- 端口映射(-p)与数据卷(-v)
- 容器日志与进入容器:logs / exec
- 构建镜像:Containerfile / Dockerfile
- rootless:非 root 运行容器的概念与意义
- 补充:镜像管理与容器网络
- 常见问题排查清单
- 总结与练习
- 参考资料
软件包安装
安装 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 的命令行(很多命令直接 docker 换 podman 就能用),遵循 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-run、podman-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,可改用sh:podman exec -it web sh。
6.3 查看容器状态细节
podman inspect web # 查看容器的详细信息(IP、端口、挂载、环境变量等)
podman stats # 查看容器资源占用
参考:docs.podman.io - podman-logs、podman-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 的镜像构建,
Containerfile和Dockerfile都能用(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
十、常见问题排查清单
podman: command not found→ 没安装,sudo dnf install -y podman。- 拉取镜像超时/失败 → 网络问题或仓库不可达;确认能访问 docker.io/quay.io,必要时换镜像源。
- 端口映射不生效 → 确认
-p 宿主机端口:容器端口写对;宿主机的防火墙是否放行了宿主机端口(呼应防火墙模块)。 - rootless 绑定 80 失败 → 非 root 无法绑定 <1024 端口,改用高位端口或 root 运行。
podman exec进不去 → 容器是否在运行(podman ps);容器里没有 bash 时改用sh。- 容器数据一删就没了 → 没用数据卷
-v,容器可写层随容器删除而丢。 container ... already exists→ 容器名冲突,换个--name或先删旧容器。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 的意义。
参考资料
- podman.io - 官方首页:https://podman.io/
- docs.podman.io - Introduction:https://docs.podman.io/en/latest/Introduction.html
- docs.podman.io - podman-run:https://docs.podman.io/en/latest/markdown/podman-run.1.html
- docs.podman.io - podman-build:https://docs.podman.io/en/latest/markdown/podman-build.1.html
- docs.podman.io - podman-logs:https://docs.podman.io/en/latest/markdown/podman-logs.1.html
- docs.podman.io - podman-exec:https://docs.podman.io/en/latest/markdown/podman-exec.1.html
- docs.podman.io - podman-network:https://docs.podman.io/en/latest/markdown/podman-network.1.html
- Rocky Linux - Podman guide:https://docs.rockylinux.org/guides/containers/podman_guide/
- podman.io - Rootless 教程:https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md
- 菜鸟教程 - Linux 教程:https://www.runoob.com/linux/linux-tutorial.html