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

第29回LXC 1.1[1]

前回以来、コンテナに関する勉強会を東京で開催したり、その他の勉強会で登壇したりしていたので、気がつけば3ヵ月も間隔が空いてしまいました。この勉強会ではLinuxコンテナの主要な機能である名前空間のカーネル内の実装のお話や、Docker関連のお話、Linux以外のコンテナ技術に関する話題も色々とお話いただいて、かなり面白い勉強会になりました。勉強会ページで一部の動画を公開していますので、興味のある方はぜひご覧ください。

この間に、この連載で何度も『次のリリースである1.0.8で修正されます』と言ったものの、さっぱりリリースされる気配のなかった1.0.8がようやくリリースされました。セキュリティホールの修正が含まれていますので1.0.7をお使いの方はバージョンアップをしてください。1.0.7から1年近く間隔が空いていますので、変更点が膨大です。変更点はlinuxcontainers.orgのNewsページに掲載されています。

さて、この連載では、これまでLXCの長期サポート版である1.0系列を取り上げて、機能を紹介してきました。

今回からはLXC 1.1を取り上げて、1.0からの変更点を中心に紹介していきたいと思います。

LXC 1.1は2015年1月末に1.1.0がリリースされ、執筆時点の現在では1.1.5が最新バージョンとなっています。

1.1で大きな新機能や改良が一段落し、1.1.0がリリースされたあとは、2015年2月に0.1がリリースされたLXDの方に大きく開発リソースが振り分けられているようで、それまでは毎日のように変化していたリポジトリにもたまにしかマージが行われなくなりました。

それではLXCが提供するコマンドで、新機能や使い方が変化した機能を中心に順に紹介していきたいと思います。

今回の実行例はUbuntu 15.04上にインストールしたLXC 1.1.2を使用しています。

lxc-startのデフォルト動作の変更

この変更については、第8回でも少し紹介しました。

1.0系ではlxc-startコマンドを使ってコンテナを起動させると、デフォルトではフォアグラウンドで起動しました。

動作確認を行う際などを除いて、実際にコンテナを起動させて使う場合にフォアグラウンドで起動させるケースはあまりないと思います。私も1.0系を使っていると、ついつい-dオプションの指定を忘れてしまい、フォアグラウンドで起動させてから「しまった」と思って、コンテナを起動しなおすケースが結構あります。

そこで1.1系ではlxc-startはバックグラウンド起動がデフォルトとなり、-dを付けなくても良くなりました。逆にフォアグラウンドで起動させる場合は-Fオプションを使います。1.0系でも、1.1以降への移行の際に問題にならないように、1.0.6で-Fオプションが新設されました。

$ lxc-start --version
1.1.2
$ sudo lxc-start -n ct01
$ sudo lxc-ls -f
NAME  STATE    IPV4        IPV6  GROUPS  AUTOSTART  
--------------------------------------------------
ct01  RUNNING  10.0.3.169  -     -       NO         

以上のようにオプションを指定しない場合、コンテナがバックグラウンドで起動しています。

1.0系を使っていて、シェルスクリプトなどでlxc-startを使い、オプションを指定せずにコンテナをフォアグラウンド起動させている場合は、1.1以降にバージョンアップする際に動作が変化しないように、-Fオプションを付けておくと良いでしょう。

アプリケーションコンテナ環境の構築が楽に

LXCでアプリケーションコンテナを実行する方法については第10回で説明しました。

そこで紹介した通り、アプリケーションコンテナを実行する場合はlxc-executeコマンドを使うと便利です。しかし、LXC 1.0系列でlxc-executeコマンドを使う場合は、init.lxcコマンドをコンテナ内に準備する必要があり少し不便です。init.lxcコマンドをコンテナ内にコピーするかバインドマウントをすれば良いものの、1.0のinit.lxcはダイナミックリンクされており、依存するライブラリも準備する必要があったためです。

1.1では、スタティックリンクされたlxc.initが準備され、コンテナ内にlxc.initが見つからない場合は、スタティックリンクされたlxc.initがコンテナ内にバインドマウントされます。このため、lxc.initを準備する必要はなくなり、単にlxc-executeを実行すれば良くなりました。ファイル名が少し変わって、ダイナミックリンクされたファイルはinit.lxcスタティックリンクされたファイルはinit.lxc.staticとなっています。

