能書き
自宅サーバー構築譚:基本構想に基づく自宅サーバー構築、Ubuntu22.04LTSインストールその2の続きです。
少々考えている事がありまして、このタイミングでコンテナを構築します。それもLXDとDockerを両方という贅沢仕様。意味が無い!と周囲に一蹴されたのですが、私なりに必然性を持った計画なのです。
ただ、Dockerとの同時インストールはLXDの公式も否定的であるので、もしかすると試行錯誤の末に諦めるかも知れません。
なお「LXD」の正しい読み方は「レクスディー」のようです。
目標
- LXDでシステムコンテナを起動
- コンテナのネットワークをブリッジ接続して、外部からアクセス
- ネットワークのIPアドレスは固定
参考文献
- 第582回いろいろなディストリビューションでsnapとLXDを利用する - Ubuntu Weekly Recipe - gihyo.jp
- snapパッケージの関連ディレクトリ - 第714回 Firefoxを含むsnapパッケージとの付き合い方 - gihyo.jp
- Ubuntuでsnapパッケージを管理する! - LAB4ICT
- LXD ドキュメント
- 外部からコンテナへの通信について - LXDにおけるネットワーク通信について - LXDを使用して瞬時にサーバを量産する(Ubuntu18.04)
スナップショット
後述の通り、LXDはsnapというパッケージ管理システムでインストールされています。これは関連するディレクトリが普通とは別になっているので、それを理解する必要があります。
参考文献:snapパッケージの関連ディレクトリ - 第714回 Firefoxを含むsnapパッケージとの付き合い方 - gihyo.jp
スナップショットを撮ります。
sudo zfs snapshot tank/ROOT/ubuntu@$(date +%Y%m%d_%H%M%S)_before_LXD
sudo zfs snapshot tank/ROOT/ubuntu/snap@$(date +%Y%m%d_%H%M%S)_before_LXD
sudo zfs snapshot tank/ROOT/ubuntu/var/snap@$(date +%Y%m%d_%H%M%S)_before_LXD
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/snapd@$(date +%Y%m%d_%H%M%S)_before_LXD
ロールバックする場合の注意
ここまでロールバックする事などまず無いと思いますが。もしもロールバックする場合、4つのスナップショットの他に、ZFSストレージプールを破棄する必要があります。そして少々面倒臭い手順が必要です。
まず全コンテナを停止して削除します。
lxc list -c n -f csv | xargs -rt lxc stop
lxc list -c n -f csv | xargs -rt lxc delete
ZFSストレージプールを削除します。
後述しますが、ZFSストレージプール名としてデフォルト値を選んだ場合(紛らわしいですがこの場合はdefault
という名前になります)次のコマンドを実行します。
sudo zpool destroy default
そしてZFSスナップショットまでロールバックします。
zfs list -t snapshot -o name -H | grep before_LXD | xargs -rtL 1 sudo zfs rollback
ここまでやってからマシン再起動で、ロールバックを反映します。
sudo reboot
インストール
毎度おなじみのapt update
。
sudo apt update
Ubuntuには最初からsnapdがインストールされている、との事…だったんですが、Ubuntuサーバーにはインストールされていないようです。そこでまずはsnapdのインストールから。
インストール済ならばこの手順は不要です。
sudo apt install -y snapd
これでsnap
コマンドを使えます。
snap --version
LXDについて。
snap info lxd
現在のLTS版は5.0です。これをインストールします。
sudo snap install lxd --channel=5.0/stable
インストールを確認。
lxd --version
初期化
コンテナ構築前にlxdの初期化が必要です。対話式の設定は色々と解説記事もあるようですので、ここでは非対話式で設定してみます。
ほぼ全てデフォルトですが、3箇所だけ。
- ネットワークブリッジのIPv4アドレスは固定で
192.168.0.1/24
とします。 - IPv6は
none
にしました。一般論ですが、トラブルの元になる場合が散見されるので。きちんと理解していれば良いんですが、私はまだIPv6を理解していないのです。 - イメージの自動更新はしません。安定稼働していたサーバがある日突然停止した、という事故が怖いので。
参考文献:LXDを初期化するには - LXDを使い始めるには
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: 30GiB
description: ""
name: default
driver: zfs
profiles:
- config: {}
description: ""
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
projects: []
cluster: null
___
コンテナ構築
利用可能なイメージを探す
利用可能なイメージを探します。今回はUbuntuの最新版である22.04通称jammyにします。
参考文献:利用可能なイメージをフィルタする - 利用可能なイメージを一覧表示する - イメージを管理するには
lxc image list images: ubuntu jammy architecture=x86_64 type=container
出力例。
$ 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) | 633d8a9878c2 | yes | Ubuntu jammy amd64 (20230415_07:42) | x86_64 | CONTAINER | 116.44MB | Apr 15, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+----------+-------------------------------+
| ubuntu/jammy/cloud (3 more) | 6c1ee3154ef0 | yes | Ubuntu jammy amd64 (20230415_07:43) | x86_64 | CONTAINER | 133.32MB | Apr 15, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+----------+-------------------------------+
因みに、jammy
ではなくて22.04
と指定しても同じ結果になりました。
$ 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) | 633d8a9878c2 | yes | Ubuntu jammy amd64 (20230415_07:42) | x86_64 | CONTAINER | 116.44MB | Apr 15, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+----------+-------------------------------+
| ubuntu/jammy/cloud (3 more) | 6c1ee3154ef0 | yes | Ubuntu jammy amd64 (20230415_07:43) | x86_64 | CONTAINER | 133.32MB | Apr 15, 2023 at 12:00am (UTC) |
+-----------------------------+--------------+--------+-------------------------------------+--------------+-----------+----------+-------------------------------+
コンテナ作成
コンテナを作成します。IPv4アドレスを固定で192.168.0.2
にします。
参考文献:インスタンスを作成するには
lxc init images:ubuntu/22.04 container-name --device eth0,ipv4.address=192.168.0.2
コンテナを作成しましたが停止状態です。
$ lxc list
+----------------+---------+------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+----------------+---------+------+------+-----------+-----------+
| container-name | STOPPED | | | CONTAINER | 0 |
+----------------+---------+------+------+-----------+-----------+
開始コマンドは下記です。
lxc start container-name
確認はlist
コマンドで。
$ lxc list
+----------------+---------+--------------------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+----------------+---------+--------------------+------+-----------+-----------+
| container-name | RUNNING | 192.168.0.2 (eth0) | | CONTAINER | 0 |
+----------------+---------+--------------------+------+-----------+-----------+
list
コマンドのオプションも色々あります。lxc list --help
で調べてみて下さい。
例えばコンテナ名とIPv4アドレスを取得してCSVで出力する場合は下記になります。
$ lxc list -c n4 -f csv
container-name,192.168.0.2 (eth0)
また、init
とstart
を同時に実行するのがlaunch
です。
$ 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
です。
$ 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
です。
$ lxc delete container-name2
$ lxc list
+----------------+---------+------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+----------------+---------+------+------+-----------+-----------+
| container-name | STOPPED | | | CONTAINER | 0 |
+----------------+---------+------+------+-----------+-----------+
なお稼働状態だと削除できません。
$ 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
コンテナ内ファイルへのアクセス
ファイルのpushとpull
テストに使用するファイルを用意します。中身は何でもいいのですが。
cat <<___ >/tmp/twinkle.txt
Twinkle, twindle, little star,
How I wonder what you are!
___
コンテナの中へ送付します。後述しますが、Ubuntuのコンテナにはデフォルトの一般ユーザーとしてubuntuが用意されていましたので、そのホームディレクトリに置いてみます。
lxc file push /tmp/twinkle.txt container-name/home/ubuntu/littlestar.txt
今度はコンテナ内から取得。
lxc file pull container-name/home/ubuntu/littlestar.txt /tmp
2つのファイルが一致する事を確認します。
$ diff -s /tmp/twinkle.txt /tmp/littlestar.txt
Files /tmp/twinkle.txt and /tmp/littlestar.txt are identical
因みにファイルパスとしてハイフン-
を指定すると、標準入出力になるそうです。
コンテナ内に送付する場合のコマンド例:
lxc file push - container-name/home/ubuntu/up.txt <<___
Up above the world so high,
Like a diamond in the sky.
___
コンテナから取得する場合の実行結果例:
$ lxc file pull container-name/home/ubuntu/up.txt -
Up above the world so high,
Like a diamond in the sky.
直接編集
コンテナ内のファイルを直接編集する事も可能です。エディタはデフォルトでnanoのようです。私にとって使い慣れたviを指定する場合は、環境変数EDITOR
で指定します。
EDITOR=vi lxc file edit container-name/home/ubuntu/littlestar.txt
削除
コンテナ内のファイルを直接削除する事も可能です。
lxc file delete container-name/home/ubuntu/up.txt
コンテナ内でコマンド実行
コマンドの実行
exec
サブコマンドを指定します。オプションを指定する場合は--
で区切ります。
参考文献:インスタンス内でコマンドを実行するには
例えば:
lxc exec container-name -- ls -l /home/ubuntu
Ubuntuコンテナでは最初からubuntuユーザーが用意されていました。そう言ったコンテナ内ユーザーとしてコンテナに入る為には下記コマンドを実行します。
lxc exec container-name -- su --login ubuntu
ところで、このubuntuユーザのパスワードはubuntuという記事を見かけましたが、実際に入力するとどうも違うようです。
$ passwd
Changing password for ubuntu.
Current password:
passwd: Authentication token manipulation error
passwd: password unchanged
exit
仕方が無いので、rootでubuntuユーザのパスワードを設定しておきましょう。
lxc exec container-name passwd ubuntu <<___
ubuntu
ubuntu
___
コンソールに接続
コンソールに接続してみます。
参考文献:コンソールにアクセスするには
lxc console container-name
これでコンソールに接続します。わかりにくいですが、ログインの要求が始まっています。
$ lxc console container-name
To detach from the console, press: <ctrl>+a q
ubuntu
Password:
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-69-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
* Introducing Expanded Security Maintenance for Applications.
Receive updates to over 25,000 software packages with your
Ubuntu Pro subscription. Free for personal use.
https://ubuntu.com/pro
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.
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
ubuntu@container-name:~$ exit
logout
Ubuntu 22.04.2 LTS container-name console
container-name login:
このコンソールから抜けるには Ctrl-a の後に q を入力します。
ネットワーク
コンテナ内から外部へ
デフォルトで、コンテナ内から外部へアクセスできます。名前解決も出来ています。
lxc exec container-name -- ping -c2 example.com
実行結果。
$ lxc exec container-name -- ping -c2 example.com
PING example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=52 time=119 ms
64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=2 ttl=52 time=119 ms
--- example.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 118.755/118.767/118.779/0.012 ms
外部からコンテナ内へ
まずは動作確認に備えて、openssh-server
をインストールしておきます。
lxc exec container-name -- apt install -y openssh-server
外部からコンテナ内へのアクセスについては、ポートフォワーディングを設定するのが最も理解し易いようです。
ただ、参考文献に載っていた方法は、少々癖があってわかりにくい。
参考文献:ネットワークフォワードを設定するには
まず「ネットワークフォワード」と呼ばれる構造を作成します。
-
lxdbr0
は最初の初期化時に作られたネットワークの名前 - 172.16.1.3はホストのIPアドレス(0.0.0.0では上手くいかないようです)
lxc network forward create lxdbr0 172.16.1.3
それから、この「ネットワークフォワード」に、ポートの割り当てを追加します。
- 192.168.0.2はコンテナのIPアドレス(上述の通り、コンテナ作成時に指定したIPv4アドレス)
lxc network forward port add lxdbr0 172.16.1.3 tcp 10022 192.168.0.2 22
これで外部からコンテナへ接続が可能になります。
ssh -p 10022 ubuntu@172.16.1.3
少し異なる設定方法として、下記のコマンドを実行すると、一発で設定できる模様。
参考文献:外部からコンテナへの通信について - LXDにおけるネットワーク通信について - LXDを使用して瞬時にサーバを量産する(Ubuntu18.04)
lxc config device add container-name sshForward proxy listen=tcp:172.16.1.3:20022 connect=tcp:192.168.0.2:22 bind=host
接続確認。
ssh -p 20022 ubuntu@172.16.1.3
仕舞い
一通り設定できた所で、例によって/etc
をコミットします。
sudo svn st /etc
今回の実行結果。
$ sudo svn st /etc
M /etc/cups/subscriptions.conf
M /etc/cups/subscriptions.conf.O
M /etc/passwd
M /etc/shadow
? /etc/systemd/system/multi-user.target.wants/snap-core20-1852.mount
? /etc/systemd/system/multi-user.target.wants/snap-lxd-24322.mount
? /etc/systemd/system/multi-user.target.wants/snap-snapd-18596.mount
? /etc/systemd/system/multi-user.target.wants/snap.lxd.activate.service
? /etc/systemd/system/snap-core20-1852.mount
? /etc/systemd/system/snap-lxd-24322.mount
? /etc/systemd/system/snap-snapd-18596.mount
? /etc/systemd/system/snap.lxd.activate.service
? /etc/systemd/system/snap.lxd.daemon.service
? /etc/systemd/system/snap.lxd.daemon.unix.socket
? /etc/systemd/system/snap.lxd.user-daemon.service
? /etc/systemd/system/snap.lxd.user-daemon.unix.socket
? /etc/systemd/system/snapd.mounts.target.wants
? /etc/systemd/system/sockets.target.wants/snap.lxd.daemon.unix.socket
? /etc/systemd/system/sockets.target.wants/snap.lxd.user-daemon.unix.socket
? /etc/udev/rules.d/70-snap.snapd.rules
M /etc/zfs/zfs-list.cache/tank
M /etc/zfs/zpool.cache
sudo svn st /etc | grep "^?" | cut -b9- | xargs -I{} sudo find {} -type f -or -type d -or -type l | xargs -t sudo svn add
sudo svn ci /etc -m"LXD setting"
残りの操作としてcloud-initを使いたいとかありますが、それはまた後日にします。
それを除けば、これでLXDを一通り操作できました。やったね