DevOpsの実行に必要となる技術(1) コンテナ
はじめに
DevOpsを実践するに当たって、開発の現場でなくてはならないツールとなっているのが「コンテナ」です。コンテナと言えば真っ先に思い浮ぶのは「Docker」ですが、Docker = コンテナというわけではありません。Dockerはあくまでもコンテナを使いやすくするためのツールだからです。Dockerの登場によりコンテナはぐっと身近なものになりましたが、コンテナのことをよく知らなくてもDockerを介することで簡単にコンテナを使用できてしまいます。「Dockerは使えるけど、コンテナのことはよくわからない」という方も少なくないはずです。
そこで今回は、そもそもコンテナとは何なのか、どのような流れを経て、なぜ今流行っているのかという視点からコンテナについて説明します。
コンテナとは
コンテナは「コンテナ型仮想化」とも呼ばれる仮想化技術の1つです。アプリケーションとその動作に必要なランタイム・ライブラリなどの依存関係にあるすべてのものがコンテナ内に含まれています。アプリケーションの動作環境はコンテナ内で完結しいるため、コンテナを実行する環境にはアプリケーションの動作に必要な設定をする必要はありません。コンテナはどこで実行しても同じように動作します。
コンテナはLinuxカーネルの機能を使って環境の分離を実現しています。コンテナ内で実行したプロセスはホストOS側から見ると1つのプロセスでしかありません。これはコンテナが仮想マシンのような完全に分離された環境でプロセスを実行しているわけではないからです。コンテナはあくまでもホストOS上で実行したプロセスをカーネルの機能を使って、あたかも分離された環境で実行しているかのように見せています。そのため「ホストOSとカーネルを共有している」と言われています。
コンテナは、よく海上コンテナに例えられます。鉄でできた大きな箱は国際的に標準化されており、船舶・鉄道・自動車などに乗せて移動します。移動中にコンテナを開けて積荷の入れ替えなどは行いません。規格サイズのコンテナをそのまま別の乗り物に積み替えて目的地へと運びます。コンピューターの世界でもコンテナの効果は同じです。コンテナの実装は標準化されており、船舶や鉄道の代わりにコンテナランタイムの上で動作します。一度パッケージングしたアプリケーションはコンテナイメージを作り替えるまで更新されることはありません。
コンテナイメージとは
「コンテナイメージ」とは、コンテナの元となるテンプレートです。コンテナはコンテナイメージからファイルシステムやアプリケーションの実行に必要なメタデータを継承して実行します。一度作成されたコンテナイメージは不変なため、コンテナイメージから実行されるコンテナは常に同じ状態からスタートします。
コンテナイメージはベースイメージに変更を加えることで作成します。ベースイメージには最小限のコンポーネントで構成されたOSイメージや、NGINXなどのミドルウェアがインストールされたイメージ、PythonやRubyなどのプログラミング言語ランタイムがインストールされたイメージなどを選択できます。ベースイメージはDocker Hubなどのコンテナレジストリから入手可能です。
コンテナイメージの中に構築されるファイルシステムはレイヤー構造となっています。ベースイメージに変更を加えるごとにレイヤーが作成され、すべてに変更が透過的に積み重なって1つのファイルシステムとなります。コンテナイメージに構築されたレイヤーを「イメージレイヤー」と呼び、コンテナには読み取り専用として提供されます。
コンテナを実行するとイメージレイヤー上に書き込み可能なレイヤーを追加します。これを「コンテナレイヤー」と呼びます。コンテナレイヤーは一時的なレイヤーのため、コンテナを削除すると一緒に削除されます。コンテナ内で行った変更はイメージレイヤーに反映されることはありません。
実は古くからあるコンテナ型仮想化
近年、コンテナを使用した開発が一般的となってきましたが、コンテナやそれに類似した技術は古くから多数存在します。いくつか例を挙げてみます。
- 1979年、Unix Vertion 7に新機能として追加された「chroot」というシステムコールがコンテナという考え方の起源だとされています。chrootはあるプロセスのルートディレクトリを別のディレクトリに変更することでプロセスを特定のディレクトリ以下に閉じ込めます。
- 2000年にFreeBSD jailが登場します。FreeBSD jailはchrootの機能を強化しファイルシステムやユーザー、ネットワークなどを分離できます。現在使用しているコンテナの原型とされています。
- 2008年、Linux Containers(LXC)が登場します。LXCはLinuxカーネルの機能を使って分離を実現します。Docker(後述)も初期の頃はLXCをコンテナライブラリとして使用しました。現在使われているLinuxコンテナの形を作ったと言えます。
- 2013年、dotCloud社によりDockerが発表されます。Dockerはコンテナイメージのビルドから配布、実行までを一環したツールで簡単に行えます。
Docker登場以前のコンテナは「システムコンテナ」と呼ばれ、仮想マシンのようにあたかもLinuxが起動しているかのような動きをしていました。システムコンテナはLinuxを扱うのと同じように設定できるため、レンタルサーバーやバーチャルプライベートサーバー(VPS)などで使用されていました。
Dockerの登場以後、コンテナと言うとアプリケーションコンテナを指すのが一般的になりました。アプリケーションコンテナは起動時にinitプログラムではなくアプリケーションを直接実行します。こうすることでシステムの初期化や、その初期化に必要なプログラムが不要になり、コンテナはさらに軽量で高速になりました。
コンテナと仮想マシン
コンテナや仮想マシンは、どちらも仮想化を利用して環境を分離する技術です。しかし、開発の現場では仮想マシンよりもコンテナの利用が 進んでいます。この2つの仮想化技術の違いを見ていきます。
仮想マシンとは
「仮想マシン」とは、物理的なハードウェアを仮想化したものであり、エミュレーターです。1台のコンピューター上に複数の仮想マシンを作成できます。
仮想マシンを作成および実行するには「ハイパーバイザー」と呼ばれるソフトウェアが必要です。ハイパーバイザーは「ベアメタル」型と「ホスト」型の2種類に分類できます。ベアメタル型はハードウェア上で直接ハイパーバイザーを実行でき、OSによる制限を受けないためホスト型よりも高速に動作します。VMware ESXiやHyper-Vなどがベアメタル型です。
一方で、ホスト型はハイパーバイザーをホストOSにインストールして実行します。導入が簡単なため誰でもすぐに始められます。VMware PlayerやVirtualBoxがホスト型に当たります。仮想マシンはハイパーバイザー上で動作し、ホストから完全に独立しているためホストOSとは別のOSを実行できます。
仮想マシンの目的
仮想マシンは複数のサーバーを1台のコンピューターに集約する目的で使用されます。例えば、メールサーバー、ファイルサーバー、アプリケーションサーバーの3つがあったとします。これらのソフトウェアがそれぞれ違うOSで動いていたとするとマシンを集約できません。空きリソースを遊ばせておくのはもったいないですし、ソフトウェアを追加するたびにマシンを調達していては時間やお金がかかってしまいます。そこで空きリソースを効率的に使用するため仮想マシンを導入します。仮想マシンは様々なOSを並列で動かせるため、1台のコンピューターに3つのソフトウェアを集約できます。仮想マシンに集約することでマシン調達にかかる時間やマシンの運用費を節約できます。
コンテナの目的
コンテナは様々な環境で同一のアプリケーションを実行する目的で使用されます。開発者はローカル環境からプロダクション環境へ一環して移動します。例えば、アプリケーションの新しい機能を開発する環境をローカルマシンで実行します。完成した新機能はそのままコンテナにパッケージングし、様々なテストの実施後にステージングやプロダクション環境で実行されます。また、プロダクション環境で発見されたバグの調査をするのにも役立ちます。プロダクション環境と同じコンテナイメージを使ってローカル環境でコンテナを実行することで、バグを含んだアプリケーションとその動作環境を簡単に再現できます。
コンテナの普及
昨今のクラウドネイティブなアプリケーション開発では、デプロイのしやすさや高いスケーラビリティなどが求められます。コンテナは軽量で高速に動作するため、クラウドネイティブなアプリケーション開発にはなくてはならない技術となっています。なぜ仮想マシンではなくコンテナを使うのか、そのコンテナの特徴を解説します。
軽量・高速
コンテナは仮想マシンよりも軽量です。仮想マシンには完全なOSがインストールされています。Linuxをインストールしていれば数GB、Windowsをインストールしていれば数十GB以上のストレージが必要になります。一方でコンテナにはアプリケーションとその依存関係にあるコンポーネントのみが含まれているため軽量です。コンテナイメージは数MBから提供されています。コンテナは様々な環境で実行されますが、環境を越えて実行するにはネットワークを経由したコンテナイメージの取得が必要です。コンテナイメージは軽量であるため、これを可能にします。
また、コンテナは仮想マシンよりも高速に起動します。仮想マシンはハードウェアをエミュレートするため起動時に様々な処理が行なわれます。完全なOSを起動後、アプリケーションを実行するためにアプリケーションへアクセスするには数分程度はかかるでしょう。一方でコンテナはホストOS上で隔離されたプロセスを実行するだけなので数秒でアクセス可能です。起動の速さはスケーラビリティに直結します。コンテナは数秒で起動できるため、急なアクセス増加などにも秒単位のスケールで対応できます。
効率的
コンテナはOSを起動しないため、仮想マシンよりもリソースを消費しません。仮想マシンはアプリケーションの他に、仮想マシン内で起動するOSに必要なだけのリソースを要求します。しかし、コンテナはプロセスが起動しているだけなので、アプリケーションに必要なリソースのみ要求します。リソース消費が少なければ実行できるアプリケーション数も増え、リソースを効率的に消費できます。
おわりに
今回は、Docker登場前からあるコンテナ、Docker登場後に普及したコンテナ、この2つコンテナの違いやそれぞれの特徴など、「普段Dockerから操作しているコンテナとは何だったのか」という視点で説明しました。簡単ですが、コンテナの歴史についても触れました。
次回は、Dockerとは何か、そして、そのメリット・デメリットについて解説していきます。