docker
kubernetes
ibmcloud

コンテナ・デザイン・パターンの論文要約 

Brendan Burns, David Oppenheimerらの論文「Design patterns for container-based distributed systems」を読んで、コンテナを活用したシステム設計や開発に、とても有用と感じたので、図を中心にした要約にしてみた。

要約内容に誤りや理解不足な部分もあると思うので、原文も参照していただきたい。また、自身の理解のために、論文中に無い図を加えた点、独自の注釈も加えている。

背景

コンテナ化されたソフトウェアコンポーネントから構築されたマイクロサービスアーキテクチャの人気が高まり、分散システム開発においても同様の革命が起っている。

コンテナの境界の壁は、分散システムの基本的なオブジェクトの境界に適している。そこで、コンテナを活用して、コードの低レベルの詳細を抽象化し、アプリケーションやアルゴリズムに共通する高レベルのパターンを見出すことができる。

本稿では、3つのタイプの設計パターンについて説明

  • コンテナ管理用の単一コンテナパターン
  • 密接に協調するコンテナの単一ノードパターン (シングルノード・マルチコンテナ・パターン)
  • 分散アルゴリズム用のマルチノードパターン (マルチノード・アプリケーション・パターン)

コンテナ管理用の単一コンテナパターン

コンテナ管理システム(コンテナ・オーケストレータ)は、従来のコンテナに対するAPIは、run, pause, stop などしかなく、制限が多いため、コンテナベースのシステムを運用するオペレータ、そして、アプリケーションの開発に必要な情報を提供する。 また、コンテナ上の実行中のアプリケーション・プログラムであるプロセスに対して、終了が必要となった場合に、SIGKILLで強制終了する前に、SIGTERMシグナルを与える事で、対応中の要求を完了させ、状態を保存するなどの終了処理をする時間を与える。

スクリーンショット 2018-03-06 18.14.51.png

コメント
これまでは、アプリをインストールするサーバーに、インフラの状態を収集する、また、アプリの実行状態を取得するなどの監視用のエージェントを設定して、運用状態の把握に務めてきた。仮想サーバであってもベアメタルのサーバーであっても、これらモニタリングに関わる手間は同じで、生産性にとって課題であった。しかし、コンテナ管理システムが、コンテナの内容を変更する事なく、外界から監視できる点は、画期的な進化と考えられる。

シングルノード・マルチコンテナ・パターン

シングルノードで動作するアプリケーションを対象という意味ではなく、最も基本的なパターンとして、3つのパターンを挙げます。

サイドカー・パターン

ところで、サイドカーってなんだろう?と思う人は、少年漫画のヒーロー人造人間キカイダーのサイドマシーン を見ると分かり易いとか思います。 バイクの側面に車をつけた乗り物をサイドカーと言います。

Kubernetesのポッドには、複数のコンテナを動かすことができます。 ポッドの中で、主となるコンテナを補助する様なコンテナを持つポッドを構造を持ったポッドをサイドカーと呼んでいます。

次の図の様に、ウェブサーバーの主コンテナを補助して、ログ転送するコンテナ、外部からコンテンツを定期的にプルするコンテナなどがあります。

スクリーンショット 2018-03-06 19.38.55.png

サイドカーの利点を列挙すると以下になります。

  • Main コンテナは CPUを優先的に割り当て低レイテンシで応答させ、Sidecar コンテナは Mainコンテナが暇な時間を割り当てる
  • 2つの独立したチーム間で開発の責任を分けやすくなり、独立してテストできる
  • コンテナの再利用ができる。 Log Saverコンテナは、別の用途のログを出力するコンテナと組み合わせて利用できる
  • コンテナは障害の封じ込めの境界を提供、全体が停止するのを防止する
  • コンテナはデプロイの単位であり、各機能をアップグレードし、必要に応じて個別にロールバックできる

コメント
k8sのポッドは、一つのIPアドレスを持ち、複数のコンテナが同時に稼働します。 そして各コンテナは、例えば、CentOS7 や Ubuntu 16.04 など異なるOSイメージのコンテナが動作させて、コンテナで開いたリッスンポートは、localhost 127.0.0.1のアドレス上のポート番号で相互にアクセスできます。このため、もちろん、コンテナ同士でポート番号が重ならない様に注意が必要です。また、ポッドをホストするノード上に一時的なボリュームを確保して、ポッドに永続ボリュームをアタッチして、コンテナ間のデータの受け渡し利用できます。
サイドカーコンテナは、OSバージョンや開発言語を隠蔽して、同一IPホスト内で動作する独立性の高い画期的なユニットと言えます。 この同一ポットで複数のコンテナを動作させることで、フレームワークとアプリのコアを分離して、パターンを構成していける点が、これまでに無い新しさと思います。

参考資料
Kubernetes サイドカーの作り方とファイル共有

アンバサダー・パターン

