Ubuntu 16.04 LTSでLXD 2.0をセットアップして使ってみる

参考記事

公式ドキュメントのLinux Containers - LXD - はじめに - コマンドラインによくまとまっているのですが、より詳細には The LXD 2.0 Story (Prologue) | Ubuntu Insights にリストアップされている記事がわかりやすかったです。

Ubuntu 16.04 serverでのLXDの初期セットアップ

Ubuntu 16.04 serverならLXDはインストール済みなので、 apt-get install lxdnewgrp lxd は不要でした。

LXCではコンテナ一覧表示は lxc-ls、コンテナ作成は lxc-create のように別々のコマンドになっていましたが、 LXDではそれぞれ lxc list, lxc launchlxc コマンドのサブコマンドになっています。

また lxd というプログラムもあります。 man lxdman lxc してみると lxd はコンテナのハイパーバイザのデーモンで、 lxc はコンテナのハイパーバイザのクライアントです。

まずバージョンを確認してみます。

$ lxd --version
2.0.0
$ lxc --version
2.0.0

ちなみに、 lxc のほうは lxc versionversion サブコマンドも用意されていますが、 lxd versionerror: Unknown arguments とエラーになりました。

コンテナ一覧を表示してみます。まだ1つもコンテナを作っていないので一覧は空です。

$ lxc list
Generating a client certificate. This may take a minute...
If this is your first time using LXD, you should also run: sudo lxd init

+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+

lxc list の出力の1行目にある通り、初回実行時にはクライアント証明書が生成されます。 ~/.config/lxc/client.key に秘密鍵、 ~/.config/lxc/client.crt に証明書が作られました。

また、 lxc list の出力の2行目に LXDを初めて使うときは sudo lxd init を実行するようにも書かれていますので、実行します。

すると、いくつか質問されるので入力していきます。

$ sudo lxd init
sudo: unable to resolve host ubuntu-xenial
Name of the storage backend to use (dir or zfs): dir
Would you like LXD to be available over the network (yes/no)? no
Do you want to configure the LXD bridge (yes/no)? yes
Warning: Stopping lxd.service, but it can still be activated by:
  lxd.socket
LXD has been successfully configured.

1つ目はストレージバックアップの選択です。選択肢は dirzfs ですが、上記では dir にしました。

2つ目はLXDをネットワーク越しで利用するかどうかです。上記では no にしました。 すると上記の警告にあるとおり lxd.service が停止されました。 sudo systemctl status lxd で確認すると Active: の右が inactive (dead) になっていました。

一方で、 lxd.socket は稼働しています。 sudo systemctl status lxd.socket で確認すると Active: の右が active (running) になっていました。

/lib/systemd/system/lxd.socket を見ると /var/lib/lxd/unix.socket というファイル名でUnixドメインソケットが作られていることがわかりました。

3つ目はLXDのブリッジを設定するかどうかです。上記は yes にしました。すると CUI でダイアログが次々開いて DHCPで発行するIPv4やIPv6のアドレスの範囲などを聞かれるので、順次入力していきます。ランダムなアドレスの範囲が事前入力されているので、特に変更不要な場合はenterキーを連打していけばOKでした。

再度 lxc list を実行してみると、今度はクライアント証明書を生成したとか、 sudo lxc init を実行せよとかの文言は表示されなくなりました。

$ lxc list
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+

別パターンの初期化の検証

このパターンではLXDをネットワーク越しに使うかの質問に yes と答えました。すると、バインドするアドレスとポートを聞かれます。ポートは 8443 がお勧めと書かれていますが、enterキー空打ちではだめで、ちゃんと値を入力する必要がありました。

$ sudo lxd init
sudo: unable to resolve host ubuntu-xenial
Name of the storage backend to use (dir or zfs): dir
Would you like LXD to be available over the network (yes/no)? yes
Address to bind LXD to (not including port): 0.0.0.0
Port to bind LXD to (8443 recommended):
Invalid input, try again.

Port to bind LXD to (8443 recommended): 8443
Trust password for new clients:
Again:
Do you want to configure the LXD bridge (yes/no)? no
LXD has been successfully configured.

この設定の後に sudo systemctl status lxd を実行すると Active: の右は active (running) になっていました。

また、上記ではLXDブリッジを設定するかの質問に no と答えてみました。この場合は CUIのダイアログは開かれず、すぐに LXD has been successfully configured. が表示されて完了しました。

