コンテナ化の “ベストプラクティス” にはコンテクストが重要

通常、コンテナごとに1つのサービスを使用して、関心のある領域を分離することをお勧めします。複数のプロセスがあっても問題ありませんが、Dockerを最大限に活用するには、1つのコンテナがアプリケーション全体で複数の役割を持たせることを避けてください。

https://docs.docker.com/config/containers/multi-service_container/(英文)

Dockerの公式ドキュメントサイト(英文)に掲載されているこの言葉は、コンテナを利用する際の原則です。基本的に、Dockerはコンテナごとに1つのプロセスを実行します。

この原則に従わなくてよい正当な理由はあるのでしょうか?
1つのコンテナで複数のプロセスを実行することが許容されるのは、どのような場合でしょうか?

簡単に答えると「Yes」であり、そしてそれは「人々が一般的に考えるよりも頻繁」です。
この答えを理解するために、まずコンテナ化の本質的なコンテキストを考えてみましょう。

コンテナを実行するタイミング

私たちがアプリケーションをコンテナでホストするのは、以下の理由からです。

  • 基盤となるインフラをより管理しやすくする
  • サービスを分離して、より安全で信頼性の高いものにする
  • より一貫した運用環境を構築する

もちろん、これらの効果を得るための手段はコンテナだけではありません。たとえば、ネイティブ OS、仮想マシン、サーバーレス ホストで直接実行するための優れた技術も存在します。コンテナは魔法のような技術ではありませんが、多くの生産的な研究と努力のおかげで、業界で広く使用されるようになりました。

テクノロジーが異なれば、プロファイルも異なります。仮想マシンとコンテナは、動作環境の標準化とセキュリティ上の懸念という点で似ていますが、実際のアプリケーションは大きく異なります。Dockerのドキュメントで推奨されているように、コンテナのベストプラクティスは、各コンテナを1つのサービスに制限することです。対照的に、仮想マシンの場合には、1つのアプリケーションのすべての依存関係を仮想マシンにロードすることでした。

ただしこれらは慣例的なものであり、多くのアプリケーションを別々の仮想マシンで動作するように構成したり、コンテナの境界を広げて複数の異なるプロセスを実行することもあります。「1 つのコンテナに 1 つのアプリケーション」といったアーキテクチャ上のルールは、機能的であると同時に様式的でもあります。

つまり、コンテナ管理における真の知恵とは、「ベスト プラクティス」に盲目的に従うことではなく、そのベストプラクティスをどのように適用し、いつ調整すべきかを知ることなのです。

データベースの選択

次のような例を考えてみましょう。ある組織では、複雑な機器のインベントリをデータベースで管理しています。データベースへのアクセスはすべてアプリケーションを介しておこなわれ、他のエントリ ポイントや用途はありません。アプリケーションを垂直・水平スケーリングする必要は特にありません。

10年前は、このようなアプリケーションを仮想マシンでホストしていたかもしれませんが、仮想化されたファイル システムでデータベースが適切に動作するかどうか、具体的な測定を行う必要がありました。しかし現在では、その組織の IT 部門にとっては、コンテナ化の方が標準的かもしれません。従来の実装では、データベースとその CRUD(create-read-update-delete)アクセス用に別々のコンテナを用意していました。別々のコンテナであれば、テストも保守も独立しておこなえます。

しかし、それは本当にメリットなのでしょうか?
使用方法の詳細にもよりますが、おそらくそうではないでしょう。

CRUD アプリケーションは、少なくともデータベースのモックがなければテストできません。スケーラビリティの要求はありません。ここでの説明により、データベースがアプリケーションと別に実行される可能性は低くなることでしょう。また、効率的なインフラストラクチャ部門では、アプリケーションを再ホストする必要があるかもしれませんが、2つのコンポーネントプロセスを分割しなければならない理由はありません。実際、現実的なテストやモニタリングは、ホスト内での通信とロギングによって容易になるかもしれません。高度な一元化されたスケジューリングとロギングを導入する必要はありません。Docker自体でさえ、1 つのコンテナ内で複数のプロセスを管理する方法について述べています。

ベストプラクティスには理由があり、それは概して良い理由です。同時に、敏感で思慮深い DevOps チームは、特定の要件を分析する方法を知っています。他のアプリケーションとの結合が少なく、よく理解されている問題領域にあり、スケーリングの必要性が低い、または特殊な状況では、マイクロサービスの集合体ではなく、コンテナ内のモノリスとして設計するのが最適かもしれません。他のシステムとの結合を増やしたり、データベースとその CRUD の緊密な結合を減らしたりすると、設計上の判断が変わってきます。

いずれにしても、与えられたルールを盲目的に適用するのではなく、分析してリソースを最大限に活用することがより重要です。

コンテナの中には何を入れるべきでしょうか?
ほとんどの場合、その答えは シングルプロセスになります。しかし、別の設計にする正当な理由があり、その設計をテストして維持するための健全な計画がある場合は、1 つのプロセスのルールを曲げても構いません。実際、慎重に分析することで、通常の「ベスト プラクティス」を自動的に遵守するよりも、さらに良い結果が得られる可能性があります。

作者について:

Cameron Laird は、受賞歴のあるソフトウェア開発者であり著作者です。業界のサポート団体や標準化団体に参加しており、Python Software Foundationの投票メンバーでもあります。長年テキサス湾岸に居を構え、お気に入りのアプリケーションは農業自動化向けのアプリケーションです。

(この記事は、開発元 Ranorex 社 Blog 「For Containerization ‘Best Practices,’ Context Is Key」2019年8月22日の翻訳記事です。)