Docker Compose 应用部署实战
点击上方按钮下载,压缩包包含:app.py、Dockerfile、compose.yaml、.env 和 .dockerignore。按第 5.1 节下载解压,后续直接使用。
1. Docker 与 Compose 简介
Docker 将程序、运行时和依赖打包为镜像,再由镜像启动容器。容器共享宿主机内核,适合在开发板上部署 Web 服务、数据库和设备数据采集应用。ARM64 板卡需要选择支持该架构的镜像;容器网络、资源限制等功能仍依赖宿主机内核。
Compose 用一份 YAML 文件统一描述多个容器的构建方式、端口、数据卷和启动顺序。镜像保存应用环境,容器负责运行程序,数据卷则让业务数据在容器删除或重建后继续保留。修改配置后,可用同一组命令完成部署、更新和停止。
本篇以 Python + Redis 计数面板为例:Web 容器提供网页和 API,Redis 容器保存计数,两个服务通过 Compose 网络通信。通过重建容器、更新回退和模拟故障,验证数据持久化、健康检查及自动恢复,为部署自己的应用提供参考。
2. 环境准备
2.1 适用范围与实测环境
| 项目 | 实测环境 |
|---|---|
| 板卡 | ArmSoM CM5 + CM5-IO,RK3576,2 GB 内存 |
| 系统 | 官方 Debian 12 arm64 XFCE 镜像 |
| 内核 | 6.1.118-rk3576,补充 raw 表支持后更新 |
| Docker / Compose | Docker Engine 29.9.3 / Docker Compose v5.7.1 |
| 安装前可用存储 | 约 23 GB |
| 访问方式 | 电脑浏览器访问板端 8080 端口 |
适配需要 ARM64 镜像、cgroup、OverlayFS 和容器网络支持。本文已验证 CM5 + Debian 12;其他板型、Ubuntu 和 Armbian 需另行验证。
2.2 网络和操作位置
开发板需要能访问系统软件源、Docker 软件源、Docker Hub 和 Python 包仓库。电脑与开发板连接同一局域网。本文板端命令在 root 终端执行,普通用户可先执行 sudo -i。SDK 配置与编译命令在存放 ArmSoM SDK 的 Linux 主机上执行。
ip -br address
记录 ip -br address 显示的局域网 IPv4 地址,供浏览器访问。
3. 内核配置与更新
Docker 的桥接网络需要内核支持 raw 表。若镜像尚未启用 CONFIG_IP_NF_RAW,先在 SDK 中补充配置并更新内核。
3.1 选择版型并修改配置
在自己的 Linux 主机上,进入存放 ArmSoM SDK 的目录,执行以下命令,按菜单选择对应芯片和版型。以下路径仅为示例,请替换为实际目录。
cd ~/code/armsom-sdk
./build.sh chip
CM5 选择 RK3576 下的 CM5-IO 配置。选好后,可查看当前版型使用的内核配置名称:
grep '^RK_KERNEL_CFG=' output/.config
对应配置文件位于 kernel-6.1/arch/arm64/configs/。例如 CM5 使用 armsom_linux_rk3576_defconfig,打开该文件并添加以下一行;若已有该配置项,将其改为以下值:
CONFIG_IP_NF_RAW=y
3.2 编译并更新内核
在 SDK 根目录执行:
./build.sh kernel-6.1
编译完成后,将生成的 linux-image-*.deb 和 linux-headers-*.deb 两个包复制到板端,按更新内核指南安装并重启。重新登录后确认配置已生效:
zcat /proc/config.gz | grep '^CONFIG_IP_NF_RAW='
输出应为 CONFIG_IP_NF_RAW=y。
已启用该配置的镜像可跳过本章。其他版型应修改其对应的内核配置文件;首次编译 SDK,请先按SDK 构建指南准备主机环境。
4. 安装 Docker
4.1 配置软件源
先按APT 指南检查时间和软件源。已有 Docker 的系统应先按官方说明处理软件包冲突。
apt update
apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
curl -fsSL "https://download.docker.com/linux/$ID/gpg" \
-o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
cat > /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/$ID
Suites: $VERSION_CODENAME
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
这里 ID 应为 debian 或 ubuntu,发行版代号应与系统匹配。Armbian 用户先核对其 Debian/Ubuntu 基础系统,再设置对应软件源。
按APT 指南确认索引更新成功后安装。
apt update
apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
4.2 启动并确认网络后端
示例使用的 CM5 镜像未启用 nftables,使用系统已有的 legacy 后端。若你的镜像已经支持 nftables 且 Docker 正常启动,可直接检查版本。
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
systemctl reset-failed docker
systemctl enable docker
systemctl restart docker
docker version
docker compose version
示例无登录认证,仅用于可信局域网。对外部署需配置访问控制和 HTTPS,并留意 Docker 的防火墙行为。
5. 项目与部署
5.1 下载完整示例
将文章开头的示例压缩包下载并解压到 ~/compose-demo/:
也可点击下载按钮,将 compose-demo.tar.gz 传到板端该目录,跳过 curl,直接执行解压命令。
mkdir -p ~/compose-demo
cd ~/compose-demo
curl -fL https://docs.armsom.org/downloads/docker-compose/compose-demo.tar.gz \
-o compose-demo.tar.gz
tar -xzf compose-demo.tar.gz
项目通过下面的路径工作。
电脑浏览器
→ 开发板 IPv4:8080
→ web:8000(Gunicorn + Flask)
→ redis:6379(Compose 服务名解析)
→ redis-data 数据卷(AOF 持久化)
GET /api/state 查询计数和版本,POST /api/increment 原子增加计数,GET /health 检查 Redis 连通性。页面加载与健康检查不会增加计数。
5.2 Compose 的关键配置
使用压缩包中的 compose.yaml,其中的主要配置如下。
| 配置 | 本例中的作用 |
|---|---|
build / image | 在板端构建 ARM64 Web 镜像,并为版本设置标签 |
ports | 把宿主机 8080 映射到 Web 容器 8000 |
REDIS_HOST: redis | 使用服务名访问数据库,避免固定容器 IP |
depends_on + service_healthy | 首次启动等待 Redis 的健康检查成功 |
volumes | 将 Redis 数据保存到容器生命周期之外 |
restart: unless-stopped | 进程异常退出后重启;手动停止后保持停止 |
mem_limit / cpus | 限制资源使用;实际生效依赖宿主 cgroup 支持 |
logging | 限制每个容器的日志文件大小和保留数量 |
健康检查让 Web 等待 Redis 就绪,详见 Compose 启动顺序。
使用压缩包中的 Dockerfile 构建镜像,依赖版本已固定,Gunicorn 以普通用户运行。
5.3 构建、启动与访问
cd ~/compose-demo
docker compose up -d --build --wait --wait-timeout 120
docker compose ps
curl -fsS http://127.0.0.1:8080/api/state
浏览器打开 http://开发板IP:8080,点击 Add one 增加计数;两个服务应为 healthy。

