闇の深いEC2を、EBSボリューム経由で、闇の深いDockerコンテナに転換する

みなさんDocker使ってますか。私は闇の深いEC2に阻まれて難しい状況です。闇を抱えたままDockerizeします。

# 闇が深いとは

このくらいを指すものとします。

- AMIの出所がわからない
    - EC2インスタンスのAMI IDが、自前AMIになってる
    - Linuxディストリはわかるが、起点にしたバージョンはわからない
- AMIがどうやってできたのかわからない
    - sudo vi /etc/hoge.conf してるっぽい
    - sudo yum install -y hoge してるっぽい
    - wget https://~~~~/hoge.tar.gz から make install してるっぽい
- AMI更新手順がわからない
    - 変更したい人々と、変更できる人々が違っている
    - 実施できるのは、本番環境にSSHできる極少人数
    - 簡単なはずのconfの変更も尻込みして進まない
- Dockerize & k8s移行とか盛り上がるけど、遠すぎて動きが鈍い

AWS使っててもこれよりヤバい現場や、オンプレでさらにヤバい現場はいくらでもあるでしょうけど、一旦このくらいで。

# Dockerコンテナ化したいEC2インスタンスを用意し、闇の深いEBSボリュームをデタッチする

闇の深いEC2インスタンスを用意します。NDAの都合で手頃なEC2インスタンスがないので、Amazon Linux1の最新のAMIからEC2インスタンスを作成して、でっちあげます。後の動作確認のため、説明上のサンプルの闇として、$HOMEにテキストファイルを設置しておきました。

```bash
[ec2-user@ip-172-16-12-85 ~]$ pwd
/home/ec2-user
[ec2-user@ip-172-16-12-85 ~]$ echo "hello world" > hoge.txt
[ec2-user@ip-172-16-12-85 ~]$ cat hoge.txt
hello world
[ec2-user@ip-172-16-12-85 ~]$ 
```

キモはDockerizeしたいEC2インスタンスのEBSボリュームです。これをどうにか調達できるなら、AMIからでも何でも大丈夫です。

# Dockerコンテナイメージ作成用EC2インスタンスを作る

注意事項は以下くらいを守れば雑で大丈夫です。

* 先程のEBSスナップショットと同じアベイラビリティゾーンに、EC2インスタンスを作成する
* LinuxなEC2インスタンスを作成する
* ストレージ増し(たとえばgp2で20GB)、グレード上げ(t3.small)など雑で構わないので強めに作成する
* EC2にIAMロールをつけておく。ECRにpush,pullできる権限をつけておく。

```bash
[ec2-user@ip-172-16-4-210 ~]$ sudo yum update -y
[ec2-user@ip-172-16-4-210 ~]$ sudo yum install docker
[ec2-user@ip-172-16-4-210 ~]$ sudo reboot
```
```bash
[ec2-user@ip-172-16-4-210 ~]$ sudo systemctl start docker.service
[ec2-user@ip-172-16-4-210 ~]$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[ec2-user@ip-172-16-4-210 ~]$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
```

# 闇の深いEBSボリュームを、Dockerコンテナイメージ作成用EC2インスタンスにアタッチする

AWSマネジメントコンソールで、ポチポチしてアタッチします。EC2インスタンス内でディレクトリを作成して、mountします。

```bash
[root@ip-172-16-4-210 ec2-user]# mkdir /mnt/darkness-ebs
[root@ip-172-16-4-210 ec2-user]# mount /dev/nvme1n1p1 /mnt/darkness-ebs
[root@ip-172-16-4-210 ec2-user]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        961M     0  961M   0% /dev
tmpfs           978M     0  978M   0% /dev/shm
tmpfs           978M  436K  978M   1% /run
tmpfs           978M     0  978M   0% /sys/fs/cgroup
/dev/nvme0n1p1   20G  1.5G   19G   8% /
tmpfs           196M     0  196M   0% /run/user/1000
/dev/nvme1n1p1  7.9G  1.1G  6.7G  14% /mnt/darkness-ebs
[root@ip-172-16-4-210 ec2-user]#
```

# EBSの中身で、Dockerコンテナイメージを作る

マウントポイントにEBSの中身がまるごと入ってますので、これでDockerコンテナイメージを作ります。怪しいのが出てますが、いったん気にしない。

```bash
[root@ip-172-16-4-210 ec2-user]# cd /mnt/darkness-ebs
[root@ip-172-16-4-210 darkness-ebs]# tar -c -C /mnt/darkness-ebs/ . | docker import - darkness-image
tar: ./var/run/acpid.socket: socket ignored
tar: ./var/run/dbus/system_bus_socket: socket ignored
sha256:b141609cf9664a07dc17371b8d6545e16d921c809a6cd845da66d119c85fe92f
[root@ip-172-16-4-210 darkness-ebs]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
darkness-image      latest              b141609cf966        8 seconds ago       1.04GB
[root@ip-172-16-4-210 darkness-ebs]# 
```

# Dockerコンテナを起動する

Dockerコンテナイメージを作れたので、起動してみましょう。正しくできているなら、 `/home/ec2-user/hoge.txt` の中身が闇の深いものになっているはずです。

