Docker编写-如何执行多个命令?

我想做这样的事情,我可以在以下代码中运行多个命令:

db:image: postgresweb:build: .command: python manage.py migratecommand: python manage.py runserver 0.0.0.0:8000volumes:- .:/codeports:- "8000:8000"links:- db

如何执行多个命令?

谢了

872778 次浏览

找到它,使用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: postgresweb:image: appcommand: python manage.py runserver 0.0.0.0:8000volumes:- .:/codeports:- "8000:8000"links:- dbdepends_on:- migrationmigration:build: .image: appcommand: python manage.py migratevolumes:- .:/codelinks:- dbdepends_on:- db

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

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

  2. 您希望避免多次构建,这是通过第一次使用构建和图像标记它来实现的;然后您可以在其他容器中引用图像。

如果您需要运行多个守护进程,则在未分离模式下有一个建议在Docker留档中使用Supervisord,因此所有子守护进程都将输出到标准输出。

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

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

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

制作外壳脚本文件可能是docker-entrypoint.sh(名称无关紧要),其中包含以下内容。

#!/bin/bashpython manage.py migrateexec "$@"

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

如果您在第二版中,请尝试使用“;”来分隔命令例如

command: "sleep 20; echo 'a'"

我建议使用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"

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

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

我在尝试设置jenkins容器以作为jenkins用户构建docker容器时遇到了这个问题。

我需要触摸Dockerfile中的docker.sock文件,因为我稍后将其链接到docker-compose文件中。除非我先触摸它,否则它还不存在。这对我很有效。

Dockerfile:

USER rootRUN 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-ceRUN groupmod -g 492 docker && \usermod -aG docker jenkins  && \touch /var/run/docker.sock && \chmod 777 /var/run/docker.sock
USER Jenkins

docker-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

*更新*

我认为运行某些命令的最佳方法是编写一个自定义Dockerfile,在从映像运行官方CMD之前执行我想要的所有操作。

docker-compose.yaml:

version: '3'
# Can be used as an alternative to VBox/Vagrantservices:
mongo:container_name: mongoimage: mongobuild:context: .dockerfile: deploy/local/Dockerfile.mongoports:- "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)

这可能是最干净的方法。

*老路*

我用我的命令创建了一个外壳脚本。在这种情况下,我想启动mongod并运行mongoimport,但调用mongod会阻止您运行其余部分。

docker-compose.yaml

version: '3'
services:mongo:container_name: mongoimage: mongo:3.2.12ports:- "27017:27017"volumes:- ./fixtures:/fixtures- ./deploy:/deploy- ../.data/mongodb:/data/dbcommand: 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,执行monog导入,然后杀死分叉的mongo,然后重新启动而不分离。不确定是否有方法附加到分叉进程,但这确实有效。

注意:如果您严格地想要加载一些初始数据库数据,这是执行此操作的方法:

mongo_import.sh

#!/bin/bash# Import from fixtures
# Used in build and docker-compose mongo (different dirs)DIRECTORY=../deploy/local/mongo_fixturesif [[ -d "/fixtures" ]]; thenDIRECTORY=/fixturesfiecho ${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文件是通过mongoport命令创建的。

docker-compose.yaml

version: '3'
services:mongo:container_name: mongoimage: mongo:3.2.12ports:- "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

这对我有用:

version: '3.1'services:db:image: postgresweb:build: .command:- /bin/bash- -c- |python manage.py migratepython manage.py runserver 0.0.0.0:8000
volumes:- .:/codeports:- "8000:8000"links:- db

docker-comput尝试取消引用运行命令的变量之前,因此如果您希望bash处理变量,您需要通过将它们加倍来转义美元符号…

    command:- /bin/bash- -c- |var=$$(echo 'foo')echo $$var # prints foo

…否则你会得到一个错误:

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

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

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

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

示例docker-compose.yml

version: "3"services:
api:restart: unless-stoppedcommand: ash -c "flask models init && flask run"

最干净的?

---version: "2"services:test:image: alpineentrypoint: ["/bin/sh","-c"]command:- |echo aecho becho c

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

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

在花费时间之后,决定将这些服务分离到单独的容器中,并且它像魅力一样工作

在@Bjorn答案的基础上,docker有最近推出特殊的依赖规则,允许您等待“init容器”成功退出,从而给出

db:image: postgresweb:image: appcommand: python manage.py runserver 0.0.0.0:8000depends_on:db:migration:condition: service_completed_successfullymigration:build: .image: appcommand: python manage.py migratedepends_on:- db

我不知道如果你仍然需要Buildkit或不但在我这边它的作品

DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker-compose up

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

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

services:mongo1:container_name: mongo1image: mongo:4.4.4restart: 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-clustervolumes:- ~/mongors/data1:/data/db- ./rs-init.sh:/scripts/rs-init.sh- api_vol:/data/dbenvironment:*env-varsdepends_on:- mongo2- mongo3

在Windows容器上运行:

  • 创建.bat文件(使用cmd运行,或者如果您的容器有它,您可以制作.ps1使用Powershell运行)
  • commandentrypoint中使用myFile.bat(或myFile.ps1

下载我的docker-compose.yml

version: "3.4"
services:myservicename:image: mcr.microsoft.com/dotnet/sdk:6.0container_name: mycontainernameenvironment:- PORT=44390command: buildAndRun.bat[...]

我的buildAndRun.bat

dotnet --list-sdksdotnet builddotnet run