LXC 1.0: コンテナーの高度な使い方 [3/10]

## この文書について

この文書は、連載記事「[LXC 1.0: Blog post series](https://www.stgraber.org/2013/12/20/lxc-1-0-blog-post-series/)」の一つである以下の記事を翻訳したものです。連載の目次や注意点は[こちら](http://qiita.com/m-shibata/items/ee9b295a2596824da819)を参照してください。

* https://www.stgraber.org/2013/12/21/lxc-1-0-advanced-container-usage/

この文書のライセンスは原文と同じく、[Creative Commons BY-NC-SA 2.5](http://creativecommons.org/licenses/by-nc-sa/2.5/)のもとに提供されています。

![CC-BY-NC-SA 2.5](http://i.creativecommons.org/l/by-nc-sa/2.5/88x31.png)


## コンテナーとのデータの交換方法

コンテナーはホストのファイルシステムを直接共有しているため、さまざまな方法でコンテナーにデータを渡したり、コンテナーからデータを取り出すことができます。

もっともわかりやすい方法は、コンテナーのルートファイルシステムにアクセスする方法です： `/var/lib/lxc/<コンテナー名>/rootfs/`

この方法は素晴らしいですが、場合によってはコンテナーの中の、コンテナー自身によってマウントされたファイルシステム（例えば `tmpfs` ）にアクセスしたい場合があるかもしれません。そんな時は、次の方法が使えます：

```
sudo ls -lh /proc/$(sudo lxc-info -n p1 -p -H)/root/run/
```

これにより、実行中のコンテナー「p1」の `/run` の中身を見ることができます。

ここまでは、ホストからコンテナーへアクセスする方法を見てきました。逆に、既存のコンテナーからホストへとアクセスや書き込みをしたい場合はどうすればいいでしょうか？

仮に、ホストの `/var/cache/lxc` を「p1」と共有したいとしましょう。 `/var/lib/lxc/p1/fstab` に次の行を追加すると実現できます：

```
/var/cache/lxc var/cache/lxc none bind,create=dir
```

この行は、ホストの「 `/var/cache/lxc` 」を「 `/var/cache/lxc` 」としてマウントすること（二つ目に `/` がないのは、コンテナーのルートからの相対パスを意味しています）、マウントはbind mountを使用すること（fstypeが `none` で、オプションが `mount` だから）、コンテナーにディレクトリが存在しなかったら作成すること（ `create=dir` オプション）を意味しています。

設定後に「p1」を再起動して、コンテナーの中の `/var/cache/lxc` を見れば、ホストと同じ内容が表示されることがわかるでしょう。コンテナーからは読み込みだけを許可したい場合は、fstabのマウントフラグに「 `ro` 」を追加してください。


## コンテナーの入れ子構造

LXCの素晴らしい機能（だけど多くの人にとってとても便利であるとは正直なところ言えない機能）の一つは、コンテナーの入れ子（nesting）をサポートしていることです。つまり、LXCの中でLXCをほとんどオーバーヘッドなしに実行できるのです。

Ubuntuの初期設定では、現時点ではこの機能はブロックされています。これは、コンテナーが `cgroupfs` をマウントする際に、適用されているあらゆるcgroupの制限を解除する必要があるためです。これはほとんどの環境では問題になりません。ただし、まったく信用できないコンテナーを使用する場合は、今のところ入れ子機能を使うべきではありません。

「p1」コンテナーの入れ子機能を有効化しましょう。 `/var/lib/lxc/p1/config` を開き、次の設定を追加します：

```
lxc.aa_profile = lxc-container-default-with-nesting
```

その後、「p1」を再起動します。再起動が完了したら、コンテナーの中でlxcをインストールしましょう。ホストと同じバージョンを使うことを推奨します。ただし、それは厳密な要求事項ではありません。

コンテナーにLXCをインストールできたら、次のコマンドを実行します：

```
sudo lxc-create -t ubuntu -n p1
```

コンテナーの中で `/var/cache/lxc` をbind mountしているのであれば、作成はすぐに行われるはずです（環境全体を再度ブートストラップする必要がないからです）。その後、これまでと同様に新しいコンテナーを起動してください。

この時点で、入れ子モードを導入したホスト上で `lxc-ls` を実行すると、以下のように表示されるはずです：

```
stgraber@castiana:~$ sudo lxc-ls --fancy --nesting
NAME    STATE    IPV4                 IPV6   AUTOSTART
------------------------------------------------------
p1      RUNNING  10.0.3.82, 10.0.4.1  -      NO
 \_ p1  RUNNING  10.0.4.7             -      NO
p2      RUNNING  10.0.3.128           -      NO
```

階層の数に実質的な制約はないので、好きなだけ作ることができます。ただし、10階層もネストすると嬉しい理由は思いつきませんけどね。


## 生のネットワークアクセス

前回の記事で、デバイスをホストからコンテナーに渡すことができるという話をしました。そのようなコンテナーの一つとして、私はVPN越しのリモートネットワークを構築しています。このネットワークは、OpenVPNとイーサネットTAPデバイスを直接使用しています。

私は、経路を混ぜあわせず、他のマシンからリモートサイト上のマシンにアクセスするような形で見えて欲しかったので、VPNにアクセスする完全に独立したシステムが必要でした。

このような動作を行うように、コンテナーのネットワーク設定を以下のように行いました：

lxc.network.type = phys
lxc.network.hwaddr = 00:16:3e:c6:0e:04
lxc.network.flags = up
lxc.network.link = tap0
lxc.network.name = eth0

その後、ホスト上でOpenVPNを起動し（訳注１）、tap0に接続するよう設定しました。さらに、コンテナーを起動することでそのインターフェースをコンテナー側に移動し、eth0として使うようにしました。コンテナーはDHCPでIPアドレスを取得したあと、リモートネットワークに直接接続する物理マシンのように振る舞うことになります。


## 訳注１

（訳注：記事のコメントに、なぜOpenVPNをコンテナーではなくホスト上で実行しているのかという質問に対する回答があったので、ここに追記しておきます）

OpenVPNをホスト上で実行しているのは、コンテナーのデフォルトゲートウェイ（eth0です）がVPNだからです。そのため、最初の段階ではそこに接続できないのです（鶏と卵の問題です）。

私の目的は、リモートネットワーク上の標準的なクライアントをシミュレートすることでした。しかし、ラップトップ上で実行しつつ、ラップトップのネットワークには影響を与えたくなかったのです。

MACアドレスに関しては、コンテナーをブートする度に毎回異なるIPアドレスをリモートのDHCPサーバーから設定したくなかったためです（標準の設定では、カーネルがランダムなMACアドレスを生成します）。通常使っている範囲（Xenも同じ範囲を使っており、少し足りないです……）からランダムなアドレスを設定しています。