docker-composeを使って一瞬でLAMP環境を作る方法(SSL化も)

[こちら](https://red-full-moon.com/lamp-by-docker-compose/)により見やすい記事も用意しました。
よろしければどうぞー

### 1.概要
---
本記事で出来るようになること
1コマンドで

- Nginx(SSL化用リバースプロキシ)
- MariaDB
- CentOS7
    - Apache
    - php
 
のコンテナが下記の簡略図で立ち上がり、gitかなにかでwebアプリコンテンツをDocumentRootに置けば、すぐに使えるようになります。

簡略図
![2018-4-24_18-42-59_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/125791/513bb4c4-a874-592f-3dc8-4ce6228c75b6.png)

本稿のレベルとしては
「dockerとdocker-composeが何なのかはなんとなく知ってるけど、あんまり使ったことない人」向けです。

それぞれの基本知識としては下記を斜め読みすれば十分だと思います。

- dockerについて
    - [【入門】Dockerとは？使い方と基本コマンドを分かりやすく解説します](https://www.kagoya.jp/howto/rentalserver/docker/)
- docker-composeについて
    - [複数のDockerコンテナを自動で立ち上げる構成管理ツール「Docker Compose」](https://knowledge.sakura.ad.jp/5736/)

俺はさっさと環境ができれば、どうだっていいんじゃーって人は
3.実施方法までで実施できます。
各機能の詳細や、詳細な関係が気になる人は最後まで読んでね。

### 2.動作環境
---
#### 2-1.【重要】ローカル環境
##### 2-1-1. CentOS Linux release 7.4.1708 (Core)
下記で示すDockerとdocker-composeのバージョンさえ合ってればなんでもいいです。
macOS High Sierra 10.13.4でも動作確認済みですが、本記事はCentOSでの実施手順です。

##### 2-1-2. Docker version 18.03.0-ce, build 0520e24

```sh:dockerインストール手順
$ cd /etc/yum.repos.d/ 
# dockerリポジトリを追加
$ sudo wget https://download.docker.com/linux/centos/docker-ce.repo
# インストール
$ sudo yum install docker-ce
# dockerの起動
$ sudo systemctl start docker
# docekrの自動起動設定
$ sudo systemctl enable docker
# ユーザーでdockerが使えるようにグループ設定
$ sudo groupadd docker
$ sudo gpasswd -a $USER docker
# docker再起動
$ sudo systemctl restart docker
# バージョン確認
$ docker -v
> Docker version 18.03.0-ce, build 0520e24
```

##### 2-1-3. docker-compose version 1.20.1, build 5d8c71b 以上

```sh:docker-composeインストール手順
# 資材ダウンロード
$ sudo curl -L https://github.com/docker/compose/releases/download/1.20.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 実行権限を付与
$ sudo chmod +x /usr/local/bin/docker-compose
# バージョン確認
$ docker-compose -v
> docker-compose version 1.20.1, build 5d8c71b
```

#### 2-2. 【任意】DDNSへの登録(ドメイン)
おすすめは[MyDNS](https://www.mydns.jp/)です。
任意のドメインを入手しておいてください。
後述しますが、hogehoge.mydns.jpなど人気なドメインは避けたほうが良いです。

### 3.実施方法
---
さてさてお待たせしました。
実施方法です。
(といってもここからが本番です)

カレントディレクトリは任意ですが、ユーザーディレクトリがいいと思います。
カレントディレクトリに下記のようなファイルを構築します。

```
.
├── db
│   ├── Dockerfile
│   ├── init.d/
│   ├── init.s/
│   ├── my.cnf
│   └── vol/
├── docker-compose.yml
└── web
    ├── Dockerfile
    ├── conf
    │   └── httpd.conf
    ├── html/
    └── php.ini
```

#### 3-1. docker-compose.yml
docker-compose.ymlはyml形式で書かれたファイルで、名前の通りdocker-composeの設定ファイルです。
ここで各種dockerコンテナ(今回はCentOSとNginx、MariaDB)の設定を記述します。

```yml:docker-compose.yml
# docker-composeのバージョン宣言
version: '2'
services:
  # MariaDBの設定
  maria:
    # Dockerfileの場所
    build: ./db
    # コンテナ名の定義
    container_name: maria
    # 環境変数の設定 docker runの-eオプションに対応
    environment:
      # MariaDBのrootユーザーのパスワード
      MYSQL_ROOT_PASSWORD: hogehoge
    # データ保存場所指定
    volumes:
      # データベースの永続化を定義
      - ./db/vol:/var/lib/mysql
      # データベースの初期化スクリプト置き場
      - ./db/init.s:/docker-entrypoint-initdb.d
      # データベースの初期データ置き場
      - ./db/init.d:/var/lib/ram
    # 所属するネットワークとIPを指定
    networks:
      br0:
        ipv4_address: 192.168.200.2
  # httpdの設定
  httpd:
    # Dockerfuleの場所
    build: ./web
    # コンテナ名の定義
    container_name: httpd
    # データの保存場所
    volumes:
      # DocumentRootのホスト側とのリンク
      - ./web/html:/var/www/html
    # 直前の起動コンテナの設定
    depends_on:
      - maria
    # 所属するネットワークとIPを指定
    networks:
      br0:
        ipv4_address: 192.168.200.3
  #リバースプロキシの設定
  https-portal:
    # イメージの定義
    image: steveltn/https-portal:1
    # ポートフォワーディング
    ports:
      - '80:80'
      - '443:443'
    # NATの設定
    extra_hosts:
      - '"DDNSで取得したDNS":127.0.0.1'
    # コンテナ同士の接続
    links:
      - httpd
    # 環境変数の設定
    environment:
      # 本番用
      DOMAINS: '"DDNSで取得したDNS" -> http://httpd'
      STAGE: 'production'
    # 所属するネットワークとIPを指定
    networks:
      br0:
        ipv4_address: 192.168.200.4
# 新規ブリッチを定義
networks:
  br0:
    driver: bridge
    ipam:
      config:
      - subnet: 192.168.200.0/24
        gateway: 192.168.200.1
```

#### 3-2. db/Dockerfile

```yml:db/Dockerfile
# ベースイメージを定義
FROM mariadb:5.5
# my.cnfを定義
COPY ./my.cnf /etc/
```

#### 3-3. web/Dockerfile

```yml:web/Dockerfile
# 元とするイメージ名
FROM centos:latest
# 各種ミドルウェア
RUN yum install -y php | true 
RUN yum install -y php-mysql | true
RUN yum install -y net-tools | true
RUN yum update -y
# 各種設定ファイルのコピー
COPY ./conf/httpd.conf /etc/httpd/conf/
COPY ./php.ini /etc/
# ポートの解放
EXPOSE 80
# httpdの起動
CMD /usr/sbin/httpd -DFOREGROUND
```

#### 3-4. 各種設定ファイル

- db/my.cnf
    - 普段のmariaDBで使用してるものを用意
- web/conf/httpd.conf & web/php.ini
    - こちらも普段使用しているapacheの設定ファイルと、php.iniファイルを用意
- web/html/*
    - デプロイしたいwebアプリの資材をここに入れてください

**5.デプロイ**
さて、いよいよコンテナの立ち上げです。
docker-compose.ymlがあるディレクトリまで移り

```bash
# コンテナの一層立ち上げ
$ docker-compose up -d --build
# 動作の確認
$ docker ps -a
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                                      NAMES
60c73d6a06f2        steveltn/https-portal:1   "/init"                  8 hours ago         Up 8 hours          0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   dockerlamp_https-portal_1
7af11daaa0f9        dockerlamp_httpd          "/bin/sh -c '/usr/sb…"   8 hours ago         Up 8 hours          80/tcp                                     httpd
ac12e8c7ce8c        dockerlamp_maria          "docker-entrypoint.s…"   8 hours ago         Up 8 hours          3306/tcp                                   maria
```

となれば、完了!!
取得したドメイン名でアクセスして、アプリの動作を確認してください。

#### 4.Q&A
---
- コンテナが正常に起動しない
  - `$ docker-compose logs`で各種コンテナの状況が確認できます
- 証明書の発行時にドメイン上限に引っかかって発行できない
  - 今回の証明書はletsencryptを使用してます
  - 人気ドメインでの取得場合、証明書の制限で発行できない可能性があります
      - [「letsencrypt」のSSLサーバ証明書発行枚数制限](http://readderr.blogspot.jp/2017/04/letsencryptssl.html)

#### 5. 詳細
---
##### 5-1.ネットワーク関係
序盤に簡単なネットワーク構成を書きましたが実際にはこんな感じ

![2018-4-24_18-42-45_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/125791/50269229-b4d8-bda8-1e1c-2b4f358ceaac.png)

NginxとmariaDBとCentOSベースのコンテナの3つが起動してます。
NginxとmariaDBは設定内容が簡単なことから分かる通り、そのまま使用しています。
CentOSのコンテナのみweb/Dockerfileでyumを使った初期インストールでApacheやphpを導入しています。
(そこを変更すればpythonだって環境を作ることが可能です)

コンテナ同士はdocker-compose.ymlの最後に記したネットワーク内での相互通信を行っています。

インターネット(外部)との通信はdocker-compose.ymlのNginxの部分で設定した部分(port) で定義しており、
ローカルマシンの対応するポートとポートフォワーディングで通信を行っています。
また今回はlet’s encryptではなくオレオレ証明書でアクセスでアクセスすることも可能です。
[既存環境に手を加えずにサクッとHTTPS化する (NAT配下でもok)](https://amaya382.hatenablog.jp/entry/2017/04/02/002746)

さらに、docker-compose.ymlからhttps-portalの設定を全削除して、webでポートフォワーディングを設定すればDDNSも不要になります。

#### 5-2. オプションディレクトリの説明
3章で空のディレクトリを複数作りましたが、それぞれ役割があります。
##### 5-2-1. db/init.s
docker-compose.ymlの`./db/init.s:/docker-entrypoint-initdb.d`にも書いてありますが
init.sに入れたファイルはmariaのコンテナのdocker-entrypoint-initdb.dにコピーされます。
コンテナ側のdocker-entrypoint-initdb.dというディレクトリは特殊で
ここに入れられたshファイルや、sqlファイルはコンテナ立ち上げ時にアスキーコード順に実行されます。
なので、ここにはDBの初期データを流し込むスクリプトファイルなどを入れます。
##### 5-2-2. db/init.d
docker-compose.ymlの`./db/init.d:/var/lib/ram`にも書いてありますが
init.dに入れたファイルはmariaのコンテナの/var/lib/ramにコピーされます。
ここは単純にコピーされるだけなので
init.sで実施されるスクリプトが読みに来るDBのダンプデータなどを入れます。
##### 5-2-3. db/vol
ここはDBのデータそのものが入ります。
テーブルスキームや、カラムの値などが入っています。
ここのデータをコピーしておけばバックアップとして使えます。

### 6.終わり
---
よきdockerライフを!!

ブログ始めました、よかったら遊びに来てください
https://red-full-moon.com/