Translated message

A translation of this page exists in English.

Linux コンテナー入門

更新 -

Linux コンテナーの基礎

Linux コンテナーは、軽量なアプリケーション分離にイメージベースのデプロイ方法の柔軟性を取り入れた、主要なオープンソースアプリケーションのパッケージングおよび配信の技術を提供するために生まれました。

Red Hat Enterprise Linux 7 は、リソースを管理するコントロールグループ (Cgroups)、プロセスの分離を行う名前空間、セキュリティを担う SELinux など、コアな技術を使用した Linux コンテナーを実装することで、安全なマルチテナンシーを有効にし、セキュリティ上の弱点となる可能性を減らします。

Linux コンテナーのアーキテクチャー

Linux コンテナーを正しく機能させるにはコンポーネントがいくつか必要になりますが、その大部分は Linux カーネルによって提供されます。カーネルの名前空間でプロセスを分離し、cgroups を使用してシステムリソースを制御できるようになります。また、SELinux を使用すれば、ホストとコンテナー間の分離や、個々のコンテナー間の分離ができるようになります。そして、管理インターフェイスにより、上述のカーネルコンポーネントとやり取りする上位層が構成され、コンテナーを構築し管理するためのツールを提供します。

以下の図は、Red Hat Enterprise Linux 7 における Linux コンテナーのアーキテクチャーを示します。

 Linux Containers Architecture

名前空間

カーネルは、コンテナーに複数の名前空間を作成してプロセスを分離します。名前空間は、特定のグローバルシステムリソースを抽象化し、名前空間のプロセスに対する独立したインスタンスとして示すことができます。その結果、複数のコンテナーが同じリソースを同時に使用することができます。名前空間には以下のような種類があります。

  • マウント名前空間は、プロセスグループで見られるファイルシステムマウントポイントの集合に分離する ことで、異なるマウント名前空間にあるプロセスは、ファイルシステム階層の異なる見方が出来ます。mount() および umount() システムコール は(すべてのプロセスに見えている)マウントポイントのグローバルセットに対する操作を停止し、代わりに、そのコンテナープロセスに割り当てられているマウント名前空間にのみ適用される操作を実行できます。たとえば、各コンテナーにはそれぞれ独自の /tmp または /var ディレクトリを持ち、完全に異なるユーザー領域を持ちます。Docker コンテナーは次のように機能します: 全てのユーザースペースは Docker イメージからマウントされる; chroot は使用しない

  • UTS 名前空間は、uname() システムコールから返される 2 つのシステム識別子 (nodename および domainname) を分離します。これにより、各コンテナーはそれぞれ独自のホスト名と NIS ドメイン名を持つことができるため、起動および設定スクリプトでそれらの名前を設定できます。この分離をホストシステムまたはコンテナーで hostname コマンドを実行してテストすることが出来ます(ホストシステムとコンテナーにおける結果は異なるでしょう)。

  • IPC 名前空間は、System V IPC オブジェクトや POSIX メッセージキューなど、特定の IPC (interprocess communication) リソースを分離します。これは、2 つのコンテナーで共有メモリーセグメントとセマフォに同じ名前を付けることができること、異なるコンテナーのメモリーセグメントや共有メモリーとやり取りすることはできないことを示しています。

  • PID 名前空間 は、異なるコンテナーのプロセスに同じ PID を持てるようにします。これにより、さまざなシステム起動タスクとコンテナーのライフサイクルを管理するために各コンテナーに独自の init (PID1) プロセスを設定することができます。また、各コンテナーには固有の /proc ディレクトリーがあります。コンテナーからは、そのコンテナーで実行しているプロセスしか監視できないことに注意してください。つまり、コンテナーはそのネイティブプロセスだけを見ることができ、システムの別の場所で実行しているプロセスを見ることができません。一方、ホストオペレーティングシステムはコンテナー内で実行しているプロセスを見ることはできますが、プロセスに別の PID 番号を割り当てます。たとえば、ホストで ps -eZ | grep systemd$ コマンドを実行すると、コンテナー内で実行しているものを含む systemd のすべてのインスタンスを表示できます。

  • ネットワーク名前空間は、ネットワークコントローラーとネットワーキング、ファイアウォール、ルーティングテーブルに割り当てられたシステムリソースの分離できるようにします。これにより、分離した仮想ネットワークスタック、ループバックデバイス、およびプロセス領域をコンテナーが使用できます。コンテナーに仮想または物理デバイスを追加し、自身の IP アドレスと、iptables の完全ルールを割り当てることができます。ホスト上およびコンテナー内で ip addr コマンドを実行すれば、異なるネットワーク設定を表示できます。

注意

この他に、ユーザー名前空間と呼ばれるものもあります。ユーザー名前空間は PID 名前空間に類似しており、コンテナーに割り当てられたホストの UID の範囲を指定できます。そのため、プロセスにはコンテナー内で操作するための root 権限が割り当てられますが、コンテナー外の操作に対する権限はありません。互換性の問題により、 ユーザー名前空間は、現在のバージョンの Red Hat Enterprise Linux 7 では使用されていませんが、近い将来利用されることが検討されています。

