コンテナの仕組み
仮想マシンではホストマシンの各種のリソースを使ってしまう課題がありますが、その課題を回避できる技術として「コンテナ型仮想化技術」があります。(LinuCレベル2主題:2.06.1)
仮想マシンとコンテナ型仮想化の違い
前節では物理マシンに直接OSをインストールするのではなく、ホスト型・ハイパーバイザー型などの仮想化技術を利用した仮想マシンにインストールする方法について学びました。この結果、複数のOSを一つのハードウェア上で稼働させることができました。
しかし、ハードウェアを丸ごと仮想化し、仮想マシンごとにOSをインストールするため、ホストマシンのメモリーやディスクの消費量が増え、仮想マシンの制御を行う分だけCPUの負荷が高くなります。さらに、仮想マシンのバックアップに必要なディスク容量が増大したり、起動や複製に時間がかかったりするなどの問題があります。
そこで近年普及してきているのが、DockerなどホストOS上のプロセスとして動作するコンテナ型仮想化技術です。コンテナ型仮想化技術を用いると、ウェブアプリケーションや各種サーバーなどの動作に必要なコンポーネントだけを切り出してコンテナというパッケージを構成し、より高速に起動や複製を実行できます。
コンテナを実現する技術
コンテナ型仮想化は、
- コンテナエンジンを動作させる「ホストOS」
- コンテナの動作を管理する「コンテナエンジン」
- サーバーのプロセスやリソースを区画化した「コンテナ」
から構成されます。
ホスト上に区画化された空間を実現することを「コンテナ型仮想化」、実現方法を「コンテナ技術」と呼んでいます。コンテナは、アプリケーションだけでなく、動作に必要となるライブラリや設定ファイルなど、実行環境をまとめたものです。
コンテナ型仮想化の特徴としては、以下のような点が挙げられます。
- コンテナを起動するために、仮想マシンやゲストOSを起動する必要がない。
- コンテナエンジンがホストOSに常駐し、コンテナの操作・管理を行う。
- 各コンテナはコンテナエンジンが動作しているホストOSのカーネルを共有している
- 各コンテナの機能を構成するプロセスをプロセス群として扱うことができ、コンテナ間で互いのプロセスは参照できない。
上記のようにコンテナ型仮想化は、仮想マシンやゲストOSのリソースや負荷がないので、
- 仮想マシン型に比べるとコンテナのサイズは小さく、リソース消費量を抑えられる。
- ゲストOSの起動停止が不要なので、起動が高速である
- 仮想マシンは数GBのサイズになることが多いが、コンテナは数百MB以内の容量であることが多く、すべてのユーザーに同じ環境を提供することが容易になる。
などのメリットが得られます。
名前空間(namespace)
コンテナ型仮想化では、名前空間(ネームスペース)という技術を使用して、コンテナとよばれるワークスペース間の分離(isolation)を実現しています。コンテナエンジンはコンテナごとに名前空間の集合を生成します。
名前空間を扱うAPI(関数)には以下のようなものがあります。
- clone: 新たなプロセスを生成する
- setns: 呼び出したプロセスを既存の名前空間に参加させる
- unshare: 呼び出したプロセスを新しい名前空間に移動させる
コンテナ型仮想化で使用される名前空間には以下のようなものがあります。
- IPC名前空間 (プロセス間通信のリソースを分離)
- マウント名前空間 (ファイルシステムツリーを分離)
- ネットワーク名前空間 (ネットワークインターフェースを分離)
- PID名前空間 (プロセスID空間を分離)
- ユーザー名前空間(UID/GIDを分離)
- UTS名前空間(nodename, domainameのシステム識別子を分離)
各名前空間は、/proc/{pid}/ns/以下で確認できます。
root@fe4ef9552b2e:/# ls -l /proc/$$/ns/
total 0
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 ipc -> 'ipc:[4026532311]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 mnt -> 'mnt:[4026532309]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 net -> 'net:[4026532314]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 pid -> 'pid:[4026532312]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 pid_for_children -> 'pid:[4026532312]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 user -> 'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 uts -> 'uts:[4026532310]'
一方、コンテナ上でもnamespaceを確認してみます。
root@fe4ef9552b2e:/# ls -l /proc/$$/ns/
total 0
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 ipc -> 'ipc:[4026532311]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 mnt -> 'mnt:[4026532309]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 net -> 'net:[4026532314]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 pid -> 'pid:[4026532312]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 pid_for_children -> 'pid:[4026532312]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 user -> 'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 Apr 28 02:59 uts -> 'uts:[4026532310]'
例えば、pidの結果を比較すると異なるノード番号が割りあてられています。
- ホスト: pid:[4026531836]
- コンテナ: pid:[4026532312]
これにより、コンテナはホストOSのカーネルを使用していますが、コンテナ毎に異なるnamespace番号をつけることでプロセス群を分離して認識しています。
コンテナ上でpsコマンドを実行すると、ホストOSで動作しているプロセスの情報は表示されません。これは、コンテナとホストOSが異なる名前空間を使用しているためです。
# docker run -it ubuntu bash
root@fe4ef9552b2e:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
10 pts/0 00:00:00 ps
[root@centos7 ~]# ps
PID TTY TIME CMD
3716 pts/1 00:00:00 su
3724 pts/1 00:00:00 bash
3746 pts/1 00:00:00 ps
cgroups(コントロールグループ)
コンテナ型仮想化では、cgroupsを用いてリソース(CPUやメモリ)などの割り当てを行います。これに対してnamespace(名前空間)では、名前空間ごとに識別用のノード番号を割り当てて、リソースの分離を実行していました。
cgroupはLinuxカーネルの機能で、システムリソースの割り当て、優先度の変更、拒否、管理や監視レベルの制御などを行えます。
コンテナとイメージ
各コンテナはコンテナエンジン上で動作します。各コンテナのテンプレートはイメージと呼ばれ、コンテナからイメージを作ることもできますし、既に構成済みのイメージファイルを公開リポジトリからダウンロードして使用することもできます。
イメージから生成されたコンテナのインスタンスにはそれぞれユニークなIDが振られ、起動や停止、接続や削除などができます。
執筆者紹介
・太田 俊哉
・井上 博樹
このドキュメントは、LinuCレベル2の学習用の教材から抜粋して作成されたものです。教材全体は以下のPDFファイルをご覧ください。
LinuCレベル2学習教材