以下はinit.lxcを準備していないコンテナにインストールされたApacheを起動しています。

$ sudo lxc-execute -n ct02 -- /usr/sbin/apache2ctl start &
[1] 12505
$ sudo lxc-ls -f ct02
NAME  STATE    IPV4  IPV6  GROUPS  AUTOSTART  
--------------------------------------------
ct02  RUNNING  -     -     -       NO
$ sudo lxc-attach -n ct02 -- ls -F /    (/にinit.lxc.staticというファイルが存在する)
bin/   dev/  home/         lib/    media/  opt/   root/  sbin/  sys/  usr/
boot/  etc/  init.lxc.static*  lib64/  mnt/    proc/  run/   srv/   tmp/  var/
$ sudo lxc-attach -n ct02 -- file /init.lxc.static
/init.lxc.static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=ca82d892e89cb8f0e4fa60ad57b973172290e823, stripped
(init.lxc.staticファイルはスタティックリンクであることを確認)
$ sudo lxc-attach -n ct02 -- cat /proc/mounts | grep init.lxc
/dev/mapper/vivid--vg-root /init.lxc.static ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
(マウントされていることを確認)

コンテナ内のルートディレクトリを見るとinit.lxc.staticというスタティックリンクされたファイルが存在しています。そしてコンテナ内の/proc/mountsを見ると、init.lxc.staticがマウントされていることが確認できます。

全コンテナをまとめて起動

lxc-autostartコマンドは第25回で紹介した、複数のコンテナをまとめて起動したい場合に便利なコマンドです。まとめて起動したいコンテナを、lxc.groupを指定してグループ分けができます。

おさらいのためにUbuntu 14.04 LTS上の1.0.7で実行した例を見てみましょう。

"test"グループに設定されているコンテナを、以下のようにまとめて起動できました。

$ sudo lxc-ls -f
NAME  STATE    IPV4  IPV6  AUTOSTART   
-------------------------------------
ct01  STOPPED  -     -     YES (test)  
ct02  STOPPED  -     -     YES (test)  
ct03  STOPPED  -     -     YES         
$ sudo lxc-autostart -g test 
$ sudo lxc-ls -f
NAME  STATE    IPV4        IPV6  AUTOSTART   
-------------------------------------------
ct01  RUNNING  10.0.3.228  -     YES (test)  
ct02  RUNNING  10.0.3.166  -     YES (test)  
ct03  STOPPED  -           -     YES         

この場合、自動起動が設定されていても、"test"に属するコンテナのみ起動しました。グループ分けを無視して自動起動が設定されているコンテナをすべて起動するためには-aオプションを使いました。

$ sudo lxc-ls -f
NAME  STATE    IPV4  IPV6  AUTOSTART   
-------------------------------------
ct01  STOPPED  -     -     YES (test)  
ct02  STOPPED  -     -     YES         
ct03  STOPPED  -     -     NO          
$ sudo lxc-autostart -a
$ sudo lxc-ls -f
NAME  STATE    IPV4        IPV6  AUTOSTART   
-------------------------------------------
ct01  RUNNING  10.0.3.228  -     YES (test)  
ct02  RUNNING  10.0.3.166  -     YES         
ct03  STOPPED  -           -     NO          

以上のように、自動起動が設定されているコンテナすべてが起動できています。しかし1.0系では、自動起動が無効になっているコンテナをまとめて起動できませんでした。

1.1では、新たに-Aオプションが新設され、lxc.start.autoの指定を無視できるようになりました。以下のように-aオプションと組み合わせて、システム上に存在するすべてのコンテナを起動できます。

