Dockerで開発運用するためのTips

#WHY

Docker縛りなので合わせました。
現職でインフラもやっているのでインフラを書くことにしました。インフラは[Tech-Circle](https://techcircle.connpass.com/)で学びました。AnsibleとTerraform、Dockerじゃないけど役に立ってます。感謝！！

インフラ、クロラー、検索機能、軽いフロント、開発環境改善、データ分析と幅広くやっているのでインフラ専任の人には劣るかもしれませんが頑張ります。

![image](https://qiita-image-store.s3.amazonaws.com/0/10496/ddc7e0b5-73b3-cb5c-7304-ce95c53f04eb.png)

Dockerで開発、運用していると非効率な面や通常ではハマらない面でハマったりします。どのような場面で遭遇するか記述し、そのために行った解決策も追記します。

もっと良い方法が知ってるよって方がいればコメントしていただけると私だけでなくこの記事を読んで頂いた方のためにもなると思うので

なお公式にはもっと詳しく記述されていると思うので詳しく知りたい方は下記をご参照ください。

https://docs.docker.com/

この記事では開発のシーンにおいてどのような困るかという観点で記述したかったので書きました。

## ディレクトリ構成

ADDコマンドを使用したり、複数のDockerfileを使用するとファイルが散らかりがちになります。見通しを良くするためにDockerfileで直接ビルドせずにMakeファイルを使ってビルドしています。ディレクトリ構成は下記のようにしています。

```
Makefile
- conf
- data
- dockerfiles
- script
- template
```

`make ビルドしたいdockerfile`を指定して動作するようにしています。

Makefileの例は下記をご覧ください。

https://github.com/SnowMasaya/Chainer-Slack-Twitter-Dialogue/blob/master/infra/docker/Makefile

## ファイル構成

Dockerfile内で複数の設定していると見通しが悪く悪くなります。下記の書き方以外にもあると思いますが下記のように設定ごとに分けることで後で見るときに見返しやすくしています。`&&`で繋げてレイヤーを抑えないといけないので書き方は適宜工夫してください。

```
:
設定内容を記述
:
#################################################################################################################
#			何かの設定				#
#################################################################################################################
:
設定内容を記述
:
```

## ビルドが長い

Dockerfileの変更があるとイメージの再作成のためにビルドによる待ち時間が発生します。頻繁に変更があると今日はDockerのビルドだけで1日が終わった・・・ということもありえます。
解決策としては

- ビルドを早くする
- イメージへの反映は後で行う

この2点になります。

### ビルドを早くする

- 共通イメージを作成する
 - 共通イメージ用のDockerfileを作成しておくと差分のビルドだけで済みます。またチームや開発部署全体で統一しておくとコンテキストスイッチのコストが抑えられます。
- キャッシュを利用する
 - Dockerはすでにビルドされている部分はキャッシュが効くのでDockerfileの変更が発生した場合はDockerfileの追記すれば追記した箇所から下の部分を再度ビルドしてくれます。明示的な理由がない限り最初の部分で修正したり、追記しない方が良いです。

イメージ

Dockerfile

```
:
追記（ここから下が再度ビルド）
:　
:
:
:
```

### イメージへの反映は後で行う

ビルドを待っていると開発スピードが低下します。イメージの反映は後で良いからDocker環境内で動作確認したい場合に使う手法です。
 
- entrypointオプション-itオプションと-vオプションを使用する
 - entrypointに"bash"を設定し-itオプションを設定すると対話モードでdockerの中に入れます。-vオプションによって開発環境のコードを同期させられるのでこれでdocker内で動作確認ができます。(注意：CMDでコマンド実行を設定していない場合のみ使えます。)
- イメージのビルドは自動化
 - Jenkinsなどでgithubにコードが修正された瞬間にJenkinsのサーバーでビルドを走らせてDockerhubなどにpushする

![image](https://qiita-image-store.s3.amazonaws.com/0/10496/ea2e0437-b1f7-45e0-8861-a4d5e15b8e86.png)


上記の手法でDocker内で動作確認できたら、そのコードをgithubに上げて、あとは自動的にイメージに反映するようにすれば待ち時間はなくせます。

## デプロイの時間が長い

Dockerのイメージのデプロイはイメージが肥大化してくると非常に時間がかかります。

- Jenkinsでの自動デプロイ
 - stagingの環境には基本的に最新のイメージが自動的にデプロイされるようにJenkinsなどで設定しておけば、人の手を煩わせずに作業が行えます。
 

## gitの変更内容が反映されない

Dockerのキャッシュの都合上、githubが更新されてもそれを感知できずにビルドされてしまいます。これはもっと良い解決法があると思いますが現状ではこのような方法で解決しています。

- `date`コマンドでファイルの内容をビルド前に書き換え、ビルド時にgit pullなどのコマンドの前に変更したファイルをADDで加える

多分もっと良い方法があると思います。

## 回帰テスト

回帰テストは自動でテストを行いたいのが心情です。dockerを起動すると起動中のコンテナが残って消す作業が発生します。これを自動で消してくれるオプションがdockerには備わっています。

 - docker run時に`-rm`オプションをつけると自動で`run`が終了時に起動中のコンテナを削除してくれます。

## ログに関して

docker内で標準出力されたログを確認したいニーズはあると思います。

fluentdを使用してs3に保存しておけばdockerのログを後で確認できます。
タグ名をつけておけばどのコンテナからのログかも把握できるので便利です。

```
docker run -d -it --log-driver=fluentd --log-opt fluentd-address={fluentdのアドレス}:ポート番号 --log-opt tag={ログのタグ名}"
```

公式ドキュメント

https://docs.docker.com/engine/admin/logging/fluentd/

#まとめ

Dockerは便利な反面、余分な時間がかかる面もあります。なるべく時間をかけずに効率良く使っていくための知識共有になると幸いです。
他にも工夫している点があれば教えて頂けると幸いです。

最後までお付き合いいただきありがとうございました。
明日は、[@ike_dai](http://qiita.com/ike_dai)さんです。よろしくおねがいします！