ip a で確認すると、この場合も lxdbr0 というネットワークインターフェース自体は作成されていました。ただし、IPアドレスは設定されていない状態です。

$ ip a
...()...
4: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 0a:b4:d4:fa:b3:71 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::8b4:d4ff:fefa:b371/64 scope link
       valid_lft forever preferred_lft forever
    inet6 fe80::1/64 scope link
       valid_lft forever preferred_lft forever

ただ、その後 lxc launch でコンテナを起動した後再度確認すると lxdbr0 の左の番号が 4: から 5: に変わっていて、IPv4アドレスも設定されていました。また lxc.service も起動していました。

sudo ss -antp で確認したところ、LXDをネットワーク越しに使う設定を yes にしたときは lxd のプロセスが指定したポート(上記の例では8443番ポート)をLISTENしていますが、 no にしたときはLISTENしていませんでした。

リモートとローカルのイメージ一覧表示

lxc image サブコマンドでイメージを取り扱います。 lxc image -h と入力すると使用方法が表示されます。

lxc image list の説明の部分を以下に引用します。 LANG 環境変数が ja_JP.UTF8 ならヘルプメッセージは日本語で表示されます。

lxc image list [remote:] [filter]
    LXD のイメージストア内のイメージを一覧表示します。プロパティでフィルタ
    を行う場合は、フィルタは <key>=<value> の形になります。フィルタはイメー
    ジハッシュの一部やイメージエイリアス名の一部も指定できます。

英語のヘルプメッセージを見たい場合は LANG=C をつけて LANG=C lxc image のように実行すればOKです。 lxc image list の英語ヘルプメッセージを以下に引用します。

lxc image list [remote:] [filter]
    List images in the LXD image store. Filters may be of the
    <key>=<value> form for property based filtering, or part of the image
    hash or part of the image alias name.

リモートのイメージ一覧は lxc image list images: で表示できます。最後の : はリモートの指定か区別するために必要です。

ローカルのイメージ一覧は lxc image list で表示できます。1つもコンテナを作っていない時は空になります。

[remote:] の部分に指定可能なリモートの一覧は lxc remote list で確認できます。

$ lxc remote list
+-----------------+------------------------------------------+---------------+--------+--------+
|      NAME       |                   URL                    |   PROTOCOL    | PUBLIC | STATIC |
+-----------------+------------------------------------------+---------------+--------+--------+
| images          | https://images.linuxcontainers.org       | lxd           | YES    | NO     |
+-----------------+------------------------------------------+---------------+--------+--------+
| local (default) | unix://                                  | lxd           | NO     | YES    |
+-----------------+------------------------------------------+---------------+--------+--------+
| ubuntu          | https://cloud-images.ubuntu.com/releases | simplestreams | YES    | YES    |
+-----------------+------------------------------------------+---------------+--------+--------+
| ubuntu-daily    | https://cloud-images.ubuntu.com/daily    | simplestreams | YES    | YES    |
+-----------------+------------------------------------------+---------------+--------+--------+

フィルタを指定してリモートのcentosのイメージ一覧を表示すると以下の3つがヒットしました。

$ lxc image list images: centos
+-------------------------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+
|          ALIAS          | FINGERPRINT  | PUBLIC |            DESCRIPTION            |  ARCH  |  SIZE   |         UPLOAD DATE         |
+-------------------------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+
| centos/6/amd64 (1 more) | 81c42e7d8c4e | yes    | Centos 6 (amd64) (20160507_02:16) | x86_64 | 52.23MB | May 7, 2016 at 3:15am (UTC) |
+-------------------------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+
| centos/6/i386 (1 more)  | 74c61c775024 | yes    | Centos 6 (i386) (20160507_02:16)  | i686   | 52.16MB | May 7, 2016 at 3:16am (UTC) |
+-------------------------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+
| centos/7/amd64 (1 more) | 9c8a52ca68e4 | yes    | Centos 7 (amd64) (20160507_02:16) | x86_64 | 62.93MB | May 7, 2016 at 3:16am (UTC) |
+-------------------------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+

CentOS 7のコンテナを起動してみる

起動に使用するのは lxc launch サブコマンドです。 lxc launch -h でヘルプが見られます。