```bash
[root@ip-172-16-4-210 darkness-ebs]#  docker run -itd darkness-image /bin/bash
6d326fb4879e3a3015116e3215bfe8c2376d7fc16abea0b60ec112e333d6fc52
[root@ip-172-16-4-210 darkness-ebs]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
6d326fb4879e        darkness-image      "/bin/bash"         11 seconds ago      Up 9 seconds                            ecstatic_sinoussi
[root@ip-172-16-4-210 darkness-ebs]# docker exec -it 6d326fb4879e /bin/bash
[root@6d326fb4879e /]# cd /home/ec2-user/
[root@6d326fb4879e ec2-user]# ls -alF hoge.txt
-rw-rw-r-- 1 ec2-user ec2-user 12 Oct 14 07:29 hoge.txt
[root@6d326fb4879e ec2-user]# cat hoge.txt
hello world
[root@6d326fb4879e ec2-user]# 
```

よさげ。

# DockerイメージをAWS ECRに登録する

Docker Hubにパブリックイメージとして登録できれば、取り回しも楽なのですが、ここまでの手順を踏まなければならないような状況のDockerイメージが、パブリックにできるわけもないです。ECRに登録しましょう。

```bash
[root@ip-172-16-4-210 darkness-ebs]# aws ecr get-login --no-include-email --region us-east-2
[root@ip-172-16-4-210 darkness-ebs]# docker login -u AWS -p (略)
[root@ip-172-16-4-210 darkness-ebs]# docker tag darkness-image:latest 841403573067.dkr.ecr.us-east-2.amazonaws.com/darkness-image:latest
[root@ip-172-16-4-210 darkness-ebs]# docker push 841403573067.dkr.ecr.us-east-2.amazonaws.com/darkness-image:latest
The push refers to repository [841403573067.dkr.ecr.us-east-2.amazonaws.com/darkness-image]
fd32b2439881: Pushed
latest: digest: sha256:814254568e93795d20a91c2e28dc6dcdeffe6975e960b8f1c68bb5890593b65c size: 529
[root@ip-172-16-4-210 darkness-ebs]#
```

# Dockerfileで利用する

ECRからのpullが若干煩雑ですが、それだけなんとかすれば、なんとでもなります。

```bash
[root@ip-172-16-4-210 darkness-ebs]# aws ecr get-login --no-include-email --region us-east-2
[root@ip-172-16-4-210 darkness-ebs]# docker login -u AWS -p (略)
```

あとは、いつものDockerfileで好きなように。

```bash
[root@ip-172-16-4-210 ~]# cat Dockerfile
FROM darkness-image:latest
RUN echo "hello world"
CMD /bin/bash
[root@ip-172-16-4-210 ~]# docker build -t darkness-image:1.0.0 .
Sending build context to Docker daemon  16.38kB
Step 1/3 : FROM darkness-image:latest
 ---> b141609cf966
Step 2/3 : RUN echo "hello world"
 ---> Running in aa28eeffae4f
hello world
Removing intermediate container aa28eeffae4f
 ---> d2a56a7ba2e1
Step 3/3 : CMD /bin/bash
 ---> Running in 44a51a617196
Removing intermediate container 44a51a617196
 ---> edc94cc0c123
Successfully built edc94cc0c123
Successfully tagged darkness-image:1.0.0
[root@ip-172-16-4-210 ~]#
```

ECRにpushしたら、各所で使えるようになります。

```
[root@ip-172-16-4-210 ~]# docker tag darkness-image:1.0.0 841403573067.dkr.ecr.us-east-2.amazonaws.com/darkness-image:1.0.0
[root@ip-172-16-4-210 ~]# docker push 841403573067.dkr.ecr.us-east-2.amazonaws.com/darkness-image:1.0.0
The push refers to repository [841403573067.dkr.ecr.us-east-2.amazonaws.com/darkness-image]
fd32b2439881: Layer already exists
1.0.0: digest: sha256:15a5a58ba521936180f67f12f36c311a498b477e436e7e3f7bd0c9274437e661 size: 530
[root@ip-172-16-4-210 ~]#
```

# ローカル開発環境で利用する

ECRからのpullが若干煩雑ですが、それだけなんとかすれば、なんとでもなります。

```bash
sasasin@mbp2018:~$ aws ecr get-login --no-include-email --region us-east-2
sasasin@mbp2018:~$ docker login -u AWS -p (略)
sasasin@mbp2018:~$ docker run -itd darkness-image:1.0.0 /bin/bash
```

# デーモンプロセスをどうにかする

ECRまでのpushを優先するため `/bin/bash` にしてますが、実際のところ何かデーモンプロセスが常駐して、たぶん `sysvinit`, `upstart`, `systemd` あたりのはず。どうにかがんばる必要があります。Dockerコンテナ内で `sysvinit`, `upstart`, `systemd` を動かすのもそれなり大変なので、おとなしく `supervisord` にするのが無難かと思います。

突貫にやるなら、コンテナ起動時に呼ぶ `/sbin/bootstrap.sh` みたいなのを用意すれば十分かもしれません。中身はたとえばこのように。

```bash
#!/bin/bash
/sbin/service nginx start
/sbin/service puma start
/sbin/service crond start
```

# Dockerfileを改善していく

Dockerfileにできたことで、

* DockerfileとしてGitHub管理できるようになる
* ローカル環境などで、挙動の検証がやりやすくなる
    * セキュリティパッチ入れたときとか
    * confを変更したときとか
    * 何かインストールしてみたときとか
* Dockerコンテナを動かせるところなら、どこでも動かせる
    * ECS, EKS など
    * 他のパブリッククラウドに移設してもよい

などなど、手のつけられないEC2インスタンスが、手のつけられるようになります。闇を抱えながらも、前進することができるようになります。Dockerizeしていきましょう。