コントロールグループ (cgroups)

カーネルは cgroups を使用してプロセスをグループ化し、システムリソースを管理します。cgroups は、CPU 時間、システムメモリー、ネットワーク帯域幅の割り当て、またはユーザー定義のタスクグループ間にのこれらリソースの組み合わせを割り当てます。Red Hat Enterprise Linux 7 では、cgroups は systemd スライス、スコープ、およびサービスユニットを使用して管理されます。cgroups の詳細については、Red Hat Enterprise Linux 7 Resource Management Guide を参照してください。

SELinux

SELinux は、SELinux ポリシーとラベルを適用することで、コンテナーの分離を安全に行えるようにします。また、sVirt 技術を使用して、仮想デバイスと統合します。詳細については ? を参照してください。

管理インターフェイス

SELinux を使用してコンテナーを保護する

セキュリティ上の理由から、ホストシステムをコンテナーから分離したり、コンテナーをそれぞれ分離したりする必要があります。コンテナーが使用するカーネル機能、特に cgoups および名前空間は、それぞれがセキュリティのレベルを提供します。cgroups は 1 つのコンテナーがシステムリソースを大量に使用できなくすることで、サービス妨害攻撃を防ぎます。名前空間により、コンテナー内部で作成された /dev ディレクトリーは各コンテナーには非公開のため、ホスト変更の影響は受けません。ただし、システム全体に名前空間設定またはコンテナー化されていないため、敵意を持ったプロセスがコンテナーの外に出ないようにすることはできません。したがって、SELinux を使用して別の隔離レベルを設定する必要があります。

SELinux (Security-Enhanced Linux) は、Linux カーネルにおける MAC (mandatory access control)、MLS (multi-level security)、および MCS (multi-category security) メカニズムの実装です。sVirt プロジェクトは SELinux に構築され、Libvirt と統合され、仮想マシンとコンテナーに MAC フレームワークを提供します。このアーキテクチャーによって、コンテナー内の root プロセスがコンテナー外で実行している他のプロセスに干渉させないことで安全なコンテナー分離できるようにします。Docker で作成したコンテナーは、SELinux ポリシーで指定された SELinux コンテキストが自動的に割り当てられます。

デフォルトでは、libvirt ツールで作成したコンテナーには virtd_lxc_t ラベルが割り当てられます (ps -eZ | grep virtd_lxc_t を実行)。コンテナー内のプロセスに静的または動的なラベルを設定することで sVirt を適用できます。

注意

ホストシステムで enforcing モードで実行していても、コンテナー内で SELinux が無効になっている可能性があります。これは、ホストとコンテナー内でそれぞれ getenforce コマンドを実行すれば確認できます。これは、setenforce など SELinux を有効とするユーティリティが、コンテナー内で SELinux アクティビティの実行を妨げるために発生します。

ホストマシンで SELinux が無効か permissive モードで実行している場合、コンテナーの分離が十分でないことに注意してください。SELinux の詳細については Red Hat Enterprise Linux 7 SELinux Users and Administrators Guide を参照してください。sVirt については Red Hat Enterprise Linux 7 Virtualization Security Guide を参照してください。

注意

現在、Btrfs(B-tree file system) 上に SELinux を有効にした状態でコンテナーを実行することはできません。したがって、SELinux を有効にした Docker を使用する場合は、/var/lib/docker を Brtfs に配置しないよう強く推奨します。Brtfs で Docker を実行する場合は、/lib/systemd/system/docker.service 設定ファイルから --selinux-enabled エントリーを削除して SElinux を無効にします。

コンテナーの使用事例

Red Hat Enterprise Linux 7 で Linux コンテナーを使用する二つの一般的なシナリオを紹介します。まずは、ホストコンテナーをアプリケーションのサンドボックスのためのツールとして使用する方法です。また、イメージベースのコンテナーの拡張機能を利用することもできます。

ホストコンテナー

Linux コンテナー機能を持つ Red Hat Enterprise Linux 7 ホストのオペレーティングシステムを使用すると、軽量のアプリケーションサンドボックスとしてコンテナーを作成できます。起動したすべてのホストコンテナーは同一です。 各コンテナーは同じユーザー領域をホストシステムとして実行するため、ホストコンテナーで実行しているすべてのアプリケーションは Red Hat Enterprise Linux 7 のユーザー領域とランタイムをベースにしています。このアプローチの利点は、yum update コマンドを使用して、セキュリティエラータなどのアップデートをこれらのコンテナーに適用できる点にあります。

 A scheme depicting the architecture of host containers.

イメージベースのコンテナー

