# 12.3 Podman 容器管理

容器化技术是操作系统级虚拟化的重要实现形式，通过隔离的用户空间实例提供应用程序运行环境。Podman 是由红帽（Red Hat）主导开发的开源容器运行时，作为 Docker 的替代方案，其命令行接口与 Docker 高度兼容。Podman 采用无守护进程（daemonless）架构，提升了系统安全性——无需始终运行后台守护进程，每个容器作为独立进程运行，降低了单点故障风险。在 FreeBSD 平台上，Podman 基于原生的 Jail 机制实现容器隔离，Jail 作为 FreeBSD 成熟的操作系统级虚拟化技术，为容器提供了可靠的安全隔离边界，用户可以使用命令 `jls` 查看当前运行的容器。

## 安装 Podman

本节介绍 Podman 在 FreeBSD 上的安装和配置方法。在安装 sysutils/podman-suite 元包时，会同时安装 sysutils/buildah（用于构建容器镜像）、sysutils/podman（容器运行时）和 sysutils/skopeo（用于操作容器镜像）。

1. **使用 pkg 安装**：

   ```sh
   # pkg install podman-suite
   ```
2. **使用 Ports 安装**：

   ```sh
   # cd /usr/ports/sysutils/podman-suite/ 
   # make install clean
   ```
3. **查看安装后的配置信息**：

   ```sh
   # pkg info -D podman
   podman-5.3.2_2:
   On install:                              # 安装时：
   The FreeBSD port of the Podman container engine is experimental and should be
   used for evaluation and testing purposes only.
   # Podman 容器引擎的 FreeBSD 移植版本是实验性的，仅供评估和测试使用。

   $ sudo podman run --rm quay.io/dougrabson/hello

   Podman can restart containers after a host is rebooted. To enable this, use:
   # Podman 可以在主机重启后自动重启容器。要启用此功能，请执行以下命令：

   $ sudo sysrc podman_enable=YES

   and start the container with a restart policy:
   # 并使用重启策略启动容器：

   $ sudo podman run -d --restart=always myimage

   It is possible to run many Linux container images using FreeBSD's Linux emulation:
   # 可以通过 FreeBSD 的 Linux 仿真功能运行多数 Linux 容器镜像：

   $ sudo sysrc linux_enable=YES
   $ sudo service linux start
   $ sudo podman run --rm --os=linux alpine cat /etc/os-release | head -1
   NAME="Alpine Linux"

   On upgrade from podman<4.7.1:           # 当从版本小于 4.7.1 的 Podman 进行升级时：
   In Podman-4.7.0 and later, registry authentication creds moved from
   /run/containers/0/auth.json to /root/.config/containers/auth.json. Either move
   the file to the new location or just re-authenticate to the required registries.
   # 从 Podman 4.7.0 及更高版本起，注册表认证凭据已从
   # `/run/containers/0/auth.json` 移动到 `/root/.config/containers/auth.json`。
   # 用户可以将该文件移动到新位置，或重新登录到所需的镜像注册表
   ```

## 配置 fstab

在 FreeBSD 上使用 Podman，需要配置文件系统挂载点。fdescfs 是 FreeBSD 提供的文件描述符文件系统，用于将进程的文件描述符暴露为文件系统节点，Podman 依赖该文件系统实现容器内部的文件描述符传递。

将下列行写入 `/etc/fstab`：

```ini
fdesc   /dev/fd         fdescfs         rw      0       0
```

然后执行下列命令使之立即生效：

```sh
# mount -t fdescfs fdesc /dev/fd
```

## 配置网络

网络配置是确保容器能够正常访问外部网络的关键步骤。Podman 使用 PF（Packet Filter）防火墙实现容器网络的地址转换和流量控制，使容器可以通过宿主机网络接口访问外部网络。

首先复制 PF 配置文件示例：

```sh
# cp /usr/local/etc/containers/pf.conf.sample /etc/pf.conf
```

编辑 `/etc/pf.conf`，将 `ix0` 替换为你当前使用的网卡，可使用命令 `ifconfig` 查看：

```ini
# 设置 IPv4 出口网络接口
v4egress_if = "ix0"

# 设置 IPv6 出口网络接口
v6egress_if = "ix0"
```

接下来启动 PF 防火墙。`net.pf.filter_local=1` 参数的作用是将容器到宿主机本地地址的连接重定向到容器内部，确保容器可以正常访问宿主机服务。

```sh
# kldload pf # 加载内核模块，仅需执行一次，以后会自动加载
# echo 'net.pf.filter_local=1' >> /etc/sysctl.conf.local # 将容器主机的连接重定向到容器内部
# sysctl net.pf.filter_local=1 # 立即生效
# service pf enable # 启用 pf 防火墙服务
# service pf start # 启动 pf 防火墙
```

## 创建 ZFS 存储池

为了更好地管理容器的存储资源，建议创建专用的 ZFS 文件系统，具体操作如下：

创建 ZFS 文件系统 `zroot/containers`，并将挂载点设置为 `/var/db/containers`：

```sh
# zfs create -o mountpoint=/var/db/containers zroot/containers
```

## 启动服务

完成所有配置后，需要启动相关服务以使配置生效，具体操作如下：

```sh
# service linux enable       # 设置 Linux 仿真服务开机自启
# service linux start        # 启动 Linux 仿真服务
# service podman enable      # 设置 Podman 服务开机自启
# service podman start       # 启动 Podman 服务
```

项目结构：

