LXDとcloud-initを使ってコンテナインスタンスを自動作成する

株式会社 日立製作所 OSSソリューションセンタ の山田陽介です。
コンテナといえばDockerが有名ですが、仮想マシンを一時的に立ち上げて複数のアプリを動作させたい場合もありますよね。そういった場合に便利なコンテナ技術である、LXDを活用する手順を解説します。
この記事は執筆者の試行内容を記したものであり、所属企業およびThe Ubuntu Projectの公式ドキュメントではありません。

#はじめに
Dockerはアプリケーション単位の仮想化に向くコンテナ技術ですが、LXDはKVMやVirtualBoxなどの完全仮想化・準仮想化に近いシステムコンテナ技術です。ホスト・ゲストのLinux Kernelの機能を使うのでゲストもLinuxである必要がありますが、ハードウェアのエミュレーションを省けるので速度面では有利です。
本記事ではUbuntu18.04の環境で、コンテナや仮想マシンインスタンスの自動設定ができるCloud-initを使って、LXDコンテナを作る方法を解説します。

## 0. 検証環境
Ubuntu 18.04

```
ubuntu@ub1804:~$ lxc --version
3.0.3
ubuntu@ub1804:~$ lxd --version
3.0.3
```

## 1. LXDを使うための初期設定
・lxc-utilsをインストールします。

```
ubuntu@ub1804:~$ sudo apt install lxc-utils
```

・各質問に対しEnterを入力してデフォルトの設定を適用します。

```
ubuntu@ub1804:~$ sudo lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:  #クラスタリング無効
Do you want to configure a new storage pool? (yes/no) [default=yes]:  #ストレージプールを新規作成
Name of the new storage pool [default=default]:  #ストレージプール名は「default」
Name of the storage backend to use (btrfs, dir, lvm) [default=btrfs]:  #btrfsをバックエンドに使用
Create a new BTRFS pool? (yes/no) [default=yes]:  #btrfsのプールを作成する
Would you like to use an existing block device? (yes/no) [default=no]:  #既存のブロックデバイスは指定しない
Size in GB of the new loop device (1GB minimum) [default=15GB]:  #loopデバイスのサイズ
Would you like to connect to a MAAS server? (yes/no) [default=no]:  #MAASサーバに接続しない
Would you like to create a new local network bridge? (yes/no) [default=yes]:  #ローカルネットワークブリッジを作る
What should the new bridge be called? [default=lxdbr0]:  #ネットワークブリッジ名は「lxdbr0」
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:  #IPv4はauto
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:  #IPv6はauto
Would you like LXD to be available over the network? (yes/no) [default=no]:  #LXDをネットワーク経由で使用可能にする
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]  #イメージファイルを自動更新する
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:  #作成したコンテナのYAMLファイルを表示する
```

## 2. リモートのイメージソース一覧を確認
使用できるコンテナイメージの保管場所の一覧です。

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

imagesからコンテナイメージ一覧を取得してみます。

## 3. コンテナイメージ一覧を確認
・一覧の先頭部分

```
ubuntu@ub1804:~$ lxc image alias list images: | head
+-------------------------------------+--------------+-------------+
|                ALIAS                | FINGERPRINT  | DESCRIPTION |
+-------------------------------------+--------------+-------------+
| alpine/3.10                         | 8f304a1cba4c |             |
+-------------------------------------+--------------+-------------+
| alpine/3.10/amd64                   | 8f304a1cba4c |             |
+-------------------------------------+--------------+-------------+
| alpine/3.10/arm64                   | 1bd7e0715baf |             |
+-------------------------------------+--------------+-------------+
| alpine/3.10/armhf                   | 5e57e46a130e |             |
```

・ubuntu/bionicのイメージ

```
ubuntu@ub1804:~$ lxc image alias list images: | grep "ubuntu/bionic"
| ubuntu/bionic                       | 554f6979511f |             |
| ubuntu/bionic/amd64                 | 554f6979511f |             |
| ubuntu/bionic/arm64                 | 43b0d7ac380c |             |
| ubuntu/bionic/armhf                 | f0a8d445f34e |             |
| ubuntu/bionic/cloud                 | 3a66a6ec49f7 |             |
| ubuntu/bionic/cloud/amd64           | 3a66a6ec49f7 |             |
| ubuntu/bionic/cloud/arm64           | 2625f3517ea5 |             |
| ubuntu/bionic/cloud/armhf           | 7fe340585577 |             |
| ubuntu/bionic/cloud/i386            | 3006a0c0c91a |             |
| ubuntu/bionic/cloud/ppc64el         | a8b4b9f6d7d9 |             |
| ubuntu/bionic/cloud/s390x           | 2293117591fc |             |
| ubuntu/bionic/default               | 554f6979511f |             |
| ubuntu/bionic/default/amd64         | 554f6979511f |             |
| ubuntu/bionic/default/arm64         | 43b0d7ac380c |             |
| ubuntu/bionic/default/armhf         | f0a8d445f34e |             |
| ubuntu/bionic/default/i386          | 20d34fe972ff |             |
| ubuntu/bionic/default/ppc64el       | 6e831bda70f2 |             |
| ubuntu/bionic/default/s390x         | 4f43ac87d8ef |             |
| ubuntu/bionic/i386                  | 20d34fe972ff |             |
| ubuntu/bionic/ppc64el               | 6e831bda70f2 |             |
| ubuntu/bionic/s390x                 | 4f43ac87d8ef |             |
```

