「WordPress」で「docker-compose」の理解を深めた勉強会

# 概要
現場で`docker-compose`を使っており、復習も兼ねて勉強会で取り上げてみました。まず、勉強会には`docker`やコンテナの概念が微妙な方もいらっしゃったため、まずは`WordPress`を使ってコンテナに接続して、まずは触れてもらいながら学習してもらうことにしました。その学習内容を記事にまとめさせていただきます。

勉強会自体はかなりボリュームになってしまい上記は前半の初心者向けの内容となります。なお後半は`docker-compose`で`Node.js(Express)`と`PostgresSQL`を使用した簡単なサービスを作成しました。こちらは初めてチャレンジしたモノで、それはそれで面白かったのでそちらの内容も別の記事にて投稿予定です。

それでは以降からは学習内容のまとめになります。

# そもそもdockerって何？コンテナって何？

`VirtualBox`との比較がわかりやすかったりします。以下はさくらナレッジの記事を引用です。

> VirtualBoxなどの仮想マシンでは、ホストマシン上でハイパーバイザを利用しゲストOSを動かし、その上でミドルウェアなどを動かします。それに対し、コンテナはホストマシンのカーネルを利用し、プロセスやユーザなどを隔離することで、あたかも別のマシンが動いているかのように動かすことができます。

https://knowledge.sakura.ad.jp/13265/

と説明を受けても若干イメージしづらいのが正直なところです。以下のような現実での例で説明してみました。

- `VirtualBox`などの仮想マシン：一軒家
- `Docker`などのコンテナ：マンションの１室

あと、仮想マシンは触ったことがある人が多かったので以下のような説明もしました。

- 仮想環境をアプリケーションごとに分けたいな～と思います～
- そのときに共通で使用できそうなOSなどを新しく別に作るのはダルいよね～
- アプリケーションの部分だけ別の環境として作りたいよね～
- それを実現したのが`docker`やコンテナだと思います～

# dockerのコンテナってどうやって作られているの？

まずはdocker-hubにあるOfficialのイメージをみてもらいました。いろんなサービスのコンテナのイメージがあり、自分が使いたいプログラミング言語やデータベースのイメージを使用することですぐに動作できる環境を準備できます。

- 例：Node.jsを使いたい！
  - Node.jsのイメージを使えばNode.jsを動作できる環境を作れる！

そもそも`docker`のコンテナやイメージってどうやって作られているかという話ですがほとんどが`Dockerfile`になると思います。実はOfficialイメージから各バージョンごとの`Dockerfile`を確認することができます。

- Node 14 の Dockerfile
  - https://github.com/nodejs/docker-node/blob/18ed56ea9ba03c16f48372927f5eb2553033e8de/14/stretch/Dockerfile

もし独自にコンテナあるいはイメージを作成したい場合には`Dockerfile`を作ればよいわけです。また既存のイメージから拡張したい内容を`Dockerfile`に追加することも可能です。

# 複数のサービスを連携してこそのコンテナ

１つのサービスを実行するだけだと普通の仮想マシンと変わりません。やはりコンテナ同士で連携するサービスを構築することで真価が出ると思います。口だけでいうと伝わらないと思ったので、お試しに`docker-compose`で`WordPress`を実行してもらいました。

### docker-composeって何？
１つだけのサービスなら`Dockerfile`だけで問題ありませんが、複数のコンテナの連携になると`docker-compose`が良いです。

### WordPressって何？
`WordPress`は`PHP`で作られているCMS（コンテンツ管理システム）でサイトの内容を保存するために`MySQL`を使用します。詳細については割愛させていただきますが、「`PHP`が動作する環境」と「`MySQL`のデータベース」を準備する必要があります。今回は必要な２つの環境を`docker-compose`で構築します。

# docker-composeでWordPressを動かす

#### docker-compose.yml

```yaml
version: '2'
services:
   db:
     image: mysql:5.7
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:
     image: wordpress:latest
     depends_on:
       - db
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress
```

#### 実行内容

```bash
docker-compose build
docker-compose up -d
```

### 実行内容に関する説明

まずは実行内容の`build`でコンテナを作成します。実のところ今回の場合は特に意味はありません。ただし自分で`Dockerfile`を作成した場合は`build`した方がよいです。直接`up`した場合でもイメージがなければ`build`が実行されます。

