Docker 開発ベストプラクティス

以下の開発パターンは、Docker でアプリケーションを構築する皆さんに役立つように実績があるものです。皆さんも何かを発見されたら、私たちが追加しますので お知らせください

イメージを小さく保ち続ける方法

コンテナやサービスを開始するにあたり、小さなイメージはネットワーク越しの取得をより早くし、メモリへの読み込みもより速くします。以下にあるのは経験に基づく、イメージを小さくし続けるためのルールです。

  • 適切なベースイメージで始めましょう。たとえば、 JDK が必要なら、一般的な ubuntu イメージに openjdk をインストールするのではなく、公式 openjdk イメージをベースにするのを検討します。
  • マルチステージ・ビルドを使います 。たとえば、 Java アプリケーションを構築するにあたり maven イメージを使えるとします。その時、アプリをデプロイするためには、 tomcat イメージをリセットし、Java アーティファクトを適切な場所にコピーします。これらすべてが、同じ Dockerifle 中の命令としてあります。これが意味するのは、最終イメージには構築時に取得した全てのライブラリや依存関係は含みませんが、アーティファクトと実行に必要な環境変数のみが入っています。

    • もしも使用中の Docker がマルチステージ・ビルドに対応していないバージョンであれば、イメージのレイヤ数を減らすため、Dockerfile 中でバラバラの RUN 命令の数を最小化します。この作業時に、シェルの仕組みを使って複数の RUN 命令を1つにまとめられます。以下にある1つめのイメージには2つのレイヤがありますが、2つめのイメージは1つのレイヤしかありません。
    RUN apt-get -y update
    RUN apt-get install -y python
    
    RUN apt-get -y update && apt-get install -y python
    
  • もしも、複数のイメージで共通している箇所が多いようであれば、共通コンポーネントが入った ベース・イメージ を作成し、それを自分が使う独自イメージのベースにするように検討します。Docker は共通のレイヤを一度読み込む必要がありますが、それらのレイヤはキャッシュされます。つまり、Docker ホスト上で派生するイメージが使うメモリは効率的になり、かつ処理が素早くなります。
  • プロダクション用のイメージは、スリムにし続ける必要があります。しかし、デバッグ可能にするため、プロダクション用イメージをベース・イメージにした、デバッグ用のイメージ作成を検討します。テストやデバッグ用のツールの追加は、プロダクション用イメージの上に追加できるでしょう。
  • イメージの構築時、常に分かりやすいタグを付けます。タグには、バージョン情報の明示、展開先の対象(たとえば prodtest )、安定性、あるいはその他の情報が、様々なアプリケーションをデプロイする時に役立ちます。

テストとデプロイのために CI/CD を使う

  • ソースコントロールに対する変更処理、あるいはプルリクエスト作成を処理する時、 Docker Hub や他の CI/CD パイプラインを使い、Docker イメージの自動構築やタグ付け、テストを行えます。
  • プロダクションにデプロイする前に、開発、テスト、セキュリティチームが イメージへの署名 が必要となるでしょう。その場合は、イメージをプロダクションにデプロイする前に、たとえば開発、品質およびセキュリティチームによって、イメージのテストを署名をします。

開発環境とプロダクション環境の違い

開発 プロダクション
バインド・マウントを使い、コンテナがソースコードにアクセスできるようにする ボリュームを使い、コンテナ・データを保管する
Docker Desktop for Mac や Docker Desktop for Windows を使う Docker Engine を使い、可能であれば Docker プロセスをホスト側プロセスと大きく隔離するため、 userns マッピング を使う
時刻のズレを気にする必要はない 各コンテナのプロセス内と Docker ホスト上では、常に NTP クライアントを実行し、同じ NTP サーバと全て同期する。また、コンテナと同様、 Docker の各ノードも同じ時刻のソースを使って同期する

参考

Docker development best practices
https://docs.docker.com/develop/dev-best-practices/