【初心者】WordPressのdocker-composeで何が行われているのか確認して、ひとつひとつ構築してみた

# 対象の読者について
コンテナ初心者向けとなります。
自分も今、コンテナを学習している初心者です。

# 書くこととその理由
WordPressをDocker Composeで超簡単に構築できますが、なにがどのように構築されているのかさっぱりわかりませんでした。
この記事では、WordPressをコンテナで構築するとき、Docker Composeを使う場合と使わない場合(ひとつひとつ手作業で行った場合)の、行われていることを詳しく見ていきたいと思います。
その中で、Dockerの基本的なコマンドやネットワークの作成、そしてボリュームのマウントについて見ていきたいと思います。

# 事前準備
環境と前提をお伝えします。

## 環境
本記事の環境は以下のとおりとなっております。
| 項目 | バージョン |
|:-|:-|
| OS |  CentOS 7 |
| Docker | 23.0.1 |
| Docker Compose | 2.4.1 |

## 前提
Docker EngineとDocker Composeはインストール済みの前提で話を進めます。

### (補足)Docker EngineとDocker Composeのインストール(CentOS)
CentOS 7において行った、Docker EngineとDocker Composeのインストール手順を、コマンドベースで簡単にメモしておきます。
※ネット上にインストール方法が複数掲載されていたため、自分の環境で成功した流れとなります。

#### (補足)Docker Engineのインストール
```text
$ sudo yum update

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

$ sudo yum install -y yum-utils

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

$ sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

$ sudo systemctl start docker

$ sudo systemctl enable docker

$ sudo docker --version
Docker version 23.0.1, build a5ee5b1
```

#### (補足)Docker Composeのインストール
```text
$ sudo curl -SL https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

$ sudo chmod +x /usr/local/bin/docker-compose

$ docker-compose --version
Docker Compose version v2.4.1
```

#### (補足)dockerグループに一般ユーザー追加
```text
$ sudo usermod -aG docker [一般ユーザー名]
```

## Dockerの現状確認
構築に入る前にDockerインストール直後のDockerの状態を確認しておきます。
```console
$ docker image ls # Dockerイメージはありません。
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

$ docker container ls -a # Dockerコンテナももちろんありません。
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

$ docker volume ls # Dockerのボリュームもありません。
DRIVER    VOLUME NAME

$ docker network ls # Dockerのネットワークはデフォルトで3つ作られています。
NETWORK ID     NAME      DRIVER    SCOPE
704184225f25   bridge    bridge    local
0ab7ffc72fa6   host      host      local
2eee63585150   none      null      local
```