ここで気を付けてほしいのが以前に`build`したコンテナがある場合はそのコンテナを実行します。例えばDockerfileで読み込むプログラムを更新した場合でも`up`だと以前のコンテナを実行するので、更新したプログラムが取り込まれないまま実行されます。新しい状態を作り直す意味でも`build`をすることを意識しておいて損はありません。

#### docker-compose -d の -d って何？
`-d`をつけるとバックグラウンドで動作します。逆につけない場合は実行したコンソールでコンテナが稼働するため、実行したコンソールでは他の作業ができなくなります。もし`-d`をつけ忘れて停止させたいよ～ってなった場合は、`Windows`の方は`Ctrl`+`C`、`Mac`の方は`Control`+`C`で停止させることができます。

### docker-compose.ymlに関する説明
注意すべきポイントを抜粋して説明します。

#### WordPressのポート設定

まずはポートの設定を確認します。

```yaml
   wordpress:
   # ～省略～ #
     ports:
       - "8000:80"
```

右がコンテナのポートで左がホストのポートです。ホストというのは今自分が操作しているでありコンテナを動かしている端末です。この設定では`WordPress`のコンテナのポート80を、ホストのポート8000に転送しています。これは`WordPress`自体がデフォルトの設定ではポート80に転送されており、それをホストのポート8000に転送しています。
この設定により自分の端末（ホスト）のブラウザから http://localhost:8000 でアクセスすることができます。

最初の頃は何がどうポート転送されているか把握しづらいのが正直なところです。このシンプルな構成でも`WordPress`のデフォルトのポートが80であることを知らなければ、なぜ`8000:80`になっているかわからないまま進むことになるので、１つずつ説明しながら理解を深めてもらいました。

### 環境変数を確認する

環境変数を確認します。

```yaml
   db:
     # ～省略～ #
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:
     # ～省略～ #
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress
```

元のコンテナイメージですでに使用されている環境変数を上書きすることができます。

今回は`MySQL`というデータベースを使用しており、データベースのパスワードの場合は`MYSQL_PASSWORD`という環境変数を設定することでパスワードの内容を上書き・変更することができます。使うコンテナのイメージごとに設定されいている環境変数は異なりますので調べる必要はあります。環境変数の調べ方ですがサンプルなどで見つかったりするのと、ちゃんと調べる場合にはコンテナイメージのリポジトリなどを確認するとよいと思います。

今回使う`MySQL`のコンテナイメージのリポジトリを調べてみると`docker-entrypoint.sh`で`MYSQL_PASSWORD`を使っていることが確認できました。

https://github.com/docker-library/mysql/blob/bc6e37a2bed792b1c4fc6ab1ec3ce316e6a5f061/5.7/docker-entrypoint.sh

`MySQL`の場合は`MYSQL_ROOT_PASSWORD`などの環境変数を設定することで、データベース・ユーザーの作成などを自動的に行ってくれるようです。これらの設定は`docker`のコンテナの中に入ったときに改めて確認します。

### コンテナの中に入ってみる

#### コンテナの中に入る

コンテナの中に入ってみます。今回はデータベースのコンテナに入ります。

```bash
docker-compose exec db bash
```


もし`Windows`の方で以下のようなメッセージが表示された場合は、`winpty`を頭につければコンテナに入ることができます。

```bash
the input device is not a TTY.  If you are using mintty, try prefixing the command with 'winpty'

winpty docker-compose exec db bash
```

#### コンテナ内のデータベース(mysql)に接続する

コンテナの中に入った後は以下のコマンドを実行します。
（root@eb769a915d4d:/# は入力しないでください）

```
root@eb769a915d4d:/# mysql -U wordpress -D wordpress -p
```

これは`MySQL`のデータベースに接続しようとしています。`-U`はユーザー名、`-D`はデータベース名を示し、`-p`でパスワードを使用します。ここの設定は`docker-compose.yml`の環境変数で設定したモノになり、ユーザー名などを忘れてしまった場合には`docker-compose.yml`を確認するとよいと思います。
この実行後パスワードを入力するよう求められるので`wordpress`と入力します。

```bash
Enter password:
```