イメージベースのコンテナーを使用して、アプリケーションはホストのオペレーティングシステムから独立した個々のランタイムスタックにパッケージングされます。これによって、異なるプラットフォームで開発された複数のアプリケーションインスタンスを実行することができます。これはコンテナーのランタイムとアプリケーションのランタイムがイメージ形式でデプロイされることで可能になります。たとえば、Runtime A が Red Hat Enterprise Linux 6.5、Runtime B がバージョン 6.6 とします。

 A scheme depicting the architecture of image-based containers.

イメージベースのコンテナーは、複数のインスタンスとアプリケーションのバージョンをホストし、オーバーヘッドを最小化、柔軟性を高めることができます。このようなコンテナーは、ホストに限定した設定には縛られず、移植できるようになります。

Docker フォーマットは、Red Hat Enterprise Linux 7 にコピーオンライトを実装する LVM スナップショットの高度な機能である device mapper のシンプロビジョニング技術を使用しています。

 A scheme depicting image layers used in Docker.

この図は、イメージベースのコンテナーで基本となるコンポーネントを示しています。

  • コンテナー: (狭義では) アプリケーションが実行するアクティブなコンポーネントです。各コンテナーは、必要な設定データを保持するイメージをベースとしています。イメージからコンテナーを起動すると、書き込み可能な層がこのイメージの上に追加されます。(docker commit コマンドを使用して) コンテナーをコミットするたびに、変更を保存するためのイメージ層が新たに追加されます。

  • イメージ: コンテナー設定の静的なスナップショットです。イメージは読み取り専用層なので編集されず、 すべての変更は最上位の書き込み可能層に行われ、保存は新しいイメージを作成することで行われます。それぞれのイメージは、1 つ以上の親イメージによって異なります。

  • プラットフォームイメージ: 親イメージのないイメージです。プラットフォームイメージは、実行するためにコンテナーに重ねられたアプリケーションに必要なランタイム環境、パッケージ、ユーティリティを定義します。Docker との連携は、通常、プラットフォームイメージを取得するところから始まります。プラットフォームイメージは読み取り専用であるため、変更は、その上に重ねられたコピーイメージに適用されます。Red Hat は Red Hat Enterprise Linux 7 と Red Hat Enterprise Linux 6 のプラットフォームイメージと、... リンクを提供します。

プラットフォームイメージに重ねられたイメージは、コンテナーに重ねられたアプリケーションに対するソフトウェアの依存関係を含むアプリケーション層を作成します。たとえば、? に重ねたイメージは、コンテナーに重ねたアプリケーションに必要なソフトウェア依存関係を追加することができました。

コンテナー全体を非常に大きくしたり、逆に小さくしたりできます。これには、アプリケーション層に含まれるパッケージ数が関係します。サードパーティに依存しないソフトウェアベンダーのソフトウェアなど、イメージをさらに重ねることができます。ユーザーからは 1 つのコンテナーがあるように見えますが、オペレーション上では、その背後に多くの層が存在する場合があります。

Linux コンテナーと KVM 仮想化の比較

仮想マシンは、仮想マシン自身のカーネルを必要とします。Linux コンテナーは、ホストのオペレーティングシステムのカーネルを共有します。通常、同じハードウェアで仮想マシンよりも多くのコンテナーを起動することが可能ですが、単一のコンテナーまたは仮想マシンは、すべての物理リソースを消費することができます。

Linux コンテナーと KVM 仮想化にはそれぞれの長所と短所があるため、どちらの技術がより一般的に選択されるかはその使用事例によって異なります。

KVM 仮想化:

  • KVM 仮想化は、Linux など、さまざまな OS の起動を有効にします。ホストで起動できる仮想マシンの数は同一ホストで実行できるコンテナーの数よりも少ないです。

  • カーネルインスタンスを別々に実行することで分離とセキュリティを提供します。一つのカーネルが突然終了しても、システム全体が停止したりはしません。

  • ゲストの仮想マシンは、ホスト変更の影響は受けず、同じアプリケーションの異なるバージョンをホストと仮想マシンでそれぞれ実行することができます。また、KVM は、ライブマイグレーションなどの便利な機能を多数提供します。これらの機能の詳細は、Red Hat Enterprise Linux 7 Virtualization Deployment and Administration Guide を参照してください。

Linux コンテナー:

  • Linux コンテナーは、1 つ以上のアプリケーションの分離をサポートするために設計されました。

  • システムワイドの変更は、各コンテナーに適用されます。たとえば、ホストマシンのアプリケーションをアップグレードすると、このアプリケーションのインスタンスを実行するすべてのサンドボックスにこの変更が適用されます。

  • コンテナーは軽量であるため、ホストマシン上で同時に多数のコンテナーを実行できます。理論上、コンテナーの数は最大 6000、そして root のファイルシステムディレクトリのバインドマウントは 12,000 個となります。

その他のリソース

Linux コンテナーの詳細およびアーキテクチャーについては以下のリソースを参照してください。

インストールされているドキュメント

  • docker(1) — docker コマンドの man ページ

オンラインドキュメント

Comments