Docker だけじゃない Containers の世界

# Containers の世界と LXC、そして Docker
## 昔からあるコンテナ技術
コンテナ技術を取り囲む現在の状況と、それを踏まえた上でのLXCとDockerの根本的な違いについて説明したいと思う。Linux Containers(LXC)は、どうやって我々がアプリケーションを動かしスケールさせるかという問題を変化させる可能性を持っている。コンテナ技術は新しいものではない。そして、LXCに関して言うと、追加パッチをLinux Kernelに適用させることなく、vanilla Linux Kernel上で稼働させることができる。なお、LXCのVersion1は、長期サポートバージョンであり、5年間サポートされることになる。話が逸れるが、vanilla Linux Kernelとは、Linux作者のLinus Torvalds氏がリリースするプレーンなKernelのことである。それをベースに様々なベンダーが追加で拡張していくのである。また、vanillaという言葉には「普通の、ありきたりな、おもしろみのない」という意味がある。

話を戻そう。

コンテナ技術は、最近登場した新技術ではない。昔から存在し色んな所で採用されている。FreeBSDにはJailがあり、SolarisにはZoneがある。それに加えて、OpenVZやLinux VServerのようなContainersも存在する。その歴史は、`chroot`に始まり、FreeBSD Jailを経て、Linux Containers(LXC)に至る。`chroot`では、大雑把に言って、ディレクトリーツリーの分離を行っていた。プロセスリスト自体は共有するようなモデルである。`chroot`のユースケースとしては、開発者向けのテスト/ビルド用環境である。FreeBSD Jailでは、`chroot`の機能に加えて、プロセスリストとネットワークスタックも分離(というか隔離)された。ユースケースとしては、`root`権限の一般ユーザへの委譲、またそれに頼る形でのホスティングサービスである。LXCでは、リソース管理テーブルを隔離し、`cgroups`によるシステムリソース(CPU、メモリ、ディスク、etc)の制御を行えるようになった。これにより、LXCは、軽量な仮想環境と見なすことができるようになった。

## なぜ皆コンテナに騒いでいるのか
コンテナは、ホストシステムからアプリケーションのワークロードを隔離、あるいはカプセル化する。コンテナを、ホストOS内にあるアプリケーションが実行されているOSと見なすことができ、かつ、それはVirtual Machineのように振る舞うのである。このエミュレーションは、Linux Kernelそれ自体と、様々なディストリビューションとコンテナを使ってアプリケーションを動かすユーザのためにコンテナ用OSのテンプレートを提供するLXC Projectによって、実現されている。このように、Containers技術が仮想マシンのように振る舞うことが可能になったことが、一気に注目を浴びる原因となったのである。

## コンテナの価値は?
コンテナは、アプリケーションをホストOSから分離、抽象化することで、LXCをまたぐシステム間でのポータビリティをもたらす。また、コンテナは、ハードウェアをエミュレートすることなく、`cgroups`と`namespaces`を駆使してLinux Kernel内でベアメタルに近いスピードの軽量なOS環境を実現している。シンプルで高速、かつハードウェアの仮想化よりもよりポータビリティーがありスケールしやすいという構造により、コンテナは、根本的なユーザのワークロードやアプリケーションの仮想化の方法を変えるものなのである。なお、ここでいうポータビリティーとはDockerによりもたらされる、どこでも同一のアプリケーションを稼働することができるという意味ではない。

## LXC
LXCプロジェクトは、コンテナ用のOSテンプレートとライフサイクル管理のための幅広いツールセットを提供しています。現在、Canonicalのサポートのもと、Stephane GraberとSerge Hallynにより開発は主導されています。

LXCは、活発に開発されているがその割にはドキュメントが少ない。特にUbuntu以外のディストリビューションで利用する際のドキュメントが欠如しており、多くの機能はまずUbuntu上で実装される。他のディストリビューションを利用しているユーザーからしたら、とてもフラストレーションのたまることである。また、ネット上には数多くの誤解を招くような情報があふれ、混乱を招いている状況も少なからずある。広くマーケットで存在感を示しているDockerと混同されたり、そもそもの情報の多さが混乱の元となっていたりする。

LXCは、Dockerのようなフロントエンドのアプリケーションのためのローレイヤー層なのか、はたまた、DockerがLXC上に構築されたユーザーフレンドリーなフロントエンドなのか？こういった不確かな情報が広く出回っている。コンテナ技術のメリットを享受するために必ずしもDockerを使う必要はない。Dockerはコンテナ利用の一つの選択でしかないのである。

