Docker Compose 中执行多条命令的方法

Docker Compose 中执行多条命令的方法

技术背景

在使用 Docker Compose 部署应用时,有时需要在一个服务中执行多条命令,例如在启动 Django 应用时,可能需要先执行数据库迁移命令,再启动开发服务器。然而,Docker Compose 默认只能指定一个 command,因此需要找到一种方法来执行多条命令。

实现步骤

方法一:使用 bash -c

可以使用 bash -c 来执行多条命令,示例如下:

1
2
3
4
5
6
7
8
9
version: '3'
services:
web:
build: .
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
volumes:
- .:/code
ports:
- "8000:8000"

也可以写成多行形式:

1
2
3
4
5
6
7
8
9
10
11
version: '3'
services:
web:
build: .
command: >
bash -c "python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000"
volumes:
- .:/code
ports:
- "8000:8000"

方法二:使用 sh -c

对于大多数基于 Unix 的镜像,shbash 更常用,示例如下:

1
2
3
4
5
6
7
8
9
version: '3'
services:
app:
build:
context: .
command: >
sh -c "python manage.py wait_for_db &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"

方法三:使用单独的临时容器

可以将预启动的操作(如数据库迁移)放在一个单独的临时容器中执行,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: '2'
services:
db:
image: postgres
web:
image: app
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
depends_on:
- migration
migration:
build: .
image: app
command: python manage.py migrate
volumes:
- .:/code
links:
- db
depends_on:
- db

方法四:使用数组形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: '3.1'
services:
web:
build: .
command:
- /bin/bash
- -c
- |
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db

方法五:使用 entrypoint

可以创建一个启动脚本,将其作为 entrypoint 执行,示例如下:

1
2
3
4
# docker-entrypoint.sh
#!/bin/bash
python manage.py migrate
exec "$@"
1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
web:
build: .
entrypoint: /docker-entrypoint.sh
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db

核心代码

以下是使用 bash -c 执行多条命令的完整 docker-compose.yml 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
version: '3'
services:
db:
image: postgres
web:
build: .
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db

最佳实践

  • 选择合适的方法:根据镜像的基础系统和具体需求选择合适的方法。如果镜像中没有安装 bash,可以使用 sh -c;如果需要将预启动操作和主服务分离,可以使用单独的临时容器。
  • 使用脚本:将复杂的命令逻辑封装在脚本中,提高代码的可读性和可维护性。
  • 处理依赖关系:使用 depends_on 确保服务的启动顺序正确,对于需要等待数据库等服务就绪的情况,可以使用 wait-for-it.sh 等工具。

常见问题

镜像中没有安装 bash

如果镜像中没有安装 bash,可以使用 sh -c 代替,例如:

1
2
3
4
5
version: '3'
services:
app:
build: .
command: sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"

depends_on 不能保证服务就绪

depends_on 只能保证服务按顺序启动,但不能保证服务已经就绪。可以使用 wait-for-it.sh 等工具来解决这个问题,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
db:
image: postgres
web:
build: .
command: >
bash -c "./wait-for-it.sh db:5432 -- python manage.py makemigrations
&& python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000"
depends_on:
- db

变量替换问题

docker-compose 在运行命令之前会尝试解析变量,如果需要 bash 处理变量,需要对美元符号进行转义,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: '3.1'
services:
web:
build: .
command:
- /bin/bash
- -c
- |
var=$$(echo 'foo')
echo $$var # prints foo
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db

Docker Compose 中执行多条命令的方法
https://119291.xyz/posts/2025-04-22.docker-compose-execute-multiple-commands-method/
作者
ww
发布于
2025年4月23日
许可协议