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


目的

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

コード

対応概要

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

DinD 環境構築のポイント

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

ダウンロード

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

インストール(準備)

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

pip install -r requirements.txt

direnv のインストール

sh bin/install_direnv.sh

ログインシェルの再起動

direnv インストール後、.bashrc に追記されるので、
読み込むためにシェルを再起動する。(. ~/.bashrc としても良い)

DinD コンテナのビルド&起動

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 コンテナの起動確認

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コンテナcontainer1container2 の中で、docker コマンドが実行できることを確認する。

dind$ ls
Dockerfile  LICENSE  README.md  bin  container1  container2  docker-compose.yml  rc  requirements.txt
dind$ 
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 コマンドの確認

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

docker-compose コマンドの確認

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:~$ 

コンテナ実行の終了

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

コンテナのリモート操作

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

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

DOCKER_HOST 環境変数の確認

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

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

SSH接続

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

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.
[email protected]'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_hostsecdsaを含む行(最終行)を削除するか、known_hosts の行をすべて削除することで、再接続できるようになる。

DinD 環境の全削除

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

$ 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