Dockerの勉強会（ハンズオン）用のテキストをつくってみた - 応用編

# はじめに

- [前回](https://qiita.com/neriai/items/99de30f568e43727987f)に続いて開催してみました。
- 第2回としては、DockerfileやDocker Composeについて触れています。

# アジェンダ

## 目的とゴール

Dockerfileを使って、イメージを作成してみよう。
Docker Composeを用いて、複数のサーバを連携してみよう。

1. 前回の復習　※約10分
2. Dockerfileについて　※約20分
3. Docker Composeについて　※20分
4. 演習:使い勝手を考えてみよう　※約10分

## 進め方

- ノートパソコンを用意してください。（64bitマシンが必要です）
- ペアプログラミングでもかまいません。用意が難しいけど参加してみたい場合は、相談ください。
- 事前にDockerをインストールしておいてください。
    - Windows: https://www.docker.com/docker-windows
    - Mac: https://www.docker.com/docker-mac
- 事前にDocker Hubのアカウントを取得しておいてください。
    - https://hub.docker.com/
- 特に前提知識はありません。アジェンダに添って事前に予習していただいてもかまいません。
- 開始も終了も時間厳守にします。あまりにも中途半端な場合は宿題 or 次回持越とします。

# Dockerfileについて

## Dockerfileプロジェクトの作成

```
mkdir sample-dockerfile
```

## RSA公開鍵の配置

※ 事前に公開鍵および秘密鍵を作成してください。

```
mv ./sample-dockerfile/authorized_keys
```

## 共有フォルダの作成

```
mkdir ./sample-dockerfile/volumes
```

## 接続確認用のPHPファイルを作成

```
touch ./sample-dockerfile/volumes/index.php
```

```
echo "<?php echo phpinfo(); ?>" >> ./sample-dockerfile/volumes/index.php
```

## Dockerfileの作成

```
touch ./sample-dockerfile/Dockerfile
```

```
FROM centos:6
MAINTAINER Keita Neriai <neriai@hoge.co.jp>

# プロキシの設定
ENV http_proxy {プロキシURL}
ENV https_proxy {プロキシURL}
ENV ftp_proxy {プロキシURL}
ENV no_proxy=localhost,127.0.0.1,172.17.0.0/16

# yumのダウンロードのタイムアウトを5分に変更
RUN echo "timeout=300" >> /etc/yum.conf

# タイムゾーンを日本時間にする。
RUN echo 'ZONE="Asia/Tokyo"' > /etc/sysconfig/clock

# yumの初期設定
RUN yum clean all && yum -y update
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
RUN yum clean all

# 必要なソフトウェアのインストール
RUN yum install -y sudo syslog

# SSHのインストール
RUN yum install -y openssh-server
RUN sed -ri "s/^UsePAM yes/#UsePAM yes/" /etc/ssh/sshd_config
RUN sed -ri "s/^#UsePAM no/UsePAM no/" /etc/ssh/sshd_config

# SSH認証の設定
RUN mkdir -m 700 /root/.ssh
ADD authorized_keys authorized_keys
RUN mv authorized_keys /root/.ssh/authorized_keys
RUN chmod 600 /root/.ssh/authorized_keys && chown root:root /root/.ssh/authorized_keys

RUN chkconfig sshd on

# Apacheのインストール
RUN yum install -y httpd

# Apacheの初期設定
RUN sed -i -e 's/\#ServerName www.example.com:80/ServerName example-web-server.example.com/g' /etc/httpd/conf/httpd.conf

RUN chkconfig httpd on

# PHPのインストール
RUN yum -y --enablerepo=remi-php56 install \
php \
php-opcache \
php-devel \
php-mysql \
php-mcrypt \
php-phpunit-PHPUnit \
php-pecl-xdebug \
php-pecl-xhprof \
php-mbstring

# PHPの初期設定
RUN sed -i -e "s|^;expose_php =.*$|expose_php = Off|" /etc/php.ini
RUN sed -i -e "s|^;date.timezone =.*$|date.timezone = Asia/Tokyo|" /etc/php.ini
RUN sed -i -e "s|^;mbstring.language =.*$|mbstring.language = Japanese|" /etc/php.ini
RUN sed -i -e "s|^;mbstring.encoding_translation =.*$|mbstring.encoding_translation = On|" /etc/php.ini
RUN sed -i -e "s|^;mbstring.detect_order =.*$|mbstring.detect_order = auto|" /etc/php.ini
RUN sed -i -e "s|^;mbstring.substitute_character =.*$|mbstring.substitute_character = none|" /etc/php.ini

EXPOSE 22 80

ENTRYPOINT /etc/rc.d/init.d/sshd start && /etc/rc.d/init.d/httpd start && /bin/bash
```

## イメージのビルド

```
docker build --no-cache=true -t  neriai/sample-dockerfile:latest ./sample-dockerfile
```

## イメージの起動

```
docker run -v "/Users/neriai/Develops/docker/neriai/sample-dockerfile/volumes:/var/www/html/" -i -t -p 10022:22 -p 10080:80 neriai/sample-dockerfile:latest /bin/bash
```

## SSHの接続確認

```
ssh root@127.0.0.1 -p 10022 
```

# Docker Composeについて

## Docker Composeプロジェクトの作成

※ 以下のようなディレクトリおよびファイルを作成してください。

```
/sample-dockercompose
|--database
|  |--Dockerfile
|  |--authorized_keys
|  |--volumes
|  |  |--init.sh
|  |  |--init.sql
|--docker-compose.yml
|--web
|  |--Dockerfile
|  |--authorized_keys
|  |--volumes
|  |  |--index.php
```

## DatabaseイメージのDockerfileを作成

```
FROM centos:6
MAINTAINER Keita Neriai <neriai@hoge.co.jp>

# プロキシ設定
ENV http_proxy {プロキシURL}
ENV https_proxy {プロキシURL}
ENV ftp_proxy {プロキシURL}
ENV no_proxy=localhost,127.0.0.1,172.17.0.0/16

# yumのダウンロードのタイムアウトを5分に変更
RUN echo "timeout=300" >> /etc/yum.conf

# タイムゾーンを日本時間にする。
RUN echo 'ZONE="Asia/Tokyo"' > /etc/sysconfig/clock

# yumの初期設定
RUN yum clean all && yum -y update
RUN yum install -y http://repo.mysql.com/mysql-community-release-el6-4.noarch.rpm
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
RUN yum clean all

# 必要なソフトウェアのインストール
RUN yum install -y sudo syslog

# SSHのインストール
RUN yum install -y openssh-server
RUN sed -ri "s/^UsePAM yes/#UsePAM yes/" /etc/ssh/sshd_config
RUN sed -ri "s/^#UsePAM no/UsePAM no/" /etc/ssh/sshd_config

# SSH認証の設定
RUN mkdir -m 700 /root/.ssh
ADD authorized_keys authorized_keys
RUN mv authorized_keys /root/.ssh/authorized_keys
RUN chmod 600 /root/.ssh/authorized_keys && chown root:root /root/.ssh/authorized_keys

RUN chkconfig sshd on

# MySQLのインストール
RUN yum install -y mysql-community-server
RUN chkconfig mysqld on

# MySQLの初期設定
RUN echo "" >> /etc/my.cnf
RUN echo "[mysql]" >> /etc/my.cnf
RUN echo "default-character-set=utf8" >> /etc/my.cnf
RUN echo "" >> /etc/my.cnf
RUN echo "[client]" >> /etc/my.cnf
RUN echo "default-character-set=utf8" >> /etc/my.cnf

EXPOSE 22 3306

ENTRYPOINT /etc/rc.d/init.d/sshd start && /etc/rc.d/init.d/mysqld start && /bin/bash
```

## データベースの起動確認用のシェルおよびSQLファイルを作成

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

mysql -uroot < /tmp/init.sql
```

```sql:init.sql
CREATE DATABASE IF NOT EXISTS docker DEFAULT CHARACTER SET utf8;

GRANT ALL ON *.* TO 'root'@'%';

FLUSH PRIVILEGES;

CREATE TABLE IF NOT EXISTS docker.sample(id int, name varchar(20));

DELETE FROM docker.sample;

INSERT IGNORE INTO docker.sample (id, name) VALUES (1, "hoge");
INSERT IGNORE INTO docker.sample (id, name) VALUES (2, "fuga");
INSERT IGNORE INTO docker.sample (id, name) VALUES (3, "foo");
INSERT IGNORE INTO docker.sample (id, name) VALUES (4, "baa");
```

## データベースのRSA秘密鍵の配置

※ 事前に公開鍵および秘密鍵を作成してください。

```
mv ./sample-dockercompose/database/authorized_keys
```

## ウェブイメージのDockerfileの作成

※ 上記Dockerfileプロジェクトのものを流用してください。

## 接続確認用のPHPファイルを作成

```
touch ./sample-dockercompose/volumes/index.php
```

```php:index.php
<html>
<head>
<head>
<body>
    <div>
        <ul>
            <?php
                define('DATABASE_NAME', 'docker');
                define('PDO_CONNECT', 'mysql:host=172.18.0.1;port=13306;dbname=' . DATABASE_NAME);

                define('USER_NAME', 'root');
                define('PASSWORD', '');

                try {
                    $db = new PDO(PDO_CONNECT, USER_NAME, PASSWORD);
                    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

                    $query = $db->query('SELECT * FROM sample');
                    $sample = $query->fetchAll(PDO::FETCH_ASSOC);

                    foreach ($sample as $value) {
                            echo "<li>";
                            echo "ID:" . $value['id'] . "  " . "NAME:" . $value['name'];
                            echo "</li>";
                    }
                } catch(PDOException $e) {
                    echo $e->getMessage();
                    exit;
                }
                ?>
        </ul>
    </div>
</body>
```

## ウェブのRSA公開鍵の配置

※ 事前に公開鍵および秘密鍵を作成してください。

```
mv ./sample-dockercompose/web/authorized_keys
```

## docker-composeの設定

```
touch ./sample-dockercompose/docker-compose.yml
```

```yaml:docker-compose.yml
version: '2'
services:
  web:
    build: ./web
    ports:
      - "10022:22"
      - "10080:80"
    depends_on:
      - database
    volumes:
      - ./web/volumes:/var/www/html
    tty: true
    restart: always
  database:
    build: ./database
    expose:
        - "13306"
    ports:
      - "10023:22"
      - "13306:3306"
    volumes:
      - ./database/volumes:/tmp
    tty: true
    restart: always
```

## イメージをまとめてビルドする

```
docker-compose build
```

## docker-composeに設定されたイメージを起動する

```
docker-compose up
```

## データベースの起動確認用のシェルおよびSQLファイルを実行する

```
docker-compose exec database /bin/bash
```

```
sh /tmp/init.sh
```

## 起動を確認する

```
http://localhost:10080
```

## その他のコマンドを実行

```
docker-compose ps
docker-compose down
```

# 演習:使い勝手を考えてみよう

## Gitと連携したい

## コンテナを起動時にシェルやSQLを実行したい

※ ヒント：docker-entrypoint-initdb.d

## Dockerfileやdocker-compose.ymlなどのプロジェクトを管理したい