折角なのでクラウド向きのubuntu/bionic/cloud/amd64を使います。
最新のアップデートを適用した「インストール済み」のイメージのため、ダウンロード容量や時間の節約になります。
[第565回　サーバー向けインストール済みイメージを活用しよう：Ubuntu Weekly Recipe｜gihyo.jp … 技術評論社](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0565)

## 4. Cloud-init設定ファイルの作成
コンテナを自動設定するためのCloud-initファイルを作成します。
・openssh-serverパッケージを自動でインストールさせます。
・ホストに~/.ssh/id_rsa および ~/.ssh/id_rsa.pub がなければ、ssh-keygenコマンドで作っておきます。
　下記のssh-rsa行には~/.ssh/id_rsa.pubファイルの公開鍵を記入します。
・ユーザubuntuを作成し、sshの公開鍵を設定し、sudoを実行できるようにします。
・/tmp/testfile.txtにtestfileと書き込みます。

```
ubuntu@ub1804:~$ vi cloud-init-config.yml

#cloud-config

hostname: ubuntu00

packages:
  - openssh-server

users:
  - name: ubuntu
    shell: /bin/bash
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCv9PA1puJ/E6sWEAHr5TUBdOwbtQTvPg2+FhoQoRqGOE/gTONEFy7Ma5oMhRMD8zqLw15ugdtDh4zn13jkqbXPxJ5FMkSLy8wAk+Ej+MhLhtLoECRbO66nW7KSU4uIHrngAMo2k5K6cb9rwlhPTS/pFZnldlg2UYHnC4TBGV+xE9KNxADdVUyKgHUnVmKqXlaRgykYzxR9e5Cg3bdwkBV8XDxx41BOOaHPexqzaS5aRW9Wq85DYnjmk44e6sPBbaAhQ7Xt7hMWAYqz7KGFsH0qFwoKo0aTdmiWzhZDtlwQPR8kqSS7S2WLDNbB6dxEiH3bxnncyLCg/lLGHHiENMu7 ubuntu@ub1804
    sudo: ALL=(ALL) NOPASSWD:ALL

runcmd:
  - [sh, -c, "echo 'testfile' > /tmp/testfile.txt"]

```

