docker-compose.ymlのcommandプロパティに複数コマンドを設定する方法

Bash, Docker, Linux

はじめに

Docker Composeは非常に便利ですね。

3層構造(クライアント、Web、DB)のアプリケーションを作る際には、最低限Webのコンテナ、DBのコンテナの2つを同時に立ち上げる必要があります。

Docker Composeなら簡単に環境を構築できます。

これらのコンテナを立ち上げる前の準備処理を行ってきたい場合があります。
(initコンテナとでも呼びましょうか。例えば設定ファイルを作ったり。)

docker-compose.ymlcommand プロパティにこれらの初期処理を設定したかったのですが、シェルを複数コマンド記述したり、リダイレクトさせたりで少々ハマったので共有します。

検証環境

$ uname -moi
x86_64 MacBookPro11,4 Darwin

$ docker-compose --version
docker-compose version 1.25.2, build 698e2846

どんなことがしたかったか?

初期処理として、以下のような2行のコマンドを実行してファイルを作成したいとします。

echo "Konnichiwa!" > /shared_dir/hello.txt
chmod 600 /shared_dir/hello.txt

シェルで記述すると非常に簡単です。
ワンライナーだと以下のように記述できますね。

echo "Konnichiwa!" > /shared_dir/hello.txt; chmod 600 /shared_dir/hello.txt

改行で区切る代わりに ; を指定しています。

さて、このような処理をさせる docker-compose.yml を記述してみます。

  • Konnichiwa! という文字列を hello.txt に出力
  • ついでにパーミッションも変更する
  • hello.txt は共有フォルダに配置しているので、ローカルから見える
version: "3"
services:
  init:
    image: bash
    volumes:
      - $PWD:/shared_dir
    command:
      echo "Konnichiwa!" > /shared_dir/hello.txt; chmod 600 /shared_dir/hello.txt

この定義ファイルを使って docker-compose up してみます。

# なにか echo されました。
$ docker-compose up
WARNING: Found orphan containers (work_before_1, work_web_1, work_after_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Starting work_init_1 ... done
Attaching to work_init_1
init_1  | Konnichiwa! > /shared_dir/hello.txt; chmod 600 /shared_dir/hello.txt
work_init_1 exited with code 0

# ファイルもできていない
$ ll
-rw-rw-r-- 1 genzouw wheel 228  1 25 08:54 docker-compose.yml

echo 以降の文字列がそのまま表示されてしまいました。

sh -c を使う

それでは解決方法に進みます。
sh -c "..." の構文をつかって、処理させたい複数のコマンドを囲んでやります。

version: "2"
services:
  init:
    image: bash
    volumes:
      - $PWD:/shared_dir
    command:
      sh -c 'echo "Konnichiwa!" > /shared_dir/hello.txt; chmod 600 /shared_dir/hello.txt'
$ docker-compose up
WARNING: Found orphan containers (work_after_1, work_web_1, work_before_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Starting work_init_1 ... done
Attaching to work_init_1
work_init_1 exited with code 0

$ ls -l
total 8
-rw-rw-r-- 1 genzouw wheel 188  1 25 09:01 docker-compose.yml
-rw------- 1 genzouw wheel  12  1 25 09:02 hello.txt

$ cat hello.txt
Konnichiwa!

ちなみに、以下のように折り返して記述することもできます。

version: "2"
services:
  init:
    image: bash
    volumes:
      - $PWD:/shared_dir
    command: >
      sh -c '
        echo "Konnichiwa!" > /shared_dir/hello.txt
        chmod 600 /shared_dir/hello.txt
      '

ひとこと

本当は各コンテナの entrypoint.sh などで実現するのが正しいやり方でしょうか?

Bash, Docker, Linux