能書き
自宅サーバー構築譚:基本構想に基づく自宅サーバー構築、Ubuntu22.04LTSインストールその2の続きです。
前回はLXDをインストールして、一通り触ってみました。今回はLXDと併存する形でDockerをインストールします。
Dockerとの同時インストールはLXDの公式も否定的であるようです。その辺も確認して対策します。
目標
- Dockerでアプリケーションコンテナを起動
- Dockerコンテナに外部からアクセス
- LXDのシステムコンテナも同時に動くようにする
参考文献
- Install Docker Engine on Ubuntu - Docker Engine - docker docs
- Docker Composeを使ってサクッとNginxコンテナを起動する - Qiita
- コマンドでDockerコンテナを停止・削除、イメージの削除をする - Qiita
- LXD と Docker の問題を回避する - ファイアウォールを設定するには
- LXDとDockerを同時利用するためにiptables設定を調整 - hnakamur's blog
事前にLXDをインストールしているのが、今回の前提条件です。
スナップショット
今回のスナップショットはこんな感じです。
sudo zfs snapshot tank/ROOT/ubuntu@$(date +%Y%m%d_%H%M%S)_before_install_Docker
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/apt@$(date +%Y%m%d_%H%M%S)_before_install_Docker
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/dpkg@$(date +%Y%m%d_%H%M%S)_before_install_Docker
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/docker@$(date +%Y%m%d_%H%M%S)_before_install_Docker
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/containerd@$(date +%Y%m%d_%H%M%S)_before_install_Docker
インストール
Docker
定番のapt update
。
sudo apt update
Dockerのaptリポジトリを追加するのに必要な道具をインストールします。
sudo apt install -y ca-certificates curl gnupg
DockerのGPG鍵を追加します。
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
リポジトリのセットアップ。
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
そして再度apt update
です。
sudo apt update
ここでいよいよ Docker Engine のインストール!最新バージョンが良いでしょう。
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
インストールは以上となります。
docker --version
/etc
/etc
はこんな風に変化しました。
$ sudo svn st /etc
? /etc/apt/keyrings/docker.gpg
? /etc/apt/sources.list.d/docker.list
? /etc/bash_completion.d
? /etc/containerd
? /etc/default/docker
? /etc/docker
M /etc/group
M /etc/gshadow
? /etc/init
? /etc/init.d/docker
M /etc/ld.so.cache
? /etc/rc0.d/K01docker
? /etc/rc1.d/K01docker
? /etc/rc2.d/S01docker
? /etc/rc3.d/S01docker
? /etc/rc4.d/S01docker
? /etc/rc5.d/S01docker
? /etc/rc6.d/K01docker
? /etc/systemd/system/multi-user.target.wants/containerd.service
? /etc/systemd/system/multi-user.target.wants/docker.service
? /etc/systemd/system/sockets.target.wants/docker.socket
Subversionで登録しておきましょう。
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"install Docker"
ユーザーグループ
dockerグループに所属しているユーザーならば、docker
コマンド実行時にsudo
は不要のようです。
sudo usermod -aG docker $USER
自分自身のグループを変更したので、反映させる為に一度ログアウトしてログインし直します。
logout
正しく動作できるかの確認は、下記を実行します。
docker run hello-world
「hello, world」の1行を表示するだけかと思ったら、何だか色々とメッセージを表示してくれますね。一瞬、エラーが発生したのかと勘違いしました。
終わった後もDockerが残っています。
$ docker ps -a
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 19 months ago 13.3kB
綺麗に消しましょう。
docker ps -aq | xargs -rt docker rm
docker images -q | xargs -rt docker rmi
ネットワークについて
LXD
軽くチェック
どうやらUbuntuServerとXubuntuとで、ネットワークの挙動が違うようです。どなたか詳しい方がいらっしゃいましたら、詳細について記事を書いて、コメントください。私はお手上げです。
Xubuntuの場合、この時点でLXDコンテナはネットワークが遮断されたような挙動になります。
$ lxc start container-name
$ lxc exec container-name -- ping -c2 example.com
PING example.com (93.184.216.34) 56(84) bytes of data.
--- example.com ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1006ms
ダメだった場合の対応
※UbuntuServerの場合は前節でpingが通りますので、この節の設定は不要です。
問題は解決方法ですが。
これに従うと何やら訳のわからないエラーが。
$ iptables -I $USER -o lxdbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables v1.8.7 (nf_tables): Couldn't load match `conntrack':No such file or directory
Try `iptables -h' or 'iptables --help' for more information.
意外と当てになりませんな公式。
こちらの参考文献に従ったら成功しました。
参考文献:LXDとDockerを同時利用するためにiptables設定を調整 - hnakamur's blog
具体的には次の2つのコマンドです。
sudo iptables -I FORWARD -o lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
sudo iptables -I FORWARD 2 -i lxdbr0 -m comment --comment "generated for LXD network lxdbr0" -j ACCEPT
こんな感じ。
$ 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=117 ms
--- example.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 2561ms
rtt min/avg/max/mdev = 116.663/117.585/118.508/0.922 ms
但しこれ、起動する度に実行の必要があるとの事。それについても解決策が載っていました。ありがたや。
しかし、私の手順でインストールしていると、なぜかnft
コマンドを使えません。UbuntuServerだと使えるようなので、Xubuntuだけかも知れませんが。
$ nft
-bash: nft: command not found
仕方無いのでiptables
コマンドを使った設定にしておきます。
lxd_network=lxdbr0
cat <<___ | sudo tee /etc/systemd/system/iptables-for-lxd-with-docker.service >/dev/null
[Unit]
Description=Add iptables rules for LXD coexisting with Docker
After=docker.service
[Service]
Type=oneshot
# https://discuss.linuxcontainers.org/t/lxd-and-docker-firewall-redux-how-to-deal-with-forward-policy-set-to-drop/9953/7
ExecStart=iptables -I FORWARD -o $lxd_network -m comment --comment "generated for LXD network $lxd_network" -j ACCEPT
ExecStart=iptables -I FORWARD 2 -i $lxd_network -m comment --comment "generated for LXD network $lxd_network" -j ACCEPT
[Install]
WantedBy=multi-user.target
___
sudo systemctl daemon-reload
sudo systemctl enable --now iptables-for-lxd-with-docker
これで、再起動してもLXDコンテナでネットワークがOKになります。
sudo reboot
$ 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=117 ms
64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=2 ttl=52 time=118 ms
--- example.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1258ms
rtt min/avg/max/mdev = 116.933/117.549/118.166/0.616 ms
動作確認
コンテナ内から外部へのネットワーク接続を確認できたら、ソフトをインストールしてみます。
lxc exec -- container-name apt install -y nginx
外部からコンテナ内への接続を定義。
-
lxdbr0
は今回のLXDコンテナのブリッジネットワーク -
172.16.1.3
はホストマシンのIPアドレス -
192.168.0.2
はLXDコンテナのIPアドレス
※前回の続きでlxdbr0
の設定が残っていたら、このcreate
は飛ばして次のport add
だけ実行してください。
lxc network forward create lxdbr0 172.16.1.3
lxc network forward port add lxdbr0 172.16.1.3 tcp 10080 192.168.0.2 80
ここで……
食らえ!HTTP/0.9!
echo -en "GET /\r\n" | nc 172.16.1.3 10080
なぜ化石のような規格のHTTP/0.9を使うかと言いますとですね。レスポンスにヘッダが付かないというメリットがあるんですね。
だからこんな荒技も出来るんです。
diff -s --label GET <(echo -en "GET /\r\n" | nc 172.16.1.3 10080) --label IN_CONTAINER <(lxc file pull container-name/var/www/html/index.nginx-debian.html -)
実行結果はこうなります。
$ diff -s --label GET <(echo -en "GET /\r\n" | nc 172.16.1.3 10080) --label IN_CONTAINER <(lxc file pull container-name/var/www/html/index.nginx-debian.html -)
Files GET and IN_CONTAINER are identical
美しい……
以上でLXDの方は動作確認できました。
Docker
今度はDockerです。
まず設定ファイルdocker-compose.yml
を準備。難しい事はしないのでDockerfile
は要りません。
mkdir ~/nginx
cd ~/nginx
cat >docker-compose.yml <<___
version: '3'
services:
nginx:
image: nginx:latest
build: .
ports:
- "20080:80"
___
バックグラウンドで起動します。
docker compose up -d
今度もHTTP/0.9でアクセスしますが……
今回は、docker compose cp
コマンドで出力にハイフン - を指定する(これは標準出力を表す)と、良く分からないデータを頭にくっつけやがる(そして抑制できない)という謎仕様の為、1行に纏める事が出来ませんでした。
なぜかプロセス置換もエラーになってしまってダメです。
仕方が無いので/tmp
に一時ファイルを作成しました。
docker compose cp nginx:/usr/share/nginx/html/index.html /tmp/test.html >&/dev/null
diff -s --label GET <(echo -en "GET /\r\n" | nc 172.16.1.3 20080) --label IN_CONTAINER /tmp/test.html
実行結果。
$ docker compose cp nginx:/usr/share/nginx/html/index.html /tmp/test.html >&/dev/null
$ diff -s --label GET <(echo -en "GET /\r\n" | nc 172.16.1.3 20080) --label IN_CONTAINER /tmp/test.html
Files GET and IN_CONTAINER are identical
ま、とにかく、Dockerコンテナがちゃんと動いている事は間違い無いようです。
確認が終わったら、綺麗に消しましょう。
docker compose down --rmi all --volumes
仕舞い
/etc
を確認。
$ sudo svn st /etc
M /etc/group
M /etc/gshadow
殆ど差がありませんな。一応、いつもの手順で登録。
sudo svn st /etc | grep "^?" | cut -b9- | xargs -I{} sudo find {} -type f -or -type d -or -type l | xargs -rt sudo svn add
sudo svn ci /etc -m"Docker with LXD setting"
今回はDockerをインストールし、LXDとDockerが同時に稼働できる事を確認しました。Xubuntuの場合はダメのようですが、対応する設定をして、そして同時に稼働できました。
やったね