LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第35回 コンテナのネスト[1]

この記事を読むのに必要な時間:およそ 5 分

前回は,名前空間ごとに仮想化したcgroupツリーが見える,Linuxカーネルのcgroup名前空間という機能を紹介しました。

今回はそのcgroup名前空間の応用例を紹介することを兼ねて,コンテナ内でコンテナを動作させてみます。つまりコンテナをネストさせて遊んでみようという企画です。

今回はroot権限で動作するコンテナを使ってネストを試してみます。試している環境はUbuntu 16.04です。コマンドの実行例は,実行している環境が,ホストなのかどのコンテナなのかがわかりやすいようにプロンプトまで引用しています。

親コンテナの作成と起動

まずはホスト上にコンテナを作成します。

ubuntu@host:~$ sudo lxc-create -n parent -t download -- -d ubuntu -r xenial -a amd64

ここではネストさせるコンテナの「親」という意味でparentという名前のコンテナを作成しました。ここまでは通常のコンテナを作成する場合と同じです。

コンテナのネストを行うためには,ネスト用の設定を行う必要があります。LXC では標準でそのために設定ファイルnesting.confが付属していますので,lxc-createで作成したコンテナの設定ファイルにincludeの設定を行うだけです。

ubuntu@host:~$ sudo sed -i '$ a lxc.include = /usr/share/lxc/config/nesting.conf' /var/lib/lxc/parent/config

これでコンテナの中でコンテナを起動する準備ができました。このコンテナを起動し,コンテナ内にlxcパッケージをインストールしましょう。

ubuntu@host:~$ sudo lxc-start -n parent (コンテナの起動)
ubuntu@host:~$ sudo lxc-ls -f (コンテナの起動確認)
NAME   STATE   AUTOSTART GROUPS IPV4       IPV6 
parent RUNNING 0         -      10.0.3.169 -
ubuntu@host:~$ sudo lxc-attach -n parent(コンテナ環境に入る)
root@parent:~# apt-get update && apt-get install lxc
(LXCのインストール)
  :(略)

子コンテナの作成と起動

ここまででparentコンテナ内でコンテナを作成する準備が整いました。⁠親」の中に「子」コンテナを作成して,先の例と同様にネスト用の設定ファイルをincludeする設定を足しておきましょう。

root@parent:~# lxc-create -n child -t download -- -d ubuntu -r xenial -a amd64
root@parent:~# sed -i '$ a lxc.include = /usr/share/lxc/config/nesting.conf' /var/lib/lxc/child/config

コンテナ名はchildとしました。

root@parent:~# lxc-start -n child (子コンテナの起動)
root@parent:~# lxc-ls -f (子コンテナ起動の確認)
NAME  STATE   AUTOSTART GROUPS IPV4       IPV6 
child RUNNING 0         -      10.0.4.181 -    

特に問題なく起動しています。

ネストしたコンテナの確認

ところで,lxc-lsコマンドには--nestingというオプションがあり,ネストしたコンテナの状態が表示できます。

一旦,ホスト上のシェルに戻ってlxc-lsコマンドを実行してみましょう。

ubuntu@host:~$ sudo lxc-ls -f --nesting
NAME   STATE   AUTOSTART GROUPS IPV4                 IPV6 
parent RUNNING 0         -      10.0.3.169, 10.0.4.1 -    
\child RUNNING 0         -      10.0.4.181           -    

以上のように,ホスト上で直接parentが実行されており,その中でchildが実行されている様子が確認できます。また,parent内でLXCをインストールしたため,LXCがブリッジを作成しています。コンテナ起動時に作成されるvethインターフェースに割りあたっているアドレスだけでなく,そのブリッジに割りあたっているIPアドレス10.0.4.1も表示されています。

孫コンテナの作成と起動

以上で,コンテナ内でコンテナを起動できることが確認できました。LXCでは,ネストしたコンテナ内でさらにコンテナを起動する機能をサポートしていますので試してみましょう。

さきほど作成した「子」コンテナchild内でさらにコンテナを作成し,起動してみます。⁠親」コンテナから見ると孫ですね。

