跳到主要内容

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 / ComposeDocker 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。

电脑浏览器访问 CM5 上运行的 Compose 计数面板

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 状态,依据负载调整限制
联系我们