$ sudo lxc-ls -f
NAME  STATE    IPV4  IPV6  GROUPS  AUTOSTART  
--------------------------------------------
ct01  STOPPED  -     -     test    BY-GROUP   
ct02  STOPPED  -     -     -       YES        
ct03  STOPPED  -     -     -       NO         
$ sudo lxc-autostart -a -A
$ sudo lxc-ls -f
NAME  STATE    IPV4        IPV6  GROUPS  AUTOSTART  
--------------------------------------------------
ct01  RUNNING  10.0.3.185  -     test    BY-GROUP   
ct02  RUNNING  10.0.3.224  -     -       YES        
ct03  RUNNING  10.0.3.242  -     -       NO         

以上のように、自動起動が設定されたコンテナだけでなく、自動起動がオフになっているコンテナも起動しています。

また、上記の実行例で示したように、lxc-lsコマンドが表示するグループと自動起動の表示が分離して見やすくなっていますね。

lxc-lsの新しい出力項目

前述のようにlxc-lsに"GROUPS"というカラムが新設された以外に、もう1つ表示できる項目が増えました。

以下のように--fancy-formatオプションに"interfaces"というキーワードが指定できるようになりました。コンテナ内のネットワークインターフェースを一覧できます。

$ sudo lxc-ls --fancy --fancy-format=name,state,ipv4,interfaces
NAME  STATE    IPV4                        INTERFACES      
---------------------------------------------------------
ct01  RUNNING  10.0.3.185                  eth0, lo        
ct02  RUNNING  10.0.3.224                  eth0, lo        
ct03  RUNNING  10.0.3.242, 10.200.200.239  eth0, eth1, lo  

上記の例では、"ct03"には2つのネットワークインターフェースが定義されています。

lxc-topコマンドのバイナリ化

1.0系ではluaで書かれていたlxc-topコマンドが、1.1でC言語を使って書き直されました。

luaで書かれていたためか、Ubuntu 14.04 LTSではlxc-topコマンドはパッケージでLXCを入れてもインストールされませんでした。一方、Ubuntu 15.04でインストールされるLXC 1.1系のパッケージではインストールされるようになっています。

$ sudo lxc-top
Container               CPU      CPU      CPU      BlkIO        Mem
Name                   Used      Sys     User      Total       Used
ct01                   0.36     0.23     0.16    0.00      16.09 MB
ct02                   0.38     0.33     0.15    0.00      16.00 MB
ct03                   0.37     0.26     0.15    0.00      16.00 MB
TOTAL 3 of 3           1.11     0.82     0.46    0.00      48.09 MB

コンテナ作成時にテンプレートの指定が必須に

1.0.7までではlxc-createコマンドはコンテナ名を指定することのみが必須で、テンプレートを指定せずに実行すると、空のコンテナが作成されました。

1.1系では、-tオプションを指定することが必須となりました。1.0.7まででテンプレートを指定せずに実行した場合と同じように、空のコンテナを作成したい場合は、-t noneのように指定します。

また1.0系でも、1.0.8でバグ修正として1.1と同じように-tオプションが必須になりました。空のコンテナを作成する際には-t noneと指定をするのも同じです。

$ sudo lxc-create -t none -n empty
$ sudo lxc-ls -f
NAME   STATE    IPV4  IPV6  GROUPS  AUTOSTART  
---------------------------------------------
empty  STOPPED  -     -     -       NO
$ sudo ls -F /var/lib/lxc/empty/
config

以上のようにコンテナディレクトリが作成され、ディレクトリには設定ファイルのみが作成されます。設定ファイルは以下のように作成時にコンテナに設定される、コンテナのデフォルト設定ファイルがコピーされただけの状態になっています。

$ sudo cat /var/lib/lxc/empty/config
lxc.network.type=veth
lxc.network.link=lxcbr0
lxc.network.flags=up

ただし、Ubuntu 15.04にインストールされている1.1.2では、バグのために-t noneを指定してもエラーになるようです。

lxc-config lxc.cgroup.* の表示

第28回「lxc-configの改良」で紹介したように、lxc-configでcgroup関係のシステム設定が表示されるようになりました。

lxc-start-ephemeral --cdir オプション

第23回で説明した通り、lxc-start-ephemeralコマンドは既存のコンテナの一時的なコピーを使ってコンテナを作成し、起動するコマンドです。

このコマンドのオプションにホスト上のディレクトリをコンテナ内にバインドマウントするための--bdirというオプションがありました。