## DockerとLXCでは何が違うのか
Docker視点から見たLXCとの違いについて説明する。

そもそもLXCに対してDockerが提供している機能とは何なのか。まず第一に言われることは、どのようなホストOSであってもポータブルなデプロイが可能である点である。Dockerはアプリケーションをビルドするためのフォーマットが定義されている。この定義をまとめて記述するためにDockerfileファイルを利用する。このDockerfileファイルはビルドでよく使われるmakefileファイル同様にDocker Containersの構成情報をまとめて記述するテキストファイルである。このファイルに記述する定義情報が全ての依存関係をカプセル化しているため、それはどこで実行してもアプリケーション実行環境が同一になるのです。LXCのプロセスのサンドボックスもポータビリティーを持っているが、もしLXCのコンフィグをカスタマイズしているとしたら、ネットワークやストレージ、ディストリビューションの違いにより、それは別環境で稼働しない可能性が高くなります。Dockerはその全てを抽象化するためどんな環境でも稼働させることができるのである。

Dockerについて言及するエンジニアは、総じてアプリケーション寄りのエンジニアである。Dockerは、軽量な仮想マシンとしての利用というよりもアプリケーションのデプロイに最適化されている。これはDocker自体のAPIやデザインの設計思想に反映されている。それとは対照的に、LXCは軽量な仮想マシンとしての利用に注力している。Dockerには、gitに似たバージョン管理機能が含まれている。バージョン間のdiffの取得やCommit、ロールバックが可能となっている。それによって、Containersの変更を誰がどのように行ったのかについての全てのログを追うことができる。

他にもDockerの利点は多く存在するが、主にこのような点により、Dockerは、コンテナそのもの対する見方を変えるきっかけを作った。今まで軽量な仮想マシンとして見られていたコンテナ技術をアプリケーションとしてのコンテナとしてエンジニアに再認識させることに成功したのである。

# LXCを使ってみよう
LXCの基本的なコマンドを使ったコンテナ操作を，Ubuntu14.04をベースにした環境を使って説明していきたい。

## LXCのインストール
Ubuntuの最新版であるUbuntu 14.04 LTSでは、LXC 1.0.7がlxcというパッケージ名で提供されている。また、Debian 8 (Jessie) では、LXC 1.0.6のパッケージが提供されている。

インストールは以下のコマンドを叩くだけである。

```shell-session
$ sudo apt-get install lxc
```

## LXCで仮想環境を立ち上げる
LXCによる仮想環境を立ち上げるためには、まずテンプレートと呼ばれる設定ファイルを用いる。デフォルトでメジャーディストリビューションのテンプレートはすでに同梱されているためこちらを利用する。テンプレートは`/usr/share/lxc/templates`に配置されている。

```shell-session
$ ls /usr/share/lxc/templates/
lxc-alpine    lxc-archlinux  lxc-centos  lxc-debian    lxc-fedora  lxc-openmandriva  lxc-oracle  lxc-sshd    lxc-ubuntu-cloud
lxc-altlinux  lxc-busybox    lxc-cirros  lxc-download  lxc-gentoo  lxc-opensuse      lxc-plamo	 lxc-ubuntu
```

Ubuntuのテンプレートを用いてtest-container-101という名前のUbuntuのコンテナを立ち上げる。

```shell-session
$ sudo lxc-create -t ubuntu -n test-container-101
```

これでコンテナの`root`ディレクトリに相当するディレクトリに必要なものがインストールされる。コンテナの場所は以下のディレクトリである。

```
/var/lib/lxc/<コンテナ名>/
```

そこで、test-container-101の`rootfs`の中を覗いてみると以下の通りとなる。

```shell-session
$ sudo ls -F /var/lib/lxc/test-container-101/rootfs/
bin/  boot/  dev/  etc/  home/	lib/  lib64/  media/  mnt/
opt/  proc/  root/	run/  sbin/  srv/  sys/  tmp/  usr/  var/
```

インストールしたコンテナの起動には以下のコマンドを実行する。

```shell-session
$ sudo lxc-start -n test-container-101 -d
```

-dオプションでデーモンとしてコンテナを起動する。この状態で`lxc-console`コマンドを用いてコンソール接続することでコンテナの内部にログインすることができる。

```shell-session
$ sudo lxc-console -n test-container-101
```

コンテナから抜ける際には、`Ctrl+A`を入力してその後`Q`を押す。また、デフォルトのユーザは`ubuntu`で、パスワードも`ubuntu`である。インストール時に以下のメッセージが表示されているはずである。

