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

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

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

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

  • 適切なベースイメージで始めましょう。例えば、 JDK が必要なら、一般的な ubuntu イメージに openjdk をインストールするのではなく、公式 openjdk イメージをベースにするのを検討します。

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

    • もしも使用中の 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 )、安定性、あるいはその他の情報が、様々なアプリケーションをデプロイするときに役立ちます。自動的に作成される latest タグに頼らないでください。

アプリケーション・データの保持はどこで、どのように

  • ストレージドライバ を使うコンテナの書き込み可能なレイヤ内に、アプリケーションのデータを保存 しないでください 。これにより、コンテナの容量が増えます。さらに、ボリュームやバインドマウントの利用に比べ、 I/O 観点から効率が良くありません。

  • その代わり、データの保存には ボリューム を使います。

  • バインドマウント の使用がふさわしい場面は、ソースディレクトリやバイナリをそのままコンテナ内にマウントしたい開発段階です。プロダクションでは、代わりにボリュームを使い、開発段階でバインドマウントしたのと同じ場所へマウントします。

  • プロダクションでは、サービスによって使われる機微なアプリケーションデータを保管するのに シークレット を使います。また機微ではないデータのためには コンフィグ を使います。現時点でスタンドアロンなコンテナを使っている場合、 単一から複数(single-replica) のサービスへの移行を検討すると、サービスのみが利用できる機能を活用できるようになります。

テストとデプロイのために 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/