Ubuntu18.04 のDinD:Docker in Docker 環境を複数構築する

# 目的

DinD(Docker in Docker) は、alpine のイメージがほとんどで、Ubuntu18.04 対応の DinD イメージがなかったので、作成する。（Docker Hub に登録されているのは、Ubuntu 16.04と古いイメージをベースとしている。）
セミナー、教育用の環境や同じ環境で複数の処理を実行したい場合などに重宝するので、広く利用できるように記事としてまとめておく。

# コード
- https://github.com/tkosht/dind

# 対応概要

- 日本語対応(ja_JP.UTF-8)
- 日本時刻対応(Asia/Tokyo)
- Pythonのインストール
- 一般ユーザ(sudo, docker)を追加
- dockerコンテナへのSSH接続許可
- dockerコンテナのリモート操作

# DinD 環境構築のポイント

- 要は、`Dockerfile` 内の`ENTRYPOINT ["wrapdocker"]`
- `docker-compose.yml` 内の buildで、 `args`に `PORT`変数を指定
    - `Dockerfile`内で、EXPOSE する（リモート操作用）
    - `docker-compose.yml` 内で、ポートフォワーディングはなくてもよい
- `docker-compose.yml` で、`privileged`、`tty` を `true` にセット
    - `tty: true`は、常駐化させるため
- 各DinD コンテナの利用切り替えを、`cd` でできるように、`direnv` を利用
    - 合わせて、`docker-compose.yml` 内で、volume を設定

# ダウンロード

```bash
git clone https://github.com/tkosht/dind.git
cd dind
```

# インストール（準備）

## Python ライブラリのインストール

```bash
pip install -r requirements.txt
```

## direnv のインストール

```bash
sh bin/install_direnv.sh
```
## ログインシェルの再起動
`direnv` インストール後、`.bashrc` に追記されるので、
読み込むためにシェルを再起動する。（`. ~/.bashrc` としても良い）

# DinD コンテナのビルド＆起動

```bash
dind$ sh bin/reup.sh
Removing network dind_net                                                                            
WARNING: Network dind_net not found.                            
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] Total reclaimed space: 0B         
container2 uses an image, skipping                                         
Building container1                                                                 
Step 1/32 : FROM ubuntu:18.04                                                    
 ---> 4c108a37151f                                                             

: (snip)

Successfully tagged ubuntu:container
Creating network "dind_net" with driver "bridge"
Creating container1 ... done
Creating container2 ... done
invoke-rc.d: could not determine current runlevel
 * Restarting OpenBSD Secure Shell server sshd                                                                             [ OK ]
invoke-rc.d: could not determine current runlevel
 * Restarting OpenBSD Secure Shell server sshd                                                                             [ OK ]
dind$
```

## DinD コンテナの起動確認

```bash
dind$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                            NAMES
2d81b85143a6        ubuntu:container    "wrapdocker"        10 seconds ago      Up 6 seconds        22/tcp, 0.0.0.0:7275->2375/tcp   container2
714ec5314490        ubuntu:container    "wrapdocker"        14 seconds ago      Up 10 seconds       22/tcp, 0.0.0.0:7175->2375/tcp   container1
dind$ 
```

## DinD コンテナの利用

各DinDコンテナ`container1`、`container2` の中で、`docker` コマンドが実行できることを確認する。

```bash
dind$ ls
Dockerfile  LICENSE  README.md  bin  container1  container2  docker-compose.yml  rc  requirements.txt
dind$ 
```

```bash
dind$ cd container1/
direnv: loading .envrc
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

user@714ec5314490:~$ 
```

### docker コマンドの確認

```bash
user@714ec5314490:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
user@714ec5314490:~$ 
```

### docker-compose コマンドの確認

```bash
user@2b32d40addb9:~$ docker-compose version
docker-compose version 1.24.1, build 4667896
docker-py version: 3.7.3
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.1  11 Sep 2018
user@2b32d40addb9:~$ 
```

### コンテナ実行の終了

```bash
user@2b32d40addb9:~$ exit
exit
direnv: export +DOCKER_HOST +SSH
$ 
```

### コンテナのリモート操作
exit 後の`container1`、`container2` ディレクトリで、`docker` コマンドを実行すると対応するDinDコンテナに対して、dockerコマンドによりリモート操作できる。

```bash
container1$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
container1$ 

```

#### DOCKER_HOST 環境変数の確認

より正確には、`DOCKER_HOST` 環境変数に対応するコンテナにdocker コマンド経由で、リモート操作している。

```bash
container1$ env | egrep HOST
DOCKER_HOST=tcp://192.168.200.11:2375
container1$ 
```

### SSH接続

各コンテナに対応する ssh 接続するためのコマンドが`SSH` 環境変数に保存されているため、`$SSH` と実行するだけで、SSH接続できる。
初回アクセス時は、本当に接続してよいか聞いてくるので、`yes` と答える。
次に、パスワードを聞かれるので、`user` と入力する。（ユーザ名と同じ）

```bash
container1$ $SSH
The authenticity of host '192.168.200.11 (192.168.200.11)' can't be established.
ECDSA key fingerprint is SHA256:XZMmmbEyAIS2Fdf6kWf+yjK8x3bBbd+roVGc8rtrynI.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.200.11' (ECDSA) to the list of known hosts.
user@192.168.200.11's password:
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-54-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.

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.

user@2b32d40addb9:~$ 
```

ここで、イメージを削除して再度SSH接続すると、$HOME/.ssh/known_hosts の情報と変わっていることによるセキュリティエラーが発生する。このエラーに対しては、`known_hosts` の`ecdsa`を含む行（最終行）を削除するか、`known_hosts` の行をすべて削除することで、再接続できるようになる。


# DinD 環境の全削除

DinD 環境が不要になったときは、削除用コマンド`bin/clean.sh` を実行する。

```bash
$ sh bin/clean.sh 
Removing container2 ... done
Removing container1 ... done
Removing network dind_net
Removing image ubuntu:container
Removing image ubuntu:container
WARNING: Image ubuntu:container not found.
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] Deleted Volumes:
858243556e6f314d76a2ef1b95740adf6827ee06d1a82c10a8ca9e1ec5d5117a
d61be00fa200eb0b3430b32c968a1acb743234adf7e028c24fef2f5a4452f0e1

Total reclaimed space: 426kB
$ 
```


# 参考URL
- dind
https://blog.stormcat.io/post/entry/docker-dind-compose/

- timezone
https://qiita.com/hashibiroko/items/38046a42b6d0461491d0

- encoding
https://qiita.com/YuukiMiyoshi/items/f389ea366060537b5cd9

- sudo
http://akuwano.hatenablog.jp/entry/20120302/1330656001