如何在 docker-compose 中执行多条命令?

command 字段用 sh -c "cmd1 && cmd2 && cmd3" 串多条命令,YAML 用 > 折叠多行书写;更规范的做法是把初始化逻辑放 entrypoint 脚本。本文给出写法与注意事项。

最佳实践
如何在 docker-compose 中执行多条命令?封面

写法:在 command 里用 shell 串联——command: > sh -c "命令1 && 命令2 && 命令3"(> 是 YAML 折叠语法,多行会拼成一行)。&& 表示前一条成功才执行下一条;无论成败都执行用 ;。

基本写法

services:
  app:
    build: .
    command: >
      sh -c "python manage.py migrate &&
             python manage.py collectstatic --noinput &&
             exec python manage.py runserver 0.0.0.0:8000"

典型场景:启动前执行一次性命令再起服务。示例 runserver 仅供开发;多副本启动时迁移可能并发,应使用独立迁移任务或锁协调。command 不会自动启动 shell,且仍需核对镜像原有 ENTRYPOINT。

更规范的做法:entrypoint 脚本

命令多了之后 command 会越来越难读,推荐抽成脚本:

#!/bin/sh
set -e
python manage.py migrate
python manage.py collectstatic --noinput
exec gunicorn -w 4 app.wsgi:application
services:
  app:
    entrypoint: ["/app/entrypoint.sh"]

好处:set -e 会在许多命令失败时退出,但条件、管道等有例外,关键步骤应显式检查、exec 让主进程成为 PID 1(能收到停止信号)、脚本可独立测试、逻辑可版本管理。

注意事项

  1. 最后一条命令要以前台运行:主进程退出 = 容器退出。不要在末尾加 & 或 daemonize。
  2. && 与 ; 的区别:迁移失败就不该起服务,用 &&。
  3. 信号处理:容器停止信号通常发给 PID 1,使用 exec 才能让最终服务替换 shell;前置命令执行期间也需考虑中断;若需要同时跑多个长期进程,该拆成多个服务(sidecar)或用 supervisord。
  4. 依赖顺序:迁移需要数据库先就绪,配 depends_on 的 condition: service_healthy + 健康检查,或在脚本里做等待重试。

初始化失败时,先保存迁移命令的错误输出。需要跨重建保留记录的服务,可按观测云 容器日志采集指南配置采集与轮转,并用一次失败迁移验证日志是否带有服务名、容器标识和时间;不要等容器删除后再启用采集。

常见问题(FAQ)

Q:YAML 里 > 和 | 有什么区别?
A:> 折叠(换行变空格,适合拼成一条命令);| 保留换行。两种都可以配合显式 sh -c 使用,选择取决于是否需要保留换行,不能统一要求用 >。

Q:command 和 entrypoint 都写会怎样?
A:command 作为参数传给 entrypoint;是否执行这些参数取决于入口程序,入口脚本需用 exec "$@" 等方式显式执行,覆盖 entrypoint 还可能绕过镜像初始化。

Q:能在 command 里写 shell 变量和判断吗?
A:可以,走 sh -c 就是完整 shell 语法,容器内展开的变量要避免被 Compose 提前插值,例如写 $$HOSTNAME;复杂了就该进 entrypoint 脚本。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台