複数のdocker imageとcontainerを使ってサクッと環境を整えたいときにdocker composeってとても便利ですよね。 単純な構成だと公式ドキュメントを読めばわりと簡単に思い通りになるのですが、 意外と慣れるまではどんな設定をしてどうファイルを配置するか迷いがちだと思います。 そんなわけで今更感が強いですがベストプラクティス的なものをまとめておきます。
今月のブログ書くネタに困って今更になってdocker composeを選んだわけでは…うっ… ベストプラクティスと言いつつ半年以上前の情報の可能性が…うっ…
さっそくベストプラクティスについてですが、幾つかのフェーズがあります。より後ろのフェーズであるほど設定が複雑化されるのでなるべく避けたいわけです。
フェーズ1: docker-compose.ymlで完結させる
まずdocker-compose.ymlはversion 3を使用しましょう。その方が設定が簡潔に書けます。 2と3はそんなに変わらない印象なので2でも良いのですが。(実はこのブログ書いてる時に3が出てることを知りましたw)
当然のことですがdocker-compose.ymlの1ファイルで構成が完結できたらハッピーですよね。 これでやりたい構成ができちゃうことは少ないかもしれませんが、docker imageの作りが良い場合はenvironmentの設定でなんとかなることもあります。
docker-compose-example/docker-compose.yml at master · innossh/docker-compose-example · GitHub
version: '3' services: mysql: image: mysql:5.7.18 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: my-secret-pw postgres: image: postgres:9.6.2 ports: - "5432:5432" environment: POSTGRES_PASSWORD: mysecretpassword
あまり例が良くないですが、基本ホストマシンで作業してるけどちょっとDBだけ別で欲しい時にちょろっと書いて立ち上げる時に使えると思います。
それdocker runでいいじゃんって思う人もいますが、名前付け面倒だしオプションとかすぐ忘れるんでcomposeと設定ファイルでやる方が便利です。
ちょっとコンテナの中覗きたいって時も docker-compose exec mysql /bin/bash
これでいけます、自然で気持ち良い。
フェーズ2: data volumeを使う
使用するdocker imageを調べて欲しい環境変数が用意されていなくて、思い通りの構成にできないからDockerfile書くか…と思うのはいったん待ってください。 意外とdata volumeを使って設定ファイルなどを置き換えることでうまくできることがあります。
docker-compose-example/docker-compose.yml at master · innossh/docker-compose-example · GitHub
version: '3' services: nginx: image: nginx:1.11.13-alpine ports: - "80:80" volumes: - ./nginx/index.html:/usr/share/nginx/html/index.html logging: driver: fluentd options: fluentd-address: "127.0.0.1:24224" tag: "docker.{{.Name}}" depends_on: - fluentd fluentd: image: fluent/fluentd:v0.14.14 ports: - "24224:24224" volumes: - ./fluentd/etc/fluent.conf:/fluentd/etc/fluent.conf
例えばこのようにピンポイントでfluent.confやindex.htmlを置き換えれば、localhostにアクセスすると配置したhtmlを返してくれて nginxのログはfluentdコンテナの標準出力に吐き出すことができます。 構成を実現するためのファイルは増えましたが、Dockerfileが増えたわけではないので docker-compose.ymlをパッと見た時にあまり複雑さは増していないと思います。そこまで不安になりませんw
フェーズ3: Dockerfileを用意する
とうとう来てしまいました。Dockerfileを自前で用意するなんて…いやだいやだいやだ。 もしかしたらDockerfileを書きたくないだけなのかもしれません。オレオレになりがちなんですよね。 まあそのあたりはDockerfileのベストプラクティスもあると思うのでここでは触れません。(逃げ)
ここでのサンプルはnginxのログをfluentdに流してmysqlにinnodb memcached pluginで投入するものです。 ただのサンプルなので無理やりdemo_testテーブルを使ってリクエスト件数を準リアルタイムに保存してます。
docker-compose-example/docker-compose.yml at master · innossh/docker-compose-example · GitHub
version: '3' services: nginx: image: nginx:1.11.13-alpine ports: - "80:80" logging: driver: fluentd options: fluentd-address: "127.0.0.1:24224" tag: "docker.{{.Name}}" depends_on: - fluentd fluentd: build: ./fluentd ports: - "24224:24224" volumes: - ./fluentd/etc/fluent.conf:/fluentd/etc/fluent.conf mysql: image: mysql:5.7.18 ports: - "3306:3306" - "11211:11211" volumes: - ./mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d environment: MYSQL_ROOT_PASSWORD: my-secret-pw
やむなくDockerfileを用意する場合でも、そのDockerfileがシンプルであるに越したことはないですよね。 やりがちなのは使いたいdocker imageのDockerfileをコピペしていじりたい部分だけ修正する方法なのですが、 例えばfluentdのpluginをインストールしたいだけでしたら下記のように対象のimageを指定してRUNコマンドを書くだけでよいのです。
docker-compose-example/Dockerfile at master · innossh/docker-compose-example · GitHub
FROM fluent/fluentd:v0.14.14 RUN gem install fluent-plugin-memcached --no-rdoc --no-ri
あとはENTRYPOINTやCMDを変更したいだけでしたら、docker-compose.yml内のentrypointの指定で解決できる場合もあるので
なんとかフェーズ2でおさえることができないか検討した方がよいでしょう。
どうしてもDockerfileが必要な場合は有りものを使ってなるべくシンプルに。
なにか不具合があってDockerfileをいじって再度起動したいときは docker-compose up --force-recreate --build -d
のようにimageをビルドし直すのをお忘れなく。
docker composeのベストプラクティス
- なるべくdocker-compose.ymlで完結
- 必要ならdata volumeでコンテナのファイルを置き換え
- 諦めてDockerfileを書く場合でもよりシンプルに
以上今更でした。