Raspberry Pi 3 Model B+ に lxc/lxd でコンテナ環境を構築した件

# やりたいこと
以前、[Raspberry Pi 3 Model B に LXC と LXD を使ってコンテナ環境を実現した](https://qiita.com/hatayan1126/items/79d9ba7f3dd1d3803f49)のですが、今回は Raspberry Pi 3 Model B<font color="Red">**+**</font> を新調し、改めて LXC と LXD をインストールしてコンテナ環境を実現します。

コンテナ環境には、自宅用のDNS/DHCPサーバー、メールサーバー、linebot用のWEBサーバー、子ども用スマホの通信制御用Firewall、環境データ(温度、湿度、気圧)保存用のDBサーバー などを構築しますが、詳細は別記事の「[自宅サーバー構築記録(Part 0)](https://qiita.com/hatayan1126/items/dcf70c26d518d07f4e47)」で紹介していきます。


# 環境
- Raspberry Pi 3 Model B<font color="Red">**+**</font>
- 2019-04-08-raspbian-stretch
- microSD 64GB

```shell-session
pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.9 (stretch)
Release:        9.9
Codename:       stretch
pi@raspberrypi:~ $
```

# やったこと

## パッケージ管理ツール snapd をインストール
今回は LXC/LXD 3.0.x[^1] を snap からインストールしたいので snapd パッケージを apt でインストールします。

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo apt install snapd -y
pi@raspberrypi:~ $
```

## snap で lxd をインストール  

lxdパッケージがあるか確認

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo snap info lxd
Name             Version        Publisher   Notes  Summary
lxd-demo-server  0+git.0227b57  stgraber    -      Online software demo sessions using LXD
lxd              3.13           canonical?  -      System container manager and API
pi@raspberrypi:~ $ 
```

lxdパッケージの詳細を確認

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo snap info lxd
name:      lxd
summary:   System container manager and API
publisher: Canonical?
license:   unset
description: |
  **LXD is a system container manager**

  With LXD you can run hundreds of containers of a variety of Linux
  distributions, apply resource limits, pass in directories, USB devices
  or GPUs and setup any network and storage you want.

  LXD containers are lightweight, secure by default and a great
  alternative to running Linux virtual machines.


  **Run any Linux distribution you want**

  Pre-made images are available for Ubuntu, Alpine Linux, ArchLinux,
  CentOS, Debian, Fedora, Gentoo, OpenSUSE and more.

  A full list of available images can be [found
  here](https://images.linuxcontainers.org)

  Can't find the distribution you want? It's easy to make your own images
  too, either using our `distrobuilder` tool or by assembling your own image
  tarball by hand.


  **Containers at scale**

  LXD is network aware and all interactions go through a simple REST API,
  making it possible to remotely interact with containers on remote
  systems, copying and moving them as you wish.

  Want to go big? LXD also has built-in clustering support,
  letting you turn dozens of servers into one big LXD server.


  **Configuration options**

  Supported options for the LXD snap (`snap set lxd KEY=VALUE`):
   - criu.enable: Enable experimental live-migration support [default=false]
   - daemon.debug: Increases logging to debug level [default=false]
   - daemon.group: Group of users that can interact with LXD [default=lxd]
   - ceph.builtin: Use snap-specific ceph configuration [default=false]
   - openvswitch.builtin: Run a snap-specific OVS daemon [default=false]

  [Documentation](https://lxd.readthedocs.io)
snap-id:      J60k4JY0HppjwOjW8dZdYc8obXKxujRu
tracking:     3.0/stable
refresh-date: yesterday at 00:24 JST
channels:
  stable:        3.13        2019-05-13 (10758) 48MB -
  candidate:     3.13        2019-05-10 (10758) 48MB -
  beta:          ↑
  edge:          git-2609835 2019-05-16 (10781) 48MB -
  3.0/stable:    3.0.3       2018-11-26  (9665) 45MB - ★ 今回はこれをインストールする
  3.0/candidate: 3.0.3       2019-01-19  (9943) 45MB -
  3.0/beta:      ↑
  3.0/edge:      git-eaa62ce 2019-02-19 (10213) 45MB -
  2.0/stable:    2.0.11      2018-07-30  (8017) 23MB -
  2.0/candidate: 2.0.11      2018-07-27  (8017) 23MB -
  2.0/beta:      ↑
  2.0/edge:      git-c7c4cc8 2018-10-19  (9255) 22MB -
installed:       3.0.3                   (9665) 45MB devmode
pi@raspberrypi:~ $
```

channel 3.0/stable を指定してインストール

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo snap install lxd --channel=3.0/stable
pi@raspberrypi:~ $
```

確認

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc --version
3.0.3
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxd --version
3.0.3
pi@raspberrypi:~ $
```

## ブリッジインターフェース作成
LXCコンテナが接続されるネットワークについては、有線LAN(eth0)と同じ 192.168.33.0/24 のセグメントにしたいのでブリッジインターフェース(br0)を作成します。

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo apt install bridge-utils
pi@raspberrypi:~ $
```

br0インターフェースを追加

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo vi /etc/network/interfaces
　：
auto br0
iface br0 inet manual
    bridge_ports eth0
    bridge_stp off
　：
pi@raspberrypi:~ $
```

DHCPを無効化し固定IPを割り当てる
/etc/network/interfaces に記述しても動作するが /etc/dhcpcd.conf に記述するように注意書きがしてあるのでそれに従って設定する。
参考：「[Raspbian jessie で bridge する備忘録](https://www.labohyt.net/blog/server/post-881/)」

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo vi /etc/dhcpcd.conf
　：
denyinterfaces eth0
　：
interface br0
static ip_address=192.168.33.12/24
static routers=192.168.33.254
static domain_name_servers=192.168.33.21
　：
pi@raspberrypi:~ $
```

再起動して確認

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo reboot
pi@raspberrypi:~ $

pi@raspberrypi:~ $
pi@raspberrypi:~ $ ip add show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000
    link/ether b8:27:eb:a0:1b:8d brd ff:ff:ff:ff:ff:ff
pi@raspberrypi:~ $
pi@raspberrypi:~ $ ip add show br0
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b8:27:eb:a0:1b:8d brd ff:ff:ff:ff:ff:ff
    inet 192.168.33.12/24 brd 192.168.33.255 scope global br0
       valid_lft forever preferred_lft forever
    inet6 240f:30:d187:1:3bfb:538a:a9a6:a0cc/64 scope global mngtmpaddr noprefixroute dynamic
       valid_lft 270sec preferred_lft 270sec
    inet6 fe80::ba27:ebff:fea0:1b8d/64 scope link
       valid_lft forever preferred_lft forever
pi@raspberrypi:~ $
pi@raspberrypi:~ $ sudo brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.b827eba01b8d       no              eth0
pi@raspberrypi:~ $
```

## LXD初期設定

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ 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]:
Name of the storage backend to use (btrfs, ceph, dir, lvm) [default=btrfs]: dir
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]: no ★ 既存の br0 を使うので "no"
Would you like to configure LXD to use an existing bridge or host interface? (yes/no) [default=no]: yes ★ br0 を使うので "yes"
Name of the existing bridge or host interface: br0 ★作成した "br0" を指定
Would you like LXD to be available over the network? (yes/no) [default=no]:
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]: yes
config: {}
networks: []
storage_pools:
- config: {}
  description: ""
  name: default
  driver: dir
profiles:
- config: {}
  description: ""
  devices:
    eth0:
      name: eth0
      nictype: bridged
      parent: br0
      type: nic
    root:
      path: /
      pool: default
      type: disk
  name: default
cluster: null
pi@raspberrypi:~ $
```

## 設定確認

プロファイル

```shell-session
pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ lxc profile list
+---------+---------+
|  NAME   | USED BY |
+---------+---------+
| default | 0       |
+---------+---------+
pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ lxc profile show default
config: {}
description: Default LXD profile
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: br0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default
used_by: []
pi@raspberrypi:~ $
```

ネットワーク

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc network list
+-------+----------+---------+-------------+---------+
| NAME  |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+-------+----------+---------+-------------+---------+
| br0   | bridge   | NO      |             | 0       |
+-------+----------+---------+-------------+---------+
| eth0  | physical | NO      |             | 0       |
+-------+----------+---------+-------------+---------+
| wlan0 | physical | NO      |             | 0       |
+-------+----------+---------+-------------+---------+
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc network show br0
config: {}
description: ""
name: br0
type: bridge
used_by: []
managed: false
status: ""
locations: []
pi@raspberrypi:~ $
```

コンテナのテンプレートイメージが置いてあるリモートサーバー一覧

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ 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    |
+-----------------+------------------------------------------+---------------+-----------+--------+--------+
pi@raspberrypi:~ $
```


「images:」というリモートサーバーにあるテンプレート一覧
最新のテンプレート一覧はこちら [https://images.linuxcontainers.org](https://images.linuxcontainers.org)

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc image list images:
+--------------------------------------+--------------+--------+----------------------------------------------+---------+-----------+-------------------------------+
|                ALIAS                 | FINGERPRINT  | PUBLIC |                 DESCRIPTION                  |  ARCH   |   SIZE    |          UPLOAD DATE          |
+--------------------------------------+--------------+--------+----------------------------------------------+---------+-----------+-------------------------------+
| alpine/3.6 (3 more)                  | 01019a788334 | yes    | Alpine 3.6 armhf (20190520_13:00)            | armv7l  | 3.11MB    | May 20, 2019 at 12:00am (UTC) |
+--------------------------------------+--------------+--------+----------------------------------------------+---------+-----------+-------------------------------+
| alpine/3.6/amd64 (1 more)            | 235b94fa821a | yes    | Alpine 3.6 amd64 (20190520_13:00)            | x86_64  | 3.17MB    | May 20, 2019 at 12:00am (UTC) |
+--------------------------------------+--------------+--------+----------------------------------------------+---------+-----------+-------------------------------+
| alpine/3.6/arm64 (1 more)            | 3a8dbcdc2fa2 | yes    | Alpine 3.6 arm64 (20190520_13:00)            | aarch64 | 3.07MB    | May 20, 2019 at 12:00am (UTC) |
+--------------------------------------+--------------+--------+----------------------------------------------+---------+-----------+-------------------------------+
　：
　：
　：
pi@raspberrypi:~ $
```

# コンテナの基本操作

## コンテナ作成

テンプレート名「centos/7」を使って、「c1-centos7」というコンテナを作成する

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc launch images:centos/7 c1-centos7
Creating c1-centos7
Starting c1-centos7
pi@raspberrypi:~ $
```

## 作成したコンテナを確認

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc list
+------------+---------+-----------------------+------------------------------------------+------------+-----------+
|    NAME    |  STATE  |          IPV4         |                   IPV6                   |    TYPE    | SNAPSHOTS |
+------------+---------+-----------------------+------------------------------------------+------------+-----------+
| c1-centos7 | RUNNING | 192.168.33.163 (eth0) | 240f:30:d187:1:216:3eff:fe40:b209 (eth0) | PERSISTENT | 0         |
+------------+---------+-----------------------+------------------------------------------+------------+-----------+
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc info c1-centos7
Name: c1-centos7
Remote: unix://
Architecture: armv7l
Created: 2019/05/20 15:27 UTC
Status: Running
Type: persistent
Profiles: default
Pid: 26403
Ips:
  eth0: inet    192.168.33.163   vethTPUHMD
  eth0: inet6   240f:30:d187:1:216:3eff:fe40:b209       vethTPUHMD
  eth0: inet6   fe80::216:3eff:fe40:b209        vethTPUHMD
  lo:   inet    127.0.0.1
  lo:   inet6   ::1
Resources:
  Processes: 1
  CPU usage:
    CPU usage (in seconds): 4
  Memory usage:
    Memory (current): 35.75MB
    Memory (peak): 36.84MB
  Network usage:
    eth0:
      Bytes received: 9.29kB
      Bytes sent: 1.37kB
      Packets received: 58
      Packets sent: 11
    lo:
      Bytes received: 0B
      Bytes sent: 0B
      Packets received: 0
      Packets sent: 0
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc config show c1-centos7
architecture: armv7l
config:
  image.architecture: armhf
  image.description: Centos 7 armhf (20190520_07:08)
  image.os: Centos
  image.release: "7"
  image.serial: "20190520_07:08"
  volatile.base_image: ab193fd6af55d6281600a2fa14db00cb9172f6f19540d86c198d80bbd9211d2a
  volatile.eth0.hwaddr: 00:16:3e:40:b2:09
  volatile.idmap.base: "0"
  volatile.idmap.next: '[{"Isuid":true,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.idmap: '[{"Isuid":true,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.power: RUNNING
devices: {}
ephemeral: false
profiles:
- default
stateful: false
description: ""
pi@raspberrypi:~ $
```

## コンテナにログインする

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc exec c1-centos7 /bin/bash
[root@c1-centos7 ~]#
[root@c1-centos7 ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (AltArch)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (AltArch)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

[root@c1-centos7 ~]#
[root@c1-centos7 ~]# exit
exit
pi@raspberrypi:~ $
```

## コンテナを停止させる

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc stop c1-centos7
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc list
+------------+---------+------+------+------------+-----------+
|    NAME    |  STATE  | IPV4 | IPV6 |    TYPE    | SNAPSHOTS |
+------------+---------+------+------+------------+-----------+
| c1-centos7 | STOPPED |      |      | PERSISTENT | 0         |
+------------+---------+------+------+------------+-----------+
pi@raspberrypi:~ $
```

## コンテナを削除する

削除するときはコンテナを停止させておく必要がある。

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc delete c1-centos7
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc list
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
pi@raspberrypi:~ $
```


[^1]: [LXC 3.0.0 will be supported until June 2023 and our current LTS release.](https://discuss.linuxcontainers.org/t/lxc-3-0-0-has-been-released/1449)