LXD3.0 tips


# これは何？

- Ubuntu 18.04 の LXD 3.0 の tips
- 随時更新。。。


# サイズの小さな Ubuntu イメージを使いたい。

- 参考、「[A closer look at Minimal Ubuntu for LXD ? Mi blog lah!](https://blog.simos.info/a-closer-look-at-minimal-ubuntu-for-lxd/)」

```sh
# リモート登録（ubuntu-minimal という名前で登録）
$ lxc remote add --protocol simplestreams ubuntu-minimal https://cloud-images.ubuntu.com/minimal/releases/

# イメージリスト
$ lxc image list ubuntu-minimal:
$ lxc image alias list ubuntu-minimal:

# イメージ情報
$ lxc image info ubuntu-minimal:18.04

# 18.04のイメージから、コンテナ作成＆起動（コンテナ名 minimal）
$ lxc launch ubuntu-minimal:18.04 minimal

# コンテナに ubuntu でログイン
$ lxc exec minimal -- sudo --user ubuntu --login
```



# ブリッジ(lxdbr0)のDNS有効化

- `lxd init` の初期設定をデフォルトで設定した場合、LXDコンテナをブリッジ(lxdbr0)でつなぐようになっているはず。
- この時、
    - コンテナ to コンテナ
        -  `ping <コンテナ名>` は通る。
    - LXDホスト to コンテナへの
        -  `ping <コンテナ名>` は **通らない。** ・・・**これが、通るようにする。**
        -  もっとも、`ping <コンテナのIP>` なら通る。
- 参考、「[How to use LXD container hostnames on the host in Ubuntu 18.04 ? Mi blog lah!](https://blog.simos.info/how-to-use-lxd-container-hostnames-on-the-host-in-ubuntu-18-04/)」


- 手っ取り早くDNSを有効にするだけなら、以下の１コマンド実行するだけでよい。(環境変数は適切に設定必要だが)

```sh
$ /usr/bin/systemd-resolve --interface ${LXDINTERFACE} --set-dns ${LXDDNSIP} --set-domain ${LXDDOMAIN}
```

- 以下、systemdのサービスとして、自動化するスクリプト

```sh
# lxd_host_dns_start.sh
cat <<'__EOS__' | sudo tee /usr/local/bin/lxd_host_dns_start.sh > /dev/null
#!/bin/sh
LXDINTERFACE=lxdbr0
LXDDOMAIN=lxd
LXDDNSIP=$(lxc network get ${LXDINTERFACE} ipv4.address | sed -E 's#/.+##')
/usr/bin/systemd-resolve --interface ${LXDINTERFACE} --set-dns ${LXDDNSIP} --set-domain ${LXDDOMAIN}
systemd-resolve --status ${LXDINTERFACE}
__EOS__
sudo chmod +x /usr/local/bin/lxd_host_dns_start.sh

# lxd_host_dns_stop.sh
cat <<'__EOS__' | sudo tee /usr/local/bin/lxd_host_dns_stop.sh > /dev/null
#!/bin/sh
LXDINTERFACE=lxdbr0
/usr/bin/systemd-resolve --interface ${LXDINTERFACE} --revert
systemd-resolve --status ${LXDINTERFACE}
__EOS__
sudo chmod +x /usr/local/bin/lxd_host_dns_stop.sh

# lxd-host-dns.service
cat <<'__EOS__' | sudo tee /lib/systemd/system/lxd-host-dns.service > /dev/null
[Unit]
Description=LXD host DNS service
After=lxd-containers.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/lxd_host_dns_start.sh
RemainAfterExit=true
ExecStop=/usr/local/bin/lxd_host_dns_stop.sh
StandardOutput=journal

[Install]
WantedBy=multi-user.target
__EOS__

# サービス起動
sudo systemctl start lxd-host-dns

# 次回以降の為、サービス有効化
sudo systemctl enable lxd-host-dns

# サービス設定確認
# systemctl list-unit-files --type=service | grep lxd
# sudo systemctl status lxd-host-dns
# sudo journalctl -u lxd-host-dns

# DNS現在設定表示
# systemd-resolve --status lxdbr0
```

- これで `ping <コンテナ名>` あるいは `ping <コンテナ名>.lxd` が通るようになる。

# otherPCs --> socks(LXD Host) --> containers

- otherPCs から http[s], ssh で containers へ接続できるようにする。
- 以下例は、otherPCs = Windwos10 のケース

```
# ---------------------------------------------------------------------------
# LXD Host：socks proxy を立てる
#   socks5 を立て、これを踏み台にしてネットワーク(lxdbr0)に入れるようにする。
# ---------------------------------------------------------------------------

# lxd-socks-proxy.service
cat <<'__EOS__' | sudo tee /lib/systemd/system/lxd-socks-proxy.service > /dev/null
[Unit]
Description=LXD socks proxy service
After=lxd-host-dns.target

[Service]
User=root
ExecStart=/usr/bin/ssh -gNT -D 1080 -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o TCPKeepAlive=no -o StrictHostKeyChecking=no root@localhost
RestartSec=30
Restart=always

[Install]
WantedBy=multi-user.target
__EOS__

# サービス起動
sudo systemctl start lxd-socks-proxy

# 次回以降の為、サービス有効化
sudo systemctl enable lxd-socks-proxy

# サービス設定確認
# systemctl list-unit-files --type=service | grep lxd
# sudo systemctl status lxd-socks-proxy
# sudo journalctl -u lxd-socks-proxy

# ---------------------------------------------------------------------------
# Windows10 : ブラウザへの socks proxy 設定
# ---------------------------------------------------------------------------

# Windows10
# C:/Users/<user>/proxy.pac
#   |// .lxd ドメインは、socks を通す
#   |function FindProxyForURL(url, host){
#   |  if (dnsDomainIs(host, ".lxd")){
#   |    return "SOCKS5 localhost:1080; DIRECT";
#   |  }
#   |  return "DIRECT";
#   |}
# これをブラウザに設定する。

# ---------------------------------------------------------------------------
# Windows10 : ssh の socks proxy 設定
# ---------------------------------------------------------------------------

# Windows10、git-bashより
# vi ~/.ssh/config
#   |Host *.lxd
#   |  User ubuntu
#   |  ProxyCommand connect -S localhost:1080 %h %p
# ssh <CONTAINER>.lxd でコンテナにログインできる。
# あるいは
#   |$ ssh -v -o 'ProxyCommand connect -S localhost:1080 %h %p' <USER>@<CONTAINER>.lxd
# でログインできる。
```





# LXDのネットワークのipv6 無効化
- コンテナにipv6アドレスが付与されるので、これを無効化する。
    - ブリッジのipv6を削除することで実現する。

```sh
$ lxc network set lxdbr0 ipv6.address none
```

- 本当は、OS レベルでOFFにするのが正解っぽい？



# lxdログ
- 何かあった時の調査に。。。

```sh
$ tail -f /var/log/lxd/lxd.log
```



# LXDホストから、コンテナへ公開鍵を登録＆パスワードの上書き

- LXDホストから以下実行する。
    - そもそも、sshdがインストールされていない場合は、インストールする。
    - sudo の実行などで、パスワードが必要なこともあるので、password上書きしておく。 

```sh
$ CONTAINER=c1  # 登録先コンテナ名
$ UNAME=ubuntu  # 登録先ユーザ名
$ PUBFILE=~/.ssh/id_rsa.pub  # 登録したい公開鍵

# sshd インストール
$ lxc exec $CONTAINER -- apt install -y openssh-server

# 公開鍵登録
$ cat $PUBFILE | lxc exec $CONTAINER -- sudo --user $UNAME --login sh -c 'mkdir -p ~/.ssh; chmod 700 ~/.ssh; touch ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys; cat - >> ~/.ssh/authorized_keys'
  
# password上書き
$ echo "${UNAME}:${UNAME}" | lxc exec $CONTAINER -- chpasswd
```

- メモ、まず、`lxc exec` で ssh をパスワードでログインできるようにしておいて、あとは、`ssh-copy-id` したほうが手順簡単かも。




# LXDコンテナ内で、dockerを動かす

### docker run で `docker: Error response from daemon: OCI runtime create failed: ` エラー

- LXDコンテナ内で、dockerを動かすと上記エラーが発生することがある。
`lxc config set <CONTAINER> security.nesting true` で解決できる。
- あるいは、最初から `-c security.nesting=true` オプションを付けて、LXDコンテナを作成しておけばよい。

### docker image pull で `no space left on device` エラー

- 結論としては、ストレージバックエンドに btrfs を使っている場合、`df` では空き容量があるように見えても、容量不足になることがあり、`btrfs balance start` で再構成することで、空き領域を増やせる。

```sh
ubuntu@c1:~$ docker image pull gihyodocker/echo:latest
latest: Pulling from gihyodocker/echo
723254a2c089: Pull complete
abe15a44e12f: Pull complete
409a28e3cc3d: Pull complete
503166935590: Pull complete
abe52c89597f: Pull complete
ce145c5cf4da: Extracting [==================================================>]  104.3MB/104.3MB
96e333289084: Download complete
39cd5f38ffb8: Download complete
22860d04f4f1: Download complete
7528760e0a03: Download complete
failed to register layer: ApplyLayer exit status 1 stdout:  stderr: write /usr/local/go/pkg/tool/linux_amd64/cover: no space left on device・・・★
ubuntu@c1:~$

#
ubuntu@c1:~$ df -H
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop0      5.4G  3.9G  736M  84% /・・・★空いてるっぽいが？
none            504k     0  504k   0% /dev
udev            1.1G     0  1.1G   0% /dev/tty
tmpfs           103k     0  103k   0% /dev/lxd
tmpfs           103k     0  103k   0% /dev/.lxd-mounts
tmpfs           1.1G     0  1.1G   0% /dev/shm
tmpfs           1.1G  283k  1.1G   1% /run
tmpfs           5.3M     0  5.3M   0% /run/lock
tmpfs           1.1G     0  1.1G   0% /sys/fs/cgroup
tmpfs           210M     0  210M   0% /run/user/1000
ubuntu@c1:~$
```
- LXDホスト側があやしいか？

```sh
#
# 使用しているLXDストレージ確認
#
vagrant@ubuntu-bionic:~$ lxc storage list
+---------+-------------+--------+--------------------------------+---------+
|  NAME   | DESCRIPTION | DRIVER |             SOURCE             | USED BY |
+---------+-------------+--------+--------------------------------+---------+
| default |             | btrfs  | /var/lib/lxd/disks/default.img | 6       |
+---------+-------------+--------+--------------------------------+---------+
vagrant@ubuntu-bionic:~$ lxc storage show default
config:
  size: 5GB
  source: /var/lib/lxd/disks/default.img
description: ""
name: default
driver: btrfs
used_by:
- /1.0/containers/c1
- /1.0/images/1aa1f3f518faa2d70934d8ca31e9c01722a37b0ad4dc1b36a3dd09430eaa2d74
- /1.0/images/7c938d905646e461be9983d1be0e64dc6fc9d2055952c4cd393c62eb829fcf60
- /1.0/images/9c9dc41729167ab124f4fbc61c6a45f5006ebb9c2586b326762e0215d042c8ae
- /1.0/images/de48fd11aab9c3a8b4a9d84c05626ae4480043d7fecf08fe6f6c0dcb0d0de2e5
- /1.0/profiles/default
status: Created
locations:
- none
vagrant@ubuntu-bionic:~$ lxc storage info default
info:
  description: ""
  driver: btrfs
  name: default
  space used: 1.90GB・・・★やはり空きがあるように見えるが？
  total space: 5.00GB
used by:
  containers:
  - c1
  images:
  - 1aa1f3f518faa2d70934d8ca31e9c01722a37b0ad4dc1b36a3dd09430eaa2d74
  - 7c938d905646e461be9983d1be0e64dc6fc9d2055952c4cd393c62eb829fcf60
  - 9c9dc41729167ab124f4fbc61c6a45f5006ebb9c2586b326762e0215d042c8ae
  - de48fd11aab9c3a8b4a9d84c05626ae4480043d7fecf08fe6f6c0dcb0d0de2e5
  profiles:
  - default
vagrant@ubuntu-bionic:~$


#
vagrant@ubuntu-bionic:~$ df --si
Filesystem      Size  Used Avail Use% Mounted on
udev            1.1G     0  1.1G   0% /dev
tmpfs           210M  697k  209M   1% /run
/dev/sda1        11G  7.4G  3.0G  72% /
tmpfs           1.1G     0  1.1G   0% /dev/shm
tmpfs           5.3M     0  5.3M   0% /run/lock
tmpfs           1.1G     0  1.1G   0% /sys/fs/cgroup
vagrant         240G  237G  2.4G 100% /vagrant
tmpfs           103k     0  103k   0% /var/lib/lxd/shmounts
tmpfs           103k     0  103k   0% /var/lib/lxd/devlxd
/dev/loop0      5.4G  1.7G  2.8G  37% /var/lib/lxd/storage-pools/default・・・★空きがあるように見える
tmpfs           210M     0  210M   0% /run/user/1000
tmpfs           210M     0  210M   0% /run/user/0
vagrant@ubuntu-bionic:~$

#
vagrant@ubuntu-bionic:~$ sudo btrfs filesystem df --si /var/lib/lxd/storage-pools/default
Data, single: total=4.26GB, used=1.49GB・・・★空きがあるように見える
System, DUP: total=8.39MB, used=16.38kB
Metadata, DUP: total=536.87MB, used=52.59MB
GlobalReserve, single: total=16.78MB, used=0.00B
vagrant@ubuntu-bionic:~$


#
vagrant@ubuntu-bionic:~$ sudo btrfs filesystem show --si
Label: 'default'  uuid: 141d7de0-4a7f-4872-9454-79ee88d4760a
        Total devices 1 FS bytes used 1.54GB
        devid    1 size 5.37GB used 5.35GB path /dev/loop0・・・★あれ？空きがない！

vagrant@ubuntu-bionic:~$

#
# 再構成（クリーンアップ）
#
vagrant@ubuntu-bionic:~$ sudo btrfs balance start /var/lib/lxd/storage-pools/default
WARNING:

        Full balance without filters requested. This operation is very
        intense and takes potentially very long. It is recommended to
        use the balance filters to narrow down the scope of balance.
        Use 'btrfs balance start --full-balance' option to skip this
        warning. The operation will start in 10 seconds.
        Use Ctrl-C to stop it.
10 9 8 7 6 5 4 3 2 1
Starting balance without any filters.
Done, had to relocate 11 out of 11 chunks
vagrant@ubuntu-bionic:~$

#
vagrant@ubuntu-bionic:~$ sudo btrfs filesystem show --si
Label: 'default'  uuid: 141d7de0-4a7f-4872-9454-79ee88d4760a
        Total devices 1 FS bytes used 1.53GB
        devid    1 size 5.37GB used 2.21GB path /dev/loop0・・・★used 5.35GB が 2.21GB に減った

vagrant@ubuntu-bionic:~$
```


# 例）LXDコンテナ作成＆実行

```sh
(
  set -ex

  IMAGE=ubuntu-minimal:18.04
  CONTAINER=c4
  UNAME=ubuntu
  PUBFILE=~/.ssh/id_rsa.pub

  # コンテナ作成＆実行
  lxc launch $IMAGE $CONTAINER
  
  # ネット接続に失敗することがあるので、少しsleepする。
  # todo: stateを見たほうがいい
  sleep 10

  # apt update
  lxc exec $CONTAINER -- apt update
  #lxc exec $CONTAINER -- apt upgrade

  # sshd
  lxc exec $CONTAINER -- apt install -y openssh-server

  # $UNAME : 公開鍵登録
  cat $PUBFILE | lxc exec $CONTAINER -- sudo --user $UNAME --login sh -c 'mkdir -p ~/.ssh; chmod 700 ~/.ssh; touch ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys; cat - >> ~/.ssh/authorized_keys'
  
  # $UNAME : password設定(sudoするときに使う)
  echo "${UNAME}:${UNAME}" | lxc exec $CONTAINER -- chpasswd

  # timezone
  lxc exec $CONTAINER -- ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
  lxc exec $CONTAINER -- apt install -y tzdata
  lxc exec $CONTAINER -- dpkg-reconfigure --frontend noninteractive tzdata

  # ssh 接続確認
  echo "(set -ex; hostname; id)" |  ssh -o StrictHostKeyChecking=no ${UNAME}@${CONTAINER} -- bash

  # 作成したコンテナの情報
  lxc config show c1
  lxc info $CONTAINER

  # いろいろインストール
  lxc exec $CONTAINER -- apt install -y curl vim
  
  # todo: docker install
)
```