cloud-initの設定方法についてはこちらの記事も参考になります。
[cloud-initを使ったLinux OSの初期設定 - Qiita](https://qiita.com/yamada-hakase/items/40fa2cbb5ed669aaa85b)

## 5. コンテナの作成
imagesのubuntu/bionic/cloud/amd64イメージを使ってコンテナを作成します。

```
ubuntu@ub1804:~$ lxc init images:ubuntu/bionic/cloud/amd64 ubuntu00
Creating ubuntu00
```

## 6. スナップショット作成
・初期状態のスナップショットを取っておきます。

```
ubuntu@ub1804:~$ lxc snapshot ubuntu00 snap0
```

・SNAPSHOTが1になっています。

```
ubuntu@ub1804:~$ lxc list
+-------------+---------+------+------+------------+-----------+
|    NAME     |  STATE  | IPV4 | IPV6 |    TYPE    | SNAPSHOTS |
+-------------+---------+------+------+------------+-----------+
| ubuntu00    | STOPPED |      |      | PERSISTENT | 1         |
+-------------+---------+------+------+------------+-----------+
```

・snap0が保存されています。

```
ubuntu@ub1804:~$ lxc info ubuntu00
Name: ubuntu00
Remote: unix://
Architecture: x86_64
Created: 2020/11/24 23:56 UTC
Status: Stopped
Type: persistent
Profiles: default
Snapshots:
  snap0 (taken at 2020/11/25 00:38 UTC) (stateless)
```

## 7. Cloud-initの設定
コンテナに設定ファイルをセットします。

```
ubuntu@ub1804:~$ lxc config set ubuntu00 user.user-data - < cloud-init-config.yml
```

## 8. コンテナを起動
・すぐにプロンプトが戻り、15秒程でコンテナが起動します。

```
ubuntu@ub1804:~$ lxc start ubuntu00
```

・コンテナ一覧でIPアドレスを確認します。

```
ubuntu@ub1804:~$ lxc list
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
|    NAME     |  STATE  |         IPV4         |                     IPV6                      |    TYPE    | SNAPSHOTS |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu00    | RUNNING | 10.15.254.159 (eth0) | fd42:381d:b412:d566:216:3eff:fe9d:4acc (eth0) | PERSISTENT | 1         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
```

・SSHでログインできます。

```
ubuntu@ub1804:~$ ssh ubuntu@10.15.254.159
The authenticity of host '10.15.254.159 (10.15.254.159)' can't be established.
ECDSA key fingerprint is SHA256:IRFCuz+XXTi3e2/pfXAfoXgklcysXHalnGhMpJZRl2k.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.15.254.159' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-118-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
```

・/tmpにファイルができています。

```
ubuntu@ubuntu00:~$ ls /tmp
systemd-private-1f436a39dd8c43eb825d4cd9863f53f8-systemd-resolved.service-DDB7dQ  testfile.txt
ubuntu@ubuntu00:~$ cat /tmp/testfile.txt
testfile
```

・sudoでルート権限が使えます。

```
ubuntu@ubuntu00:~$ sudo su
root@ubuntu00:/home/ubuntu# exit
exit
```

## 9. コンテナを停止
・停止も簡単です。

```
ubuntu@ub1804:~$ lxc stop ubuntu00
```

## 10. スナップショットでリストア
ubuntu00コンテナをsnap0を撮った状態に戻せます。

```
ubuntu@ub1804:~$ lxc restore ubuntu00 snap0
```

## 11. コンテナを複数作成

・ワンライナーで10個のコンテナを作ります。

```
ubuntu@ub1804:~$ for i in `seq -w 10`; \
do lxc init images:ubuntu/bionic/cloud/amd64 ubuntu${i}; \
sed "s/ubuntu00/ubuntu${i}/" cloud-init-config.yml > cloud-init-config${i}.yml; \
lxc config set ubuntu${i} user.user-data - < cloud-init-config${i}.yml; \
lxc start ubuntu${i}; \
done
```

・10個のコンテナができました。

```
ubuntu@ub1804:~$ lxc list
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
|    NAME     |  STATE  |         IPV4         |                     IPV6                      |    TYPE    | SNAPSHOTS |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu00    | RUNNING | 10.15.254.159 (eth0) | fd42:381d:b412:d566:216:3eff:fe9d:4acc (eth0) | PERSISTENT | 1         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu01    | RUNNING | 10.15.254.248 (eth0) | fd42:381d:b412:d566:216:3eff:fe90:d741 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu02    | RUNNING | 10.15.254.251 (eth0) | fd42:381d:b412:d566:216:3eff:fe94:2486 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu03    | RUNNING | 10.15.254.157 (eth0) | fd42:381d:b412:d566:216:3eff:fe00:bf33 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu04    | RUNNING | 10.15.254.182 (eth0) | fd42:381d:b412:d566:216:3eff:fed4:de71 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu05    | RUNNING | 10.15.254.31 (eth0)  | fd42:381d:b412:d566:216:3eff:fea5:648d (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu06    | RUNNING | 10.15.254.212 (eth0) | fd42:381d:b412:d566:216:3eff:fe2f:6b55 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu07    | RUNNING | 10.15.254.160 (eth0) | fd42:381d:b412:d566:216:3eff:fe55:2972 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu08    | RUNNING | 10.15.254.18 (eth0)  | fd42:381d:b412:d566:216:3eff:fea6:2166 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu09    | RUNNING | 10.15.254.117 (eth0) | fd42:381d:b412:d566:216:3eff:fe35:73a8 (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
| ubuntu10    | RUNNING | 10.15.254.10 (eth0)  | fd42:381d:b412:d566:216:3eff:fe54:dfd (eth0)  | PERSISTENT | 0         |
+-------------+---------+----------------------+-----------------------------------------------+------------+-----------+
```

・コンテナごとにストレージを数百MBずつ使っているようです。


```
ubuntu@ub1804:~$ lxc storage info default
info:
  description: ""
  driver: btrfs
  name: default
  space used: 2.46GB
  total space: 15.00GB
used by:
  containers:
  - ubuntu00
  - ubuntu00
  - ubuntu01
  - ubuntu02
  - ubuntu03
  - ubuntu04
  - ubuntu05
  - ubuntu06
  - ubuntu07
  - ubuntu08
  - ubuntu09
  - ubuntu10
  images:
  - 3a66a6ec49f7d5ba13c9900b4f5ad950f49501ecf8b5a4b2fe773f36349e34ed
  profiles:
  - default
```

同じファイル構成を持つ大量のVMが要る場合は、Overlayfs等を使っても良いかもしれません。
[Overlay でLXC コンテナを作成する - Qiita](https://qiita.com/TsutomuNakamura/items/801079cb33fce8448e24)

## 12. コンテナの停止・削除
使い終わったら停止し、削除しておきましょう。

```
ubuntu@ub1804:~$ lxc stop ubuntu00
ubuntu@ub1804:~$ lxc delete ubuntu00
```


# 参考文献
・[LXD3.0入門（コンテナ起動～スナップショット～バックアップ） - Qiita](https://qiita.com/gounx2/items/39181e69e7f72316d5f2)
　イメージの作成、バックアップの手順など参考になります。
・[第561回　ローカルインストール時もcloud-initを活用する：Ubuntu Weekly Recipe｜gihyo.jp … 技術評論社](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0561?page=1)
　Cloud-initについての解説です。
・[cloud-initを使ったLinux OSの初期設定 - Qiita](https://qiita.com/yamada-hakase/items/40fa2cbb5ed669aaa85b)
　Cloud-initの仕組みの図解が参考になります。