書籍「Dockerによるアプリケーション開発環境構築ガイド」part3 Baseimage-dockerを使った1コンテナでの複数サービス管理

# はじめに

以下の書籍の演習をやったので、そのまとめ。
Docker初心者でも実際に手を動かしながら、Dockerの概念や基本を学ぶことが出来るので良本だと思います。演習のホストOSはCentOS7で試しています。


書名：[Dockerによるアプリケーション開発環境構築ガイド](https://www.amazon.co.jp/Docker%E3%81%AB%E3%82%88%E3%82%8B%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%82%AC%E3%82%A4%E3%83%89-%E6%AB%BB%E4%BA%95-%E6%B4%8B%E4%B8%80%E9%83%8E/dp/4839964580)
著者：櫻井 洋一郎, 村崎 大輔 (著)

### 関連
[[part1] docker基本コマンド](https://qiita.com/s_szk/items/fa9512d0d5c28e7deaa3)
[[part2] Dockerfile記述方法](https://qiita.com/s_szk/items/f02d7981e12ad7ae33cf)

#Baseimage-dockerとは
一つのコンテナに複数のサービスを動かすことに適したベースイメージ（初心者に使いやすいらしい）
特徴

- Ubuntuベース
- initプロセスを使っている
- syslog, cronがインストール済み
- スーパーバイザRunit（コンテナ内で複数の子プロセスを管理するもの）がインストール済み
- SSHサーバ関連の設定済み


#Baseimage-dockerを使ってみる
###イメージのpull

```
[root@testvm WordPress]# docker pull phusion/baseimage:latest
Trying to pull repository docker.io/phusion/baseimage ... 
latest: Pulling from docker.io/phusion/baseimage
281a73dee007: Pull complete 
2aea1b77cff7: Pull complete 
59a714b7d8bf: Pull complete 
0218064da0a9: Pull complete 
ebac621dcea3: Pull complete 
a3ed95caeb02: Pull complete 
b580731643cc: Pull complete 
faa5fbdba239: Pull complete 
Digest: sha256:29479c37fcb28089eddd6619deed43bcdbcccf2185369e0199cc51a5ec78991b
Status: Downloaded newer image for docker.io/phusion/baseimage:latest
[root@testvm WordPress]# docker images
REPOSITORY                    TAG                       IMAGE ID            CREATED             SIZE
docker.io/phusion/baseimage   latest                    166cfc3f6974        22 months ago       209 MB
```

###コンテナの起動
-itオプションにより、出力結果ではinitとサービスが立ち上がった後に入力待ちになる。


```
[root@testvm SampleData_20180518]# docker run --rm -it docker.io/phusion/baseimage
*** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
*** Running /etc/my_init.d/10_syslog-ng.init...
Nov 25 08:19:18 5e4b21077ccf syslog-ng[10]: syslog-ng starting up; version='3.5.6'
Nov 25 08:19:18 5e4b21077ccf syslog-ng[10]: WARNING: you are using the pipe driver, underlying file is not a FIFO, it should be used by file(); filename='/dev/stdout'
Nov 25 08:19:19 5e4b21077ccf syslog-ng[10]: EOF on control channel, closing connection;
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 16
Nov 25 08:19:19 5e4b21077ccf cron[19]: (CRON) INFO (pidfile fd = 3)
Nov 25 08:19:19 5e4b21077ccf cron[19]: (CRON) INFO (Running @reboot jobs)
```

bashコマンドを指定して立ち上げた場合は、Baseimage-dockerのinitを経由しないため、以下の通りbashのプロンプトが表示される。
Baseimage-dockerでは実行コマンドを指定しない場合、独自のinitプログラムである`/sbin/my_init`を実行するようになっている。

```
[root@testvm SampleData_20180518]# docker run --rm -it docker.io/phusion/baseimage bash -l
root@58ea53aff93b:/# 
```

以下の場合は`my_init`を経由してからbashのプロセスを立ち上げることができる
この場合、指定したコマンド（bash）の終了時にmy_initもシャットダウン処理を実行してから終了するようになっている。

```
[root@testvm SampleData_20180518]# docker run --rm -it docker.io/phusion/baseimage /sbin/my_init -- /bin/bash -l
*** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
*** Running /etc/my_init.d/10_syslog-ng.init...
Nov 25 08:24:43 321da8daacc0 syslog-ng[10]: syslog-ng starting up; version='3.5.6'
Nov 25 08:24:43 321da8daacc0 syslog-ng[10]: WARNING: you are using the pipe driver, underlying file is not a FIFO, it should be used by file(); filename='/dev/stdout'
*** Running /etc/rc.local...
Nov 25 08:24:44 321da8daacc0 syslog-ng[10]: EOF on control channel, closing connection;
*** Booting runit daemon...
*** Runit started as PID 16
*** Running /bin/bash -l...
Nov 25 08:24:44 321da8daacc0 cron[21]: (CRON) INFO (pidfile fd = 3)
Nov 25 08:24:44 321da8daacc0 cron[21]: (CRON) INFO (Running @reboot jobs)
root@321da8daacc0:/# 
```

###コンテナ内部のプロセスの確認

```
root@321da8daacc0:/# ps axwf
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /usr/bin/python3 -u /sbin/my_init -- /bin/bash -l
   10 ?        S      0:00 /usr/sbin/syslog-ng --pidfile /var/run/syslog-ng.pid -F --no-caps
   16 ?        S      0:00 /usr/bin/runsvdir -P /etc/service
   18 ?        Ss     0:00  \_ runsv cron
   21 ?        S      0:00  |   \_ /usr/sbin/cron -f
   19 ?        Ss     0:00  \_ runsv sshd
   17 ?        S      0:00 /bin/bash -l
   34 ?        R+     0:00  \_ ps axwf
```

PID16の`/sur/bin/runsvdir`がスーパバイザの大元のプロセス。
ここから`runsv`を経由してcronやsshdを立ち上げている。

```
root@321da8daacc0:/# sv status cron sshd
run: cron: (pid 21) 443s
down: sshd: 443s
root@321da8daacc0:/# ls /etc/service/cron/
run  supervise
root@321da8daacc0:/# ls /etc/service/sshd/
down  run  supervise
```

cronはPID21で実行中、sshdは停止していることがわかる。
サービスの自動起動の設定は`/etc/service/サービス名`の下に`down`が有るか無いかで制御されている。
`sv down`, `sv up`でサービスの開始、終了ができる。

```
root@321da8daacc0:/# sv down cron
root@321da8daacc0:/# ps axwf
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /usr/bin/python3 -u /sbin/my_init -- /bin/bash -l
   10 ?        S      0:00 /usr/sbin/syslog-ng --pidfile /var/run/syslog-ng.pid -F --no-caps
   16 ?        S      0:00 /usr/bin/runsvdir -P /etc/service
   18 ?        Ss     0:00  \_ runsv cron
   19 ?        Ss     0:00  \_ runsv sshd
   17 ?        S      0:00 /bin/bash -l
   41 ?        R+     0:00  \_ ps axwf
root@321da8daacc0:/# sv up cron
root@321da8daacc0:/# Nov 25 08:36:13 321da8daacc0 cron[48]: (CRON) INFO (pidfile fd = 3)
Nov 25 08:36:13 321da8daacc0 syslog-ng[10]: WARNING: you are using the pipe driver, underlying file is not a FIFO, it should be used by file(); filename='/dev/stdout'
Nov 25 08:36:13 321da8daacc0 cron[48]: (CRON) INFO (Skipping @reboot jobs -- not system startup)

root@321da8daacc0:/# ps axwf
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /usr/bin/python3 -u /sbin/my_init -- /bin/bash -l
   10 ?        S      0:00 /usr/sbin/syslog-ng --pidfile /var/run/syslog-ng.pid -F --no-caps
   16 ?        S      0:00 /usr/bin/runsvdir -P /etc/service
   18 ?        Ss     0:00  \_ runsv cron
   48 ?        S      0:00  |   \_ /usr/sbin/cron -f
   19 ?        Ss     0:00  \_ runsv sshd
   17 ?        S      0:00 /bin/bash -l
   49 ?        R+     0:00  \_ ps axwf
```

#Dockerイメージを構築する

```
[root@testvm 03-my-wordpress]# cat Dockerfile 
FROM phusion/baseimage:0.10.0
[root@testvm 03-my-wordpress]# docker build -t my-wordpress .
Sending build context to Docker daemon 2.048 kB
Step 1/1 : FROM phusion/baseimage:0.10.0
Trying to pull repository docker.io/phusion/baseimage ... 
0.10.0: Pulling from docker.io/phusion/baseimage
281a73dee007: Already exists 
2aea1b77cff7: Already exists 
59a714b7d8bf: Already exists 
0218064da0a9: Already exists 
ebac621dcea3: Already exists 
a3ed95caeb02: Already exists 
b580731643cc: Already exists 
faa5fbdba239: Already exists 
Digest: sha256:d72f41957bf41161c2b7ec00ed665573d17e8dfaaef55492063901a7e844532a
Status: Downloaded newer image for docker.io/phusion/baseimage:0.10.0
 ---> 166cfc3f6974
Successfully built 166cfc3f6974
```

```
[root@testvm 03-my-wordpress]# pwd
/root/SampleData_20180518/Chapter03/03-my-wordpress
[root@testvm 03-my-wordpress]# docker run --rm -it -v "$(pwd):/build" -w /build my-wordpress bash -l
root@87cebe41806d:/build# 
```

`-v "$(pwd):/build"`：カレントディレクトリとコンテナ内の/buildを同期（アクセス可能に）する
`-w /build `：コンテナ内の作業用ディレクトリを`/build`に指定する
コンテナ内では`/sbin/my_init bash -l`が実行される。

下記のApache, Mysql, PHP 7をインストールしLAMP環境を構築するスクリプトを、ホストのカレントディレクトリ/scripts配下に作成して、コンテナ内の/build/scripts配下のスクリプトとして認識させる。

```
[root@testvm SampleFile]# cat 3-3-2-1/01-provisioning-install-packages.sh 
#!/bin/bash

# シェルの動作を設定する
#   -e: コマンドがエラーになった時点でエラー終了する
#   -u: 未定義変数を参照した場合にエラー終了する
#   -x: 実行されるコマンドを引数を展開した上で表示する
set -eux

# インストールするパッケージのリスト
INSTALL_PACKAGES="\
    apache2 \
    language-pack-ja \
    libapache2-mod-php7.0 \
    mysql-server-5.7 \
    php7.0 \
    php7.0-mbstring \
    php7.0-mysql \
    php7.0-opcache \
    tzdata \
"

# パッケージのインストール時に、対話形式のユーザーインタフェースを抑制する
export DEBIAN_FRONTEND=noninteractive

# 日本国内のミラーサイトを使うようにし、ソースインデックスは取得しない
sed -i \
    -e 's,//archive.ubuntu.com/,//jp.archive.ubuntu.com/,g' \
    -e '/^deb-src /s/^/#/' \
    /etc/apt/sources.list

# パッケージリストを取得する
apt-get update

# パッケージをインストールする
apt-get install -y --no-install-recommends ${INSTALL_PACKAGES}
```

```
[root@testvm 03-my-wordpress]# mkdir scripts
[root@testvm 03-my-wordpress]# cp ../SampleFile/3-3-2-1/01-provisioning-install-packages.sh scripts/
[root@testvm 03-my-wordpress]# ls scripts/
01-provisioning-install-packages.sh
```

同様に以下のタイムゾーン設定用のスクリプトもscripts/配下に作成する

```
[root@testvm 03-my-wordpress]# cat ../SampleFile/3-3-2-2/02-provisioning-set-locales.sh 
#!/bin/bash

set -eux

# 設定するタイムゾーンのファイル
LOCALTIME_FILE=/usr/share/zoneinfo/Asia/Tokyo

# パッケージのインストール時に、対話形式のユーザーインタフェースを抑制する
export DEBIAN_FRONTEND=noninteractive

# ロケールを日本語にセットするが、メッセージ出力は翻訳しない
update-locale LANG=ja_JP.UTF-8 LC_MESSAGES=C

# 前のスクリプトでtzdataがインストールされていることを確認する
if [ ! -f "${LOCALTIME_FILE}" ] ; then
    echo "${LOCALTIME_FILE} does not exist."
    exit 1
fi

# タイムゾーンを日本時間にセットする（Ubuntu 16.04での設定方法）
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
dpkg-reconfigure tzdata
```

#####用意したスクリプトをコンテナbuild時に実行するようにする
以下のDockerfileでbuildしてみる

```
[root@testvm 03-my-wordpress]# cp ../SampleFile/3-3-2-3/Dockerfile ./
cp: overwrite ‘./Dockerfile’? y
[root@testvm 03-my-wordpress]# cat Dockerfile 
FROM phusion/baseimage:0.10.0
WORKDIR /build/

COPY scripts/*-provisioning-*.sh scripts/

# パーミッションをセットしてからスクリプトを実行する
RUN chmod 755 scripts/*.sh \
    && scripts/01-provisioning-install-packages.sh \
    && scripts/02-provisioning-set-locales.sh
```

```
[root@testvm 03-my-wordpress]# docker build -t my-wordpress .
Sending build context to Docker daemon 6.144 kB
Step 1/4 : FROM phusion/baseimage:0.10.0
 ---> 166cfc3f6974
Step 2/4 : WORKDIR /build/
 ---> b6bd0914b57e
Removing intermediate container d365ecdc7999
Step 3/4 : COPY scripts/*-provisioning-*.sh scripts/
 ---> a96386217bd0
Removing intermediate container c8bb054c08e8
Step 4/4 : RUN chmod 755 scripts/*.sh     && scripts/01-provisioning-install-packages.sh     && scripts/02-provisioning-set-locales.sh
 ---> Running in 1dd602fe24d5

+ INSTALL_PACKAGES='    apache2     language-pack-ja     libapache2-mod-php7.0     mysql-server-5.7     php7.0     php7.0-mbstring     php7.0-mysql     php7.0-opcache     tzdata '
+ export DEBIAN_FRONTEND=noninteractive
+ DEBIAN_FRONTEND=noninteractive
+ sed -i -e s,//archive.ubuntu.com/,//jp.archive.ubuntu.com/,g -e '/^deb-src /s/^/#/' /etc/apt/sources.list
+ apt-get update
Get:1 http://jp.archive.ubuntu.com/ubuntu xenial InRelease [247 kB]
Get:2 http://jp.archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB]
Get:3 http://jp.archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB]

（〜以下省略〜　パッケージがインストールされる）

Removing intermediate container 1dd602fe24d5
Successfully built 8dcc6e2dabe7
```