Docker-Composeを使用して、複数のコマンドを実行する方法


500

複数のコマンドを順番に実行できるようにしたいのですが。

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

回答:


861

それを理解し、を使用します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
  "

6
@Pedram実際にbashがインストールされているイメージを使用していることを確認してください。いくつかの画像はまた、bashの例への直接パスを必要とするかもしれない/bin/bash
codemaven

5
bashがインストールされていない場合は、sh -c "your command"
Chaoste

bashに渡すときは、コマンドを引用符で囲んでください。dbが稼働していることを確認するために「sleep 5」を入力する必要がありましたが、それでうまくいきました。
2016年

74
@Chaosteが推奨して使うように行う-アルパインベースのイメージは、実際にはbashがインストールされていないように見えるsh代わりに:[sh, -c, "cd /usr/src/app && npm start"]
フロリアン湖

1
ash高山だけでも使用できます:)
ジョナサン

160

私は移行のような起動前のものを別のエフェメラルコンテナーで実行します(注、構成ファイルはバージョン '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

これは、物事を清潔に分離するのに役立ちます。考慮すべき2つの点:

  1. 正しい起動シーケンスを確認する必要があります(depends_onを使用)

  2. ビルドとイメージを使用して最初にタグ付けすることで達成される複数のビルドを避けたい場合。他のコンテナの画像を参照できます


2
これは私にとって最良のオプションのようであり、私はそれを使用したいと思います。複数のビルドを回避するためにタグ付けの設定について詳しく説明できますか?私は余分なステップを避けたいので、これがいくつかを必要とするなら、私はbash -c上記で行くかもしれません。
Stavros Korokithakis

3
上記のyamlでは、移行セクションでビルドとタグ付けが行われます。一見して明らかではありませんが、ビルドとイメージプロパティを指定すると、docker-composeがタグを付けます。これにより、イメージプロパティがそのビルドのタグを指定します。その後、新しいビルドをトリガーせずにそれを使用できます(Webを見ると、ビルドがなく、イメージプロパティのみがあることがわかります)。ここでは、いくつかの詳細がありますdocs.docker.com/compose/compose-file
ビョルンStiel

26
私はこれのアイデアが好きですが、depends_onはそれらがその順序で開始することを保証するだけであり、その順序で準備ができているということではないという問題があります。wait-for-it.shは、一部の人々が必要とするソリューションである可能性があります。
2016年

2
これは完全に正しいことであり、docker-composeがコンテナーが終了するのを待つ、またはポートでリッスンを開始するのを待つような細かい制御をサポートしないことは少し残念です。しかし、はい、カスタムスクリプトでこれを解決できます。
Bjoern Stiel、2016年

1
この回答は、depends_onがどのように機能するかについての誤った、潜在的に破壊的な情報を提供します。
antonagestam

96

とは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 -開発サーバーを起動します

2
個人的には、これが私のお気に入りの、そして最もクリーンなソリューションです。
BugHunterUK 2018年

1
あまりにも私のもの。@LondonAppDevが指摘しているように、スペースを最適化するためにすべてのコンテナでデフォルトでbashを使用することはできません(たとえば、Alpine Linuxの上に構築されたほとんどのコンテナ)
ewilan

2
私はマルチライン&&を\でエスケープする必要がありました
Andre Van Zuydam

@AndreVanZuydamうーん、奇妙なことに、私はそうする必要はありませんでした。引用符で囲みましたか?実行しているdockerの種類は何ですか?
LondonAppDev 2018年

2
@oligofrenは>、複数行の入力を開始するために使用されます(stackoverflow.com/a/3790497/2220370を参照)
LondonAppDev

40

これは私にとってはうまくいきます:

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で変数を処理する場合は、2倍にしてドル記号をエスケープする必要があります...

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

そうしないと、エラーが発生します。

サービス「web」の「コマンド」オプションの無効な補間形式:


やあ。私は問題に遭遇しました: `` `認識できない引数:/ 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はシェル環境を探しています。代わりに試してみてください$${Types}$${Client}。これにより、docker composeがそれらの変数を解釈し、docker-composeを呼び出すシェルでそれらの値を探すことができなくなると思います。これは、それらがbashがそれらを逆参照するためにまだ残っていることを意味します(dockerがファイルを処理した.env)。
MatrixManAtYrService

ご意見ありがとうございます。私はあなたが実際言ったことをしました。したがって、エラー情報に$(Client)が含まれています。Pythonでos.getenvを使用するように環境変数を読み取る方法を変更しました。とにかくありがとう。
イモリ

23

ここでエントリポイントを使用できます。dockerのエントリポイントはコマンドの前に実行されますが、commandはコンテナの起動時に実行されるデフォルトのコマンドです。そのため、ほとんどのアプリケーションは一般にエントリポイントファイルでセットアップ手順を実行し、最後にコマンドの実行を許可します。

シェルスクリプトファイル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 ....
thisismydesign

18

別のアイデア:

この場合のように、コンテナーを構築する場合は、コンテナーに起動スクリプトを配置して、コマンドでこれを実行するだけです。または、起動スクリプトをボリュームとしてマウントします。


はい、最後にrun.shスクリプトを作成しました:(#!/bin/bash \n python manage.py migrate \n python manage.py runserver 0.0.0.0:8000醜いoneline)
fero

9

*更新*

いくつかのコマンドを実行する最良の方法は、公式のCMDがイメージから実行される前に、必要なすべてを実行するカスタムDockerfileを作成することだと考えました。

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

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: 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を強制終了し、切り離さずに再び起動します。フォークされたプロセスにアタッチする方法があるかどうかはわかりませんが、これは機能します。

注:いくつかの初期dbデータを厳密にロードしたい場合は、これがその方法です。

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

5

複数のデーモンプロセスを実行する必要がある場合、すべてのサブデーモンがstdoutに出力されるように、非分離モードでSupervisordを使用するようにDockerドキュメントに提案されています。

別のSOの質問から、子プロセスの出力をstdoutにリダイレクトできることがわかりました。 そうすれば、すべての出力を見ることができます!


これをもう一度見てみると、この回答は、複数のコマンドを逐次ではなく並列に実行するのに適しています。
Tim Tisdall 2018


1

wait-for-itやdockerizeなどのツールを使用します。これらは、アプリケーションのイメージに含めることができる小さなラッパースクリプトです。または、独自のラッパースクリプトを記述して、よりアプリケーション固有のコマンドを実行します。によると:https : //docs.docker.com/compose/startup-order/


0

私はjenkinsコンテナーをセットアップしてjenkinsユーザーとしてDockerコンテナーを構築しようとしているときにこれに遭遇しました。

後でdocker-composeファイルでリンクするときに、Dockerfileのdocker.sockファイルをタッチする必要がありました。最初に触れない限り、まだ存在していませんでした。これでうまくいきました。

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

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

これは別の質問に対する答えのようです。
ケノーブ

-7

「;」を使用してみてください バージョン2の場合はコマンドを分離する

command: "sleep 20; echo 'a'"

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.