ここでは images のリモートの centos/7/amd64 のエイリアスのイメージを起動して cent01 というコンテナ名を付けてみます。どれぐらい時間がかかるか計測するため time コマンドを付けて実行してみました。

$ time lxc launch images:centos/7/amd64 cent01
Creating cent01
Retrieving image: 100%
Starting cent01

real    0m58.036s
user    0m0.056s
sys     0m0.036s

Retrieving image: 100% と表示されているように初回はイメージのダウンロードを行うので少し時間がかかります。私の環境では1分弱でした。

起動直後に lxc list を実行すると、 IPv6アドレスは付与されていますが、 IPv4アドレスはまだ空です。

$ lxc list
+--------+---------+------+-----------------------------------------------+------------+-----------+
|  NAME  |  STATE  | IPV4 |                     IPV6                      |    TYPE    | SNAPSHOTS |
+--------+---------+------+-----------------------------------------------+------------+-----------+
| cent01 | RUNNING |      | fd36:b946:6537:931e:216:3eff:fec9:2e18 (eth0) | PERSISTENT | 0         |
+--------+---------+------+-----------------------------------------------+------------+-----------+

数秒立ってから再度実行するとIPv4アドレスが付与されていました。

$ lxc list
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
|  NAME  |  STATE  |         IPV4         |                     IPV6                      |    TYPE    | SNAPSHOTS |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
| cent01 | RUNNING | 10.64.177.167 (eth0) | fd36:b946:6537:931e:216:3eff:fec9:2e18 (eth0) | PERSISTENT | 0         |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+

この時点でローカルのイメージ一覧を表示してみると、CentOS 7のイメージが追加されていました。

$ lxc image list
+-------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+
| ALIAS | FINGERPRINT  | PUBLIC |            DESCRIPTION            |  ARCH  |  SIZE   |         UPLOAD DATE         |
+-------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+
|       | 9c8a52ca68e4 | no     | Centos 7 (amd64) (20160507_02:16) | x86_64 | 62.93MB | May 7, 2016 at 7:13am (UTC) |
+-------+--------------+--------+-----------------------------------+--------+---------+-----------------------------+

同じイメージで2つめのコンテナを起動してみると今度はローカルのイメージを使うので起動時間は短くてすみました。私の環境では約10秒でした。

$ time lxc launch images:centos/7/amd64 cent02
Creating cent02
Starting cent02

real    0m10.189s
user    0m0.044s
sys     0m0.008s

起動直後にコンテナ一覧を確認すると、今起動した cent02 コンテナのIPv4アドレスはやはり空です。

$ lxc list
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
|  NAME  |  STATE  |         IPV4         |                     IPV6                      |    TYPE    | SNAPSHOTS |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
| cent01 | RUNNING | 10.64.177.167 (eth0) | fd36:b946:6537:931e:216:3eff:fec9:2e18 (eth0) | PERSISTENT | 0         |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
| cent02 | RUNNING |                      | fd36:b946:6537:931e:216:3eff:fe18:680a (eth0) | PERSISTENT | 0         |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+

数秒立ってから再度確認すると centos02 コンテナにもIPv4アドレスが付与されていました。

$ lxc list
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
|  NAME  |  STATE  |         IPV4         |                     IPV6                      |    TYPE    | SNAPSHOTS |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
| cent01 | RUNNING | 10.64.177.167 (eth0) | fd36:b946:6537:931e:216:3eff:fec9:2e18 (eth0) | PERSISTENT | 0         |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+
| cent02 | RUNNING | 10.64.177.34 (eth0)  | fd36:b946:6537:931e:216:3eff:fe18:680a (eth0) | PERSISTENT | 0         |
+--------+---------+----------------------+-----------------------------------------------+------------+-----------+

コンテナ内でコマンドを実行する

例えば cent01 コンテナで bash を起動するには lxc exec cent01 bash と実行します。するとコンテナ内で root ユーザになってプロンプトが表示されるので、好きなコマンドを入力して実行します。