パスワードは入力中の内容が他の人から見られないよう入力したい内容が表示されません。間違ってしまった場合（間違ったような気がした場合）は`backspace`で消しきるか、`Ctrl`+`C`などで抜けてもう一度`MySQL`の接続からやり直してみてください。パスワードの入力が正しくできていればデータベースに接続できているはずです。

#### データベースのテーブルを確認する

テーブルの確認をしてみます。
（mysql> は入力しないでください）

```bash
mysql> show tables;
```

まだ`WordPress`の設定されていないのでテーブルは何も作成されていない状態です。

```bash
Empty set (0.00 sec)
```

#### データベースから抜ける ＆ コンテナから抜ける

以下のコマンドでデータベースから抜けます。
（mysql> は入力しないでください）

```bash
mysql> \q
```

データベースから抜けるとコンテナの中に入っている状態になりますので以下のコマンドでコンテナから抜けます。
（root@eb769a915d4d:/# は入力しないでください）

```bash
root@eb769a915d4d:/# exit
```

#### WordPressを設定する

自分のパソコンのブラウザを開いて http://localhost:8000/ に接続します。
接続したら日本語を選択して画面を参考にしながら設定しましょう。
今回は`WordPress`で何かサイトを作るわけではないので適当に設定します。

<img width="1127" alt="WordPressの設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/370c73ca-b04f-5ff1-ce9f-d1789794dd5f.jpeg">

<img width="644" alt="WordPressの設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/4fca73c7-93e9-676b-9baa-38d99c2ae79d.jpeg">

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/215a7f8e-1e5c-2fc6-2726-268058f91e84.png)

無事に`WordPress`のインストールが完了できたら、改めてデータベースに接続してみます。


### WordPressインストール後にデータベースに接続する

いちいちコンテナの中に入ってからデータベースに接続するのは面倒だったりします。以下のコマンドで直接データベースに接続することも可能です。
（the input device is not a TTY. のメッセージが表示されたら頭に`winpty`をつけてください）

```bash
docker-compose exec db mysql -U wordpress -D wordpress -p
```

実行できた場合はパスワードを求められると思いますので`wordpress`と入力します。
データベースに接続できたらテーブルを取得してみましょう。

```bash
mysql> show tables;
+-----------------------+
| Tables_in_wordpress   |
+-----------------------+
| wp_commentmeta        |
| wp_comments           |
| wp_links              |
| wp_options            |
| wp_postmeta           |
| wp_posts              |
| wp_term_relationships |
| wp_term_taxonomy      |
| wp_termmeta           |
| wp_terms              |
| wp_usermeta           |
| wp_users              |
+-----------------------+
12 rows in set (0.00 sec)
```

`WordPress`のインストールによって必要なテーブルが作成されていることが確認できます。更にユーザーのテーブルを確認してみましょう。

```bash
mysql> select * from wp_users \G ;
*************************** 1. row ***************************
                 ID: 1
         user_login: test
          user_pass: $P$BTqvOi17OHGROkW0ukBzJk0W356aVu0
      user_nicename: test
         user_email: test@test.com
           user_url: http://localhost:8000
    user_registered: 2020-06-23 07:25:13
user_activation_key:
        user_status: 0
       display_name: test
1 row in set (0.00 sec)
```

インストール時に設定したユーザー情報があることが確認できました。
確認できたら`\q`でデータベースから抜けてください。

### コンテナを停止させる

以下のコマンドでコンテナを停止させます。

```bash
docker-compose down
```

これでコンテナを停止させることができました。ただし停止するとデータベースの状態が初期化され`WordPress`の設定などはなくなります。コンテナのデータの永続性については注意する必要があります。永続化させたい場合は`docker-compose.yml`で`volumes`の設定を行うなど少し工夫が必要になります。今回は学習内容が多くなってしまうので割愛させていただきます。

# 学習内容をまとめてみた結果

内容自体は既存の`WordPress`というサービスを使ってみるだけのカンタンなモノですが`docker-compose`を理解しながらとなると学習量は多いと感じました。今回の勉強会ではかなりボリュームがあるとの感想をいただいたので、少し様子を見ながら勉強会の内容を分けていくことも検討しようかなと思います。
といいながらも何か理解しながら作り出すとドンドン進みたく性分なので、そこらへんを上手く付き合いながら取り組んでいきます。