```sh
/
├── etc/
│   ├── fstab # 文件系统挂载配置
│   ├── pf.conf # PF 防火墙配置
│   └── sysctl.conf.local # 本地 sysctl 配置
├── dev/
│   └── fd/ # 文件描述符设备
├── run/
│   └── containers/
│       └── 0/
│           └── auth.json # 旧版认证凭据位置
├── root/
│   └── .config/
│       └── containers/
│           └── auth.json # 新版认证凭据位置
├── var/
│   └── db/
│       └── containers/ # 容器数据库目录
└── usr/
    ├── local/
    │   └── etc/
    │       └── containers/
    │           └── pf.conf.sample # PF 防火墙配置示例
    └── ports/
        └── sysutils/
            └── podman-suite/ # Podman Ports 目录
```

## 测试 Ubuntu 镜像

服务启动完成后，可以通过测试拉取 Ubuntu 镜像来验证 Podman 是否正常工作：

1. **测试拉取 Ubuntu 镜像**：

   ```sh
   # podman pull --os=linux docker.io/library/ubuntu:latest
   Trying to pull docker.io/library/ubuntu:latest...
   Getting image source signatures
   Copying blob 0622fac788ed done   |
   Copying config a0e45e2ce6 done   |
   Writing manifest to image destination
   a0e45e2ce6e6e22e73185397d162a64fcf2f80a41c597015cab05d9a7b5913ce
   ```
2. **查看当前拉取的镜像**：

   ```sh
   # podman images
   REPOSITORY                TAG         IMAGE ID      CREATED      SIZE
   docker.io/library/ubuntu  latest      a0e45e2ce6e6  3 weeks ago  80.6 MB
   ```
3. **打印系统版本（仅打印前 5 行）**：

   ```sh
   # podman run --os=linux ubuntu /usr/bin/cat "/etc/os-release" | head -5
   PRETTY_NAME="Ubuntu 24.04.2 LTS"
   NAME="Ubuntu"
   VERSION_ID="24.04"
   VERSION="24.04.2 LTS (Noble Numbat)"
   VERSION_CODENAME=noble
   ```
4. **进入容器**：

   ```sh
   # podman run -it --os=linux ubuntu /bin/bash # 进入容器
   root@3b6d47dea81e:/# apt update # 当前已进入容器内部
   Get:1 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB]
   Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]

   ……以下省略……

   root@3b6d47dea81e:/# exit # 退出容器
   exit
   # # 回到了宿主机
   ```

## 测试 FreeBSD 维护者打包的 nginx 容器

除了 Linux 镜像外，Podman 也可以运行 FreeBSD 原生容器。本节将测试一个由 FreeBSD 维护者打包的 nginx 容器：

```sh
# 从 quay.io 拉取 nginx 镜像
podman pull quay.io/dougrabson/nginx

# 使用该镜像创建并后台运行名为 mynginx 的容器，将宿主机 8080 端口映射到容器 80 端口
podman run -d --name mynginx -p 8080:80 quay.io/dougrabson/nginx
```

在浏览器中打开 `http://ip:8080` 即可访问 nginx 测试页面。

## 更多用法

本节介绍 Podman 的一些常用操作方法：

1. **查看日志**：

   ```sh
   # podman logs 容器名称
   ```
2. **查看容器运行状态**：

   ```sh
   # podman ps # 查看当前运行的容器
   CONTAINER ID  IMAGE                            COMMAND               CREATEDSTATUS        PORTS                 NAMES
   ca088c9c56fc  quay.io/dougrabson/nginx:latest  /usr/local/sbin/n...  3 minutes agoUp 3 minutes  0.0.0.0:8080->80/tcp  mynginx
   # podman ps -a # 查看所有状态，包括运行失败的容器
   CONTAINER ID  IMAGE                            COMMAND               CREATED STATUS                     PORTS                              NAMES
   e8ea65b7e6c9  docker.io/library/nginx:latest   nginx -g daemon o...  17 minutes ago Exited (0) 292 years ago   0.0.0.0:8080->80/tcp               nginx-test
   ca088c9c56fc  quay.io/dougrabson/nginx:latest  /usr/local/sbin/n...  3 minutes ago Up 3 minutes               0.0.0.0:8080->80/tcp               mynginx
   ```
3. **停止并删除容器**：

   ```sh
   # podman stop 容器名称 # 停止容器
   # podman rm 容器名称  # 删除容器
   ```
4. **删除镜像（必须先删除引用该镜像的容器）**：

   ```sh
   # podman rmi 镜像名称
   ```

## 拉取 FreeBSD

除了第三方维护者提供的容器外，也可以直接从 Docker Hub 拉取官方的 FreeBSD 镜像：

从 Docker Hub 拉取 FreeBSD 14.2 runtime 镜像：

```sh
# podman pull docker://freebsd/freebsd-runtime:14.2
```

更多信息请参见：freebsd/freebsd-runtime\[EB/OL]. \[2026-03-26]. <https://hub.docker.com/r/freebsd/freebsd-runtime/tags>

## 参考文献

* Podman 项目. Podman Installation Instructions\[EB/OL]. \[2026-03-25]. <https://podman.io/docs/installation>. 官方安装教程，详述 Podman 部署步骤
* Josphat Mutai. Install Podman and run Containers in FreeBSD 14\[EB/OL]. cloudspinx.com, \[2026-03-25]. <https://cloudspinx.com/install-podman-and-run-containers-in-freebsd/>. 提供 FreeBSD 14 上 Podman 实用配置指南

## 课后习题

1. 使用 Port sysutils/buildah 构建一个自定义的 FreeBSD 容器镜像，验证其是否能在 Podman 中正常运行。
2. 查找 FreeBSD Jail 机制的实现代码，对比 Podman 如何基于 Jail 实现容器隔离，思考 Jail 起到了何种基石作用。
