今日も今日もでコンテナ立ち上げ
いままでコマンドラインでせっせとdocker runでコンテナ立ち上げていた人。はいそれは私です。
単純なコンテナならコマンドラインでもいいのですが、ちょっと複雑なオプションだったり、コンテナ同士の連携をやろうとすると手打ちでコマンド打っていくのとてもつらいです…。
シェルスクリプトでコンテナ立ち上げとかやっていたのですが、専用のツール使ったほうがいいかと思いDockerComposeを使い始めた次第です。
なかなか使い方がわからなくて勉強していましたので、せっかくだから記事にまとめてみるべと思いました。
ちょっと長い記事ですが、基本的なことは抑えられたかなと思います。
DockerComposeを使う
Dockerツール群の一つであるDockerComposeを使うと、コンテナ立ち上げ設定をファイル化(yml形式)して管理することが可能になります。
自前のシェルスクリプトでも同じようなことはできますが、手軽さが段違いです。
DockerComposeはPythonで書かれています。
DockerComposeに関しての情報は以下がおすすめです。公式ドキュメントの日本語訳です。
Docker Compose(日本語)
http://docs.docker.jp/compose/toc.html
DockerComposeインストール
導入方法は公式のページで解説されています。
Install Docker Compose(英語)
https://docs.docker.com/compose/install/
日本語訳もあります。参照してください。
Docker Compose のインストール(日本語)
http://docs.docker.jp/compose/install.html
いくつかのディストリビューションではパッケージがあるかと思いますので検索してみてください。
Arch Linuxにはパッケージありました。
DockerComposeはPythonアプリなのでpipからインストールすることも可能です。
ymlってなんだ?
@MINOはRails on Rubyをほとんど触ったことがないのであまりyml形式のファイルに慣れていません。
と思っていたのですが、そういやtmuxのtmuxinaterがRuby製で設定ファイルがyml形式だったことを忘れていました。
ymlは
データ構造を記述するフォーマット
の一つということで、jsonみたいなものの仲間と考えて良さそうですね。
というかymlはjsonのスーパーセット(上位互換みたいな感じ)だそうで、json形式でもymlとして認識してくれるらしいです。
ただjsonみたく波括弧をたくさん書かなくてよく、キーとインデントで構造を作っていくので記述するのが結構楽でいいですね。
キー:値
キー:値
キー:
- 値
- 値
キー:値
キー:値
DockerComposeではこのyml形式ファイルを使って、コンテナ起動に関してを記述していきます。
DockerComposeで使うファイルは
docker-compose.yml
というファイル名にします。任意のファイル名でも使えますが、このファイル名だとファイル指定を行わなくても自動的に認識してくれますので楽ですよ。
保存場所は任意の場所でも構いませんが、後々Dockerfile指定などのコンテキストのために、プロジェクトの作業ディレクトリのルートに置くのが普通のようです。
記述に関してのversionの存在
DockerComposeではymlの記述に関してversion1と2が存在しています。
が、すでにversion1は廃止が決定していますので、今後使えなくなります。
ですので新しくymlを記述する場合はversion2のほうが無難です。またversion2の方がより柔軟に記述できるようになっています。
version2を指定する方法は以下です。
version: '2'
この行が無い場合、composeはymlをversion1と判断します。
さらにversion2ではデータ構造のトップレベルとしてservicesという構造(キー)が必要になります。
version2として記述するには最低限以下の2行が必要ということになります。
version: '2'
services:
サービスの名前を指定
services構造直下に各コンテナに関しての記述を行っていくのですが、次の構造(キー)として各サービス名があります。
コンテナ一つでサービス担っている場合もありますが、複数のコンテナで一つのサービスを提供している場合もあります。
その場合立ち上げるコンテナごとに記述内容が異なるはずですので、区分して記述するために構造を分割します。
例えば、webサイトを表示させるコンテナを記述する場合、「web」などという名前で構造を作ります。もちろん任意の名前でokです。
注意点としてはこの名前がコンテナの名前になるわけではありません。
コンテナ名の指定は別途指定の方法があります。
サービス名を指定すると以下の様になります。今回はbusyboxでテストするのでshellという名前にしました。
version: '2'
services:
shell:
imageを指定する
次にコンテナを生成するためのイメージに関して記述します。
以下の様に単にimageを指定すると、すでに存在するimageを探してくれます。docker runの時と同じ様にまずローカルのimageから検索して、なければDockerHubからの取得を試みてくれます。
たとえばbusyboxを立ち上げたい場合は以下の様になります。
version: '2'
services:
shell:
image: busybox
2つのサービスを記述する場合の構造は以下のような感じになります。(意味のない組み合わせですが…)
version: '2'
services:
shell:
image: busybox
os:
image: debian
ymlの最小構成とサービスの起動
おそらく先程のimageを指定しただけのymlファイルが最小構成になると思います。この状態でもdocker-compose runコマンドでコンテナを立ち上げることが可能です。
docker-compose run
docker-compose runではymlに記述したサービス名を指定し、一つのサービス(コンテナ)を起動させることができます。
例えば先程のdocker-compose.ymlが/home/workdirにある場合、以下のようにしてコンテナを起動することができます。
shellサービス(busyboxコンテナ)を起動させてみます。
$cd /home/workdir
$ docker-compose run shell
# / ←busyboxのシェルが起動した
docker-compose up
またdocker-compose upというコマンドもあります。こちらはymlに記述したすべてのサービスを起動させます。
$ docker-compose up
Starting vimdocker_os_1
Starting vimdocker_shell_1
Attaching to vimdocker_shell_1, vimdocker_os_1
vimdocker_shell_1 exited with code 0
vimdocker_os_1 exited with code 0
しかし先のymlではdocker-compose upで起動しようとするとすぐに終了してしまいました。
これはdocker runでシェル起動するコンテナを作る場合、標準入力のバインド(iオプション)と仮想端末(tオプション)の指定をしない場合、シェルが起動しないままコンテナがすぐに終了してしまう挙動と同じことです。
コンテナでは何か継続的に動くプロセスがないと終了してしまうのは、docker runでコンテナを起動する時と変わりません。
docker-compose 「up」 「run」の違い
upとrunはどちらもコンテナを立ち上げるためのコマンドです。
upはサービス全体立ち上げ
upはdocker-compose.ymlに記述された内容をもとに、すべてのコンテナを設定通りビルド、起動、アタッチさせます。
複数コンテナで形成されるサービスを立ち上げるのが本来のupの使い方です。
またupで起動されたコンテナの出力は統合されることになります。
そのため以下のようdocker-compose.ymlでtty(docker run -tオプションに相当)、stdin_open(docker run -iオプションに相当)を記述しても、ttyはインタラクティブにはなりません。
version: '2'
services:
shell:
image: busybox
stdin: true
tty: true
runコマンドはone-off
一方runはdocker-compose.ymlに記述したコンテナを臨時にビルド、起動させます。
通常では一つのコンテナを立ち上げるために使われますので、docker-compose.ymlに記述したサービス名をもってrunするコンテナを指定します。
docker-compose runではデフォルトでdocker runのiオプション、tオプションが有効な状態で実行したのと同じ意味を持ちます。
そのためstdin(iオプション)、tty(tオプション)を記述しなくてもコンテナのシェルが(シェルが起動する設定であれば)表示されます。
$ docker-compoce run shell
# / ←busyboxのシェルが起動した
コンテナ名を指定する
docker-compose upにて起動したコンテナをdocker psで確認してみます。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a75d8da9e18f busybox "sh" 10 minutes ago Exited (0) 10 minutes ago workdir_shell_1
コンテナ名が自動で付いているのがわかるかと思います。
docker runの場合、コンテナ名を指定しないとランダムな単語の組み合わせでコンテナ名が付けれれますが、なにやらランダム単語というわけではなさそうです。
確認したところ、docker-compose upでのコンテナ名は「docker-compose.ymlが置かれているディレクトリ名」+「サービス名」+「数字」がデフォルトになっているようです。
workdir_shell_1
docker-compose runにて起動したコンテナはコンテナ名にrunが追加され、「docker-compose.ymlが置かれているディレクトリ名」+「サービス名」+「run」+「数字」となります。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c776964a6283 busybox "sh" 10 minutes ago Exited (0) 10 minutes ago workdir_shell_run_1
workdir_web_run_1
場合によってはコンテナに任意の名前を付けたい場合があるかと思います。
その場合はcontainer_nameキーにて指定します。
これはdocker runの–nameオプションに相当します。
以下ではfreeboxというコンテナ名を付けた例です。
version: '2'
services:
shell:
image: busybox
container_name: freebox
docker psで確認してみるとコンテナ名が指定したものになっています。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecfde54af4aa busybox "sh" 10 minutes ago Exited (0) 10 minutes ago freebox
dockerfileをビルドしてコンテナを立ち上げる
DockerComposeでは任意のdockerfileをビルドする設定も記述できます。
以下の様なdockerfileを作ってみました(意味なさすぎですが)。
//dockerfile
FROM busybox
RUN echo "busy!!"
このdockerfileで色々テストしてみます。
dockerfileをビルド
例えばディレクトリの中が以下のような場合
/home/workdir
dockerfile
dokcer-compose.yml
以下のようにしてビルド指定が行えます。
version: '2'
services:
shell:
build: .
build: .のドットはカレントディレクトリを意味することになります。
デフォルトで「Dockerfile(またはdockerfile)」というファイル名のDockerfileを探してくれますので、/home/workdir直下にあるdockerfileがビルドされコンテナが起動することになります。
docker-compose upを実行してみます。
$ docker-compose up
Building shell
Step 1 : FROM busybox
---> 1efc1d465fd6
Step 2 : RUN echo "busy!!"
---> Running in aa577f059517
busy!!
---> 5ec12e87cb89
Removing intermediate container aa577f059517
Successfully built 5ec12e87cb89
WARNING: Image for service shell was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating vimdocker_shell_1
Attaching to vimdocker_shell_1
vimdocker_shell_1 exited with code 0
ビルドとコンテナの起動(プロセスが無いので終了してしまってはいますが)は成功したようですが、なにやらWARNINGメッセージがでています。
これはimageが存在していなかったため、「なかったからビルドしたお」という警告です。
ビルドを伴う場合には以下のように明示的に–buildオプションを付けて実行します。(以下の実行は一旦image及びコンテナを削除して何もない状態にしてから実行しています)
$ docker-compose up --build
Building shell
Step 1 : FROM busybox
---> 1efc1d465fd6
Step 2 : RUN echo "busy!!"
---> Running in 0c489b927f30
busy!!
---> 0e489c3e3617
Removing intermediate container 0c489b927f30
Successfully built 0e489c3e3617
Creating vimdocker_shell_1
Attaching to vimdocker_shell_1
vimdocker_shell_1 exited with code 0
今度はWARNINGメッセージはでなくなりました。
またビルドのみを行う場合は以下のようにdocker-compose buildコマンドが使えます。
$ docker-compose build
Building shell
Step 1 : FROM busybox
---> 1efc1d465fd6
Step 2 : RUN echo "busy!!"
---> Running in 164c23f6fb54
busy!!
---> f5f40b09c0da
Removing intermediate container 164c23f6fb54
Successfully built f5f40b09c0da
ビルドのみが実行されています。
イメージ名を付けてビルド
docker-compose upのビルドではデフォルトでimage名が「docker-compose.ymlが置かれているディレクトリ名」+「サービス名」となります。
$docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
workdir_shell latest b105f5750fb8 2 days ago 1.095 MB
imageに任意の名前をつけるには以下のようにimageキーを記述します。buildキーが存在する場合には、このimageキーはイメージ名付与として働きます。
version: '2'
services:
shell:
build: .
image: busybox-test
docker-compose upを実行して確認すると指定した名前になっているのが確認できます。
$docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox-test latest b105f5750fb8 2 days ago 1.095 MB
dockerfileのファイル名指定
もし何かの理由で「dockerfile」から任意の名前に変えていた場合(複数のdockerfileが同じ階層に存在するなど)はファイル名を指定してビルドすることもできます。
例えば以下のような構成の場合、
/home/workdir
dockerfile
testdockerfile
dokcer-compose.yml
以下のようにしてdockerfileを指定してビルドできます。
version: '2'
services:
shell:
build: .
dockerfile: testdockerfile
image: busybox-test
コンテキスト指定
またディレクトリのコンテキストを指定することも可能です。絶対指定も行えますが、可搬性を考えると相対指定の方が良いかと思います。
例えば以下のような構成の場合、
/home/workdir
buildfiles/
dockerfile
testdockerfile
dokcer-compose.yml
以下のようにしてコンテキストを指定することができます。
version: '2'
services:
shell:
build:
context: ./buildfiles
dockerfile: testdockerfile
image: busybox-test
以下でも同じ意味になりますが、contextではGitHubなどのURLの指定も行えるため、contextを使ったほうがより柔軟な記述が可能です。
version: '2'
services:
shell:
build: ./buildfiles
dockerfile: testdockerfile
image: busybox-test
GitHubなどからの取得
contextにはGitHub等のURLも指定可能です。
以下はGitHubにあるdocker/composeリポジトリを指定してimageをビルドすることになります。
version: '2'
services:
test:
build:
context: https://github.com/docker/compose.git
image: compose-test
ただし、リポジトリのルートディレクトリ直下にDockerfileが存在していないと、composeはDockerfileを探すことができません。
Dockerfileがリポジトリのルートディレクトリ直下にないリポジトリの場合は以下のようにエラーが出て(–vervoseオプション使用時)終了してしまいます。
ERROR: compose.cli.errors.log_api_error: Cannot locate specified Dockerfile: Dockerfile
※リポジトリのルートディレクトリ直下にDockerfileが無い場合、リポジトリのTree構造(Dockerfileの場所)をどのようにyml内で指定するのかは調査不足で判明していません。
さまざまなオプション
docker runで指定するオプションとdocker-compose.ymlで指定するコマンドの対応は以下です。
※runで使用できるオプションすべてを利用できるかどうかが不明な場合もありました。ソースコードを確認しつつ表を作りましたが調査が不十分で間違っている場合がありますのでご注意ください。
キー | 相当するdocker runオプション | 機能 |
---|---|---|
cap_add | –cap-add | Linuxケーパビリティの追加 |
cap_drop | –cap-drop | Linuxケーパビリティの削除 |
command | runコマンド末尾のコマンド指定に相当 | コマンドの指定 |
cpu_shares | -c –cpu-shares | cpu共有ウエイトの設定 |
cpuset | –cpuset-cpus | cpuコアの割当 |
devices | −−devices | 特権が無いコンテナ内でもデバイスの実行を許可 |
dns | –dns | DNSの設定 |
dns_search | –dns-search | DNSの検索ドメイン |
domainname | –hostnameに相当 | ドメイン名の設定 |
entrypoint | –entrypoint | entrypointの設定 |
env_file | -eに相当? | 環境変数のファイル指定 |
environment | -e | 環境変数のバインド |
expose | -P –expose | 露出ポートの指定 |
extra_hosts | –add-host | /ext/hostsへのホスト名の書き込み |
hostname | –hostname | ホスト名の設定 |
image | runコマンド末尾のイメージ指定に相当 | イメージ指定 |
ipc | –ipc | IPC名前空間設定 |
labels | –label | ラベル |
links | –link | コンテナのリンク設定 |
log_driver | –log_driverに相当? | ログサービスを指定 |
logging | –log-driverに相当? | ログのON/OFF |
mac_address | –mac-address | MACアドレスの設定 |
mem_limit | –memory | メモリ設定 |
memswap_limit | –memory-swap | メモリスワップの設定 |
name_container | –name | コンテナ名 |
network_mode | –net | ネットワークモードの設定 |
pid | –pid | pidの設定 |
ports | -p | ポートのバインド |
privileged | –privileged | コンテナに拡張権限を与える |
read_only | -vオプションでのroに相当? | 読み込み専用 |
restart | –restart | コンテナの再起動ポリシー |
stdin_open | −i | 標準入力 |
tmpfs | –tmpfs | 一時ファイルシステムの設定 |
tty | −t | 端末の付与 |
user | -u | ユーザ指定 |
volume | -v | ボリュームの指定 |
volume_driver | -vに相当? | ボリュームドライバの指定 |
volumes_from | –volumes_from | ボリュームコンテナのバインド |
working_dir | -w | 作業ディレクトリの指定 |
? | –blkio-weight | ブロック I/O ウエイト設定 |
? | –cgroup-parent | cgroup設定 |
? | –cpu-period | CPU CFSのピリオドの上限 |
? | –cpu-quota | CPU CFSのクォータ設定 |
? | –cpuset-mems | 実行するメモリノードの割り当て |
? | –group-add | グループの追加 |
? | –health-interval | チェックを実行する間隔 |
? | –health-retries | 障害を報告するまでに必要な連続失敗回数 |
? | –health-timeout | チェックを実行できる最長時間 |
? | –kernel-memory | カーネルメモリの設定 |
? | –lxc-conf | カスタムlxc オプションの追加 |
? | –memory-reservation | メモリのソフトリミット |
? | –memory-swappiness | メモリのスワップ度合いの調整 |
? | –no-healthcheck | コンテナ固有のヘルスチェックを無効化 |
? | –oom-kill-disable | oomkillerのon/off |
? | –rm | コンテナの削除 |
? | –security-opt | セキュリティ設定 |
? | –uts | UTS名前空間モード設定 |
具体例
いくつか基本的な例を挙げていきたいと思います。
ポートの開放およびバインド
以下の様なdocker runコマンドをcomposeで再現してみます。
$ docker run -it -p 10022:22 busybox
ymlファイルは以下のようになります。
version: '2'
services:
test:
image: busybox
ports:
- "10022:22"
tty: true
stdin_open: true
upしてみます。(ttyと標準入力をtrueにしていますが、前述したとおりインタラクティブにはならず、待機状態になります)
$ docker-compose up
Recreating workdir_shell_1
Attaching to workdir_test_1
PORTSに開放しバインドしたポートが確認できます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a53b48665e45 busybox "sh" 10 seconds ago Up 8 seconds 0.0.0.0:10022->22/tcp workdir_test_1
コマンドの実行
以下の様なdocker runコマンドをcomposeで再現してみます。
$ docker run -it busybox sleep 100
ymlファイルは以下のようになります。
version: '2'
services:
test:
image: busybox
command: sleep 100
tty: true
stdin_open: true
upしてみます。(ttyと標準入力をtrueにしていますが、前述したとおりインタラクティブにはならず、待機状態になります)
$ docker-compose up
Recreating workdir_shell_1
Attaching to workdir_test_1
COMMANDがもともとbusyboxのDockerfileに指定されているshからsleep 100に上書きされました。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c1475d4e54f busybox "sleep 100" 11 seconds ago Up 7 seconds workdir_test_1
コンテナの連携
DockerComposeの真価が発揮できるのがコンテナの連携です。複数のコンテナの設定を記述することができます。
以下の様なdocker runコマンドをymlに記述していきたいと思います。
以下は公式のMySQL、WordPressイメージを使ってWordPress環境を立ち上げるコマンドです。テーマファイルを分離できるよう、ボリュームコンテナを作成してバインドしています。
WordPressはデータベースが必要になるため、コマンドラインからrunする場合は、先にデータベースコンテナを作っておく必要があります。
$ docker create --name themesdate -v /your/dir:/var/www/html/wp-content/themes/ busybox
$ docker run --name wpdb --restart=always -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=db mysql:latest
$ docker run --name wps -p 8000:80 --link db:mysql --volumes-from themesdate --restart=always -e WORDPRESS_DB_HOST=$WPDB_PORT_3306_TCP_ADDR -e WORDPRESS_DB_PASSWORD=$WPDB_MYSQL_ROOT_PASSWORD wordpress
ymlに記述すると以下のようになります。
version: '2'
services:
volume:
image: busybox
container_name: themesdata
volumes:
- "/your/dir:/var/www/html/wp-content/themes/"
datebase:
image: mysql:5.7
container_name: db
restart: always
environment:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: db
wordpress:
depends_on:
- datebase
image: wordpress:latest
container_name: wp
volumes_from:
- volume
links:
- database
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: database:3306
WORDPRESS_DB_PASSWORD: pass
この例では
- ボリュームのバインド volumes:
- ボリュームコンテナのバインド volumes-from:
- ポートの開放とバインド ports:
- link設定 links:
- コンテナ名 container_name:
- 環境変数の指定 environment:
- 依存関係の指定 depends_on:
- 再起動ポリシーの設定 restart:
が実現できています。
サービス名とコンテナ名に注意
ボリュームコンテナのバインドやlink設定、依存関係の設定の場合、指定するのは「サービス名」です。コンテナ名ではありません。
以下は誤りになります。
volumes_from:
- themesdata
しかしvolumes_fromではコンテナ名を指定したい場合、以下の様にすることができます。
volumes_from:
- container:themesdata
今回はコンテナ名も記述しましたが、意外と混乱してしまうので、サービス名とコンテナ名はちゃんと見分けられるように付けたほうがいいでしょう。
docker-compose upすると大量にログが出力されます。今回は3つのコンテナが連携することになりますが、それぞれの出力は一つにまとまります。
どのコンテナのログかは行の最初にコンテナ名が付きますので識別できます。
以下は出力の抜粋です。
$ docker-compose up
~~~~
~~~~
~~~~
wpdb | 2017-01-11T06:05:28.227391Z 0 [Note] Event Scheduler: Loaded 0 events
wpdb | 2017-01-11T06:05:28.227470Z 0 [Note] Executing 'SELECT * FROM INFORMATION_SCHEMA.TABLES;' to get a list of tables using the deprecated partition engine. You may use the startup option '--disable-partition-engine-check' to skip this check.
wpdb | 2017-01-11T06:05:28.227476Z 0 [Note] Beginning of list of non-natively partitioned tables
wpdb | 2017-01-11T06:05:28.233052Z 0 [Note] End of list of non-natively partitioned tables
wpdb | 2017-01-11T06:05:28.233156Z 0 [Note] mysqld: ready for connections.
wpdb | Version: '5.7.17' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
wp | Complete! WordPress has been successfully copied to /var/www/html
wp | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
wp | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
wp | [Wed Jan 11 06:05:30.960373 2017] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.10 (Debian) PHP/5.6.29 configured -- resuming normal operations
wp | [Wed Jan 11 06:05:30.960393 2017] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
読んでいくと最後にapache2 -D FOREGROUNDが実行されWordPress環境が構築されたことがわかります。
補足・ハマったポイント
depends_onについて
依存関係を記述するdepends_onですが、コンテナ作成開始までは待ってくれるのですが、コンテナ内部の準備が整うのを待ってくれるわけではありません。
例えば先ほどのWordPress環境で説明すると、WordPressコンテナはMySQLコンテナが作られるまでは作られません。
しかしMySQLコンテナが作られて、内部でデータベースやユーザ関係の処理が行われデータベースとして使える状態になるまでは待ちません。
ですので場合によってはMySQLコンテナの準備が間に合わず、WordPressコンテナがMySQLコンテナにアクセスしようとしても不能になる可能性もあります。
幸い公式のWordPressイメージでは接続試行を複数回(たしか20回)おこなってくれますので、そのうちにMySQLコンテナの準備が整えば接続できるようになります。
このように、コンテナを連携させる時は、「コンテナの準備の時間」が重要になってくる場合があります。
ほとんどの場合で試行回数などで対応できるかと思いますが、この辺は自作のDockerfileの場合、いろいろ弄くる必要のある箇所かもしれません。
まとめ
随分長い記事になってしまいましたが、どうにかDockerComposeの基本的なことはお伝えできたのではと思います。
それにしてもコマンドラインで長いrunコマンドを泣く泣く打っていたことを考えるととてもラクですね。
これでdockerfileで環境を管理し、立ち上げをdocker-compose.ymlで管理するという可搬性の高い状態になりますね。
本当に便利になったものです。