【2019年3月版】Ubuntu18.04でdockerが動くlxcコンテナの作り方

# はじめに
Ubuntu18.04上でdockerが動かせるlxcコンテナを構築してみます。

## 対象
- OS: Ubuntu 18.04
- LXD 3.0.x
- docker CE 

# 手順

## 1. lxd zfs のインストール

Ubuntu18.04 に LXD を入れるのは簡単です。
ただし注意として、今回のようにlxcコンテナ上でさらに docker を使う場合は LXD のストレージに ZFS を使わないとダメです。
標準の btrfs では対応できません。

```shell
$ sudo apt install lxd zfsutils-linux
$ lxd init
```

で lxd の初期処理が始まり、いくつか質問に答えます。ストレージについての質問についてはzfsを指定します。
この質問に答え終われば準備は完了です。もうすぐにでもコンテナを作成して動かせます。

## docker 用プロファイルを作っておくと便利

何度も docker 用コンテナを作る場合は専用のプロファイルをあらかじめ作っておいて、dockerようにコンテナの設定をしておいた方が楽です。

```
~$ lxc profile copy default docker
~$ lxc profile edit docker
```

とすると設定の YAML を編集するエディタが立ち上がるので、config に以下を追加します。

```shell
  raw.lxc: |-
    lxc.mount.auto=proc:rw sys:rw cgroup:rw
    lxc.cgroup.devices.allow=a
    lxc.cap.drop=
  security.privileged: "true"
  security.nesting: "true"
```

編集が終われば`Ctrl+o`で書き込み保存先を確認して`Enter`、`Ctrl+x`で終了です。
ちなみに"|-"はタイポじゃないです。yaml 形式での改行のエスケープ指定です。

# lxd 上の Ubuntu コンテナで Docker を動かす

## プロファイルを使って Ubuntu16.04 ベースで行ってみます

とりあえずコンテナの中はなんでもいいんですが Ubuntu16.04 の方でいってみます。`-p docker`で上記で設定したプロファイルを指定します。

```shell
$ lxc launch -p docker ubuntu:16.04 lxc-docker
lxc-docker を作成中
lxc-docker を起動中
```

## プロファイルを使用しない場合

プロファイルを使用しない場合は`-p docker`なしでコンテナを作成します。

```shell
$ lxc launch ubuntu:16.04 lxc-docker
lxc-docker を作成中
lxc-docker を起動中
```

この場合、profile ではなくコンテナの config を修正します。

```
$ lxc config edit lxc-docker
```

とすると設定の YAML を編集するエディタが立ち上がるので、先ほどの profile で指定したように、config に以下を追加します。

```shell
  raw.lxc: |-
    lxc.mount.auto=proc:rw sys:rw cgroup:rw
    lxc.cgroup.devices.allow=a
    lxc.cap.drop=
  security.privileged: "true"
  security.nesting: "true"
```

同様に編集が終われば`Ctrl+o`で書き込み保存先を確認して`Enter`、`Ctrl+x`で終了です。
通常の機能追加は即座に反映されるのですが、これはコンテナの再起動が必要でした。

```
$ lxc restart lxc-docker
```

そしてコンテナの中に入ります。

```shell
$ lxc exec lxc-docker bash
```

## Docker をインストール

普通に Docker をインストールします。
https://docs.docker.com/install/linux/docker-ce/ubuntu/

```
# apt update && apt upgrade -y
# apt install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
# apt update
# apt-get install -y docker-ce docker-ce-cli containerd.io
# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

## docker-composeのインストール
docker-composeのバイナリを直接ダウンロードしてしまいます。

```console
# curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
```

## 特権コンテナでない場合

ちなみに最初のコンテナ起動時に特権を与えないと docker 起動時に以下のようなエラーが出ます。

```
~# docker run hello-world
docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused "process_linux.go:424: container init caused \"rootfs_linux.go:58: mounting \\\"proc\\\" to rootfs \\\"/var/lib/docker/vfs/dir/0ad32bb78a811c940c3df11dc0c7cf9f06f09e914df8a834a3165bddd5716a7d\\\" at \\\"/proc\\\" caused \\\"permission denied\\\"\"": unknown.
ERRO[0005] error waiting for container: context canceled
```

エラーメッセージを読むと/proc をマウントしようとして権限エラーなので"lxc.mount.auto=proc:rw"の設定はなくてもいいかも？

本日は以上です。