root@parent:~# lxc-attch -n child (子コンテナに入る)
root@child:~# apt-get update -y && apt-get install lxc (LXCのインストール)
root@child:~# lxc-create -n grandchild -t download -- -d ubuntu -r xenial -a amd64
(コンテナの作成)
root@child:~# lxc-start -n grandchild (孫コンテナの起動)
root@child:~# lxc-ls -f  (孫コンテナ起動の確認)
NAME       STATE   AUTOSTART GROUPS IPV4       IPV6 
grandchild RUNNING 0         -      10.0.3.157 -    

最初の親コンテナから見ると孫になりますのでgrandchildと名づけました。

先の実行例と同様に,ホストからlxc-lsでネストされている状態を確認してみましょう。

ubuntu@host:~$ sudo lxc-ls -f --nesting
NAME         STATE   AUTOSTART GROUPS IPV4                 IPV6 
parent       RUNNING 0         -      10.0.3.169, 10.0.4.1 -    
\child       RUNNING 0         -      10.0.3.1, 10.0.4.181 -    
 \grandchild RUNNING 0         -      10.0.3.157           -    

cgroupの確認

孫コンテナまで3段のネストをさせたところで,これまでに作成したコンテナそれぞれでcgroupfsツリーがどのようになっているかを確認してみましょう。

孫コンテナのcgroup

まずは,最後に作成したネストの一番の末端である孫コンテナgrandchildで,cgroupfsがどのようになっているかを確認してみましょう。

root@grandchild:~# ls -F /sys/fs/cgroup/
blkio/    cpu,cpuacct/  freezer/  net_cls@           perf_event/
cpu@      cpuset/       hugetlb/  net_cls,net_prio/  pids/
cpuacct@  devices/      memory/   net_prio@          systemd/

/sys/fs/cgroup以下は,通常のホストOS上と同じように,サブシステムごとのディレクトリが準備されています。このうちfreezerディレクトリを見てみましょう。

root@grandchild:~# ls -F /sys/fs/cgroup/freezer/
cgroup.clone_children  freezer.parent_freezing  freezer.state      tasks
cgroup.procs           freezer.self_freezing    notify_on_release

以上のようにcgroupとfreezerサブシステム用のファイルが存在します。freezerサブシステムをオプションに指定して,cgroupfsをマウントした直後と同じ状態です。

その他のサブシステムやsystemd用のcgroupについても,ホストOS上で直接cgroupfsをマウントしたときと同じように見えます。

子コンテナのcgroup

孫コンテナのcgroupを確認したところで,ネストのひとつ上のコンテナである子コンテナchildで,cgroupがどうなっているかを確認してみましょう。先の例と同じようにfreezerディレクトリ以下を確認します。

root@child:~# tree -d /sys/fs/cgroup/freezer/
/sys/fs/cgroup/freezer/
└── lxc
    └── grandchild

今度はサブディレクトリが存在します。LXCコンテナは通常,cgroupのルートにlxcというcgroupを作成し,その下にコンテナ名のcgroupを作成します。child内でgrandchildという名前のコンテナを起動しましたので,そのコンテナ用のディレクトリlxc/grandchildが見えています。

つまり,孫コンテナ内で/sys/fs/cgroup/freezerとして見えていたcgroupは,ひとつ上の子コンテナから見た/sys/fs/cgroup/freezer/lxc/grandchildに相当します。

cgroup名前空間の機能で,⁠孫」コンテナgrandchild用に作られたcgroupが,コンテナ内ではルートとして見えていることが確認できました。

親コンテナのcgroup

親コンテナであるparent内でも同様に確認してみましょう。

root@parent:~# tree -d /sys/fs/cgroup/freezer/
/sys/fs/cgroup/freezer/
└── lxc
    └── child
        └── lxc
            └── grandchild

コンテナごとにlxc/(コンテナ名)というcgroupが作成されており,ネストしている様子がわかります。

ホストのcgroup

同様にホストから確認しましょう。

ubuntu@host:~$ tree -d /sys/fs/cgroup/freezer/
/sys/fs/cgroup/freezer/
├── lxc
│   └── parent
│       └── lxc
│           └── child
│               └── lxc
│                   └── grandchild
  :(略)

先の例と同様にcgroupがネストしていますね。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ。ファーストサーバ株式会社所属。

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/

コメント

コメントの記入