我想做这样的事情,我可以按顺序运行多个命令。
db:
image: postgres
web:
build: .
command: python manage.py migrate
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
我想做这样的事情,我可以按顺序运行多个命令。
db:
image: postgres
web:
build: .
command: python manage.py migrate
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
links:
- db
想通了,用bash -c
。
例子:
command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
多行中的相同示例:
command: >
bash -c "python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000"
或者:
command: bash -c "
python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000
"
我在一个单独的临时容器中运行启动前的东西,比如迁移,就像这样(注意,撰写文件必须是版本'2'类型):
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
这有助于保持清洁和分开。需要考虑两件事:
您必须确保正确的启动顺序(使用depends_on)。
您希望避免通过使用构建和映像第一次标记它来实现的多个构建;您可以参考其他容器中的图像。
我建议使用sh
而不是bash
因为它在大多数基于 Unix 的图像(alpine 等)上更容易使用。
这是一个例子docker-compose.yml
:
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"
这将按顺序调用以下命令:
python manage.py wait_for_db
- 等待数据库准备好python manage.py migrate
- 运行任何迁移python manage.py runserver 0.0.0.0:8000
- 启动我的开发服务器这对我有用:
version: '3.1'
services:
db:
image: postgres
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
docker-compose 会在运行命令之前尝试取消引用变量,所以如果你想让 bash 处理变量,你需要通过加倍来转义美元符号......
command:
- /bin/bash
- -c
- |
var=$$(echo 'foo')
echo $$var # prints foo
...否则你会得到一个错误:
服务“web”中“command”选项的插值格式无效:
最干净?
---
version: "2"
services:
test:
image: alpine
entrypoint: ["/bin/sh","-c"]
command:
- |
echo a
echo b
echo c
您可以在此处使用入口点。docker 中的入口点在命令之前执行,而命令是容器启动时应该运行的默认命令。所以大多数应用程序通常在入口点文件中携带设置过程,最后它们允许命令运行。
制作一个 shell 脚本文件可能是docker-entrypoint.sh
(名称无关紧要),其中包含以下内容。
#!/bin/bash
python manage.py migrate
exec "$@"
在 docker-compose.yml 文件中使用它entrypoint: /docker-entrypoint.sh
并将命令注册为command: python manage.py runserver 0.0.0.0:8000
PS:不要忘记docker-entrypoint.sh
与您的代码一起复制。
另一个想法:
如果在这种情况下,您构建容器只需在其中放置一个启动脚本并使用命令运行它。或者将启动脚本挂载为卷。
* 更新 *
我认为运行某些命令的最佳方法是编写一个自定义 Dockerfile,在从映像运行官方 CMD 之前执行我想要的所有操作。
码头工人-compose.yaml:
version: '3'
# Can be used as an alternative to VBox/Vagrant
services:
mongo:
container_name: mongo
image: mongo
build:
context: .
dockerfile: deploy/local/Dockerfile.mongo
ports:
- "27017:27017"
volumes:
- ../.data/mongodb:/data/db
Dockerfile.mongo:
FROM mongo:3.2.12
RUN mkdir -p /fixtures
COPY ./fixtures /fixtures
RUN (mongod --fork --syslog && \
mongoimport --db wcm-local --collection clients --file /fixtures/clients.json && \
mongoimport --db wcm-local --collection configs --file /fixtures/configs.json && \
mongoimport --db wcm-local --collection content --file /fixtures/content.json && \
mongoimport --db wcm-local --collection licenses --file /fixtures/licenses.json && \
mongoimport --db wcm-local --collection lists --file /fixtures/lists.json && \
mongoimport --db wcm-local --collection properties --file /fixtures/properties.json && \
mongoimport --db wcm-local --collection videos --file /fixtures/videos.json)
这可能是最干净的方法。
* 旧方式 *
我用我的命令创建了一个 shell 脚本。在这种情况下,我想启动mongod
并运行,mongoimport
但调用mongod
会阻止您运行其余的。
docker-compose.yaml:
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.2.12
ports:
- "27017:27017"
volumes:
- ./fixtures:/fixtures
- ./deploy:/deploy
- ../.data/mongodb:/data/db
command: sh /deploy/local/start_mongod.sh
start_mongod.sh:
mongod --fork --syslog && \
mongoimport --db wcm-local --collection clients --file /fixtures/clients.json && \
mongoimport --db wcm-local --collection configs --file /fixtures/configs.json && \
mongoimport --db wcm-local --collection content --file /fixtures/content.json && \
mongoimport --db wcm-local --collection licenses --file /fixtures/licenses.json && \
mongoimport --db wcm-local --collection lists --file /fixtures/lists.json && \
mongoimport --db wcm-local --collection properties --file /fixtures/properties.json && \
mongoimport --db wcm-local --collection videos --file /fixtures/videos.json && \
pkill -f mongod && \
sleep 2 && \
mongod
所以这会分叉 mongo,执行monogimport,然后杀死分离的分叉 mongo,并在不分离的情况下再次启动它。不确定是否有办法附加到分叉进程,但这确实有效。
注意:如果您严格要加载一些初始数据库数据,可以这样做:
mongo_import.sh
#!/bin/bash
# Import from fixtures
# Used in build and docker-compose mongo (different dirs)
DIRECTORY=../deploy/local/mongo_fixtures
if [[ -d "/fixtures" ]]; then
DIRECTORY=/fixtures
fi
echo ${DIRECTORY}
mongoimport --db wcm-local --collection clients --file ${DIRECTORY}/clients.json && \
mongoimport --db wcm-local --collection configs --file ${DIRECTORY}/configs.json && \
mongoimport --db wcm-local --collection content --file ${DIRECTORY}/content.json && \
mongoimport --db wcm-local --collection licenses --file ${DIRECTORY}/licenses.json && \
mongoimport --db wcm-local --collection lists --file ${DIRECTORY}/lists.json && \
mongoimport --db wcm-local --collection properties --file ${DIRECTORY}/properties.json && \
mongoimport --db wcm-local --collection videos --file ${DIRECTORY}/videos.json
mongo_fixtures/*.json 文件是通过 mongoexport 命令创建的。
docker-compose.yaml
version: '3'
services:
mongo:
container_name: mongo
image: mongo:3.2.12
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db:cached
- ./deploy/local/mongo_fixtures:/fixtures
- ./deploy/local/mongo_import.sh:/docker-entrypoint-initdb.d/mongo_import.sh
volumes:
mongo-data:
driver: local
要在 docker-compose 文件中运行多个命令,请使用bash -c
.
command: >
bash -c "python manage.py makemigrations
&& python manage.py migrate
&& python manage.py runserver 0.0.0.0:8000"
在这个线程中已经有很多很好的答案,但是,我发现其中一些的组合似乎效果最好,尤其是对于基于 Debian 的用户。
services:
db:
. . .
web:
. . .
depends_on:
- "db"
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"
先决条件:将wait-for-it.sh添加到您的项目目录。
来自文档的警告:“(在生产中使用 wait-for-it.sh 时),您的数据库可能随时变得不可用或移动主机......(此解决方案适用于不需要这种级别的弹性的人) 。”
编辑:
这是一个很酷的短期修复,但对于长期解决方案,您应该尝试在 Dockerfile 中为每个映像使用入口点。
基于 Alpine 的图像实际上似乎没有安装 bash,但您sh
可以ash
使用/bin/busybox
.
示例docker-compose.yml
:
version: "3"
services:
api:
restart: unless-stopped
command: ash -c "flask models init && flask run"
如果您需要运行多个守护进程,Docker 文档中建议在非分离模式下使用 Supervisord,以便所有子守护进程都将输出到标准输出。
从另一个 SO 问题中,我发现您可以将子进程输出重定向到标准输出。 这样你就可以看到所有的输出!
这是我对这个问题的解决方案:
services:
mongo1:
container_name: mongo1
image: mongo:4.4.4
restart: always
# OPTION 01:
# command: >
# bash -c "chmod +x /scripts/rs-init.sh
# && sh /scripts/rs-init.sh"
# OPTION 02:
entrypoint: [ "bash", "-c", "chmod +x /scripts/rs-init.sh && sh /scripts/rs-init.sh"]
ports:
- "9042:9042"
networks:
- mongo-cluster
volumes:
- ~/mongors/data1:/data/db
- ./rs-init.sh:/scripts/rs-init.sh
- api_vol:/data/db
environment:
*env-vars
depends_on:
- mongo2
- mongo3
使用诸如 wait-for-it 或dockerize之类的工具。这些是可以包含在应用程序映像中的小型包装脚本。或者编写自己的包装脚本来执行更多特定于应用程序的命令。根据:https ://docs.docker.com/compose/startup-order/
在@Bjorn 回答的基础上,docker最近引入了特殊的依赖规则,允许您等到“init 容器”成功退出,这给
db:
image: postgres
web:
image: app
command: python manage.py runserver 0.0.0.0:8000
depends_on:
db:
migration:
condition: service_completed_successfully
migration:
build: .
image: app
command: python manage.py migrate
depends_on:
- db
我不确定您是否仍然需要 buildkit,但在我这边它可以与
DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker-compose up
我在尝试设置我的 jenkins 容器以作为 jenkins 用户构建 docker 容器时遇到了这个问题。
我需要触摸 Dockerfile 中的 docker.sock 文件,因为我稍后会在 docker-compose 文件中链接它。除非我先触摸它,否则它还不存在。这对我有用。
Dockerfile:
USER root
RUN apt-get update && \
apt-get -y install apt-transport-https \
ca-certificates \
curl \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release;
echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) \
stable" && \
apt-get update && \
apt-get -y install docker-ce
RUN groupmod -g 492 docker && \
usermod -aG docker jenkins && \
touch /var/run/docker.sock && \
chmod 777 /var/run/docker.sock
USER Jenkins
码头工人-compose.yml:
version: '3.3'
services:
jenkins_pipeline:
build: .
ports:
- "8083:8083"
- "50083:50080"
volumes:
- /root/pipeline/jenkins/mount_point_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
我遇到了同样的问题,我想在端口 3000 上运行我的 react 应用程序,并在端口 6006 上运行故事书,它们都在同一个容器中。
我尝试从 Dockerfile 以及使用 docker-composecommand
选项作为入口点命令启动。
花时间在这之后,决定将这些服务分成单独的容器,它就像魅力一样
如果其他人试图用基于Windows的容器找出多个命令,则以下格式有效:
command: "cmd.exe /c call C:/Temp/script1.bat && dir && C:/Temp/script2.bat && ..."
包括“呼叫”指令是为我解决的问题。
或者,如果每个命令都可以在前面的命令不成功的情况下执行,只需用分号分隔每个命令:
command: "cmd.exe /c call C:/Temp/script1.bat; dir; C:/Temp/script2.bat; ... "
尝试使用“;” 如果您在两个版本中,则将命令分开,例如
command: "sleep 20; echo 'a'"