LXC 1.1では、--bdirに加えて、バインドマウントでなく、ホスト上のディレクトリを下層側のディレクトリとして、コンテナ用に作成したディレクトリを上層側ディレクトリとしてoverlayfsでマウントするための--cdirオプションが追加されました。

--bdirだとホスト上に存在するディレクトリやファイルが直接操作されてしまいます。新しく追加された--cdirを使うと、ホスト上のディレクトリやファイルをコンテナ内で使いたいけれども、変更はしたくない場合に使えます。

試してみましょう。

$ sudo lxc-ls -f
NAME  STATE    IPV4  IPV6  GROUPS  AUTOSTART  
--------------------------------------------
ct01  STOPPED  -     -     -       NO         
$ touch /home/ubuntu/gihyo-test

lxc-start-ephemeralコマンドで起動するコンテナの元となるコンテナを作成します。そしてホスト上に/home/ubuntu/gihyo-testというファイルを作りました。準備ができたので一時的なコンテナを起動しましょう。

$ sudo lxc-start-ephemeral -o ct01 --cdir /home -d -k
setting rootfs to .%s. /var/lib/lxc/ct01-9dcya3fq/rootfs
The ephemeral container is now started.

You can enter it from the command line with: lxc-console -n ct01-9dcya3fq
The following IP addresses have be found in the container:
 - 10.0.3.169

上記の例のように--cdir /homeと指定して、ホストの/homeがコンテナ内でも見えるようにしています。起動したところでlxc-attachコマンドでコンテナ内に入ってみます。

$ sudo lxc-attach -n ct01-9dcya3fq
root@ct01-9dcya3fq:~# cat /proc/mounts | grep overlay
none / overlay rw,relatime,lowerdir=/var/lib/lxc/ct01/rootfs,upperdir=/var/lib/lxc/ct01-9dcya3fq/tmpfs/delta0,workdir=/var/lib/lxc/ct01-9dcya3fq/tmpfs/work0 0 0
none /home overlay rw,relatime,lowerdir=/home,upperdir=/var/lib/lxc/ct01-9dcya3fq/tmpfs/delta1,workdir=/var/lib/lxc/ct01-9dcya3fq/tmpfs/work1 0 0

コンテナ内で/proc/mountsを確認してみると、第23回で説明したように/がoverlayfsでマウントされている以外に、--cdir /homeで指定した通り/homeがoverlayfsでマウントされていることがわかります。

コンテナ内の/homeを、下層ディレクトリとしてホストの/homeを使い、上層ディレクトリとしてコンテナディレクトリ内に作られたtmpfs内のdelta1というディレクトリを使い、workdirとしてtmpfs内のwork1を使い、overlayfsマウントして準備しているのがわかります。

root@ct01-9dcya3fq:~# ls /home/ubuntu
gihyo-test (ホストの/home/ubuntuの内容が見えている)
root@ct01-9dcya3fq:~# touch /home/ubuntu/container (/home/ubuntuにファイルを作成)
root@ct01-9dcya3fq:~# ls /home/ubuntu
container  gihyo-test

コンテナ内で/home/ubuntuを見てみると、確かにホスト上で作ったファイルが見えています。ここで新たにコンテナ内でファイルを作ってみましょう。コンテナ内では当然作成したファイルが見えていますね。

ここでホスト上で/home/ubuntuを確認してみましょう。

$ ls /home/ubuntu
gihyo-test (ホスト上は元のファイルしかない)

上記のようにコンテナ内で作ったファイルはありません。コンテナ用の上層ディレクトリ内を確認してみると、以下のようにコンテナ内で作成したファイルが存在しています。

$ sudo ls -F /var/lib/lxc/ct01-9dcya3fq/tmpfs/delta1/ubuntu
container (コンテナ内で作成したファイルはoverlayfsのupperdirに作成されている)

まとめ

今回はLXC 1.1の新機能や変更点のうち、主にコマンドの動きに関わる変更点を紹介しました。

次回も引き続きLXC 1.1の新機能や変更点を紹介します。

おすすめ記事

記事・ニュース一覧