# Docker Composeでの構築の場合
それではまずDocker Composeで超簡単にWordPressを作ってみたいと思います。
参考にしたドキュメントは以下になります。
[クィックスタート: Compose と WordPress](https://docs.docker.jp/compose/wordpress.html)

## 手順
公式ドキュメントと同じですので、スキップしていただいて問題ありません。
プロジェクトディレクトリは`project_wordpress`にしました。
```text
$ mkdir project_wordpress && cd project_wordpress
[project_wordpress]$ touch docker-compose.yml
[project_wordpress]$ vi docker-compose.yml # docker-compose.yml編集
[project_wordpress]$ cat docker-compose.yml
version: '3'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:

[project_wordpress]$ docker-compose up -d
[+] Running 34/34
 ⠿ db Pulled
(省略)
 ⠿ wordpress Pulled
(省略)
[+] Running 4/4
 ⠿ Network project_wordpress_default        Created 
 ⠿ Volume "project_wordpress_db_data"       Created 
 ⠿ Container project_wordpress-db-1         Started 
 ⠿ Container project_wordpress-wordpress-1  Started 
```
これだけで構築完了です。
`http://[ホスト名]:8000`にアクセスすると、WordPressの初期画面が出てきます。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252459/2b3195e5-298f-d7ca-ea96-f4e3188e5ecd.png">
でもこれじゃなにが起きているのかわからない。
確認していきます。

## 行われていること
### ログの確認
まずコンソールに表示されたログをちゃんと確認します。
```text:抜粋
 ⠿ Network project_wordpress_default        Created 
 ⠿ Volume "project_wordpress_db_data"       Created 
 ⠿ Container project_wordpress-db-1         Started 
 ⠿ Container project_wordpress-wordpress-1  Started 
```
`project_wordpress_default`というDockerネットワークが作られています。
`project_wordpress_db_data`というDockerボリュームが作られています。
`project_wordpress-db-1`というDBのコンテナがスタートしています。
`project_wordpress-wordpress-1`というWordPressのコンテナがスタートしています。

コマンドでも確認してみます。
### コマンド確認
```text
$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
wordpress    latest    29cf1d10dc09   8 days ago    615MB
mysql        5.7       be16cf2d832a   3 weeks ago   455MB

$ docker container ls -a
CONTAINER ID   IMAGE              COMMAND                   CREATED          STATUS          PORTS                                   NAMES
8cb7f5a09961   wordpress:latest   "docker-entrypoint.s…"   24 minutes ago   Up 24 minutes   0.0.0.0:8000->80/tcp, :::8000->80/tcp   project_wordpress-wordpress-1
bdd18a13020e   mysql:5.7          "docker-entrypoint.s…"   24 minutes ago   Up 24 minutes   3306/tcp, 33060/tcp                     project_wordpress-db-1

$ docker volume ls
DRIVER    VOLUME NAME
local     dc40f4bf1849138c97116b462ea5247b754baaea54960161b678307ff8de9e59
local     project_wordpress_db_data

$ docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
704184225f25   bridge                      bridge    local
0ab7ffc72fa6   host                        host      local
2eee63585150   none                        null      local
d328d2b4d339   project_wordpress_default   bridge    local
```
`docker image ls`からDBとWordPressのコンテナイメージがダウンロードされていることがわかります。
`docker container ls -a`からDBとWordPressのコンテナが実行されていることがわかります。これはコンソールログからもわかりました。
`dc40f4bf1849138c97116b462ea5247b754baaea54960161b678307ff8de9e59`と`project_wordpress_db_data`というDockerボリュームが作成されていることがわかります。
`project_wordpress_default`というDockerネットワークが作られていることがわかります。

### Dockerネットワークについて
これが一番わかりにくかったです。なぜなら、`docker-compose.yml`にネットワークの作成の定義が書かれていないからです。
結論から言うと、Docker Composeをすると、プロジェクトに対してひとつのネットワークが作成されます。
ドキュメント([Compose の ネットワーク機能networking](https://docs.docker.jp/compose/networking.html))に書かれていました。
引用します。

> デフォルトで Compose はアプリに対して１つの ネットワーク を作成します。サービス用の各コンテナはデフォルトのネットワークに接続し、そのネットワーク上で他のコンテナと相互に「 接続可能reachable 」になります。そして、コンテナ名と同じホスト名として、お互いが「 発見可能discoverable 」になります。

よって、`project_wordpress_default`というDockerネットワークは`project_wordpress`(作成したディレクトリ名)に基づいて作成され、DBコンテナとWordPressコンテナの両方から「接続可能」なネットワークとして作成されたことがわかります。

また以下のコマンドで、WordPressコンテナとDBコンテナに同じDockerネットワークが使用されていることがわかります。
DockerネットワークのIDを確認して、それがそれぞれのコンテナにアタッチされていました。
```text
$ docker network inspect project_wordpress_default
[
    {
        "Name": "project_wordpress_default",
        "Id": "d328d2b4d339140f90dda37da75c171c83ca8fc13981b7c050bb120776ffde19",
(省略)

$ docker container inspect bdd18a13020e | grep Network
            "NetworkMode": "project_wordpress_default",
        "NetworkSettings": {
            "Networks": {
                    "NetworkID": "d328d2b4d339140f90dda37da75c171c83ca8fc13981b7c050bb120776ffde19",

$ docker container inspect 8cb7f5a09961 | grep Network
            "NetworkMode": "project_wordpress_default",
        "NetworkSettings": {
            "Networks": {
                    "NetworkID": "d328d2b4d339140f90dda37da75c171c83ca8fc13981b7c050bb120776ffde19",
```

### Dockerボリュームについて
２つのボリュームが作成されていました。

`docker-compose.yml`に記載されている以下の部分があります。
```text:抜粋
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
```
```text:抜粋
volumes:
    db_data:
```
これは`db_data`というボリュームを作って、`mysql:5.7`イメージで作られるDBコンテナにアタッチする(マウントポイントは`/var/lib/mysql`)という記述ですね。


`dc40f4bf1849138c97116b462ea5247b754baaea54960161b678307ff8de9e59`というボリュームは、WordPressコンテナに接続されたボリュームとなります。
以下のコマンドで確認できました。

```text
$ docker container inspect 8cb7f5a09961 | grep volume
                "Type": "volume",
                "Source": "/var/lib/docker/volumes/dc40f4bf1849138c97116b462ea5247b754baaea54960161b678307ff8de9e59/_data",
```
`docker container inspect`コマンドでWordPressコンテナの詳細を表示し、その中でvolumeに関するところを`grep`で抜き出しました。
確かにWordPressコンテナに接続されていました。

ちなみに、`docker container inspect`コマンドでDBコンテナの詳細を表示すると、`db_data`がDBコンテナに接続されていることがわかります。
```text
$ docker container inspect bdd18a13020e | grep volume
                    "Type": "volume",
                "Type": "volume",
                "Source": "/var/lib/docker/volumes/project_wordpress_db_data/_data",
```

### Dockerイメージのダウンロードとコンテナの実行
`docker container run`コマンドでコンテナを実行しようとすると、もし土台となるイメージが無かった場合はダウンロードされます。
今回のDocker Composeでも同じことが行われています。
MySQLとWordPressのイメージは無かったためダウンロードが行われ、そこからDBコンテナとWordPressコンテナが実行されました。

また、`depends_on`句によって、`docker-compose up`した場合、DBコンテナが起動してからWordPressコンテナが起動するようになっています。
もし、`docker-compose stop`をした場合、WordPressコンテナが停止してからDBコンテナが停止します。

あと、それぞれのコンテナに`restart: always`が指定されていますが、こちらはホストOSが起動したときに常に再起動するというオプションです。

最後に、`environment:`句でコンテナに環境変数を渡しています。

## 削除
先ほど作ったものをすべて削除します。
```text
$ docker-compose down --volumes
[+] Running 4/4
 ⠿ Container project_wordpress-wordpress-1  Removed
 ⠿ Container project_wordpress-db-1         Removed
 ⠿ Volume project_wordpress_db_data         Removed
 ⠿ Network project_wordpress_default        Removed
```
Dockerイメージは残るので、下記コマンドで削除しました。
タグありのDockerイメージの一括削除です。
```text
$ docker rmi `docker images -f "dangling=false" -q`
```


# ひとつひとつ手作業でやった場合
では、Docker Composeを使用せずにWordPressをコンテナで構築してみます。
ひとつひとつ手作業で行ってみたいと思います。

## 手順
### Dockerネットワークの作成
DBコンテナとWordPressコンテナをつなぐDockerネットワークを作成します。
`project2_wordpress_default`という名前にしました。
```text
$ docker network create --driver bridge project2_wordpress_default
0626487a5a9dcc78ff5f34e64a97f2969e799f5c56bd00c89f027936031e95b9

$ docker network ls
NETWORK ID     NAME                         DRIVER    SCOPE
ef0af5aae626   bridge                       bridge    local
0ab7ffc72fa6   host                         host      local
2eee63585150   none                         null      local
0626487a5a9d   project2_wordpress_default   bridge    local
```

### ボリュームの作成
Dockerのボリュームを作成します。
ここではDBコンテナにアタッチするボリュームのみ作成します。(名前は`project2_wordpress_db_data`です)
WordPressコンテナのボリュームはWordPressコンテナを作成すれば自動的に作成されます。

```text
$ docker volume create --driver local --name project2_wordpress_db_data
project2_wordpress_db_data

$ docker volume ls
DRIVER    VOLUME NAME
local     project2_wordpress_db_data
```

### Dockerイメージのダウンロード
Dockerコンテナを走らせようとすれば、無いイメージはダウンロードされますが、ここではDockerイメージのダウンロードを個別に行ってみます。
```text
$ docker image pull wordpress
Using default tag: latest
latest: Pulling from library/wordpress
(省略)
Status: Downloaded newer image for wordpress:latest
docker.io/library/wordpress:latest

$ docker image pull mysql:5.7
5.7: Pulling from library/mysql
(省略)
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
wordpress    latest    29cf1d10dc09   9 days ago    615MB
mysql        5.7       be16cf2d832a   3 weeks ago   455MB
```
`IMAGE ID`を見てみると、Docker Composeのときにダウンロードしたイメージと同一であることがわかります。

### DBコンテナの作成と実行
DBコンテナをスタートさせます。
```
docker container run \
	--restart=always \
	--network=project2_wordpress_default \
	--volume=project2_wordpress_db_data \
    --name=project2_wordpress-db-1 \
	-e MYSQL_ROOT_PASSWORD=somewordpress \
	-e MYSQL_DATABASE=wordpress \
	-e MYSQL_USER=wordpress \
	-e MYSQL_PASSWORD=wordpress \
	-d mysql:5.7
```
* `--restart=always`は`docker-compose.yml`の中でも指定されていたオプションです。
* `--network=project2_wordpress_default`で作成したDockerネットワークをアタッチしています。
* `--volume=project2_wordpress_db_data`で作成したDockerボリュームをバインドマウントしています。
* `--name=project2_wordpress-db-1`でDBコンテナの名前を指定しています。これはWordPressコンテナから参照されます。
* `-e`オプションで環境変数を指定しています。これは`docker-compose.yml`でも指定されていたものです。
* `-d`でデタッチモードでスタートします。これがないとプロンプトが返ってきません。




WordPressコンテナをスタートさせます。
```text
$ docker container run \
	--restart=always \
	--network=project2_wordpress_default \
	--name=project2_wordpress-wordpress-1 \
	-e WORDPRESS_DB_HOST="project2_wordpress-db-1:3306" \
	-e WORDPRESS_DB_USER=wordpress \
	-e WORDPRESS_DB_PASSWORD=wordpress \
	-p 8000:80 \
	-d wordpress:latest
```
* `--restart=always`は`docker-compose.yml`の中でも指定されていたオプションです。
* `--network=project2_wordpress_default`で作成したDockerネットワークをアタッチしています。
* `--name=project2_wordpress-wordpress-1`でWordPressコンテナの名前を指定しています。
* `-e`オプションで環境変数を指定しています。`docker-compose.yml`で指定していたものと同じですが、`WORDPRESS_DB_HOST="project2_wordpress-db-1:3306"`だけはDBコンテナの名前(ホスト名)を直で指定しています。
* `-p 8000:80`でポートのマッピングをしています。`docker-compose.yml`にも書かれていました。


`http://[ホスト名]:8000`にアクセスすれば、WordPressの初期画面が表示されます。


# 所感
Docker Composeの仕組みがようやく少しわかった！
Dockerが学習コストが高いと言われる理由が少しわかった！
動きと中身が理解できてよかった！

Docker Composeは便利ですが、内容を理解して使わないとモヤモヤしてしまいますね。
ドキュメントをしっかりと読みながら使っていこうと思いました。


# 参考サイト
https://docs.docker.jp/compose/wordpress.html

https://matsuand.github.io/docs.docker.jp.onthefly/compose/install/

https://qiita.com/youtangai/items/ff67ceff5497a0e0b1af

https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/container_run/

https://docs.docker.jp/engine/reference/commandline/volume_create.html

https://docs.docker.jp/engine/reference/commandline/network_create.html