$ lxc exec cent01 bash
[root@cent01 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
37: eth0@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 00:16:3e:5f:01:7e brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.155.92.101/24 brd 10.155.92.255 scope global dynamic eth0
       valid_lft 2508sec preferred_lft 2508sec
    inet6 fe80::216:3eff:fe5f:17e/64 scope link
       valid_lft forever preferred_lft forever
[root@cent01 ~]# ping -c 3 cent02
PING cent02.lxd (10.64.177.34) 56(84) bytes of data.
64 bytes from cent02.lxd (10.64.177.34): icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from cent02.lxd (10.64.177.34): icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from cent02.lxd (10.64.177.34): icmp_seq=3 ttl=64 time=0.081 ms

--- cent02.lxd ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.034/0.061/0.081/0.019 ms
[root@cent01 ~]# exit
exit

上記の ping の例でも分かる通り、コンテナ内から別のコンテナの名前を指定して通信可能です。 ping の出力を見ると .lxd というトップレベルドメインがつけられていて、 ping -c 3 cent02.lxd でも大丈夫でした。この .lxd という値は /etc/default/lxd-bridgeLXD_DOMAIN="lxd" という設定で指定されています。

Control-Dを押すか、exit に続いてenterキーで bash から抜けます。

単一のコマンドを実行したい場合は bash の代わりにコマンドを書きます。

$ lxc exec cent01 ls /
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  selinux  srv  sys  tmp  usr  var

コマンドにオプションを指定するとエラーになりますが、コマンドの前に -- を入れれば大丈夫です。

$ lxc exec cent01 ls -a /
error: flag provided but not defined: -a
$ lxc exec cent01 -- ls -a /
.  ..  .autorelabel  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  selinux  srv  sys  tmp  usr  var

ホストOSを再起動するとコンテナは自動起動されます

LXCではホストOS起動時にコンテナを自動起動するには設定ファイルの編集が必要でしたが、LXDは特に設定は不要でした。  ホストOSを再起動して lxc list を実行してみると上記で作成した2つのコンテナのSTATEがRUNNINGになっていました。

コンテナの停止と削除

停止は lxc stop コンテナ名 、削除は lxc delete コンテナ名 で出来ます。が、 CentOS 7 のコンテナを停止するには以下の事前準備が必要でした。

CentOS 7 のコンテナを停止可能にするための設定

cent01 のところは実際のコンテナ名に置き換えて、各コンテナで実行が必要です。

lxc exec cent01 -- sh -c 'ln -s /usr/lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target && systemctl daemon-reload'

この回避方法は [lxc-users] lxc-stop doesn't stop centos, waits for the timeout で紹介されていました。

[lxc-users] lxc stop does not stop a CentOS 7 containerimages: で公開しているイメージにこの修正を取り込めないか問い合わせ中です。

コンテナやイメージのファイルの在り処

コンテナのファイルは /var/lib/lxd/containers/ にありました。操作しているユーザのuidとgidは1000なのですが、コンテナのディレクトリは100000と異なっていました。どこかでマッピングを持っているのだと思いますが、未調査です。

$ sudo ls -l /var/lib/lxd/containers/
合計 24
drwxr-xr-x+ 4 100000 100000  4096  5月  6 18:56 cent01
drwxr-xr-x+ 4 100000 100000  4096  5月  7 03:18 cent02
-rw-r--r--  1 root   root   10756  5月  7 19:47 lxc-monitord.log
drwxr-xr-x+ 4 100000 100000  4096  5月  3 20:46 my-ubuntu
$ sudo ls -l /var/lib/lxd/containers/cent01
合計 12
-rw-r--r--  1 root   root    628  1月  1  1970 metadata.yaml
dr-xr-xr-x 18 100000 100000 4096  5月  6 18:56 rootfs
drwxr-xr-x  2 root   root   4096  5月  6 18:56 templates
1$ sudo ls -l /var/lib/lxd/containers/cent01/rootfs/
合計 64
lrwxrwxrwx  1 100000 100000    7  5月  6 11:25 bin -> usr/bin
dr-xr-xr-x  2 100000 100000 4096  8月 12  2015 boot
drwxr-xr-x  4 100000 100000 4096  5月  6 11:25 dev
drwxr-xr-x 55 100000 100000 4096  5月  7 12:13 etc
drwxr-xr-x  2 100000 100000 4096  8月 12  2015 home
lrwxrwxrwx  1 100000 100000    7  5月  6 11:25 lib -> usr/lib
lrwxrwxrwx  1 100000 100000    9  5月  6 11:25 lib64 -> usr/lib64
drwxr-xr-x  2 100000 100000 4096  8月 12  2015 media
drwxr-xr-x  2 100000 100000 4096  8月 12  2015 mnt
drwxr-xr-x  2 100000 100000 4096  8月 12  2015 opt
dr-xr-xr-x  2 100000 100000 4096  8月 12  2015 proc
dr-xr-x---  3 100000 100000 4096  5月  7 03:42 root
drwxr-xr-x  7 100000 100000 4096  5月  6 11:25 run
lrwxrwxrwx  1 100000 100000    8  5月  6 11:25 sbin -> usr/sbin
drwxr-xr-x  2 100000 100000 4096  5月  6 11:25 selinux
drwxr-xr-x  2 100000 100000 4096  8月 12  2015 srv
dr-xr-xr-x  2 100000 100000 4096  8月 12  2015 sys
drwxrwxrwt  7 100000 100000 4096  5月  7 12:54 tmp
drwxr-xr-x 13 100000 100000 4096  5月  6 11:25 usr
drwxr-xr-x 19 100000 100000 4096  5月  6 18:56 var

イメージのファイルは /var/lib/lxd/images/ にありました。 lxc image list で表示されるフィンガープリント名のファイルとフィンガープリントに .rootfs を追加した名前のファイルがあります。調べてみるとtar.xz形式のファイルになっていました。

$ sudo ls -l /var/lib/lxd/images/
合計 205244
-rw-r--r-- 1 root root       588  5月  6 18:54 a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2
-rw-r--r-- 1 root root  65931516  5月  6 18:55 a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2.rootfs
-rw-r--r-- 1 root root       792  5月  3 20:32 f4c4c60a6b752a381288ae72a1689a9da00f8e03b732c8d1b8a8fcd1a8890800
-rw-r--r-- 1 root root 144223868  5月  3 20:46 f4c4c60a6b752a381288ae72a1689a9da00f8e03b732c8d1b8a8fcd1a8890800.rootfs
$ sudo file /var/lib/lxd/images/a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2
/var/lib/lxd/images/a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2: XZ compressed data
$ sudo file /var/lib/lxd/images/a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2.rootfs
/var/lib/lxd/images/a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2.rootfs: XZ compressed data
$ sudo tar tvf /var/lib/lxd/images/a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2
-rw-r--r-- 0/0             239 1970-01-01 09:00 templates/hosts.tpl
-rw-r--r-- 0/0             628 1970-01-01 09:00 metadata.yaml
-rw-r--r-- 0/0              21 1970-01-01 09:00 templates/hostname.tpl
$ sudo tar tvf /var/lib/lxd/images/a027d59858d663fb2bc12b5ba767e92196a4aee8dbb2a607db53d718b91eb5d2.rootfs | head
dr-xr-xr-x 0/0               0 2016-05-06 11:25 ./
drwxr-xr-x 0/0               0 2016-05-06 11:25 ./dev/
crw-rw-rw- 0/0             5,2 2016-05-06 11:25 ./dev/ptmx
prw------- 0/0               0 2016-05-06 11:25 ./dev/initctl
crw-rw-rw- 0/0             1,7 2016-05-06 11:25 ./dev/full
crw------- 0/0             5,1 2016-05-06 11:25 ./dev/console
crw-rw-rw- 0/0             4,4 2016-05-06 11:25 ./dev/tty4
crw-rw-rw- 0/0             4,3 2016-05-06 11:25 ./dev/tty3
crw-rw-rw- 0/0             4,2 2016-05-06 11:25 ./dev/tty2
crw-rw-rw- 0/0             4,1 2016-05-06 11:25 ./dev/tty1

/var/lib/lxd/ には他にもディレクトリやファイルが存在しています。

$ ls -l /var/lib/lxd
合計 84
drwx--x--x 5 root root  4096  5月  7 12:54 containers
drwx--x--x 5 root root  4096  5月  7 12:54 devices
drwxr-xr-x 2 root root  4096  5月  7 19:41 devlxd
drwx------ 2 root root  4096  5月  7 06:13 images
-rw-r--r-- 1 root root 43008  5月  7 19:46 lxd.db
drwx------ 4 root root  4096  5月  3 20:46 security
-rw-r--r-- 1 root root  2004  5月  3 20:26 server.crt
-rw------- 1 root root  3247  5月  3 20:26 server.key
drwx--x--x 5 root root  4096  5月  7 12:54 shmounts
drwx------ 2 root root  4096  5月  3 20:26 snapshots
srw-rw---- 1 root lxd      0  5月  7 12:51 unix.socket