```
# The default user is 'ubuntu' with password 'ubuntu'!
# Use the 'sudo' command to run tasks as root in the container.
```

コンテナの終了は、`lxc-shutdown`コマンドを実行すればよい。

```shell-session
$ sudo lxc-shutdown -n test-container-101
```

## コンテナの情報を見る
コンテナに関する情報を見てみよう。`lxc-ls`というコマンドでホスト上にあるコンテナの情報を確認することができる。`--fancy`オプションを付けることで、コンテナ名、状態、IPv4のアドレス、IPv6のアドレス、自動起動の有無を確認できる。

```shell-session
$ sudo lxc-ls --fancy
NAME                STATE    IPV4  IPV6  AUTOSTART
--------------------------------------------------
test-container-101  STOPPED  -     -     NO
```

コンテナ単体の詳細情報については`lxc-info`というコマンドが提供されている。コンテナがSTOPPEDした状態のときにはこう表示される。

```shell-session
$ sudo lxc-info -n test-container-101
Name:           test-container-101
State:          STOPPED
```

コンテナを起動すると詳細情報が表示される。

```shell-session
$ sudo lxc-info -n test-container-101
Name:           test-container-101
State:          RUNNING
PID:            20434
CPU use:        0.77 seconds
BlkIO use:      7.16 MiB
Memory use:     13.53 MiB
KMem use:       0 bytes
Link:           vethABI04E
 TX bytes:      940 bytes
 RX bytes:      592 bytes
 Total bytes:   1.50 KiB
```

このように特定の情報のみを取得することも可能である。

```shell-session
$ sudo lxc-info -n test-container-101 -c lxc.utsname -c lxc.rootfs
lxc.utsname = test-container-101
lxc.rootfs = /var/lib/lxc/test-container-101/rootfs
```

# LXDとは何か
LXDについて本家ページを元に少し説明する。LXDとはLinux Container Daemonの略である。Canonical主導で開発が進められているコンテナ技術であり、コンテナに今どきのハイパーバイザーの機能を追加するサーバプログラムである。このデーモンはREST APIを提供しているのでローカルからだけでなくネットワーク経由でのコンテナの操作が可能である。

主要機能は以下の通りである。

* 非特権コンテナ、リソース制限を用いたセキュアなデザイン
* 直感的なコマンドラインとREST API
* イメージベースのコンテナ構築
* ライブマイグレーション

特に、Docker Hubにあるイメージを利用可能になるということがアナウンスされている点が期待できる。

## LXDインストール
UbuntuユーザはPPAを使って以下の通りインストール可能である。なお、他のディストリビューションのユーザは、最新のリリースの`tarball`かgitリポジトリから直接LXDをダウンロードしてビルドできる。

```shell-session
$ sudo add-apt-repository ppa:ubuntu-lxc/lxd-git-master
$ sudo apt-get update && sudo apt-get -y install lxd
```

## LXDイメージのインポート
イメージベースなので、ダウンロードする。なお、LXDのコマンドラインは`lxc`というコマンドである。何ともややこしい。コンテナイメージのインポートは`lxc-images`というコマンドを利用する。以下では、Ubuntu14.04をインポートしている。

```shell-session
$ sudo lxd-images import lxc ubuntu trusty amd64 --alias ubuntu
```

以下のコマンドでイメージ一覧を取得できる。

```shell-session
$ sudo lxc image list
+--------+--------------+--------+-------------+--------+------------------------------+
| ALIAS  | FINGERPRINT  | PUBLIC | DESCRIPTION |  ARCH  |         UPLOAD DATE          |
+--------+--------------+--------+-------------+--------+------------------------------+
| ubuntu | 04aac4257341 | no     |             | x86_64 | Jul 15, 2015 at 1:16pm (UTC) |
+--------+--------------+--------+-------------+--------+------------------------------+
```

## LXDコンテナの起動
`lxc launch`コマンドで起動できる。

```shell-session
$ sudo lxc launch ubuntu test-container-102
Creating container...done
Starting container...done
error: saving config file for the container failed
```

できなかった。。。。どうやら[このバグ](https://github.com/lxc/lxd/issues/739)にヒットしたらしい。

改めて起動するとこのようになる。

```shell-session
$ lxc list
+--------------------+---------+------------+------+-----------+-----------+
|        NAME        |  STATE  |    IPV4    | IPV6 | EPHEMERAL | SNAPSHOTS |
+--------------------+---------+------------+------+-----------+-----------+
| test-container-103 | RUNNING | 10.0.3.138 |      | NO        | 0         |
+--------------------+---------+------------+------+-----------+-----------+
```