欢迎光临
我们一直在努力

Docker 与 Podman 服务部署完全指南

Docker 与 Podman 服务部署完全指南

📖 从 Dockerfile 到容器编排,全面掌握使用 Docker 和 Podman 部署服务的完整流程

Docker和Podman都是开源的容器化管理工具,核心功能都是构建、运行和管理容器,但在架构设计、安全模型和生态集成方面存在显著差异。相同点在于两者都遵循OCI(Open Container Initiative)标准,这意味着它们可以运行相同的容器镜像,使用相似的命令行接口(docker run vs podman run语法高度兼容),并且都支持Dockerfile构建镜像以及Docker Compose的多容器编排。这使得从Docker迁移到Podman的学习成本相对较低。

核心差异主要体现在架构和安全两个维度。Docker采用客户端-服务器(C/S)架构,守护进程(dockerd)需要以root权限运行,所有docker命令通过CLI与守护进程通信,这意味着一旦守护进程崩溃,所有容器都会受到影响,且root权限运行带来了潜在的安全风险。而Podman采用无守护进程架构,每个容器直接作为子进程由Podman命令fork产生,可以以rootless模式运行(非root用户也能管理容器),这大大降低了容器逃逸的权限提升风险,更加符合安全合规要求。

在编排和管理层面,Docker Compose依赖单独的docker-compose.yaml文件进行多容器编排,而Podman原生支持Pod概念(类似Kubernetes中的Pod),可以将多个容器组合在同一Pod中共享网络和存储,更贴近云原生架构。对于从Docker Compose迁移的场景,Podman提供了podman-compose工具或通过podman play kube命令将Compose文件转换为Kubernetes YAML进行部署,实现平滑过渡。此外,Podman默认支持systemd集成,可以直接生成系统服务文件实现容器开机自启,而不需要像Docker那样借助外部工具。

在生态和社区支持方面,Docker拥有更成熟的生态、更丰富的文档和更广泛的CI/CD集成(如Jenkins、GitHub Actions),而Podman作为Red Hat主导的项目,与RHEL/CentOS Stream等系统深度集成,在OpenShift等Kubernetes环境中表现更优。性能上两者差异不大,但Podman的rootless模式在文件系统I/O和网络性能上略低于Docker的rootful模式。 针对已有Dockerfile和Compose编排的迁移策略,建议分两步走:首先将docker run命令替换为podman run(通常无需修改),将docker-compose up替换为podman-compose up或podman play kube;其次针对复杂场景(如网络模式、卷挂载权限)进行适配测试,特别注意rootless模式下端口的绑定限制(非root用户无法绑定1024以下端口)。总体而言,Podman更适合安全敏感、需要非root运行或多租户环境,而Docker更适合开发环境、成熟CI/CD链和社区资源依赖较重的场景。 在这里插入图片描述

目录

  • 第一部分:容器镜像构建
    • 1.1 Dockerfile 基础
    • 1.2 Dockerfile 完整指令详解
    • 1.3 多阶段构建(Multi-stage Build)
    • 1.4 Docker 构建 vs Podman 构建 vs Buildah 构建
    • 1.5 镜像优化最佳实践
  • 第二部分:单容器服务部署
    • 2.1 Docker 运行容器
    • 2.2 Podman 运行容器
    • 2.3 容器网络配置
    • 2.4 数据持久化(Volume)
    • 2.5 环境变量与配置管理
    • 2.6 容器日志管理
    • 2.7 容器资源限制
    • 2.8 健康检查
  • 第三部分:Docker Compose 多服务编排
    • 3.1 Docker Compose 概述
    • 3.2 docker-compose.yml 完整语法
    • 3.3 完整实战:Web 应用 + 数据库 + 缓存
    • 3.4 Compose 命令大全
    • 3.5 Compose 环境变量与配置覆盖
  • 第四部分:Podman 多服务编排方案
    • 4.1 方案一:podman-compose(兼容 Docker Compose)
    • 4.2 方案二:Podman Pod + Kubernetes YAML
    • 4.3 方案三:Quadlet(systemd 集成,Podman 4.4+)
    • 4.4 方案四:直接使用 Podman CLI 编排
    • 4.5 四种方案对比与选择建议
  • 第五部分:Buildah 构建镜像(Podman 生态)
    • 5.1 Buildah 简介与安装
    • 5.2 使用 Dockerfile 构建
    • 5.3 使用命令行构建(无需 Dockerfile)
    • 5.4 Buildah 与 Docker Build 的差异
  • 第六部分:生产环境部署实践
    • 6.1 完整项目部署示例(前后端 + 数据库)
    • 6.2 Docker 部署方案
    • 6.3 Podman 部署方案
    • 6.4 自动化部署脚本
    • 6.5 从 Docker 迁移到 Podman
  • 第七部分:容器镜像仓库管理
    • 7.1 Docker Hub
    • 7.2 私有仓库搭建(Harbor)
    • 7.3 Skopeo 镜像管理(Podman 生态)
  • 第八部分:CI/CD 中的容器化部署
    • 8.1 GitHub Actions 中的容器构建
    • 8.2 GitLab CI 中的容器构建
    • 8.3 Jenkins 中的容器构建

第一部分:容器镜像构建

1.1 Dockerfile 基础

Dockerfile 是一个文本文件,包含了一系列指令,用于定义容器镜像的构建过程。Docker 和 Podman 使用完全相同的 Dockerfile 语法,因为两者都遵循 OCI 镜像规范。

1.1.1 第一个 Dockerfile

# 基础镜像
FROM python:3.11-slim

# 设置工作目录
WORKDIR /app

# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install –no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8000

# 启动命令
CMD ["python", "app.py"]

1.1.2 构建镜像

# Docker 构建
docker build -t myapp:v1 .
docker build -t myapp:v1 -f Dockerfile.prod .

# Podman 构建(完全相同的语法)
podman build -t myapp:v1 .
podman build -t myapp:v1 -f Dockerfile.prod .

# Buildah 构建(使用 Dockerfile)
buildah bud -t myapp:v1 .
buildah bud -t myapp:v1 -f Dockerfile.prod .

关键点:Dockerfile 在 Docker 和 Podman 之间是 100% 兼容的,无需任何修改。

1.2 Dockerfile 完整指令详解

1.2.1 基础指令
指令说明示例
FROM 指定基础镜像(必选,第一条指令) FROM python:3.11-slim
LABEL 添加元数据标签 LABEL maintainer="user@example.com"
ARG 定义构建时变量 ARG VERSION=1.0
ENV 设置环境变量(构建和运行时都生效) ENV APP_ENV=production
WORKDIR 设置工作目录 WORKDIR /app

# 基础镜像选择指南
FROM python:3.11 # 完整版,~900MB,基于 Debian
FROM python:3.11-slim # 精简版,~150MB,基于 Debian
FROM python:3.11-alpine # 最小版,~50MB,基于 Alpine
FROM ubuntu:22.04 # Ubuntu 基础
FROM node:18-alpine # Node.js 精简版
FROM golang:1.21-alpine # Go 精简版
FROM openjdk:17-slim # Java 精简版

# 特殊基础镜像
FROM scratch # 空镜像(用于静态编译的二进制文件)
FROM distroless/static # Google 的无发行版镜像

1.2.2 文件操作指令
指令说明示例
COPY 复制文件到镜像 COPY app.py /app/
ADD 复制文件(支持 URL 和自动解压) ADD archive.tar.gz /app/
RUN 执行命令 RUN apt-get update && apt-get install -y curl

# COPY 基本用法
COPY requirements.txt . # 复制单个文件
COPY src/ /app/src/ # 复制目录
COPY –chown=appuser:appgroup app.py /app/ # 复制并设置所有者

# COPY 多文件
COPY package.json package-lock.json ./
COPY . . # 复制所有文件

# .dockerignore 文件(类似 .gitignore)
# 创建 .dockerignore 来排除不需要的文件

# .dockerignore 示例
.git
.gitignore
.env
*.md
__pycache__
node_modules
.vscode
.idea
*.pyc
.DS_Store

