ChatGPT解决这个技术问题 Extra ChatGPT

使用 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

x
x-yuri

想通了,使用 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
  "

@Pedram 确保您使用的是实际安装了 bash 的图像。某些图像可能还需要 bash 的直接路径,例如 /bin/bash
如果没有安装 bash 你可以试试 sh -c "your command"
基于 Alpine 的图像实际上似乎没有安装 bash - 像 @Chaoste 推荐的那样使用 sh 代替:[sh, -c, "cd /usr/src/app && npm start"]
也可以在 alpine 上仅使用 ash :)
我使用 sh -cx,所以我也可以看到正在运行的命令。对调试很有用。
P
Pang

我在一个单独的临时容器中运行启动前的东西,比如迁移,就像这样(注意,撰写文件必须是版本'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)。您希望避免通过使用构建和映像第一次标记它来实现的多个构建;您可以参考其他容器中的图像。


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

我建议使用 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 - 启动我的开发服务器


就个人而言,这是我最喜欢的,最干净的解决方案。
我也是。正如@LondonAppDev 指出的那样,默认情况下,并非所有容器都可以使用 bash 来优化空间(例如,大多数构建在 Alpine Linux 之上的容器)
我不得不用 \ 来逃避多行 &&
@AndreVanZuydam 嗯,这很奇怪,我不需要这样做。你用引号包围了吗?你在运行什么风格的 docker?
@oligofren > 用于启动多行输入(参见 stackoverflow.com/a/3790497/2220370
P
Pang

这对我有用:

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


嗨,伙计。我遇到了一个问题:```无法识别的参数:/bin/bash -c python3 /usr/local/airflow/__init__.py -C Local -T Windows ```我的docker-compose.yml中的命令是:命令: - /bin/bash - -c - | python3 /usr/local/airflow/__init__.py -C ${Client} -T ${Types} 你知道怎么解决吗?我在 .env 文件中添加了客户端和类型。
这是给您的文档:docs.docker.com/compose/compose-file/#variable-substitution 我认为您的 .env 文件将这些变量放在容器环境中,但 docker-compose 正在查看您的 shell 环境。请改用 $${Types}$${Client}。我认为这将阻止 docker compose 解释这些变量并在您调用 docker-compose 的任何 shell 中查找它们的值,这意味着它们仍然存在让 bash 取消引用它们(after docker已处理您的 .env 文件)。
谢谢你的评论。我确实按照你说的做了。所以我在错误信息中得到了 $(Client) 。我将读取环境变量的方式改为在python中使用os.getenv,这样更容易。不管怎么说,还是要谢谢你。
M
MUHAHA

最干净?

---
version: "2"
services:
  test:
    image: alpine
    entrypoint: ["/bin/sh","-c"]
    command:
    - |
       echo a
       echo b
       echo c

当我的图像的入口点不是 sh/bash 时,这非常有效。
H
Harshad Yeola

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


请注意,这也会在您执行 docker-compose run service-name .... 时执行
r
rweng

另一个想法:

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


是的,最后我创建了一个 run.sh 脚本:#!/bin/bash \n python manage.py migrate \n python manage.py runserver 0.0.0.0:8000(丑陋的单行)
r
radtek

* 更新 *

我认为运行某些命令的最佳方法是编写一个自定义 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 会阻止您运行其余部分。

码头工人-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

A
Amritpal Singh

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

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


D
Display name

在这个线程中已经有很多很好的答案,但是,我发现其中一些的组合似乎效果最好,尤其是对于基于 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 添加到您的项目目录。

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

编辑:

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


G
GtdDev

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

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


D
Dinko Pehar

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

示例 docker-compose.yml

version: "3"
services:

  api:
    restart: unless-stopped
    command: ash -c "flask models init && flask run"

C
Community

如果您需要运行多个守护进程,则有一个处于非分离模式的 suggestion in the Docker documentation to use Supervisord,因此所有子守护进程都将输出到标准输出。

From another SO question, I discovered you can redirect the child processes output to the stdout. 这样您就可以看到所有输出!


再看一遍,这个答案似乎更适合并行而不是串行运行多个命令。
E
Eran

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


wait-for-it.sh 的链接。应该注意(正如您链接到的文档中那样)“等待数据库(例如)准备就绪的问题实际上只是分布式系统更大问题的一个子集。在生产中,您的数据库可以随时变得不可用或移动主机。您的应用程序需要对这些类型的故障具有弹性。”该解决方案适用于“不需要这种级别的弹性”的人
C
Cyril Duchon-Doris

在@Bjorn 回答的基础上,docker 有 recently introduced 特殊的依赖规则,允许您等到“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

J
Jason Anderson

我在尝试设置我的 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

这似乎是不同问题的答案。
M
Mihir Bhende

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

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

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


J
Jeremy Beale

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


c
chanllen

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

command: "sleep 20; echo 'a'"