使用Docker-Compose,如何执行多个命令

Bre*_*len 417 yaml docker docker-compose

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

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
Run Code Online (Sandbox Code Playgroud)

Bre*_*len 729

弄清楚,使用bash -c.

例:

command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
Run Code Online (Sandbox Code Playgroud)

多行中的相同示例:

command: >
    bash -c "python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000"
Run Code Online (Sandbox Code Playgroud)

  • 基于Alpine的图像实际上似乎没有安装bash - 就像@Chaoste推荐并使用`sh`代替:`[sh,-c,"cd/usr/src/app && npm start"] (56认同)
  • @Pedram确保您使用的是实际安装了bash的图像.一些图像也可能需要直接路径来打击,例如`/ bin/bash` (4认同)
  • 我使用“sh -cx”,这样我也可以看到正在运行的命令。对于调试很有用。 (4认同)
  • 如果没有安装bash,则可以尝试sh -c“您的命令” (3认同)
  • 也可以在 alpine 上只使用 `ash` :) (3认同)

Bjo*_*iel 145

我在一个单独的短暂容器中运行预启动之类的东西,比如这样(注意,compose文件必须是版本'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
Run Code Online (Sandbox Code Playgroud)

这有助于保持清洁和分离.需要考虑的两件事:

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

  2. 你想避免多次构建,这是通过使用构建和图像第一次标记它来实现的; 你可以参考其他容器中的图像

  • 虽然我喜欢这个想法,但问题是depends_on只能确保它们以该顺序开始,而不是它们按照该顺序准备好.wait-for-it.sh可能是一些人需要的解决方案. (20认同)
  • 在上面的yaml中,构建和标记发生在“迁移”部分。乍一看并不是很明显,但是当您指定构建和图像属性时,docker-compose会对其进行标记-图像属性会为该构建指定标记。然后可以在不触发新构建的情况下使用该属性(如果您查看Web,您会看到它没有构建,只有image属性)。这是更多详细信息https://docs.docker.com/compose/compose-file/) (3认同)
  • 该答案提供了有关 dependent_on 如何工作的不正确且可能具有破坏性的信息。 (3认同)
  • 对我来说,这似乎是最好的选择,我想使用它。您能否详细说明标记设置,以免出现多次构建?我宁愿避免额外的步骤,因此如果需要一些步骤,我可以使用上面的`bash -c`。 (2认同)
  • 这是绝对正确的,并且有点遗憾,docker-compose不支持任何精细控制,例如等待容器退出或开始侦听端口.但是,是的,自定义脚本确实解决了这个问题,这是重点! (2认同)

Lon*_*Dev 72

我建议使用sh而不是bash因为它在大多数基于unix的图像(高山等)上更容易获得.

这是一个例子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"
Run Code Online (Sandbox Code Playgroud)

这将按顺序调用以下命令:

  • python manage.py wait_for_db - 等待数据库准备就绪
  • python manage.py migrate - 运行任何迁移
  • python manage.py runserver 0.0.0.0:8000 - 启动我的开发服务器

  • 就个人而言,这是我最喜欢、最干净的解决方案。 (2认同)
  • 我也是。正如 @LondonAppDev 指出的那样,bash 默认情况下并不在所有容器中都可用以优化空间(例如,大多数容器构建在 Alpine Linux 之上) (2认同)
  • 我不得不用 \ 来逃避多行 && (2认同)
  • @oligofren `>` 用于启动多行输入(参见 /sf/answers/265334821/) (2认同)

MUH*_*AHA 33

最干净?

---
version: "2"
services:
  test:
    image: alpine
    entrypoint: ["/bin/sh","-c"]
    command:
    - |
       echo a
       echo b
       echo c
Run Code Online (Sandbox Code Playgroud)

  • 当我的图像的入口点不是 sh/bash 时,这非常有效。 (2认同)
  • @DerekMorrison:这是 YAML 语法。请参阅 https://yaml-multiline.info/ (2认同)

Mat*_*ice 26

这对我有用:

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
Run Code Online (Sandbox Code Playgroud)

docker-compose会运行命令之前尝试取消引用变量,因此,如果您希望bash处理变量,则需要将它们加倍以避开美元符号...

    command:
      - /bin/bash
      - -c
      - |
        var=$$(echo 'foo')
        echo $$var # prints foo
Run Code Online (Sandbox Code Playgroud)

...否则,您将得到一个错误:

服务“ Web”中“命令”选项的无效插值格式:


Jul*_*ian 23

这个线程中已经有很多很好的答案,但是,我发现其中一些答案的组合似乎效果最好,特别是对于基于 Debian 的用户。

\n
services:\n  db:\n    . . . \n  web:\n    . . .\n    depends_on:\n       - "db"\n    command: >      \n      bash -c "./wait-for-it.sh db:5432 -- python manage.py makemigrations\n      && python manage.py migrate\n      && python manage.py runserver 0.0.0.0:8000"\n
Run Code Online (Sandbox Code Playgroud)\n

先决条件:将wait-for-it.sh添加到项目目录中。

\n

来自文档的警告:“(在生产中使用 wait-for-it.sh 时),您的数据库可能会变得不可用或随时移动主机......(此解决方案适用于)不需要的人这种程度的恢复能力。”

\n

编辑:

\n

这是一个很酷的短期修复,但对于长期解决方案,您应该尝试在每个映像的 Dockerfile 中使用入口点。

\n


Har*_*ola 21

您可以在此处使用入口点.docker中的入口点在命令之前执行,而while命令是容器启动时应该运行的默认命令.因此,大多数应用程序通常在入口点文件中携带设置过程,最后它们允许命令运行.

make shell脚本文件可以是docker-entrypoint.sh(名称无关紧要),其中包含以下内容.

#!/bin/bash
python manage.py migrate
exec "$@"
Run Code Online (Sandbox Code Playgroud)

在docker-compose.yml文件中使用它entrypoint: /docker-entrypoint.sh并将命令注册为command: python manage.py runserver 0.0.0.0:8000 PS:不要忘记docker-entrypoint.sh随你的代码一起复制.

  • 请注意,当您执行“docker-compose run service-name ....”时,这也会执行 (2认同)

rwe*_*eng 18

另一个想法:

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


Gtd*_*Dev 12

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

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

Run Code Online (Sandbox Code Playgroud)


小智 11

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

command: >
    bash -c "python manage.py makemigrations
    && python manage.py migrate
    && python manage.py runserver 0.0.0.0:8000"
Run Code Online (Sandbox Code Playgroud)

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


Din*_*har 6

基于 Alpine 的图像实际上似乎没有安装 bash,但您可以使用shor ashwhich 链接到/bin/busybox.

示例docker-compose.yml

version: "3"
services:

  api:
    restart: unless-stopped
    command: ash -c "flask models init && flask run"
Run Code Online (Sandbox Code Playgroud)


Tim*_*all 5

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

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


rad*_*tek 5

*更新*

我认为运行某些命令的最佳方法是编写一个自定义Dockerfile,该文件可以在从映像运行官方CMD之前完成我想要的一切。

docker-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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

这可能是最干净的方法。

*旧方式*

我用命令创建了一个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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

因此,这会分叉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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)