# RUN 指令最佳实践:合并多个命令减少镜像层数
# ❌ 不推荐:每个 RUN 创建一层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# ✅ 推荐:合并为一个 RUN
RUN apt-get update && \\
apt-get install -y –no-install-recommends curl && \\
apt-get clean && \\
rm -rf /var/lib/apt/lists/*

1.2.3 运行时指令
指令说明示例
EXPOSE 声明容器监听的端口(文档性质) EXPOSE 8080
CMD 容器启动时的默认命令 CMD ["python", "app.py"]
ENTRYPOINT 容器的入口点(不容易被覆盖) ENTRYPOINT ["python"]
USER 指定运行容器的用户 USER appuser
HEALTHCHECK 定义健康检查 HEALTHCHECK CMD curl -f http://localhost/
VOLUME 定义挂载点 VOLUME ["/data"]
SHELL 指定默认 Shell SHELL ["/bin/bash", "-c"]

# CMD 三种格式
CMD ["python", "app.py"] # exec 格式(推荐)
CMD python app.py # shell 格式(通过 /bin/sh -c 执行)
CMD ["–help"] # 与 ENTRYPOINT 配合使用

# ENTRYPOINT 与 CMD 的配合
ENTRYPOINT ["python"]
CMD ["app.py"]
# 最终执行: python app.py
# 用户可以通过 docker run myapp other.py 覆盖 CMD 部分
# 最终执行: python other.py

# USER 指令(安全最佳实践)
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser

# HEALTHCHECK
HEALTHCHECK –interval=30s –timeout=3s –start-period=5s –retries=3 \\
CMD curl -f http://localhost:8080/health || exit 1

1.2.4 构建时变量与多平台

# ARG:构建时变量(不会保留在最终镜像中)
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine

ARG BUILD_DATE
LABEL build.date=$BUILD_DATE

# 使用 ARG 的注意事项:
# ARG 在 FROM 之前定义的,只能在 FROM 中使用
# ARG 在 FROM 之后定义的,在 FROM 之后的指令中使用

# BUILDPLATFORM:交叉编译
FROM –platform=$BUILDPLATFORM golang:1.21 AS builder
ARG TARGETARCH
RUN GOARCH=$TARGETARCH go build -o app .

FROM scratch
COPY –from=builder /app/app /app
ENTRYPOINT ["/app"]

1.3 多阶段构建(Multi-stage Build)

多阶段构建是 Docker 17.05 引入的特性,Podman 完全支持。它可以显著减小最终镜像的大小。

1.3.1 Python 应用多阶段构建

# ====== 第一阶段:构建依赖 ======
FROM python:3.11-slim AS builder

WORKDIR /app

# 安装编译依赖
RUN apt-get update && \\
apt-get install -y –no-install-recommends gcc libpq-dev && \\
rm -rf /var/lib/apt/lists/*

# 创建虚拟环境
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# 安装 Python 依赖
COPY requirements.txt .
RUN pip install –no-cache-dir –upgrade pip && \\
pip install –no-cache-dir -r requirements.txt

# ====== 第二阶段:运行镜像 ======
FROM python:3.11-slim AS runtime

WORKDIR /app

# 只安装运行时必需的库
RUN apt-get update && \\
apt-get install -y –no-install-recommends libpq5 curl && \\
rm -rf /var/lib/apt/lists/*

# 从构建阶段复制虚拟环境
COPY –from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# 创建非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser -d /app appuser

# 复制应用代码
COPY –chown=appuser:appuser . .

# 切换到非 root 用户
USER appuser

EXPOSE 8000

HEALTHCHECK –interval=30s –timeout=3s –start-period=10s –retries=3 \\
CMD curl -f http://localhost:8000/health || exit 1

CMD ["gunicorn", "–bind", "0.0.0.0:8000", "–workers", "4", "app:app"]

1.3.2 Go 应用多阶段构建

# ====== 第一阶段:编译 ======
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 安装依赖
COPY go.mod go.sum ./
RUN go mod download

# 编译(静态链接)
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server .

# ====== 第二阶段:运行 ======
FROM scratch

# 从 builder 阶段复制证书(HTTPS 请求需要)
COPY –from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# 复制编译好的二进制文件
COPY –from=builder /app/server /server

EXPOSE 8080

ENTRYPOINT ["/server"]

1.3.3 Node.js 应用多阶段构建

# ====== 第一阶段:安装依赖 ======
FROM node:18-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci –only=production && \\
cp -R node_modules /prod_modules && \\
npm ci

# ====== 第二阶段:构建 ======
FROM node:18-alpine AS builder
WORKDIR /app
COPY –from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# ====== 第三阶段:运行 ======
FROM node:18-alpine AS runtime
WORKDIR /app

RUN addgroup -g 1001 -S appuser && \\
adduser -S appuser -u 1001

COPY –from=deps /prod_modules ./node_modules
COPY –from=builder /app/dist ./dist
COPY –from=builder /app/package.json ./

USER appuser

EXPOSE 3000

HEALTHCHECK –interval=30s –timeout=3s \\
CMD wget –no-verbose –tries=1 –spider http://localhost:3000/health || exit 1

CMD ["node", "dist/server.js"]

1.3.4 Java (Spring Boot) 应用多阶段构建

# ====== 第一阶段:构建 ======
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
# 先下载依赖(利用 Docker 缓存层)
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B

# ====== 第二阶段:运行 ======
FROM eclipse-temurin:17-jre-alpine AS runtime
WORKDIR /app

RUN addgroup -g 1001 -S appuser && \\
adduser -S appuser -u 1001

COPY –from=builder /app/target/*.jar app.jar

USER appuser

EXPOSE 8080

HEALTHCHECK –interval=30s –timeout=3s –start-period=30s \\
CMD curl -f http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]

1.3.5 多阶段构建的镜像大小对比
语言不使用多阶段使用多阶段减少比例
Python ~1.2 GB ~150 MB 87%
Go ~1.1 GB ~10 MB 99%
Node.js ~900 MB ~120 MB 87%
Java (Maven) ~1.5 GB ~250 MB 83%
Rust ~2 GB ~15 MB 99%

1.4 Docker 构建 vs Podman 构建 vs Buildah 构建

特性Docker BuildPodman BuildBuildah
命令 docker build podman build buildah bud
需要 Daemon ✅ 是 ❌ 否 ❌ 否
支持 Rootless ✅ 是(v20.10+) ✅ 是 ✅ 是
Dockerfile 兼容 原生 完全兼容 完全兼容
多阶段构建
构建缓存
BuildKit 支持
无 Dockerfile 构建
OCI 镜像输出

# 三种工具的构建命令对比

# Docker
docker build -t myapp:v1 .
docker build -t myapp:v1 –no-cache .
docker build -t myapp:v1 –build-arg VERSION=1.0 .

# Podman
podman build -t myapp:v1 .
podman build -t myapp:v1 –no-cache .
podman build -t myapp:v1 –build-arg VERSION=1.0 .

# Buildah
buildah bud -t myapp:v1 .
buildah bud -t myapp:v1 –no-cache .
buildah bud -t myapp:v1 –build-arg VERSION=1.0 .

1.5 镜像优化最佳实践

1.5.1 层缓存优化

# ❌ 不推荐:每次代码变更都重新安装依赖
COPY . .
RUN pip install -r requirements.txt

# ✅ 推荐:先复制依赖文件,利用缓存
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

1.5.2 减少镜像层数

# ❌ 不推荐:每个命令一层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*

# ✅ 推荐:合并为一层
RUN apt-get update && \\
apt-get install -y –no-install-recommends curl wget && \\
apt-get clean && \\
rm -rf /var/lib/apt/lists/*

1.5.3 选择合适的基础镜像

镜像大小对比(以 Python 为例):

python:3.11 ~925 MB ← 完整版(包含大量不必要的工具)
python:3.11-slim ~150 MB ← 精简版(推荐大多数场景)
python:3.11-alpine ~50 MB ← 最小版(需要处理 musl 兼容性)

node:18 ~1.0 GB
node:18-slim ~190 MB
node:18-alpine ~170 MB

golang:1.21 ~820 MB
golang:1.21-alpine ~260 MB
scratch ~0 MB ← Go 静态编译的最佳选择

1.5.4 使用 .dockerignore

# .dockerignore 完整示例
.git
.gitignore
.env
.env.*
*.md
LICENSE
README*
__pycache__
*.pyc
*.pyo
.pytest_cache
.mypy_cache
.tox
.venv
venv
node_modules
.npm
dist
build
*.log
.DS_Store
.vscode
.idea
docker-compose*.yml
Dockerfile*
.dockerignore
tests/
test/
docs/

1.5.5 安全最佳实践

# 1. 使用非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser

# 2. 固定版本号
FROM python:3.11.6-slim # 而不是 python:3.11 或 python:latest

# 3. 不安装不必要的包
RUN apt-get install -y –no-install-recommends curl

# 4. 使用 COPY 而不是 ADD(除非需要解压)
COPY app.py /app/ # 而不是 ADD app.py /app/

# 5. 不在镜像中存储密钥
# ❌ 错误做法
COPY secret.key /app/
ENV DB_PASSWORD=mysecretpassword

# ✅ 正确做法:使用运行时环境变量或挂载
# docker run -e DB_PASSWORD=xxx -v secret:/run/secrets myapp


第二部分:单容器服务部署

2.1 Docker 运行容器

# 基本运行
docker run nginx # 前台运行
docker run -d nginx # 后台运行(detached)
docker run -d –name myweb nginx # 命名容器
docker run -d -p 8080:80 nginx # 端口映射
docker run -d -p 8080:80 –name myweb nginx # 组合使用

# 环境变量
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8

# 数据卷
docker run -d -v /host/data:/container/data nginx

# 资源限制
docker run -d –memory=512m –cpus=1.5 nginx

# 重启策略
docker run -d –restart=unless-stopped nginx

# 完整示例
docker run -d \\
–name myapp \\
–restart unless-stopped \\
-p 8080:8000 \\
-e APP_ENV=production \\
-e DB_HOST=db.example.com \\
-v /data/myapp/uploads:/app/uploads \\
-v /data/myapp/logs:/app/logs \\
–memory=1g \\
–cpus=2 \\
–health-cmd="curl -f http://localhost:8000/health || exit 1" \\
–health-interval=30s \\
myapp:v1

2.2 Podman 运行容器

# 基本运行(命令与 Docker 完全相同)
podman run nginx
podman run -d nginx
podman run -d –name myweb nginx
podman run -d -p 8080:80 nginx

# 环境变量
podman run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8

# 数据卷
podman run -d -v /host/data:/container/data nginx

# 资源限制
podman run -d –memory=512m –cpus=1.5 nginx

# 重启策略
podman run -d –restart=unless-stopped nginx

# Rootless 模式(Podman 默认,无需 root 权限)
podman run -d -p 8080:80 nginx # 直接运行,无需 sudo

# 系统化服务(Podman 独有优势)
podman run -d –name myapp \\
–label "io.containers.autoupdate=registry" \\
myapp:v1

2.3 容器网络配置

2.3.1 Docker 网络

# 网络类型
docker network ls # 查看所有网络
docker network create mynet # 创建自定义网络
docker network create –subnet=172.20.0.0/16 mynet # 指定子网
docker network create –driver bridge mynet # 桥接网络(默认)

# 容器加入网络
docker run -d –name web –network mynet nginx
docker network connect mynet existing_container
docker network disconnect mynet existing_container

# 容器间通信(同一网络中可用容器名作为主机名)
docker run -d –name db –network mynet postgres
docker run -d –name app –network mynet myapp
# app 中可以直接用 db:5432 连接数据库

2.3.2 Podman 网络

# 网络操作(与 Docker 兼容)
podman network ls
podman network create mynet
podman network create –subnet=172.20.0.0/16 mynet

# Rootless 网络
# Podman Rootless 使用 slirp4netns 或 pasta 作为网络栈
podman run -d –name web -p 8080:80 nginx

# 查看网络配置
podman network inspect mynet

# 删除网络
podman network rm mynet
podman network prune

2.3.3 端口映射详解

# 基本映射
-p 8080:80 # 宿主机 8080 -> 容器 80
-p 127.0.0.1:8080:80 # 只监听本地
-p 8080:80/udp # UDP 协议
-p 8080-8090:80-90 # 端口范围映射

# 查看端口映射
docker port container_name
podman port container_name

2.4 数据持久化(Volume)

2.4.1 Docker Volume

# 命名卷(推荐,Docker 管理存储位置)
docker volume create mydata
docker run -d -v mydata:/var/lib/mysql mysql:8
docker volume ls
docker volume inspect mydata
docker volume rm mydata

# 绑定挂载(直接映射宿主机目录)
docker run -d -v /host/path:/container/path nginx
docker run -d -v $(pwd)/config:/app/config:ro nginx # 只读挂载

# tmpfs 挂载(内存中的临时文件系统)
docker run -d –tmpfs /tmp:rw,size=100m nginx

# 匿名卷
docker run -d -v /var/lib/mysql mysql:8
# Docker 自动创建匿名卷

2.4.2 Podman Volume

# 命名卷
podman volume create mydata
podman run -d -v mydata:/var/lib/mysql mysql:8
podman volume ls
podman volume inspect mydata
podman volume rm mydata

# 绑定挂载
podman run -d -v /host/path:/container/path nginx

# Rootless Volume 注意事项
# Podman Rootless 模式下,Volume 存储在用户目录中
# 路径通常为: ~/.local/share/containers/storage/volumes/

# 使用 :Z 或 :z 标签处理 SELinux 标签
podman run -d -v /host/data:/data:Z nginx # 独占标签
podman run -d -v /host/data:/data:z nginx # 共享标签

2.5 环境变量与配置管理

# 传递环境变量
# 方式 1:-e 参数
docker run -d -e DB_HOST=localhost -e DB_PORT=5432 myapp

# 方式 2:环境变量文件
# .env 文件内容:
# DB_HOST=localhost
# DB_PORT=5432
# DB_PASSWORD=secret
docker run -d –env-file .env myapp

# 方式 3:从文件读取单个变量
docker run -d -e DB_PASSWORD=$(cat /path/to/password.txt) myapp

# Docker/Podman 通用
podman run -d -e DB_HOST=localhost myapp
podman run -d –env-file .env myapp

# 配置文件挂载
# 方式 1:绑定挂载配置文件
docker run -d \\
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \\
-v $(pwd)/conf.d:/etc/nginx/conf.d:ro \\
nginx

# 方式 2:使用 Docker Config(Swarm 模式)
# 方式 3:使用 Kubernetes ConfigMap

2.6 容器日志管理

# 查看日志
docker logs container_name
docker logs -f container_name # 实时跟踪
docker logs –tail 100 container_name # 最后 100 行
docker logs –since 1h container_name # 最近 1 小时
docker logs –since 2024-01-01 container_name

# Podman 日志
podman logs container_name
podman logs -f container_name
podman logs –tail 100 container_name

# 日志驱动配置
docker run -d \\
–log-driver=json-file \\
–log-opt max-size=10m \\
–log-opt max-file=3 \\
nginx

# 常用日志驱动
# json-file – 默认,JSON 格式文件
# syslog – 发送到 syslog
# journald – 发送到 systemd journal(Podman 默认)
# fluentd – 发送到 Fluentd
# awslogs – 发送到 AWS CloudWatch

2.7 容器资源限制

# 内存限制
docker run -d –memory=512m nginx # 限制 512MB
docker run -d –memory=512m –memory-swap=1g nginx # 内存+交换共 1GB
docker run -d –memory=512m –oom-kill-disable nginx # 禁用 OOM Kill

# CPU 限制
docker run -d –cpus=1.5 nginx # 限制 1.5 个 CPU 核心
docker run -d –cpu-shares=512 nginx # CPU 份额(相对权重)
docker run -d –cpuset-cpus="0,1" nginx # 绑定到 CPU 0 和 1

# IO 限制
docker run -d –device-read-bps /dev/sda:1mb nginx # 读取限速
docker run -d –device-write-bps /dev/sda:1mb nginx # 写入限速

# PID 限制
docker run -d –pids-limit=100 nginx # 限制最多 100 个进程

# Podman 资源限制(相同语法)
podman run -d –memory=512m –cpus=1.5 nginx

2.8 健康检查

# Dockerfile 中定义
HEALTHCHECK –interval=30s –timeout=3s –start-period=10s –retries=3 \\
CMD curl -f http://localhost:8080/health || exit 1

# 运行时覆盖健康检查
docker run -d \\
–health-cmd="curl -f http://localhost/health || exit 1" \\
–health-interval=10s \\
–health-timeout=5s \\
–health-start-period=30s \\
–health-retries=3 \\
nginx

# 查看健康状态
docker inspect –format='{{.State.Health.Status}}' container_name
# 输出: healthy / unhealthy / starting

# 各语言健康检查示例
# Python (Flask)
HEALTHCHECK CMD curl -f http://localhost:5000/health || exit 1

# Node.js (Express)
HEALTHCHECK CMD wget –no-verbose –tries=1 –spider http://localhost:3000/health || exit 1

# Java (Spring Boot)
HEALTHCHECK CMD curl -f http://localhost:8080/actuator/health || exit 1

# Go
HEALTHCHECK CMD curl -f http://localhost:8080/healthz || exit 1

# MySQL
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1

# PostgreSQL
HEALTHCHECK CMD pg_isready -U postgres || exit 1

# Redis
HEALTHCHECK CMD redis-cli ping || exit 1

# Nginx
HEALTHCHECK CMD curl -f http://localhost/ || exit 1


第三部分:Docker Compose 多服务编排

3.1 Docker Compose 概述

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件来配置应用的所有服务,然后一条命令就能创建并启动所有服务。

核心概念:

  • Service(服务):一个容器的配置模板
  • Network(网络):服务间通信的网络
  • Volume(卷):数据持久化
  • Project(项目):一组相关服务的集合

版本演变:

版本Docker 版本要求特点
v1 Docker 1.6+ 最初版本,功能有限
v2 Docker 1.10+ 引入 networks 和 volumes
v3 Docker 1.13+ 支持 Swarm 部署
Compose V2 Docker 20.10+ 用 Go 重写,作为 Docker CLI 插件

# 安装 Docker Compose
# 方式 1:Docker Desktop 自带(Windows/macOS)

# 方式 2:Linux 手动安装
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)$(uname -m)" \\
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 方式 3:Docker Compose V2(推荐,作为 Docker CLI 插件)
# Docker Desktop 已包含,Linux 需要单独安装
docker compose version

3.2 docker-compose.yml 完整语法

3.2.1 基础结构

# docker-compose.yml 完整语法参考
version: "3.8" # Compose 文件版本(Compose V2 中可省略)

services:
# 服务定义
service_name:
image: nginx:latest # 使用已有镜像
# 或
build: # 从 Dockerfile 构建
context: . # 构建上下文
dockerfile: Dockerfile # 指定 Dockerfile
args: # 构建参数
VERSION: "1.0"
target: runtime # 多阶段构建目标阶段
cache_from: # 缓存来源
myapp:latest

container_name: my_container # 容器名称
hostname: myhost # 主机名

ports: # 端口映射
"8080:80"
"443:443"
"127.0.0.1:3306:3306"

volumes: # 卷挂载
./data:/app/data # 绑定挂载
myvolume:/app/persist # 命名卷
./config/nginx.conf:/etc/nginx/nginx.conf:ro # 只读挂载

environment: # 环境变量
DB_HOST=db
DB_PORT=5432
APP_ENV=production

env_file: # 环境变量文件
.env

depends_on: # 依赖关系
db:
condition: service_healthy # 等待健康检查通过
redis:
condition: service_started

networks: # 加入的网络
frontend
backend

restart: unlessstopped # 重启策略
# no / always / on-failure / unless-stopped

deploy: # 部署配置
resources:
limits:
cpus: "2.0"
memory: 1G
reservations:
cpus: "0.5"
memory: 256M
replicas: 2 # 副本数(Swarm 模式)

healthcheck: # 健康检查
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

logging: # 日志配置
driver: jsonfile
options:
max-size: "10m"
max-file: "3"

labels: # 标签
"com.example.description=My Service"

extra_hosts: # 额外 hosts 映射
"somehost:162.242.195.82"

dns: # DNS 配置
8.8.8.8
8.8.4.4

cap_add: # 添加 Linux 能力
NET_ADMIN
cap_drop: # 移除 Linux 能力
ALL

security_opt: # 安全选项
nonewprivileges:true

sysctls: # 内核参数
net.core.somaxconn: 1024

tmpfs: # tmpfs 挂载
/tmp

command: ["python", "app.py"] # 覆盖默认命令
entrypoint: /entrypoint.sh # 覆盖入口点
user: "1000:1000" # 运行用户
working_dir: /app # 工作目录

privileged: false # 特权模式(不推荐)
stdin_open: true # 保持 stdin 打开
tty: true # 分配伪终端

networks:
frontend:
driver: bridge
backend:
driver: bridge
ipam:
config:
subnet: 172.20.0.0/16

volumes:
myvolume:
driver: local
dbdata:
driver: local
driver_opts:
type: none
o: bind
device: /data/db

3.3 完整实战:Web 应用 + 数据库 + 缓存

以下是一个完整的三层应用编排示例:

项目结构:
myproject/
├── app/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app.py
├── nginx/
│ ├── Dockerfile
│ └── nginx.conf
├── docker-compose.yml
├── .env
└── .env.example

3.3.1 应用代码

# app/app.py
import os
from flask import Flask, jsonify
import psycopg2
import redis

app = Flask(__name__)

def get_db():
return psycopg2.connect(
host=os.environ.get("DB_HOST", "db"),
port=os.environ.get("DB_PORT", "5432"),
dbname=os.environ.get("DB_NAME", "myapp"),
user=os.environ.get("DB_USER", "postgres"),
password=os.environ.get("DB_PASSWORD", "secret"),
)

def get_redis():
return redis.Redis(
host=os.environ.get("REDIS_HOST", "redis"),
port=int(os.environ.get("REDIS_PORT", "6379")),
decode_responses=True,
)

@app.route("/health")
def health():
try:
conn = get_db()
conn.close()
r = get_redis()
r.ping()
return jsonify({"status": "healthy"})
except Exception as e:
return jsonify({"status": "unhealthy", "error": str(e)}), 500

@app.route("/")
def index():
r = get_redis()
count = r.incr("visit_count")
return jsonify({"message": "Hello!", "visit_count": count})

@app.route("/users")
def users():
conn = get_db()
cur = conn.cursor()
cur.execute("SELECT id, name, email FROM users")
rows = cur.fetchall()
cur.close()
conn.close()
return jsonify([{"id": r[0], "name": r[1], "email": r[2]} for r in rows])

if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)

# app/requirements.txt
flask==3.0.0
psycopg2-binary==2.9.9
redis==5.0.1
gunicorn==21.2.0

# app/Dockerfile
FROM python:3.11-slim AS builder

WORKDIR /app
RUN apt-get update && \\
apt-get install -y –no-install-recommends gcc libpq-dev && \\
rm -rf /var/lib/apt/lists/*

RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

COPY requirements.txt .
RUN pip install –no-cache-dir -r requirements.txt

FROM python:3.11-slim

RUN apt-get update && \\
apt-get install -y –no-install-recommends libpq5 curl && \\
rm -rf /var/lib/apt/lists/*

COPY –from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

RUN groupadd -r appuser && useradd -r -g appuser -d /app appuser
WORKDIR /app
COPY –chown=appuser:appuser . .
USER appuser

EXPOSE 5000

HEALTHCHECK –interval=30s –timeout=3s –start-period=10s –retries=3 \\
CMD curl -f http://localhost:5000/health || exit 1

CMD ["gunicorn", "–bind", "0.0.0.0:5000", "–workers", "4", "–timeout", "120", "app:app"]

3.3.2 Nginx 配置

# nginx/nginx.conf
upstream app {
server app:5000;
}

server {
listen 80;
server_name _;

# Gzip 压缩
gzip on;
gzip_types text/plain application/json application/javascript text/css;

# 静态文件
location /static/ {
alias /app/static/;
expires 30d;
}

# API 代理
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 10s;
proxy_read_timeout 120s;
}

# 健康检查
location /nginx-health {
return 200 "OK";
add_header Content-Type text/plain;
}
}

# nginx/Dockerfile
FROM nginx:1.25-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
HEALTHCHECK –interval=30s –timeout=3s \\
CMD curl -f http://localhost/nginx-health || exit 1

3.3.3 Docker Compose 完整配置

# docker-compose.yml
version: "3.8"

services:
# ====== Nginx 反向代理 ======
nginx:
build: ./nginx
container_name: myproject_nginx
ports:
"80:80"
depends_on:
app:
condition: service_healthy
networks:
frontend
restart: unlessstopped
logging:
driver: jsonfile
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 256M

# ====== Python 应用 ======
app:
build:
context: ./app
target: builder # 如果有多阶段构建
container_name: myproject_app
environment:
DB_HOST=db
DB_PORT=5432
DB_NAME=${DB_NAME:myapp}
DB_USER=${DB_USER:postgres}
DB_PASSWORD=${DB_PASSWORD:secret}
REDIS_HOST=redis
REDIS_PORT=6379
APP_ENV=${APP_ENV:production}
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
app_uploads:/app/uploads
networks:
frontend
backend
restart: unlessstopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"

# ====== PostgreSQL 数据库 ======
db:
image: postgres:15alpine
container_name: myproject_db
environment:
POSTGRES_DB: ${DB_NAME:myapp}
POSTGRES_USER: ${DB_USER:postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:secret}
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
db_data:/var/lib/postgresql/data
./init.sql:/dockerentrypointinitdb.d/init.sql:ro
networks:
backend
restart: unlessstopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-myapp}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
deploy:
resources:
limits:
memory: 512M

# ====== Redis 缓存 ======
redis:
image: redis:7alpine
container_name: myproject_redis
command: redisserver appendonly yes maxmemory 256mb maxmemorypolicy allkeyslru
volumes:
redis_data:/data
networks:
backend
restart: unlessstopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
memory: 256M

networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不对外暴露

volumes:
db_data:
driver: local
redis_data:
driver: local
app_uploads:
driver: local

— init.sql(数据库初始化脚本)
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(200) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO users (name, email) VALUES
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com'),
('王五', 'wangwu@example.com')
ON CONFLICT (email) DO NOTHING;

# .env 文件
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=your_secure_password_here
APP_ENV=production

3.4 Compose 命令大全

# ====== 生命周期管理 ======
docker compose up # 创建并启动所有服务
docker compose up -d # 后台启动
docker compose up –build # 启动前重新构建镜像
docker compose up –force-recreate # 强制重新创建容器
docker compose up –no-deps app # 只启动 app 及其依赖

docker compose down # 停止并删除容器、网络
docker compose down -v # 同时删除卷
docker compose down –rmi all # 同时删除镜像
docker compose down –remove-orphans # 删除孤立容器

docker compose start # 启动已存在的服务
docker compose stop # 停止服务
docker compose restart # 重启服务
docker compose pause # 暂停服务
docker compose unpause # 恢复服务

# ====== 查看状态 ======
docker compose ps # 查看服务状态
docker compose ps -a # 包含已停止的服务
docker compose top # 查看进程
docker compose logs # 查看所有日志
docker compose logs -f # 实时跟踪日志
docker compose logs -f app # 跟踪特定服务日志
docker compose logs –tail 100 app # 最后 100 行

# ====== 扩展与更新 ======
docker compose up -d –scale app=3 # 扩展 app 到 3 个实例
docker compose pull # 拉取最新镜像
docker compose build # 构建镜像
docker compose build –no-cache # 不使用缓存构建

# ====== 执行命令 ======
docker compose exec app bash # 进入容器 Shell
docker compose exec app python manage.py migrate # 执行命令
docker compose run app python test.py # 在新容器中运行命令
docker compose run –rm app pytest # 运行后自动删除容器

# ====== 其他 ======
docker compose config # 验证并查看完整配置
docker compose config –services # 列出所有服务名
docker compose images # 查看使用的镜像
docker compose port app 80 # 查看端口映射
docker compose cp app:/app/logs ./logs # 从容器复制文件

3.5 Compose 环境变量与配置覆盖

3.5.1 环境变量优先级

# 优先级从高到低:
# 1. docker compose run -e 设置的变量
# 2. Shell 环境变量
# 3. .env 文件(位于 docker-compose.yml 同目录)
# 4. docker-compose.yml 中 environment 定义的值
# 5. Dockerfile 中 ENV 定义的值

3.5.2 配置覆盖(Override)

# docker-compose.yml(基础配置)
version: "3.8"
services:
app:
build: ./app
environment:
APP_ENV=development

# docker-compose.prod.yml(生产环境覆盖)
version: "3.8"
services:
app:
environment:
APP_ENV=production
deploy:
replicas: 3
resources:
limits:
memory: 1G

# docker-compose.test.yml(测试环境覆盖)
version: "3.8"
services:
app:
environment:
APP_ENV=test
command: pytest

# 使用覆盖文件
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# 使用环境变量指定覆盖文件
export COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml
docker compose up -d


第四部分:Podman 多服务编排方案

4.1 方案一:podman-compose(兼容 Docker Compose)

podman-compose 是一个用 Python 编写的工具,兼容 Docker Compose 的 YAML 语法,底层使用 Podman 命令。

4.1.1 安装

# pip 安装
pip install podman-compose

# 包管理器安装
# Fedora/RHEL
sudo dnf install podman-compose

# Ubuntu
sudo apt install podman-compose

# 验证安装
podman-compose –version

4.1.2 使用方式

# 使用与 docker-compose 完全相同的命令
podman-compose up -d # 后台启动
podman-compose down # 停止并删除
podman-compose ps # 查看状态
podman-compose logs -f # 查看日志
podman-compose exec app bash # 进入容器
podman-compose build # 构建镜像
podman-compose up -d –build # 构建并启动

4.1.3 使用 Docker Compose 文件

# 同一个 docker-compose.yml 文件可以同时被 docker-compose 和 podman-compose 使用
# 无需修改!

version: "3.8"
services:
web:
image: nginx:alpine
ports:
"80:80"
depends_on:
app
app:
build: ./app
environment:
DB_HOST=db
db:
image: postgres:15alpine
volumes:
pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: secret
volumes:
pgdata:

# Docker 环境
docker-compose up -d

# Podman 环境(同一个文件)
podman-compose up -d

4.1.4 podman-compose 的限制
特性docker-composepodman-compose
基本服务编排
网络管理
卷管理
扩展(scale) ⚠️ 有限支持
Deploy 配置 ✅(Swarm)
Secrets/Configs ✅(Swarm)
Watch 模式 ✅(V2)
Docker Compose V2 插件

4.2 方案二:Podman Pod + Kubernetes YAML

Podman 可以原生使用 Kubernetes YAML 来管理 Pod,这是 Podman 独有的功能。

4.2.1 创建 Pod

# 创建 Pod
podman pod create –name myapp -p 80:80 -p 443:443

# 查看 Pod
podman pod ls
podman pod inspect myapp

# 在 Pod 中运行容器
podman run -d –pod myapp –name nginx nginx:alpine
podman run -d –pod myapp –name app myapp:v1

# Pod 中的容器共享网络命名空间
# nginx 可以直接通过 localhost:5000 访问 app

4.2.2 生成 Kubernetes YAML

# 从现有 Pod 生成 K8s YAML
podman generate kube myapp > myapp.yaml

# 查看生成的 YAML
cat myapp.yaml

# myapp.yaml(podman generate kube 生成的)
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-4.7.0
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2024-01-01T00:00:00Z"
labels:
app: myapp
name: myapp
spec:
containers:
image: nginx:alpine
name: nginx
ports:
containerPort: 80
hostPort: 80
image: myapp:v1
name: app
env:
name: DB_HOST
value: db

4.2.3 从 Kubernetes YAML 创建 Pod

# 使用 K8s YAML 创建 Pod
podman play kube myapp.yaml

# 停止并删除
podman play kube –down myapp.yaml

4.2.4 完整的多服务 K8s YAML 示例

# myproject.yaml
apiVersion: v1
kind: Pod
metadata:
name: myproject
labels:
app: myproject
spec:
containers:
# Nginx 反向代理
name: nginx
image: nginx:1.25alpine
ports:
containerPort: 80
hostPort: 80
protocol: TCP
volumeMounts:
name: nginxconfig
mountPath: /etc/nginx/conf.d
readOnly: true

# Python 应用
name: app
image: myapp:v1
env:
name: DB_HOST
value: localhost
name: REDIS_HOST
value: localhost
name: APP_ENV
value: production

# Redis(与应用在同一 Pod 中共享网络)
name: redis
image: redis:7alpine
command: ["redis-server", "–appendonly", "yes"]

volumes:
name: nginxconfig
hostPath:
path: /path/to/nginx/conf.d
type: Directory

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dbdata
spec:
accessModes:
ReadWriteOnce
resources:
requests:
storage: 10Gi

# 创建
podman play kube myproject.yaml

# 生成 YAML 用于 Kubernetes 部署
podman generate kube myproject > k8s-deploy.yaml
# 可以直接用于 kubectl apply -f k8s-deploy.yaml

4.3 方案三:Quadlet(systemd 集成,Podman 4.4+)

Quadlet 是 Podman 4.4 引入的新特性,允许使用 systemd 原生的方式来管理容器。这是生产环境中推荐的 Podman 部署方式。

4.3.1 为什么使用 Quadlet
特性docker-composepodman-composeQuadlet
系统服务管理 ✅ systemd
开机自启 需配置 需配置 ✅ 原生
日志管理 自带 自带 ✅ journald
资源控制 Docker 内部 Podman 内部 ✅ cgroup
Rootless 支持
依赖管理 服务间 服务间 ✅ systemd 级别
4.3.2 Quadlet 文件位置

# 系统级(root 用户)
/etc/containers/systemd/

# 用户级(Rootless,推荐)
~/.config/containers/systemd/

4.3.3 Container 单元文件

# ~/.config/containers/systemd/myapp.container
[Unit]
Description=My Application Container
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/library/nginx:alpine
ContainerName=myapp_nginx
PublishPort=80:80
Volume=myapp_data.volume:/data:ro
Network=myapp.network
Environment=APP_ENV=production
AutoUpdate=registry # 自动更新镜像

[Service]
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

# 重载 systemd 配置
systemctl –user daemon-reload

# 启动容器服务
systemctl –user start myapp.container

# 查看状态
systemctl –user status myapp.container

# 查看日志
journalctl –user -u myapp.container -f

# 开机自启
systemctl –user enable myapp.container

4.3.4 多服务编排(Volume + Network + Container)

# ~/.config/containers/systemd/myapp-db.volume
[Volume]
VolumeName=myapp_db_data

# ~/.config/containers/systemd/myapp-redis.volume
[Volume]
VolumeName=myapp_redis_data

# ~/.config/containers/systemd/myapp.network
[Network]
NetworkName=myapp_net
Subnet=172.20.0.0/16
Gateway=172.20.0.1

# ~/.config/containers/systemd/myapp-db.container
[Unit]
Description=MyApp PostgreSQL Database
After=network-online.target

[Container]
Image=docker.io/library/postgres:15-alpine
ContainerName=myapp_db
Volume=myapp_db.volume:/var/lib/postgresql/data
Network=myapp.network
Environment=POSTGRES_DB=myapp
Environment=POSTGRES_USER=postgres
Environment=POSTGRES_PASSWORD=secret
HealthCmd=pg_isready -U postgres
HealthInterval=10s
HealthRetries=5

[Service]
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

# ~/.config/containers/systemd/myapp-redis.container
[Unit]
Description=MyApp Redis Cache
After=network-online.target

[Container]
Image=docker.io/library/redis:7-alpine
ContainerName=myapp_redis
Volume=myapp_redis.volume:/data
Network=myapp.network
Exec=redis-server –appendonly yes
HealthCmd=redis-cli ping
HealthInterval=10s

[Service]
Restart=always

[Install]
WantedBy=default.target

# ~/.config/containers/systemd/myapp-app.container
[Unit]
Description=MyApp Application
After=myapp-db.container myapp-redis.container

[Container]
Image=localhost/myapp:v1
ContainerName=myapp_app
Network=myapp.network
PublishPort=5000:5000
Volume=myapp_uploads.volume:/app/uploads
Environment=DB_HOST=myapp_db
Environment=REDIS_HOST=myapp_redis
Environment=DB_PASSWORD=secret
HealthCmd=curl -f http://localhost:5000/health
HealthInterval=30s
HealthRetries=3
AutoUpdate=registry

[Service]
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

# ~/.config/containers/systemd/myapp-nginx.container
[Unit]
Description=MyApp Nginx Proxy
After=myapp-app.container

[Container]
Image=docker.io/library/nginx:1.25-alpine
ContainerName=myapp_nginx
PublishPort=80:80
Network=myapp.network
Volume=./nginx.conf:/etc/nginx/conf.d/default.conf:ro
HealthCmd=curl -f http://localhost/nginx-health

[Service]
Restart=always

[Install]
WantedBy=default.target

# 部署所有服务
systemctl –user daemon-reload

# 按顺序启动
systemctl –user start myapp-db.container
systemctl –user start myapp-redis.container
systemctl –user start myapp-app.container
systemctl –user start myapp-nginx.container

# 或一次性启动所有
systemctl –user start myapp-*.container

# 查看所有容器服务状态
systemctl –user list-units 'myapp-*'

# 启用开机自启
systemctl –user enable myapp-*.container

# 如果需要在系统启动时就运行(不登录也运行)
sudo loginctl enable-linger $(whoami)

4.3.5 Quadlet 使用 .pod 文件(Pod 单元)

# ~/.config/containers/systemd/myapp.pod
[Pod]
PodName=myapp
PublishPort=80:80
PublishPort=443:443

[Install]
WantedBy=default.target

4.4 方案四:直接使用 Podman CLI 编排

对于简单的场景,可以直接用 Shell 脚本结合 Podman 命令来编排服务。

#!/bin/bash
# deploy.sh – 使用 Podman CLI 部署多服务应用

set -e

# 创建网络
podman network create myapp_net 2>/dev/null || true

# 创建卷
podman volume create myapp_db_data 2>/dev/null || true
podman volume create myapp_redis_data 2>/dev/null || true

# 启动数据库
echo "启动 PostgreSQL…"
podman run -d \\
–name myapp_db \\
–network myapp_net \\
-v myapp_db_data:/var/lib/postgresql/data \\
-e POSTGRES_DB=myapp \\
-e POSTGRES_USER=postgres \\
-e POSTGRES_PASSWORD=secret \\
–restart unless-stopped \\
postgres:15-alpine

# 等待数据库就绪
echo "等待数据库就绪…"
sleep 5
for i in {1..30}; do
if podman exec myapp_db pg_isready -U postgres; then
echo "数据库就绪"
break
fi
echo "等待中… ($i/30)"
sleep 2
done

# 启动 Redis
echo "启动 Redis…"
podman run -d \\
–name myapp_redis \\
–network myapp_net \\
-v myapp_redis_data:/data \\
–restart unless-stopped \\
redis:7-alpine redis-server –appendonly yes

# 启动应用
echo "启动应用…"
podman run -d \\
–name myapp_app \\
–network myapp_net \\
-e DB_HOST=myapp_db \\
-e REDIS_HOST=myapp_redis \\
-e DB_PASSWORD=secret \\
–restart unless-stopped \\
myapp:v1

# 启动 Nginx
echo "启动 Nginx…"
podman run -d \\
–name myapp_nginx \\
–network myapp_net \\
-p 80:80 \\
-v ./nginx.conf:/etc/nginx/conf.d/default.conf:ro \\
–restart unless-stopped \\
nginx:1.25-alpine

echo "部署完成!"
echo "查看状态: podman ps"
echo "查看日志: podman logs -f myapp_app"

# 停止脚本
#!/bin/bash
# stop.sh
podman stop myapp_nginx myapp_app myapp_redis myapp_db
podman rm myapp_nginx myapp_app myapp_redis myapp_db
echo "所有服务已停止并删除"

4.5 四种方案对比与选择建议

维度podman-composeK8s YAML + PodQuadletCLI 脚本
学习成本 低(兼容 Compose) 中高
生产就绪 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐
systemd 集成 ✅ 原生
开机自启 需额外配置 需额外配置 ✅ 原生 需额外配置
向 K8s 迁移 ✅ YAML 可复用
复杂场景支持 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐
Rootless 支持

选择建议:

场景推荐方案
从 Docker Compose 迁移 podman-compose(最平滑)
开发环境快速编排 podman-compose
未来要迁移到 K8s Podman Pod + K8s YAML
Linux 生产环境 Quadlet(首选推荐)
简单脚本部署 CLI 脚本
CI/CD 环境 podman-compose 或 CLI

第五部分:Buildah 构建镜像(Podman 生态)

5.1 Buildah 简介与安装

# 安装 Buildah
# Fedora/RHEL
sudo dnf install buildah

# Ubuntu
sudo apt install buildah

# 验证
buildah version

5.2 使用 Dockerfile 构建

# 与 Docker Build 完全兼容
buildah bud -t myapp:v1 .
buildah bud -t myapp:v1 -f Dockerfile.prod .
buildah bud -t myapp:v1 –no-cache .
buildah bud -t myapp:v1 –build-arg VERSION=1.0 .

# Rootless 构建
buildah bud -t myapp:v1 . # 无需 sudo

# 指定输出格式
buildah bud -t myapp:v1 –format docker . # Docker 格式
buildah bud -t myapp:v1 –format oci . # OCI 格式(默认)

5.3 使用命令行构建(无需 Dockerfile)

Buildah 独有的功能:可以用 Shell 命令逐步构建镜像,无需编写 Dockerfile。

# 从基础镜像创建容器
container=$(buildah from ubuntu:22.04)

# 运行安装命令
buildah run $container apt-get update
buildah run $container apt-get install -y python3 python3-pip
buildah run $container pip3 install flask

# 复制文件
buildah copy $container app.py /app/app.py

# 配置
buildah config –workingdir /app $container
buildah config –port 5000 $container
buildah config –cmd "python3 /app/app.py" $container
buildah config –env APP_ENV=production $container

# 提交为镜像
buildah commit $container myapp:v1

# 清理
buildah rm $container

# 运行
podman run -d -p 5000:5000 myapp:v1

# 完整的 Buildah 脚本构建示例
#!/bin/bash
set -e

# 创建容器
container=$(buildah from python:3.11-slim)

# 安装系统依赖
buildah run $containerbash -c "apt-get update && \\
apt-get install -y –no-install-recommends curl gcc && \\
rm -rf /var/lib/apt/lists/*"

# 创建应用目录
buildah run $container mkdir -p /app

# 复制文件
buildah copy $container requirements.txt /app/
buildah copy $container app.py /app/

# 安装 Python 依赖
buildah run $container — pip install –no-cache-dir -r /app/requirements.txt

# 创建用户
buildah run $containeruseradd -m appuser

# 配置
buildah config –workingdir /app $container
buildah config –user appuser $container
buildah config –port 5000 $container
buildah config –cmd "python app.py" $container

# 添加元数据
buildah config –label maintainer="dev@example.com" $container
buildah config –label version="1.0" $container

# 提交
buildah commit –rm $container myapp:v1

echo "镜像构建完成: myapp:v1"

5.4 Buildah 与 Docker Build 的差异

特性Docker BuildBuildah
需要 Daemon
需要 Dockerfile ❌(支持命令行构建)
Rootless ✅(v20.10+) ✅ 原生
多阶段构建
构建缓存
BuildKit 特性
OCI 镜像格式
Docker 格式
镜像推送到仓库 docker push buildah push

# Buildah 推送镜像
buildah push myapp:v1 docker://registry.example.com/myapp:v1
buildah push myapp:v1 docker://docker.io/user/myapp:v1

# 使用 Skopeo 推送
skopeo copy containers-storage:myapp:v1 docker://docker.io/user/myapp:v1


第六部分:生产环境部署实践

6.1 完整项目部署示例(前后端 + 数据库)

假设我们要部署一个包含以下组件的完整应用:

  • 前端:React SPA(Nginx 托管)
  • 后端:Python Flask API
  • 数据库:PostgreSQL
  • 缓存:Redis
  • 任务队列:Celery Worker

6.2 Docker 部署方案

# docker-compose.yml
version: "3.8"

services:
nginx:
image: nginx:1.25alpine
ports:
"80:80"
"443:443"
volumes:
./nginx/conf.d:/etc/nginx/conf.d:ro
./nginx/ssl:/etc/nginx/ssl:ro
frontend_build:/usr/share/nginx/html:ro
depends_on:
backend
restart: unlessstopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/nginx-health"]
interval: 30s
timeout: 3s

backend:
build:
context: ./backend
dockerfile: Dockerfile
environment:
DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@db:5432/${DB_NAME}
REDIS_URL=redis://redis:6379/0
SECRET_KEY=${SECRET_KEY}
CELERY_BROKER_URL=redis://redis:6379/1
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
backend_uploads:/app/uploads
restart: unlessstopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 5s
start_period: 20s

celery_worker:
build:
context: ./backend
dockerfile: Dockerfile
command: celery A app.celery worker loglevel=info concurrency=4
environment:
DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@db:5432/${DB_NAME}
REDIS_URL=redis://redis:6379/0
CELERY_BROKER_URL=redis://redis:6379/1
depends_on:
backend
restart: unlessstopped

db:
image: postgres:15alpine
environment:
POSTGRES_DB: ${DB_NAME:myapp}
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
db_data:/var/lib/postgresql/data
./db/init.sql:/dockerentrypointinitdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5

redis:
image: redis:7alpine
command: redisserver appendonly yes maxmemory 512mb
volumes:
redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s

# 定时备份
backup:
image: postgres:15alpine
volumes:
./backups:/backups
./scripts/backup.sh:/backup.sh:ro
environment:
PGHOST=db
PGUSER=postgres
PGPASSWORD=${DB_PASSWORD}
PGDATABASE=${DB_NAME:myapp}
entrypoint: /bin/sh
command: c "echo '0 2 * * * /backup.sh' | crontab && crond f l 8"
depends_on:
db
restart: unlessstopped

volumes:
db_data:
redis_data:
backend_uploads:
frontend_build:

networks:
default:
driver: bridge

# 部署命令
# 1. 准备环境变量
cp .env.example .env
vim .env # 修改密码等配置

# 2. 构建并启动
docker compose up -d –build

# 3. 查看状态
docker compose ps

# 4. 查看日志
docker compose logs -f

# 5. 数据库迁移
docker compose exec backend flask db upgrade

# 6. 停止
docker compose down

# 7. 停止并清除数据(谨慎!)
docker compose down -v

6.3 Podman 部署方案

方案 A:使用 podman-compose(最简单迁移)

# 直接使用相同的 docker-compose.yml
pip install podman-compose
podman-compose up -d –build
podman-compose ps
podman-compose logs -f

方案 B:使用 Quadlet(生产推荐)

# ~/.config/containers/systemd/app-network.network
[Network]
NetworkName=app_net

# ~/.config/containers/systemd/app-db.volume
[Volume]
VolumeName=app_db_data

# ~/.config/containers/systemd/app-redis.volume
[Volume]
VolumeName=app_redis_data

# ~/.config/containers/systemd/app-db.container
[Unit]
Description=PostgreSQL Database
After=network-online.target

[Container]
Image=docker.io/library/postgres:15-alpine
ContainerName=app_db
Volume=app-db.volume:/var/lib/postgresql/data
Volume=./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
Network=app.network
Environment=POSTGRES_DB=myapp
Environment=POSTGRES_USER=postgres
Environment=POSTGRES_PASSWORD=secure_password
HealthCmd=pg_isready -U postgres
HealthInterval=10s
HealthRetries=5

[Service]
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

# ~/.config/containers/systemd/app-redis.container
[Unit]
Description=Redis Cache
After=network-online.target

[Container]
Image=docker.io/library/redis:7-alpine
ContainerName=app_redis
Volume=app-redis.volume:/data
Network=app.network
Exec=redis-server –appendonly yes –maxmemory 512mb
HealthCmd=redis-cli ping
HealthInterval=10s

[Service]
Restart=always

[Install]
WantedBy=default.target

# ~/.config/containers/systemd/app-backend.container
[Unit]
Description=Backend API
After=app-db.container app-redis.container

[Container]
Image=localhost/app-backend:v1
ContainerName=app_backend
Network=app.network
PublishPort=5000:5000
Volume=app_uploads.volume:/app/uploads
Environment=DATABASE_URL=postgresql://postgres:secure_password@app_db:5432/myapp
Environment=REDIS_URL=redis://app_redis:6379/0
HealthCmd=curl -f http://localhost:5000/health
HealthInterval=30s
HealthRetries=3
AutoUpdate=registry

[Service]
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

# ~/.config/containers/systemd/app-nginx.container
[Unit]
Description=Nginx Frontend
After=app-backend.container

[Container]
Image=docker.io/library/nginx:1.25-alpine
ContainerName=app_nginx
PublishPort=80:80
PublishPort=443:443
Network=app.network
Volume=./nginx/conf.d:/etc/nginx/conf.d:ro
Volume=frontend_build.volume:/usr/share/nginx/html:ro
HealthCmd=curl -f http://localhost/nginx-health

[Service]
Restart=always

[Install]
WantedBy=default.target

# 部署命令
systemctl –user daemon-reload

# 启动所有服务
systemctl –user start app-db.container
systemctl –user start app-redis.container
# 等待数据库就绪
sleep 10
systemctl –user start app-backend.container
systemctl –user start app-nginx.container

# 开机自启
systemctl –user enable app-*.container
sudo loginctl enable-linger $(whoami)

# 查看状态
systemctl –user list-units 'app-*'
journalctl –user -u app-backend.container -f

6.4 自动化部署脚本

#!/bin/bash
# deploy.sh – 通用部署脚本(支持 Docker 和 Podman)

set -euo pipefail

# ====== 配置 ======
PROJECT_NAME="myproject"
COMPOSE_FILE="docker-compose.yml"
ENV_FILE=".env"

# ====== 检测容器引擎 ======
if command -v podman &> /dev/null; then
ENGINE="podman"
COMPOSE="podman-compose"
echo "使用 Podman 引擎"
elif command -v docker &> /dev/null; then
ENGINE="docker"
COMPOSE="docker compose"
echo "使用 Docker 引擎"
else
echo "错误:未安装 Docker 或 Podman"
exit 1
fi

# ====== 检查环境文件 ======
if [ ! -f "$ENV_FILE" ]; then
if [ -f ".env.example" ]; then
echo "警告:.env 文件不存在,从 .env.example 复制"
cp .env.example .env
echo "请编辑 .env 文件后重新运行"
exit 1
fi
fi

# ====== 构建镜像 ======
echo "构建镜像…"
$COMPOSE -f $COMPOSE_FILE build

# ====== 备份数据库 ======
if $ENGINE ps –format '{{.Names}}' | grep -q "${PROJECT_NAME}_db"; then
echo "备份数据库…"
BACKUP_FILE="backups/db_$(date +%Y%m%d_%H%M%S).sql"
mkdir -p backups
$ENGINE exec ${PROJECT_NAME}_db pg_dump -U postgres myapp > "$BACKUP_FILE"
echo "数据库备份: $BACKUP_FILE"
fi

# ====== 部署 ======
echo "部署服务…"
$COMPOSE -f $COMPOSE_FILE up -d –remove-orphans

# ====== 等待健康检查 ======
echo "等待服务就绪…"
MAX_WAIT=120
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
HEALTHY=$($ENGINE ps –filter "health=healthy" –format '{{.Names}}' | wc -l)
TOTAL=$($ENGINE ps –format '{{.Names}}' | wc -l)
echo " 就绪: $HEALTHY/$TOTAL ($ELAPSED/${MAX_WAIT}s)"

if [ "$HEALTHY" -eq "$TOTAL" ]; then
echo "所有服务就绪!"
break
fi

sleep 5
ELAPSED=$((ELAPSED + 5))
done

if [ $ELAPSED -ge $MAX_WAIT ]; then
echo "警告:部分服务未就绪,请检查日志"
$COMPOSE logs –tail=20
fi

# ====== 显示状态 ======
echo ""
echo "========================================="
echo " 部署完成"
echo "========================================="
$COMPOSE ps
echo ""
echo "查看日志: $COMPOSE logs -f"
echo "停止服务: $COMPOSE down"

6.5 从 Docker 迁移到 Podman

6.5.1 命令兼容性

# 最简单的迁移方式:设置别名
alias docker=podman
alias docker-compose=podman-compose

# 或者创建符号链接
sudo ln -s /usr/bin/podman /usr/local/bin/docker

6.5.2 需要注意的差异

# 1. 端口映射(Rootless)
# Docker:直接使用 80 等特权端口(通过 Daemon 的 root 权限)
# Podman Rootless:只能映射 1024 以上的端口
# 解决方案:
# a. 使用非特权端口
podman run -p 8080:80 nginx
# b. 设置内核参数
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
# c. 使用端口转发
podman run -p 80:80 nginx # 如果启用了 ip_unprivileged_port_start

# 2. 存储路径
# Docker: /var/lib/docker/
# Podman: ~/.local/share/containers/ (rootless)
# /var/lib/containers/ (root)

# 3. 日志驱动
# Docker 默认: json-file
# Podman 默认: journald
# 可以在 containers.conf 中配置

# 4. Docker Socket
# Docker: /var/run/docker.sock
# Podman: /run/user/1000/podman/podman.sock (rootless)
# 启用 Podman API:
podman system service –time=0 &

# 5. 镜像名称
# Docker 默认从 Docker Hub 拉取
# Podman 需要指定完整路径
# Docker: nginx (隐含 docker.io/library/nginx)
# Podman: docker.io/library/nginx 或 docker.io/nginx
# 可以配置 registry.conf

6.5.3 配置文件对照
配置DockerPodman
守护进程配置 /etc/docker/daemon.json 无(无守护进程)
容器配置 N/A ~/.config/containers/containers.conf
存储配置 /etc/docker/daemon.json ~/.config/containers/storage.conf
注册表配置 /etc/docker/daemon.json ~/.config/containers/registries.conf

# Podman 容器配置示例
# ~/.config/containers/containers.conf
[containers]
default_sysctls = [
"net.ipv4.ping_group_range=0 0",
]
log_driver = "journald"
dns_servers = ["8.8.8.8", "8.8.4.4"]

[engine]
cgroup_manager = "cgroupfs"
events_logger = "journald"

[network]
network_backend = "netavark"


第七部分:容器镜像仓库管理

7.1 Docker Hub

# 登录
docker login
podman login docker.io

# 标记镜像
docker tag myapp:v1 username/myapp:v1
podman tag myapp:v1 docker.io/username/myapp:v1

# 推送
docker push username/myapp:v1
podman push docker.io/username/myapp:v1

# 拉取
docker pull username/myapp:v1
podman pull docker.io/username/myapp:v1

7.2 私有仓库搭建(Harbor)

# docker-compose.yml for Harbor
# Harbor 使用 Docker Compose 部署
# 安装 Harbor:
# 1. 下载离线安装包
# wget https://github.com/goharbor/harbor/releases/latest/download/harbor-offline-installer-v2.10.0.tgz
# 2. 解压并配置
# tar xzf harbor-offline-installer-*.tgz
# cd harbor
# cp harbor.yml.tmpl harbor.yml
# vim harbor.yml
# 3. 安装
# ./install.sh

# 配置 Harbor 为 Podman 的可信仓库
# /etc/containers/registries.conf
[[registry]]
location = "harbor.example.com"
insecure = false

# 登录 Harbor
podman login harbor.example.com

# 推送镜像
podman tag myapp:v1 harbor.example.com/myproject/myapp:v1
podman push harbor.example.com/myproject/myapp:v1

7.3 Skopeo 镜像管理(Podman 生态)

# 安装 Skopeo
sudo dnf install skopeo # Fedora/RHEL
sudo apt install skopeo # Ubuntu

# 复制镜像(不同仓库之间)
skopeo copy docker://docker.io/library/nginx:latest docker://harbor.example.com/library/nginx:latest

# 检查远程镜像信息
skopeo inspect docker://docker.io/library/nginx:latest
skopeo inspect –format "{{.Architecture}}" docker://docker.io/library/nginx:latest

# 列出镜像标签
skopeo list-tags docker://docker.io/library/nginx

# 删除远程镜像
skopeo delete docker://harbor.example.com/myproject/myapp:v1

# 同步镜像仓库
skopeo sync –src docker –dest docker docker.io/library/nginx harbor.example.com/library

# 传输到本地文件
skopeo copy docker://nginx:latest dir:./nginx-latest
skopeo copy docker-daemon:myapp:v1 oci:./myapp-oci


第八部分:CI/CD 中的容器化部署

8.1 GitHub Actions 中的容器构建

# .github/workflows/build-and-deploy.yml
name: Build and Deploy

on:
push:
branches: [main]
tags: ['v*']

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build:
runs-on: ubuntulatest
permissions:
contents: read
packages: write

steps:
name: Checkout
uses: actions/checkout@v4

# 使用 Docker
name: Build with Docker
run: docker build t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .

# 使用 Podman
name: Build with Podman
run: |
podman build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

# 使用 Docker Compose
name: Test with Docker Compose
run: |
docker compose up -d –build
docker compose ps
sleep 30
curl -f http://localhost/health || (docker compose logs && exit 1)
docker compose down

8.2 GitLab CI 中的容器构建

# .gitlab-ci.yml
stages:
build
test
deploy

variables:
IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

# 使用 Docker 构建
build_docker:
stage: build
image: docker:24
services:
docker:24dind
script:
docker login u $CI_REGISTRY_USER p $CI_REGISTRY_PASSWORD $CI_REGISTRY
docker build t $IMAGE_NAME .
docker push $IMAGE_NAME

# 使用 Podman 构建
build_podman:
stage: build
image: quay.io/podman/stable
script:
podman login u $CI_REGISTRY_USER p $CI_REGISTRY_PASSWORD $CI_REGISTRY
podman build t $IMAGE_NAME .
podman push $IMAGE_NAME

# 使用 Docker Compose 测试
test:
stage: test
image: docker:24
services:
docker:24dind
script:
docker compose up d build
sleep 30
docker compose exec T app pytest
docker compose down

8.3 Jenkins 中的容器构建

// Jenkinsfile
pipeline {
agent any

environment {
REGISTRY = 'harbor.example.com'
IMAGE_NAME = "${REGISTRY}/myproject/myapp"
IMAGE_TAG = "${env.BUILD_NUMBER}"
}

stages {
stage('Build') {
steps {
script {
// Docker 构建
sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."

// 或 Podman 构建
// sh "podman build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
}
}
}

stage('Test') {
steps {
script {
sh """
docker compose up -d –build
sleep 30
docker compose exec -T app pytest
docker compose down
"""

}
}
}

stage('Push') {
steps {
script {
sh """
docker login -u admin -p \\$HARBOR_PASSWORD
${REGISTRY}
docker push
${IMAGE_NAME}:${IMAGE_TAG}
docker tag
${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:latest
docker push
${IMAGE_NAME}:latest
"""

}
}
}

stage('Deploy') {
steps {
script {
sh """
# 使用 Docker Compose 部署
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d –remove-orphans

# 或使用 Podman
# podman-compose -f docker-compose.prod.yml pull
# podman-compose -f docker-compose.prod.yml up -d
"""
}
}
}
}

post {
always {
sh 'docker compose down –remove-orphans || true'
}
}
}


附录:快速参考卡片

A. Docker → Podman 命令映射

docker build → podman build (或 buildah bud)
docker run → podman run
docker ps → podman ps
docker stop → podman stop
docker rm → podman rm
docker rmi → podman rmi
docker pull → podman pull
docker push → podman push
docker exec → podman exec
docker logs → podman logs
docker network → podman network
docker volume → podman volume
docker-compose up → podman-compose up
docker-compose down → podman-compose down

B. 常用组合命令

# 查看所有容器(包含已停止)
docker ps -a
podman ps -a

# 清理所有已停止的容器
docker container prune
podman container prune

# 清理所有未使用的镜像
docker image prune -a
podman image prune -a

# 一键清理所有(容器、网络、镜像、卷)
docker system prune -a –volumes
podman system prune -a –volumes

# 查看容器资源使用
docker stats
podman stats

# 导出/导入容器
docker export container > container.tar
podman export container > container.tar
docker import container.tar newimage:v1
podman import container.tar newimage:v1

# 保存/加载镜像
docker save -o myapp.tar myapp:v1
podman save -o myapp.tar myapp:v1
docker load -i myapp.tar
podman load -i myapp.tar

C. 故障排查

# 容器无法启动
docker logs container_name # 查看日志
podman logs container_name
docker inspect container_name # 查看详细信息
podman inspect container_name

# 容器网络问题
docker network inspect bridge # 查看网络
podman network inspect bridge
docker exec -it container ping # 进入容器调试
podman exec -it container ping

# 镜像构建失败
docker build –no-cache -t myapp . # 不使用缓存
podman build –no-cache -t myapp .
docker build –progress=plain . # 显示详细构建过程
podman build –log-level=debug . # Podman 调试日志

# Podman Rootless 特有问题
podman unshare cat /proc/self/uid_map # 查看 UID 映射
podman info # 查看 Podman 系统信息
podman system migrate # 迁移存储(升级后)

赞(0)
未经允许不得转载:171主机测评 » Docker 与 Podman 服务部署完全指南
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址