6. 数据持久化
6.1 重建容器后核对计数
cd ~/compose-demo
curl -fsS http://127.0.0.1:8080/api/state
docker compose down
docker compose up -d --wait --wait-timeout 120
curl -fsS http://127.0.0.1:8080/api/state
docker volume inspect armsom-compose_redis-data --format '{{.Mountpoint}}'
重建后计数应不变。数据卷路径以 inspect 输出为准,源码位于 ~/compose-demo/。
docker compose down -v 会删除数据卷。Redis 每秒同步 AOF,断电可能丢失最近约一秒的写入;本文未测试断电可靠性。
6.2 停机备份
为得到一致的文件备份,先停止 Web 和 Redis,再用临时容器读取数据卷。
cd ~/compose-demo
mkdir -p backups
docker compose stop web redis
docker compose run --rm --no-deps \
-v "$PWD/backups:/backup" redis \
sh -c 'tar -czf /backup/redis-data.tar.gz -C /data .'
docker compose up -d --wait --wait-timeout 120
tar -tzf backups/redis-data.tar.gz
备份保存到 ~/compose-demo/backups/redis-data.tar.gz,请另存到其他设备。
7. 更新与故障恢复
7.1 更新 Web 并回退
修改压缩包解压后的 app.py 和 .env,更新网页标题并用 v2 标签构建新镜像。Redis 使用原数据卷。
cd ~/compose-demo
sed -i 's/<h1>Docker Compose Lab<\//<h1>Docker Compose Lab v2<\//' app.py
sed -i 's/^APP_TAG=.*/APP_TAG=v2/; s/^APP_VERSION=.*/APP_VERSION=v2/' .env
docker compose up -d --build --wait --wait-timeout 120
curl -fsS http://127.0.0.1:8080/api/state
页面标题和 API 版本应变为 v2。回退时复用保留的 v1 镜像,并同步恢复示例源码。
sed -i 's/^APP_TAG=.*/APP_TAG=v1/; s/^APP_VERSION=.*/APP_VERSION=v1/' .env
sed -i 's/<h1>Docker Compose Lab v2<\//<h1>Docker Compose Lab<\//' app.py
docker compose up -d --no-build --wait --wait-timeout 120
curl -fsS http://127.0.0.1:8080/api/state
更新会短暂中断服务,请保留 v1 镜像用于回退。
7.2 模拟数据库不可用
cd ~/compose-demo
docker compose stop redis
curl -sS -o /tmp/compose-response.json -w '%{http_code}\n' \
http://127.0.0.1:8080/api/state
cat /tmp/compose-response.json
docker compose up -d --wait --wait-timeout 120
curl -fsS http://127.0.0.1:8080/api/state
停库时 API 返回 503,恢复后返回正常数据。持续故障时 Web 健康状态会变为 unhealthy;Docker 的普通 restart 策略针对容器进程退出,健康状态变化本身不会自动重启进程。
7.3 模拟 Web 进程异常退出
完整执行下列命令,终止本项目 Web 主进程并检查自动重启:
cd ~/compose-demo
container_id=$(docker compose ps -q web)
host_pid=$(docker inspect --format '{{.State.Pid}}' "$container_id")
test "$host_pid" -gt 1 && kill -KILL "$host_pid"
sleep 10
docker compose ps
docker inspect "$(docker compose ps -q web)" --format '{{.RestartCount}}'
curl -fsS http://127.0.0.1:8080/api/state
重启计数应增加。手动 stop 后不会自动重启,需执行 docker compose up -d 恢复。
7.4 验证整板重启恢复
保持两个服务运行,在板端重启。
reboot
重新登录后检查,无需再次执行 up。
cd ~/compose-demo
systemctl is-active docker
docker compose ps
curl -fsS http://127.0.0.1:8080/api/state
应返回 active、两个 healthy 服务和重启前的计数。
8. 板端实测
以下为 CM5 搭配官方 Debian 12 镜像的验证结果。计数先增加到 5,再执行持久化与恢复测试。
| 测试 | 实测结果 |
|---|---|
| 内核更新 | 6.1.118-rk3576 从 #274 更新为 #275,运行配置为 CONFIG_IP_NF_RAW=y |
| 构建与部署 | ARM64 镜像构建成功,Web、Redis 均为 healthy |
| 资源限制 | Web 的 cpu.max 为 100000 100000,memory.max 为 268435456,对应 1 CPU / 256 MiB |
| 容器重建 | down / up 后计数仍为 5 |
| 停机备份 | 生成 backups/redis-data.tar.gz,可列出其中的 Redis 数据文件 |
| 更新与回退 | v1 → v2 → v1,计数均为 5 |
| 数据库故障 | 停止 Redis 后 API 返回 503;持续故障时 Web 为 unhealthy;恢复后正常 |
| Web 进程故障 | 终止主进程后自动恢复,RestartCount 从 0 增加为 1 |
| 整板重启 | Docker 自动启动,两个服务 healthy,计数仍为 5 |
截图保留首次点击时的计数 1;后续恢复测试使用计数 5。以上验证针对功能和恢复流程,不代表吞吐量或长期稳定性测试。
9. 排查与扩展
cd ~/compose-demo
docker compose ps -a
docker compose logs --tail=50
journalctl -u docker -n 50 --no-pager
docker stats --no-stream
| 现象 | 检查方向 |
|---|---|
Failed to initialize nft | 核对 CONFIG_NF_TABLES 和 iptables 后端,见第 4.2 节 |
can't initialize iptables table raw | 核对正在运行的内核是否启用 CONFIG_IP_NF_RAW,见第 3 章 |
| 拉取镜像超时或限流 | 分别检查 DNS、Docker Hub 连通性和账号限流;使用组织认可的镜像仓库 |
exec format error | 镜像或自带可执行文件的 CPU 架构与板端不匹配,检查 arm64 支持 |
| 8080 被占用 | 修改 .env 中的 APP_PORT,再执行 docker compose up -d |
| Web 为 unhealthy | 查看应用日志和 Redis 状态,健康检查也包含数据库连通性 |
| 内存增长或频繁重启 | 查看 docker stats 和容器 OOM 状态,依据负载调整限制 |
