私的サーバー構築日誌：LXD on ZFS

# 能書き

[私的サーバー構築日誌：仕切り直し](https://qiita.com/katz_engineer/items/1f21de2bd9072c260ae6)からの自宅サーバー構築の続きです。

少々考えまして、この段階でコンテナサーバーを立ち上げます。まずはLXDから。

なお「LXD」の正しい読み方は「レクスディー」のようです。

## 目標

- LXDでシステムコンテナを起動
- ネットワークのIPアドレスは固定

## 参考文献

- [自宅サーバー構築譚：LXD - Qiita](https://qiita.com/katz_engineer/items/74d7b357750e51e9c61c)
- [第582回いろいろなディストリビューションでsnapとLXDを利用する - Ubuntu Weekly Recipe - gihyo.jp](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0582)
- [snapパッケージの関連ディレクトリ - 第714回 Firefoxを含むsnapパッケージとの付き合い方 - gihyo.jp](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0714#sec4)
- [Ubuntuでsnapパッケージを管理する！ - LAB4ICT](https://lab4ict.com/system/archives/919)
- [LXD ドキュメント](https://lxd-ja.readthedocs.io/ja/latest/)
- [外部からコンテナへの通信について - LXDにおけるネットワーク通信について - LXDを使用して瞬時にサーバを量産する（Ubuntu18.04）](https://nwengblog.com/ubuntu-lxd/)
- [LXDを初期化するには - LXDを使い始めるには](https://lxd-ja.readthedocs.io/ja/latest/howto/initialize/)

LXDはsnapというパッケージ管理システムでインストールされまして、snapが関連するディレクトリに関しては下記参考文献に解説されています。

- [snapパッケージの関連ディレクトリ - 第714回 Firefoxを含むsnapパッケージとの付き合い方 - gihyo.jp](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0714#sec4)

# パッケージ管理システムsnap

## スナップショット

後述の通り、LXDはsnapというパッケージ管理システムでインストールされています。これは関連するディレクトリが普通とは別になっているので、それを理解する必要があります。

ですが今は[データセットをルートディレクトリと`/home`だけにしています](https://qiita.com/katz_engineer/items/667aefcab488cc4a1caf#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E6%A7%8B%E9%80%A0%E3%81%AB%E5%90%88%E3%82%8F%E3%81%9B%E3%81%9F%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%83%E3%83%88%E4%BD%9C%E6%88%90)。その為スナップショットはルートだけ撮れば大丈夫です。

```console
sudo zfs snapshot tank/root/ubuntu@$(date +%Y%m%d_%H%M%S)_before_snap
```

## インストール

毎度おなじみの`apt update`。

```console
sudo apt update
```

Ubuntuには最初からsnapdがインストールされている、との事…だったんですが、Ubuntuサーバーにはインストールされていないようです。

```console
$ snap --version
Command 'snap' not found, but can be installed with:
sudo apt install snapd
```

そこでまずはsnapdのインストールから。

```console
sudo apt install -y snapd
```

これで`snap`コマンドを使えます。

```console
snap --version
```

## `/etc`のバージョン管理

```console
cd /etc
sudo svn st
```

こんな感じになります。

```console
$ cd /etc
$ sudo svn st
?       X11/Xsession.d/20dbus_xdg-runtime
?       apparmor.d/local/usr.lib.snapd.snap-confine.real
?       apparmor.d/usr.lib.snapd.snap-confine.real
?       apt/apt.conf.d/20snapd.conf
M       ld.so.cache
?       profile.d/apps-bin-path.sh
?       systemd/system/cloud-final.service.wants
?       systemd/system/final.target.wants
?       systemd/system/multi-user.target.wants/snapd.aa-prompt-listener.service
?       systemd/system/multi-user.target.wants/snapd.apparmor.service
?       systemd/system/multi-user.target.wants/snapd.autoimport.service
?       systemd/system/multi-user.target.wants/snapd.core-fixup.service
?       systemd/system/multi-user.target.wants/snapd.recovery-chooser-trigger.service
?       systemd/system/multi-user.target.wants/snapd.seeded.service
?       systemd/system/multi-user.target.wants/snapd.service
?       systemd/system/sockets.target.wants/snapd.socket
?       systemd/system/timers.target.wants/snapd.snap-repair.timer
?       xdg/autostart/snap-userd-autostart.desktop
M       zfs/zpool.cache
```

- `X11`とか`xdg`とか、どうもデスクトップ環境を想定した追加みたいに見えます。
- `apparmor`と`ld.so.cache`と`zpool.cache`は、いつもの例のヤツって感じですか。
- `profile.d/apps-bin-path.sh`は環境変数PATHの設定らしい。
- `apt/apt.conf.d/20snapd.conf`は、正直、よくわかりませんな。何やらapt関連のようですが。
- 後は、ディレクトリ名から察するに、systemd関連と思われます。

snap関連で設定をいじる事はありません。このままコミットしてしまいましょう。

```console
sudo svn st | grep "^?" | cut -b9- | sudo xargs -I{} find {} -type f -or -type d -or -type l | sudo xargs -rt svn add
```

```console
sudo svn ci -m"installed snap"
```

# システムコンテナLXD

いよいよLXDです。

## スナップショット

```console
sudo zfs snapshot tank/root/ubuntu@$(date +%Y%m%d_%H%M%S)_before_LXD
```

## インストール

インストール可能なLXDパッケージの一覧表を取得します。

```console
snap info lxd
```

[現在のLTS版は5.0](https://lxd-ja.readthedocs.io/ja/latest/installing/#id1)です。これをインストールします。

```console
sudo snap install lxd --channel=5.0/stable
```

インストールを確認。

```console
lxd --version
```

## `/etc`

例によって`/etc`を確認します。

```console
cd /etc
sudo svn st
```

こうなりました。

```console
$ cd /etc
$ sudo svn st
M       passwd
M       shadow
?       systemd/system/multi-user.target.wants/snap-core22-858.mount
?       systemd/system/multi-user.target.wants/snap-lxd-25353.mount
?       systemd/system/multi-user.target.wants/snap-snapd-19457.mount
?       systemd/system/multi-user.target.wants/snap.lxd.activate.service
?       systemd/system/snap-core22-858.mount
?       systemd/system/snap-lxd-25353.mount
?       systemd/system/snap-snapd-19457.mount
?       systemd/system/snap.lxd.activate.service
?       systemd/system/snap.lxd.daemon.service
?       systemd/system/snap.lxd.daemon.unix.socket
?       systemd/system/snap.lxd.user-daemon.service
?       systemd/system/snap.lxd.user-daemon.unix.socket
?       systemd/system/snapd.mounts.target.wants
?       systemd/system/sockets.target.wants/snap.lxd.daemon.unix.socket
?       systemd/system/sockets.target.wants/snap.lxd.user-daemon.unix.socket
?       udev/rules.d/70-snap.snapd.rules
```

systemd関連と、udevも何か追加されてますな。ユーザー追加もあるようです(passwd,shadow)。

```console
$ sudo svn di --diff-cmd diff -x -U0
Index: passwd
===================================================================
--- passwd      (revision 7)
+++ passwd      (working copy)
@@ -31,0 +32 @@
+lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
Index: shadow
===================================================================
--- shadow      (revision 7)
+++ shadow      (working copy)
@@ -31,0 +32 @@
+lxd:!:19587::::::
```

以上をコミットします。

```console
sudo svn st | grep "^?" | cut -b9- | sudo xargs -I{} find {} -type f -or -type d -or -type l | sudo xargs -rt svn add
```

```console
sudo svn ci -m"installed LXD"
```

## 初期化

コンテナ構築前にlxdの初期化が必要です。対話式の設定は色々と解説記事もあるようですので、ここでは非対話式で設定してみます。

ほぼ全てデフォルトですが、少々変更を。

- ネットワークブリッジのIPv4アドレスは固定で`192.168.0.1/24`とします。
- IPv6は`none`にしました。一般論ですが、トラブルの元になる場合が散見されるので。きちんと理解していれば良いんですが、私はまだIPv6を理解していないのです。
- イメージの自動更新はしません。安定稼働していたサーバがある日突然停止した、という事故が怖いので。
- ストレージプールの名前が`default`だったのですが、これが zfs pool に反映されて後で忘れそうなので、`lxd_pool`に変更しました。同時にサイズを30GiBから300GiBに拡大。

```console
lxd init --preseed <<___
config:
  images.auto_update_interval: "0"
networks:
- config:
    ipv4.address: 192.168.0.1/24
    ipv4.nat: "true"
    ipv6.address: none
  description: ""
  name: lxdbr0
  type: ""
  project: default
storage_pools:
- config:
    size: 300GiB
  description: ""
  name: lxd_pool
  driver: zfs
profiles:
- config: {}
  description: ""
  devices:
    eth0:
      name: eth0
      network: lxdbr0
      type: nic
    root:
      path: /
      pool: lxd_pool
      type: disk
  name: default
projects: []
cluster: null
___
```

## zfs

storageの設定を確認します。

```console
zpool list
zfs list
```

こうなっていました。

```console
$ zpool list
NAME       SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
bpool     3.75G   344M  3.41G        -         -     0%     8%  1.00x    ONLINE  -
lxd_pool   298G   646K   298G        -         -     0%     0%  1.00x    ONLINE  -
tank      1.86T  2.09G  1.86T        -         -     0%     0%  1.00x    ONLINE  -
$ zfs list
NAME                                USED  AVAIL     REFER  MOUNTPOINT
bpool                               343M  3.29G       96K  /boot
bpool/boot                          342M  3.29G       96K  none
bpool/boot/ubuntu                   342M  3.29G      124M  /boot
lxd_pool                            646K   289G       24K  legacy
lxd_pool/buckets                     24K   289G       24K  legacy
lxd_pool/containers                  24K   289G       24K  legacy
lxd_pool/custom                      24K   289G       24K  legacy
lxd_pool/deleted                    144K   289G       24K  legacy
lxd_pool/deleted/buckets             24K   289G       24K  legacy
lxd_pool/deleted/containers          24K   289G       24K  legacy
lxd_pool/deleted/custom              24K   289G       24K  legacy
lxd_pool/deleted/images              24K   289G       24K  legacy
lxd_pool/deleted/virtual-machines    24K   289G       24K  legacy
lxd_pool/images                      24K   289G       24K  legacy
lxd_pool/virtual-machines            24K   289G       24K  legacy
tank                               2.09G  1.80T       96K  /
tank/root                          2.08G  1.80T       96K  none
tank/root/ubuntu                   2.08G  1.80T     1.58G  /
tank/userdata                      1.10M  1.80T       96K  /
tank/userdata/admin                 576K  1.80T      180K  /home/admin
tank/userdata/root                  452K  1.80T      160K  /root
```

# 動作確認

## 利用可能なイメージを探す

利用可能なイメージを探します。今回はUbuntuの最新版である22.04通称jammyにします。

```console
lxc image list images: ubuntu jammy architecture=x86_64 type=container
```

出力例。

```console
$ lxc image list images: ubuntu jammy architecture=x86_64 type=container
To start your first container, try: lxc launch ubuntu:22.04
Or for a virtual machine: lxc launch ubuntu:22.04 --vm

+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
|            ALIAS            | FINGERPRINT  | PUBLIC |             DESCRIPTION             | ARCHITECTURE |   TYPE    |   SIZE    |          UPLOAD DATE          |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
| ubuntu/jammy (7 more)       | 36248534620c | yes    | Ubuntu jammy amd64 (20230817_07:42) | x86_64       | CONTAINER | 116.52MiB | Aug 17, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
| ubuntu/jammy/cloud (3 more) | 1d88a1ba9d5d | yes    | Ubuntu jammy amd64 (20230817_07:42) | x86_64       | CONTAINER | 133.50MiB | Aug 17, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
```

因みに、`jammy`ではなくて`22.04`と指定しても同じ結果になりました。

```console
$ lxc image list images: ubuntu 22.04 architecture=x86_64 type=container
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
|            ALIAS            | FINGERPRINT  | PUBLIC |             DESCRIPTION             | ARCHITECTURE |   TYPE    |   SIZE    |          UPLOAD DATE          |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
| ubuntu/jammy (7 more)       | 36248534620c | yes    | Ubuntu jammy amd64 (20230817_07:42) | x86_64       | CONTAINER | 116.52MiB | Aug 17, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
| ubuntu/jammy/cloud (3 more) | 1d88a1ba9d5d | yes    | Ubuntu jammy amd64 (20230817_07:42) | x86_64       | CONTAINER | 133.50MiB | Aug 17, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+-----------+-------------------------------+
```

## コンテナ作成

コンテナを作成します。IPv4アドレスを固定で`192.168.0.2`にします。

```console
lxc init images:ubuntu/22.04 container-name --device eth0,ipv4.address=192.168.0.2
```

コンテナを作成しましたが停止状態です。

```console
$ lxc list
+----------------+---------+------+------+-----------+-----------+
|      NAME      |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+----------------+---------+------+------+-----------+-----------+
| container-name | STOPPED |      |      | CONTAINER | 0         |
+----------------+---------+------+------+-----------+-----------+
```

開始コマンドは下記です。

```console
lxc start container-name
```

確認は`list`コマンドで。

```console
$ lxc list
+----------------+---------+--------------------+------+-----------+-----------+
|      NAME      |  STATE  |        IPV4        | IPV6 |   TYPE    | SNAPSHOTS |
+----------------+---------+--------------------+------+-----------+-----------+
| container-name | RUNNING | 192.168.0.2 (eth0) |      | CONTAINER | 0         |
+----------------+---------+--------------------+------+-----------+-----------+
```

なお`init`と`start`を同時に実行するのが`launch`です。

```console
$ lxc launch images:ubuntu/jammy container-name2 --device eth0,ipv4.address=192.168.0.3
Creating container-name2
Starting container-name2
$ lxc list
+-----------------+---------+--------------------+------+-----------+-----------+
|      NAME       |  STATE  |        IPV4        | IPV6 |   TYPE    | SNAPSHOTS |
+-----------------+---------+--------------------+------+-----------+-----------+
| container-name  | RUNNING | 192.168.0.2 (eth0) |      | CONTAINER | 0         |
+-----------------+---------+--------------------+------+-----------+-----------+
| container-name2 | RUNNING | 192.168.0.3 (eth0) |      | CONTAINER | 0         |
+-----------------+---------+--------------------+------+-----------+-----------+
```

コンテナの停止は`stop`です。

```console
$ lxc stop container-name container-name2
$ lxc list
+-----------------+---------+------+------+-----------+-----------+
|      NAME       |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+-----------------+---------+------+------+-----------+-----------+
| container-name  | STOPPED |      |      | CONTAINER | 0         |
+-----------------+---------+------+------+-----------+-----------+
| container-name2 | STOPPED |      |      | CONTAINER | 0         |
+-----------------+---------+------+------+-----------+-----------+
```

コンテナの削除は`delete`です。

```console
$ lxc delete container-name2
$ lxc list
+----------------+---------+------+------+-----------+-----------+
|      NAME      |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+----------------+---------+------+------+-----------+-----------+
| container-name | STOPPED |      |      | CONTAINER | 0         |
+----------------+---------+------+------+-----------+-----------+
```

なお稼働状態だと削除できません。

```console
$ lxc start container-name
$ lxc list
+----------------+---------+--------------------+------+-----------+-----------+
|      NAME      |  STATE  |        IPV4        | IPV6 |   TYPE    | SNAPSHOTS |
+----------------+---------+--------------------+------+-----------+-----------+
| container-name | RUNNING | 192.168.0.2 (eth0) |      | CONTAINER | 0         |
+----------------+---------+--------------------+------+-----------+-----------+
$ lxc delete container-name
Error: The instance is currently running, stop it first or pass --force
```

`--force`オプションを付けると稼働状態でも削除できるようです。それだけに気を付けなければなりませんが。

```console
$ lxc delete --force container-name
$ lxc list
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
```

## `/etc`

```console
cd /etc
sudo svn st
```

こうなりました。

```console
$ cd /etc
$ sudo svn st
M       zfs/zpool.cache
```

念の為にコミットしておきましょうか。

```console
sudo svn ci -m"created LXD container"
```

# 仕舞い

LXDをインストールしました。良く使いそうな操作については、[以前一通り調べました](https://qiita.com/katz_engineer/items/74d7b357750e51e9c61c)ので、今回は省略します。またcloud-initによる初期設定も[以前調べました](https://qiita.com/katz_engineer/items/7ac5cadce3bdde9c76dc)。そちらを御参照ください。