776

我想做这样的事情,我可以按顺序运行多个命令。

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
4

19 回答 19

1217

想通了,用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
  "
于 2015-05-05T22:16:53.983 回答
209

我在一个单独的临时容器中运行启动前的东西,比如迁移,就像这样(注意,撰写文件必须是版本'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

这有助于保持清洁和分开。需要考虑两件事:

  1. 您必须确保正确的启动顺序(使用depends_on)。

  2. 您希望避免通过使用构建和映像第一次标记它来实现的多个构建;您可以参考其他容器中的图像。

于 2016-03-09T15:01:48.173 回答
196

我建议使用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- 启动我的开发服务器
于 2018-10-04T07:41:51.857 回答
121

这对我有用:

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”选项的插值格式无效:

于 2019-03-28T20:42:23.983 回答
57

最干净?

---
version: "2"
services:
  test:
    image: alpine
    entrypoint: ["/bin/sh","-c"]
    command:
    - |
       echo a
       echo b
       echo c
于 2021-01-05T18:25:14.977 回答
25

您可以在此处使用入口点。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与您的代码一起复制。

于 2016-08-06T08:21:30.253 回答
21

另一个想法:

如果在这种情况下,您构建容器只需在其中放置一个启动脚本并使用命令运行它。或者将启动脚本挂载为卷。

于 2015-07-09T19:30:50.263 回答
14

* 更新 *

我认为运行某些命令的最佳方法是编写一个自定义 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
于 2019-02-08T22:58:20.793 回答
10

要在 docker-compose 文件中运行多个命令,请使用bash -c.

command: >
    bash -c "python manage.py makemigrations
    && python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000"

来源:https ://intellipaat.com/community/19590/docker-run-multiple-commands-using-docker-compose-at-once?show=19597#a19597

于 2020-04-05T12:29:44.467 回答
9

在这个线程中已经有很多很好的答案,但是,我发现其中一些的组合似乎效果最好,尤其是对于基于 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 中为每个映像使用入口点。

于 2020-07-22T14:52:05.253 回答
6

基于 Alpine 的图像实际上似乎没有安装 bash,但您sh可以ash使用/bin/busybox.

示例docker-compose.yml

version: "3"
services:

  api:
    restart: unless-stopped
    command: ash -c "flask models init && flask run"
于 2020-10-09T10:22:37.360 回答
5

如果您需要运行多个守护进程,Docker 文档中建议在非分离模式下使用 Supervisord,以便所有子守护进程都将输出到标准输出。

从另一个 SO 问题中,我发现您可以将子进程输出重定向到标准输出。 这样你就可以看到所有的输出!

于 2016-04-27T14:08:21.167 回答
3

这是我对这个问题的解决方案:

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

于 2021-12-02T18:39:35.190 回答
2

使用诸如 wait-for-it 或dockerize之类的工具。这些是可以包含在应用程序映像中的小型包装脚本。或者编写自己的包装脚本来执行更多特定于应用程序的命令。根据:https ://docs.docker.com/compose/startup-order/

于 2016-07-11T11:46:55.413 回答
1

在@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
于 2021-09-29T13:59:58.187 回答
0

我在尝试设置我的 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
于 2018-12-26T22:01:07.147 回答
0

我遇到了同样的问题,我想在端口 3000 上运行我的 react 应用程序,并在端口 6006 上运行故事书,它们都在同一个容器中。

我尝试从 Dockerfile 以及使用 docker-composecommand选项作为入口点命令启动。

花时间在这之后,决定将这些服务分成单独的容器,它就像魅力一样

于 2021-01-29T22:51:34.323 回答
0

如果其他人试图用基于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; ... "

于 2021-10-06T16:13:57.470 回答
-9

尝试使用“;” 如果您在两个版本中,则将命令分开,例如

command: "sleep 20; echo 'a'"

于 2017-01-13T00:11:06.180 回答