标签: Podman

  • RHEL 10 使用 Podman Quadlet 实现容器开机自动启动

    在 RHEL 10 Server 上使用 Podman 部署容器服务时,可以通过 Podman Quadlet 与 systemd 进行集成,将容器以 systemd 服务的方式统一管理。本文介绍如何使用 Kubernetes YAML 定义 Pod 和容器,并通过 Quadlet 配置实现容器服务的开机自动启动、停止、重启及状态管理,同时结合实际部署场景说明目录挂载、持久化数据以及服务管理中的常见问题,帮助在 RHEL Server 环境中建立更加规范、稳定的 Podman 容器运行方式。

    相比手动执行:

    podman kube play xxx.yaml
    

    使用 Quadlet 后,可以让 systemd 负责容器服务的启动、停止和开机自动启动。

    本文以 Uptime Kuma 为例,使用已有的 Kubernetes YAML 文件,通过 Quadlet 实现开机自动启动。

    1. 准备 Podman Kube YAML

    假设 Uptime Kuma 的 Kubernetes YAML 保存在:

    /opt/data/uptime-kuma/uptime-kuma.yaml
    

    例如:

    apiVersion: v1
    kind: Pod
    metadata:
      name: uptime-kuma
    
    spec:
      restartPolicy: Always
    
      containers:
        - name: uptime-kuma
          image: docker.io/louislam/uptime-kuma:2
    
          ports:
            - containerPort: 3001
              hostPort: 3001
              protocol: TCP
    
          env:
            - name: TZ
              value: "Asia/Shanghai"
    
          volumeMounts:
            - name: data
              mountPath: /app/data
    
          securityContext:
            capabilities:
              add:
                - NET_RAW
            runAsUser: 0
            runAsGroup: 0
    
      volumes:
        - name: data
          hostPath:
            path: /opt/data/uptime-kuma/data
            type: DirectoryOrCreate
    

    先创建数据目录:

    mkdir -p /opt/data/uptime-kuma
    

    2. 创建 Quadlet 配置目录

    root 用户使用的 Quadlet 文件可以放在:

    /etc/containers/systemd/
    

    创建目录:

    mkdir -p /etc/containers/systemd
    

    Podman 官方文档将 /etc/containers/systemd/ 作为 rootful Quadlet 的系统管理员配置目录。

    3. 创建 .kube 文件

    创建:

    vim /etc/containers/systemd/uptime-kuma.kube
    

    写入:

    [Unit]
    Description=Uptime Kuma Podman Pod
    
    [Kube]
    Yaml=/opt/data/uptime-kuma/uptime-kuma.yaml
    
    [Install]
    WantedBy=multi-user.target
    

    这里最重要的是:

    [Kube]
    Yaml=/opt/data/uptime-kuma/uptime-kuma.yaml
    

    它告诉 Quadlet 使用哪个 Kubernetes YAML 文件。

    而:

    [Install]
    WantedBy=multi-user.target
    

    表示该服务加入系统正常运行目标,从而实现系统启动时自动启动。

    Podman 官方文档也明确给出了 .kube 配合 [Install] WantedBy=multi-user.target 实现开机启动的方式。

    4. 重新加载 systemd

    创建 Quadlet 文件后执行:

    systemctl daemon-reload
    

    Quadlet 会通过 systemd generator 根据:

    /etc/containers/systemd/uptime-kuma.kube
    

    生成对应的:

    uptime-kuma.service
    

    可以检查:

    systemctl cat uptime-kuma.service

    如果看到类似:

    # Automatically generated by /usr/lib/systemd/system-generators/podman-system-generator
    

    说明 Quadlet 已经正常识别。

    也可以:

    systemctl status uptime-kuma.service
    

    5. 启动服务

    直接启动:

    systemctl start uptime-kuma.service
    

    检查:

    systemctl status uptime-kuma.service
    

    正常情况下应该看到:

    Active: active (running)
    

    同时检查 Podman:

    podman ps
    

    应该可以看到 Uptime Kuma 容器正在运行。

    6. 为什么不能执行 systemctl enable

    这里有一个和普通 systemd 服务不同的地方。

    不要执行:

    systemctl enable uptime-kuma.service
    

    Quadlet 生成的 systemd 服务属于 generated/transient unit,不能按照普通 .service 文件的方式执行 systemctl enable。

    如果执行:

    systemctl enable uptime-kuma.service
    

    可能看到:

    Failed to enable unit:
    Unit /run/systemd/generator/uptime-kuma.service
    is transient or generated
    

    这不是 Quadlet 配置失败。

    Quadlet 会在生成 systemd unit 时,根据 .kube 文件里的:

    [Install]
    WantedBy=multi-user.target
    

    自动建立对应的启动关系。

    这是 Podman Quadlet 与普通 systemd unit 的一个重要区别。

    7. 验证开机自动启动

    可以查看生成的服务:

    systemctl cat uptime-kuma.service
    

    确认存在:

    [Install]
    WantedBy=multi-user.target
    

    然后可以重启服务器进行实际验证:

    reboot
    

    服务器重新启动后:

    systemctl status uptime-kuma.service
    

    以及:

    podman ps
    

    如果 Uptime Kuma 已经自动运行,就说明配置完成。

    8. 日常管理

    以后不需要再手动执行:

    podman kube play uptime-kuma.yaml
    

    直接使用 systemd:

    启动:

    systemctl start uptime-kuma.service
    

    停止:

    systemctl stop uptime-kuma.service
    

    重启:

    systemctl restart uptime-kuma.service
    

    查看状态:

    systemctl status uptime-kuma.service
    

    查看日志:

    journalctl -u uptime-kuma.service
    

    实时查看日志:

    journalctl -fu uptime-kuma.service
    

    9. Quadlet 的工作原理

    整个启动流程实际上是:

    服务器开机
        │
        ▼
    systemd
        │
        ▼
    podman-system-generator
        │
        ▼
    /etc/containers/systemd/uptime-kuma.kube
        │
        ▼
    uptime-kuma.service
        │
        ▼
    podman kube play
        │
        ▼
    Uptime Kuma Pod
        │
        ▼
    Uptime Kuma Container
    

    因此,Kubernetes YAML 负责描述容器,Quadlet 负责把它交给 systemd 管理。

    Podman 官方文档中,.kube 文件就是用于通过 podman kube play 将 Kubernetes YAML 作为 systemd 服务运行的 Quadlet 类型。

    10. 最终目录结构

    最终可以保持这样的结构:

    /opt/data/uptime-kuma/
    └── uptime-kuma.yaml
    
    /opt/data/uptime-kuma/data
    └── Uptime Kuma 数据
    
    /etc/containers/systemd/
    └── uptime-kuma.kube
    

    其中:

    uptime-kuma.yaml
    

    负责定义 Pod 和容器。

    uptime-kuma.kube
    

    负责告诉 systemd 如何使用这个 YAML。

    /opt/data/uptime-kuma/data
    

    负责保存 Uptime Kuma 的持久化数据。

  • Higress 部署:使用 Podman Kube 搭建 AI Gateway

    最近在研究 AI Gateway,除了常见的 DIFY、Apache APISIX 等方案之外,也关注到了阿里云开源的 Higress。

    Higress 是一个云原生 API Gateway,同时也提供了面向 AI 场景的相关能力。这次不使用 Docker Compose,而是直接使用 Podman Kube 部署 Higress All-in-One。

    这样也可以和我服务器上其他使用 Podman Kube 管理的服务保持统一。

    1. 准备工作

    首先创建 Higress 工作目录:

    mkdir -p /opt/data/higress
    cd /opt/data/higress
    

    后续 Higress 容器中的 /data 会挂载到这个目录,用于保存相关配置和数据。

    2. 创建 Podman Kube YAML

    创建 higress-ai.yaml:

    nano higress-ai.yaml
    

    写入以下内容:

    apiVersion: v1
    kind: Pod
    metadata:
      name: higress-ai
    spec:
      containers:
        - name: higress-ai
          image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest
          ports:
            - containerPort: 8001
              hostPort: 8001
              protocol: TCP
            - containerPort: 8080
              hostPort: 8080
              protocol: TCP
            - containerPort: 8443
              hostPort: 8443
              protocol: TCP
          volumeMounts:
            - name: higress-data
              mountPath: /data
      volumes:
        - name: higress-data
          hostPath:
            path: /opt/data/higress
            type: DirectoryOrCreate
    

    3. 启动 Higress

    执行:

    podman kube play higress-ai.yaml
    

    查看 Pod:

    podman pod ps
    

    查看容器:

    podman ps
    

    如果启动正常,可以看到 higress-ai Pod 正常运行。

    4. 查看日志

    查看 Higress 日志:

    podman logs higress-ai-higress-ai
    

    实时查看日志:

    podman logs -f higress-ai-higress-ai
    

    如果不确定容器名称,可以直接执行:

    podman ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
    

    5. 端口说明

    这次部署映射了三个端口:

    宿主机端口容器端口用途
    80018001Higress UI 控制台入口
    80808080网关 HTTP 协议入口
    84438443网关 HTTPS 协议入口

    本次使用 Podman Kube 部署,因此将三个端口直接映射到宿主机:

    ports:
      - containerPort: 8001
        hostPort: 8001
        protocol: TCP
      - containerPort: 8080
        hostPort: 8080
        protocol: TCP
      - containerPort: 8443
        hostPort: 8443
        protocol: TCP
    

    部署完成后,可以通过访问Higress控制台:

    http://服务器IP:8001/

    6. 停止 Higress

    使用 Podman Kube 部署后,可以直接通过 YAML 文件停止并删除 Pod:

    podman kube down higress-ai.yaml
    

    这个操作会删除对应的 Pod 和容器,但不会删除宿主机上的:

    /opt/data/higress
    

    因此挂载到 /data 的数据可以继续保留。

    7. 重新启动 Higress

    需要重新启动时,再执行:

    cd /opt/data/higress
    podman kube play higress-ai.yaml
    

    Podman 会根据 YAML 文件重新创建 Higress Pod。

    8. 更新 Higress

    由于这里使用的是 latest 标签,因此后续需要更新 Higress 时,可以先拉取最新镜像:

    podman pull higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest && \
    podman kube down higress-ai.yaml && \
    podman kube play higress-ai.yaml
    

    这样就完成了一次 Higress 镜像更新。

  • Web 部署新选择:Docker 还是 Podman

    容器化已成为现代 Web 网站部署的核心策略。无论是 Docker 还是 Podman,都能将你的网站及其所有依赖打包成一个独立、可移植的单元,从而极大地简化部署流程。作为开发者,你需要了解它们在架构和使用上的差异,因为这些差异会直接影响你的部署效率、系统安全性,甚至是未来的可扩展性。容器仅仅是一种工具,而非最终目的。

    Docker

    Docker 作为容器技术的先行者,凭借其强大的生态系统和丰富的工具链,已成为 Web 应用部署的事实标准。

    优点:

    • 海量镜像资源,开发部署高效: Docker Hub 上拥有庞大的官方和社区镜像库,涵盖了 Nginx、Node.js、MySQL 等各类服务。这意味着你无需从头配置,就能快速拉取所需环境,大幅缩短开发和部署周期。
    • Docker Compose 简化多服务部署: 现代 Web 应用常由多个服务构成(如 Web 服务器、数据库、缓存)。docker-compose.yml 文件允许你通过一份声明式配置,一次性定义并启动所有相关服务,实现“一键部署”,极大地简化了开发、测试和生产环境的管理。
    • 与云原生编排工具无缝集成: 如果你的网站未来需要扩展到集群环境以应对高并发(例如使用 Kubernetes 或 Docker Swarm),Docker 能提供良好的兼容性。这为你的大规模部署奠定了坚实的基础,确保平滑过渡。
    • 跨平台一致性,提升团队协作效率: 无论团队成员使用 Windows、macOS 还是 Linux,Docker Desktop 都能提供统一的容器开发和运行体验,有效减少“在我机器上能跑”的问题,确保开发与生产环境的高度一致。

    适用场景:

    • 容器技术初学者,希望快速入门并能找到大量学习资料和社区支持。
    • 需要同时管理多个相互依赖的服务,例如 WordPress + MySQL。
    • 计划将 Web 应用部署到大型云平台或 Kubernetes 集群。
    • 团队成员操作系统多样,需要统一的开发环境以提高协作效率。

    Podman

    Podman 是容器领域的一颗新星,以其独特的无守护进程架构和卓越的安全性在 Linux 环境中脱颖而出。

    优点:

    • 无守护进程,支持无 Root 运行,安全性更高: 这是 Podman 的核心优势。它没有常驻后台的守护进程,并且支持“无根容器”(rootless containers)。这意味着你可以以普通用户身份运行容器,即使容器被攻陷,攻击者也难以获得宿主机的 Root 权限,显著降低了安全风险。
    • 与 Systemd 原生集成,简化服务管理: 在 Linux 服务器上,你可以将容器直接注册为 systemd 服务,享受系统级的自启动、守护和监控功能。这让 Web 服务的长期管理变得异常简单和可靠,特别适合在 VPS 或物理服务器上部署。
    • 资源占用低,提升边缘设备性能: 由于 Podman 没有常驻守护进程,它仅在执行命令时才消耗资源。这使得它在资源有限的服务器(如小型 VPS 或边缘设备)上更为高效,能有效节省内存和 CPU,提升系统整体性能。
    • 支持 Pod 架构,与 Kubernetes 理念一致: Podman 能够管理“Pod”(一组共享网络和存储的容器),这与 Kubernetes 的设计理念完全一致。你可以将 Web 服务和数据库打包进一个 Pod,简化它们之间的通信和数据共享,同时也为未来迁移到 Kubernetes 做了技术储备。

    适用场景:

    • 对安全性有极高要求,希望容器能够在无 Root 权限下运行。
    • 主要在 Linux 服务器上进行部署,并希望容器能与系统服务 (systemd) 紧密集成。
    • 资源受限的环境,追求极致的性能和效率。
    • 希望提前熟悉 Kubernetes 的 Pod 概念,为未来的云原生转型做准备。

    实际使用中的关键差异

    除了核心特性,实际部署中还有一些细节差异值得开发者注意:

    • 1. 命令行兼容性并非百分百: 尽管 Podman 的命令与 Docker 大致相似,但在一些高级用法、网络配置或特定参数上仍存在细微差别。习惯 Docker 的用户可能需要短暂的适应期。
    • 2. 镜像构建方式: Docker 主要使用 docker build 命令和 Dockerfile 来构建镜像。Podman 虽然也支持 podman build,但它更推崇与 Buildah 工具集成。Buildah 提供了更底层的控制和更多样的构建方式(甚至无需 Dockerfile),这对于需要高度定制化构建流程的开发者来说非常有用。
    • 3. 存储卷与权限处理: 在 Linux 系统下,Docker 和 Podman 在处理容器存储卷的默认权限和 SELinux 安全上下文时可能有所不同。特别是在 Podman 的无根容器模式下,存储卷的权限配置需要开发者更加细致地处理,以避免潜在的文件访问问题。

    特性对比

    特性/维度DockerPodman
    架构有守护进程(dockerd)无守护进程,命令直接调用容器引擎
    无 Root 运行需要 Root (或 sudo)支持 rootless 模式
    多容器编排Docker Compose / Swarm支持 Pod,但 Compose 支持较弱
    与 Systemd 集成需额外配置或借助外部工具原生支持 systemd 生成服务文件
    镜像构建docker build (基于 Dockerfile)podman build + Buildah (更灵活)
    资源占用较高 (后台常驻 dockerd)更低 (按需启动,无守护)
    安全性中等 (需注意权限)高 (支持无 Root 容器,强权限隔离)

    Docker 和 Podman 并非相互对立,它们代表了两种不同的容器设计理念:

    • Docker = 生态成熟 + 上手快 + 支持云原生全流程。
    • Podman = 安全优先 + 系统集成强 + 更贴近 Linux 哲学。
  • 使用 Podman 部署 Cockpit 和 Immich 机器学习容器

    使用 Podman 部署安装 Cockpit 管理工具并使用 Podman 启动 Immich 的机器学习容器。以便在浏览器中方便配置和访问

    一、开放所需端口

    在默认情况下,Linux 防火墙(firewalld)可能会阻止一些端口的外部访问。为了确保 Cockpit 和 Immich 模块能够正常被访问,需要永久放行相关端口。

    1. 放行 9090 端口(用于 Cockpit)

    firewall-cmd --add-port=9090/tcp --permanent
    firewall-cmd --reload

    2. 放行 3003 端口(用于 Immich 机器学习容器)

    firewall-cmd --permanent --add-port=3003/tcp
    firewall-cmd --reload

    二、安装 Cockpit 和 Podman

    Cockpit 是一款轻量级的 Web 管理工具,可用于查看系统信息、容器、服务等。

    dnf install podman cockpit cockpit-podman -y

    安装完成后,启用并启动 Cockpit:

    systemctl enable --now cockpit.socket

    然后可通过浏览器访问 Cockpit:

    https://<你的服务器IP>:9090

    注意:首次访问时浏览器可能提示 SSL 证书不安全,可选择“继续前往”。

    三、部署 Immich Machine Learning 容器

    Immich 是一个支持自动图片整理、面部识别等功能的自托管照片管理系统。我们配置immich的远程机器学习提高计算速度

    1. 下载镜像

    podman pull ghcr.io/immich-app/immich-machine-learning:release

    2. 运行容器

    podman run \
      --name immich_machine_learning \
      --restart=always \
      --replace \
      -p 3003:3003 \
      -v model-cache:/cache \
      -e TZ=Asia/Shanghai \
      -d \
      ghcr.io/immich-app/immich-machine-learning:release

    此命令的作用如下:

    • --name: 指定容器名称
    • --restart=always: 容器自动重启策略
    • --replace: 替换已有同名容器
    • -p 3003:3003: 映射本地端口
    • -v model-cache:/cache: 使用持久卷缓存模型
    • -e TZ=Asia/Shanghai: 设置时区
    • -d: 后台运行容器

    四、配置容器开机自动启动(可选但推荐)

    虽然运行容器时使用了 --restart=always,但 Podman 默认并不会像 Docker 一样在系统启动时自动重启容器。要实现真正的“开机自启”,需依赖 systemd 启动服务。

    1. 生成并安装 systemd 单元文件

    podman generate systemd --name immich_machine_learning --files --restart-policy=always

    这将在当前目录生成 container-immich_machine_learning.service 文件。将其移动到系统服务目录并启用:

    mv container-immich_machine_learning.service /etc/systemd/system/
    systemctl daemon-reexec
    systemctl enable container-immich_machine_learning.service

    五、验证部署

    • 访问 Cockpit Web 控制台查看容器状态:
      https://<你的服务器IP>:9090
    • 访问 Immich ML 控制台查看容器状态:
      http://<你的服务器IP>:3003