アンバサダーすなわち大使、使節、代表という意味で、外部のサービスを代表するコンテナを同一ポッド内に持つパターンです。 次の例では、Memcached や Redis のシャーディング用のツールとして利用される twemproxyを利用するケースです。 アプリケーション・コンテナから見れば、ローカルホストのポートをアクセスしているだけですが、シャーディングされて複数のMemcached へ分散されてデータが格納されます。 これによりキャッシュへのアクセス集中がボトルネックとなる事を回避することができます。 シャーディングを目的としているので、キャッシュの可用性は他の方法と組み合わせる必要があります。

スクリーンショット 2018-03-06 19.53.35.png

アンバサダー・パターンの利点

  • アプリの開発者は、シングルのサーバーをアクセスするだけの考慮で開発ができる
  • テストの時は、シングルサーバーと接続してテストするだけで済む
  • Twemproxyのアンバサダーコンテナは他のアプリケーション・コンテナと組み合わせて再利用できる

コメント
アプリケーションのコンテナと同一のポットに、アンバサダー・コンテナを置く事で、ポッドのレプリカセットで複数もつ事できるので、プロキシーとなるプロセスの可用性も一緒に改善する事ができます。

アダプター・パターン

こちらは、外部からのアクセスに対して、汎用的共通なインタフェースを持たせることを実現します。

スクリーンショット 2018-03-06 20.12.23.png

アダプター・パターンのユースケースとしては、次の様な様々なアプリケーションを共通のインターフェースでモニタリングする場合に利用されています。

スクリーンショット 2018-03-06 20.55.27.png

コメント
Kubernetesのダッシュボード用の時系列データベースの Prometheus は、プル型でデータを収集しますが、このアダプターパターンは、Prometheusのアダプターを想定したパターンであろうと思います。

分散アルゴリズム用のマルチノードパターン

モジュール化されたコンテナは、マルチノード分散アプリケーションの構築を容易する例を3つ挙げます。

リーダ選出パターン

分散処理のノード間で、リーダー選出が必要な際に参考となるパターンです。

スクリーンショット 2018-03-06 21.01.19.png

Java言語で書かれたリーダ選出のライブラリを利用したプロセスをコンテナ化しておき、他のプログラム言語で書かれたコンテナと組み合わせて再利用します。

スクリーンショット 2018-03-06 21.02.05.png

コメント
サイドカーとして、リーダー選挙コンテナをポッドに同居させるもので、例えば、Javaで書かれたZooKeeperを利用したリーダー選挙コンテナとNode.jsなどで書いた分散アプリケーションを一つのポッドにまとめて、複数のレプリカセットを持つデプロイメントを構築する事が実現できることになります。

作業キューパターン

並列に処理可能な大量の処理を短時間で実行するためのパターンで、大量のメールの送信、様々のケースを評価して最適解を求めるモンテカルロ・シミュレーション、エンコーディング処理などの応用があります。

スクリーンショット 2018-03-06 21.03.19.png

コメント
実装として、外部からの要求をRabbitMQへ格納して、アプリケーション・ポッドが、要求やデータをキューから取り出して、処理を進めていくタイプの並列処理が簡単に作れます。RabbitMQへ処理キューへ入れる部分、キューか要求を取り出す部分は、汎用的な処理ですから、再利用可能なコンテナとして、アプリケーションのコンテナと組み合わせる事ができます。 要求をキューから取り出したコンテナは、ポッドの共有ボリュームを使って、アプリケーション・コンテナへ、JSONやCSV形式などのファイルで渡す事ができます。

スキャッター・ギャザー・パターン

最後の分散システムパターンは、散布/収集です。 そのようなシステムでは、外部クライアントは「ルート」または「親」ノードに初期要求を送信します。 このルートは、並列に計算を実行するために要求を多数のサーバーに送ります。 各シャードは部分データを返し、ルートはこのデータを元の要求に対する単一の応答に集約します。

スクリーンショット 2018-03-06 21.03.46.png

コメント
要求やデータを小さな複数の範囲に分割して、並列に処理した後、再び統合して、一つの要求に対する結果として応答するものです。 検索エンジン、MapReduceタイプの処理などに適用する事ができます。

結論

オブジェクト指向プログラミングがオブジェクト指向の「デザインパターン」の出現と体系化につながったのと同様に、コンテナアーキテクチャはコンテナベースの分散システムの設計パターンにつながります。本稿では、システム管理のための単一コンテナパターン、密接に協調するコンテナの単一ノードパターン、分散アルゴリズムのためのマルチノードパターンの3種類のパターンを確認しました。すべてのケースで、コンテナは、複数のチーム間での実装の分割と新しいコンテキストでのコンポーネントの再利用を容易にするなど、オブジェクト指向システムのオブジェクトと同じ利点の多くを提供します。さらに、コンポーネントを個別にアップグレードしたり、複数の言語で書かれたり、システム全体が正常に機能低下したりするなど、分散システム固有の利点をいくつか提供します。コンテナパターンの集合は成長するだけであり、今後数十年間に、分散システム開発の標準化と正規化を可能にすることにより、オブジェクト指向プログラミングがこれまでの数十年間に行ったように、分散システムプログラミングに革命を起こすと考えています。