Docker環境を構築する


# はじめに
最近管理ツール系をいちいちAnsibleなどで構築するのも面倒になってきたのでDockerでちゃちゃっと作れるようにしたいなと思ってきた。
とりあえず[中井さんの本](https://www.amazon.co.jp/Docker%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80%E2%80%95%E2%80%95Linux%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E5%BF%9C%E7%94%A8%E3%81%BE%E3%81%A7-%E4%B8%AD%E4%BA%95%E6%82%A6%E5%8F%B8-ebook/dp/B015IZT854)の本を読んで、DockerサーバーとDockerレジストリ環境を構築したのでメモしておく。

# 環境
- Centos7.2

# Dockerサーバー構築
## インストール
Centosのデフォルトのリポジトリにdockerのパッケージはあるので、yumでインストールしてあげればおk。

```
$ sudo yum -y install docker
$ sudo systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: http://docs.docker.com
$ 
```

## 起動してみる
systemctlで起動できる。

```
$ sudo  systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: active (running) since 金 2016-06-17 16:33:48 JST; 1s ago
     Docs: http://docs.docker.com
 Main PID: 1315 (sh)
   CGroup: /system.slice/docker.service
           ├─1315 /bin/sh -c /usr/bin/docker-current daemon $OPTIONS            $DOCKER_STORAGE_OPTIONS            $DOCKER_NETWORK_OPTIONS            $A...
           ├─1316 /usr/bin/docker-current daemon --selinux-enabled
           └─1317 /usr/bin/forward-journald -tag docker

 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.596617886+09:00" level=warning msg="Running modprobe bridge br_netfilte...
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.611868786+09:00" level=info msg="Firewalld running: false"
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.680960068+09:00" level=info msg="Default bridge (docker0) is ass...ddress"
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.770856879+09:00" level=info msg="Loading containers: start."
 6月 17 16:33:48 docker-server forward-journal[1317]: 
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.771113423+09:00" level=info msg="Loading containers: done."
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.771257480+09:00" level=info msg="Daemon has completed initialization"
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.771286359+09:00" level=info msg="Docker daemon" commit="ab77bde/...n=1.9.1
 6月 17 16:33:48 docker-server forward-journal[1317]: time="2016-06-17T16:33:48.783647539+09:00" level=info msg="API listen on /var/run/docker.sock"
 6月 17 16:33:48 docker-server systemd[1]: Started Docker Application Container Engine.
Hint: Some lines were ellipsized, use -l to show in full.
$
```

## 使ってみる
ここではDocker社が運用しているPublicの[DockerHub](https://hub.docker.com/)からコンテナイメージを取得したイメージを基にDockerfileで新たなイメージを作成して起動してみる。
ここでは Officialなリポジトリである `Nginx` のイメージを利用する。

### イメージのダウンロード

```
$ docker search --stars=1000 nginx # starが1000個以上あるものだけをsearch
INDEX       NAME              DESCRIPTION                STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/nginx   Official build of Nginx.   3260      [OK]       
$ docker pull docker.io/nginx # 最新版のイメージをローカルにダウンロード
$ docker images # ローカルのイメージ一覧
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
docker.io/nginx     latest              89732b811e7f        2 weeks ago         182.7 MB
$ 
```

### Dockerfileからのイメージのbuild
Dockerfileを使ってnginxの起動やコンテンツの配置を定義してやる。
先ほどダウンロードした `docker.io/nginx` をベースに `nginx` を起動して `/bin/bash` を起動するDockerfileは以下となる。

```nginx/Dockerfile
FROM docker.io/nginx
MAINTAINER akito1986
ADD index.html /usr/share/nginx/html/index.html
ADD init.sh /usr/local/bin/init.sh
RUN chmod +x /usr/local/bin/init.sh
CMD ["/usr/local/bin/init.sh"]
```

起動スクリプトは以下。
コンテナ停止時にnginxも止めるようにしている。

```nginx/init.sh
#!/bin/bash
nginx

cat <<EOF >>~/.bashrc
trap "pkill -TERM nginx; sleep 3; exit 0" TERM
EOF
exec /bin/bash
```

コンテンツは以下。

```nginx/index.html
HOGEHOGE
```

以下のコマンドでイメージを作成できる。
中間イメージが作成されていることがわかる。

```
$ docker build -t akito1986/nginx:v0.1 nginx/
Sending build context to Docker daemon 4.096 kB
Step 1 : FROM docker.io/nginx
 ---> 89732b811e7f
Step 2 : MAINTAINER Akito Ueno
 ---> Running in e8be994a1190
 ---> 1128103d931a
Removing intermediate container e8be994a1190
Step 3 : ADD index.html /usr/share/nginx/html/index.html
 ---> cf111ae19c91
Removing intermediate container 3314abbb377d
Step 4 : ADD init.sh /usr/local/bin/init.sh
 ---> ad1f38c9eb8d
Removing intermediate container 36a02891945e
Step 5 : RUN chmod +x /usr/local/bin/init.sh
 ---> Running in 4ec8fcb465f1
 ---> 40452263c6db
Removing intermediate container 4ec8fcb465f1
Step 6 : CMD /usr/local/bin/init.sh
 ---> Running in 5c0573098338
 ---> 1d5c6562d9af
Removing intermediate container 5c0573098338
Successfully built 1d5c6562d9af
$
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
akito1986/nginx     v0.1                1d5c6562d9af        11 minutes ago      182.7 MB
docker.io/nginx     latest              89732b811e7f        2 weeks ago         182.7 MB
$
```

`akito1986/nginx` というイメージが作成されているのがわかる。

### コンテナの起動
以下のコマンドで先ほど作成したイメージからnginxという名前のコンテナを起動する。また `-p` オプションでポートフォワーディング設定をしており、これはDockerサーバーの `port:8080` をコンテナの `port:80` に転送している。
`-d` オプションを指定することでバックグラウンドで実行してくれる。

```
$ docker run -itd --name nginx -p 8080:80 akito1986/nginx:v0.1
$ docker ps # /usr/local/bin/initスクリプトが実行されていることがわかる
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                           NAMES
c5ca19c89f2e        akito1986/nginx:v0.1   "/usr/local/bin/init."   18 minutes ago      Up 18 minutes       443/tcp, 0.0.0.0:8080->80/tcp   nginx
$ 
$ curl http://localhost:8080/ # 実際にアクセスしてみる
HOGEHOGE
$
```


# Dockerレジストリ構築
次にDockerのイメージを保存するためのプライベートDockerレジストリを構築してみる。

## Install
Dockerレジストリは epelパッケージに入っているので以下のコマンドを実行することでDockerレジストリはインストールできる。

```
$ sudo yum -y install epel-release
$ sudo yum -y install docker-registry python-sqlalchemy
```

## DBファイル格納用のディレクトリ作成

```
$ mkdir -p /var/lib/docker-registry
```

## 設定変更
### Dockerレジストリ
データーベースファイルのパスと、データベースクライアントを指定する。

```/etc/sysconfig/docker-registry
SEARCH_BACKEND=sqlalchemy # 追加
```

```/etc/docker-registry.yml
sqlalchemy_index_database: _env:SQLALCHEMY_INDEX_DATABASE:sqlite:////var/lib/docker-registry/docker-registry.db # 変更
```

### Dockerサーバー 
Private環境のDockerレジストリを利用できるように以下のように設定を追記する。
`docker-registry` はアクセス可能なDockerレジストリサーバーのIPなりFQDNなりに読み替える。

```/etc/sysconfig/docker
ADD_REGISTRY='--add-registry docker-registry:5000'
INSECURE_REGISTRY='insecure-registry docker-registry:5000'
```

### サービス起動
#### Dockerレジストリ
以下のコマンドでDockerレジストリを起動する。

```
$ sudo systemctl start docker-registry.service
```

#### Dockerサーバー
以下のコマンドでDockerサーバーを再起動する。

```
$ sudo systemctl restart docker.service
```

以下のコマンドでDockerレジストリに接続できているかを確認する。
エラーが発生しなければ接続できている。

```
$ docker search docker-registry:5000/nginx
INDEX     NAME      DESCRIPTION   STARS     OFFICIAL   AUTOMATED
$
```

### イメージファイルのDockerレジストリへの登録
先ほど作成したイメージファイルをプライベートのDockerレジストリにpushしてみる。
まずは先ほど作成したイメージにプライベートDockerレジストリ用の名前を付与してやる。

```
$ docker tag akito1986/nginx:v0.1 docker-registry:5000/akito1986/nginx:v0.1
$ docker images
akito1986/nginx                        v0.1                1d5c6562d9af        31 hours ago        182.7 MB
docker-registry:5000/akito1986/nginx   v0.1                1d5c6562d9af        31 hours ago        182.7 MB
$
```

同じイメージIDの別名のイメージが作成されたのがわかる。
さてこれでpushする準備が整ったので以下のコマンドで構築したDockerレジストリにpushしてやる。
中間イメージも登録されているのがわかる。

```
$ docker push docker-registry:5000/akito1986/nginx:v0.1
The push refers to a repository [docker-registry:5000/akito1986/nginx] (len: 1)
Sending image list
Pushing repository docker-registry:5000/akito1986/nginx (1 tags)
23286f48d129: Image successfully pushed 
cbee5247e891: Image successfully pushed 
358fca72eb67: Image successfully pushed 
70f682aa6f8b: Image successfully pushed 
d92c26bdbb83: Image successfully pushed 
f10563ca252d: Image successfully pushed 
b96018ff7ebe: Image successfully pushed 
89732b811e7f: Image successfully pushed 
1128103d931a: Image successfully pushed 
cf111ae19c91: Image successfully pushed 
ad1f38c9eb8d: Image successfully pushed 
40452263c6db: Image successfully pushed 
1d5c6562d9af: Image successfully pushed 
Pushing tag for rev [1d5c6562d9af] on {http://docker-registry:5000/v1/repositories/akito1986/nginx/tags/v0.1}
$
```

以下のコマンドで実際にDockerレジストリに登録されているのがわかる。

```
$ docker search docker-registry:5000/nginx
INDEX             NAME                                   DESCRIPTION   STARS     OFFICIAL   AUTOMATED
docker-registry   docker-registry:5000/akito1986/nginx                 0                    
$
```

# おわりに
結構すんなり環境構築ができた。
今度はもともとの目的の管理系サーバーをDockerで構築して運用してみる。