docker-composeを使用したコンテナでの開発環境セットアップ(CakePHP3)

## 前回までのあらすじ
社内外でvSphereやVirtualBox、Vagrantで仮想マシン環境を人力でつくりまくってきたコンテナ初心者、社内外の環境の違いを吸収するために今までのノウハウを使ってコンテナ環境をセットアップ。

[Qiita:VirtualBox + Vagrant + DockerによるOSに縛られないコンテナ環境セットアップ](https://qiita.com/GCkurabe/items/151c2a57688c03cfbdd8)

## 今回の内容

というわけで実際にコンテナ環境ができたので、この環境をベースにしてDocker-composeを使って開発環境を整えていきます。会社のWindows環境でもほぼ同じことができたのは確認済みです。

ただしWSLとVagrantの相性が悪かったため結果としてコマンドプロンプトからVagrant操作することとなりました......WSL2に期待します......

今回開発環境として作りたいのは、社内で人に教えたりするCakePHP3です。bakeコマンドで雛形をさくっとつくることができ、PHPであることからそこまで難しくありません。

そのベースとなるDocker-composeとは、さくらのナレッジでの記載によりますと

> Dockerビルドやコンテナ起動のオプションなどを含め、複数のコンテナの定義をymlファイルに書き、それを利用してDockerビルドやコンテナ起動をすることができます。一つの簡単なコマンドで複数のコンテナを管理できるようになります。

[さくらのナレッジ：Docker入門（第六回）〜Docker Compose〜](https://knowledge.sakura.ad.jp/16862/)

ymlファイルということは、AnsibleのPlaybookに近いものなのでしょうか。

少し調べて以下のふたつの記事を見てみると、相性こそ悪い場合もあるようですが、AnsibleからDocker Composeを操作することもできそうな勢いです。

[identail:AnsibleとDocker Composeの相性問題に気づいた話](https://www.indetail.co.jp/blog/170313/)

[hawksnowlog:Ansible から docker-compose を使ってみた](https://hawksnowlog.blogspot.com/2018/06/ansible-with-docker-service-module.html)

もともとAnsibleは動作するかどうかチェックしてみたことはありましたので、試してみる価値はありそうです。Ansibleって本当になんでもできるんですね。しかし、今回はDocker-composeのみで動かせるようにしてみます。

今回も情報を整理するためにアーキテクチャを書いてみます。

![docker_compose_ar.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/4938b05e-0308-610f-ee94-e7fed5ba8073.jpeg)


こんな感じでしょうか。ymlファイルはPythonと書き方も似ていますので読みづらいとかもあまりないでしょうから、これなら私でも大丈夫そうです。

## 対象読者

- 前回の記事をご覧になった方
- かつ前回の記事と同一もしくはそれに準ずる環境を作成された方
- かつWebアプリケーションフレームワークで開発をされている方
- かつコンテナで開発環境をただちに配ったりすることを企んでいる方
- つまり私

## 前提条件
事前に前回の記事と同一もしくはそれに準ずる環境の準備をお願いします。おそらくDocker for windowsでも、Docker for macでもなんとかなるとは思いますが、具体的な検証をしていないので適宜調査をお願いします。

## 今回の使用環境

- macOS Mojave 10.14.5
- VirtualBox 6.0.4
- Vagrant 2.2.4
- CentOS Linux release 7.6.1810 (Core)
- Docker 18.09.6
- docker-compose 1.24.0

## 実施する内容
0. Gitのインストール
1. リポジトリのクローン
2. docker-composeのインストール
3. 初期設定
4. コンテナの起動

## 0. Gitのインストール
まだこのCentOS7 VMではGitを入れていなかったです。

```
$ git --version
bash: git: コマンドが見つかりません
```

yumコマンドでGitをインストールできますが、今回はyum以外の方法を個人的に知りたいので、以下の手順に従ってGitのインストールをします。yumでGitをインストールされても構いません。

[Qiita:CentOS7 に最新版の Git をインストールする方法](https://qiita.com/tomy0610/items/66e292f80aa1adc1161d)

まずは依存関係のあるライブラリをインストールします。

```
$ sudo yum -y install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker autoconf
```
インストールに最適な場所（と信じて）移動

```
$ cd /usr/local/src/
```
サイトからGitの圧縮ファイルをダウンロード

```
$ sudo wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz
```
ファイルを解凍

```
$ sudo tar xzvf git-2.9.5.tar.gz
```
終わったらディレクトリに移動して

```
$ cd git-2.9.5/
```
makeコマンドを実行します(ほんの少し時間がかかります)。

makeコマンドについて：  
[cybertrust:makeコマンドを使ってみよう #1](https://www.miraclelinux.com/tech-blog/0icygs)

```
$ sudo make prefix=/usr/local all
$ sudo make prefix=/usr/local install
```
インストールされたか確認します。

```
$ git --version
git version 2.9.5
```
インストールできたみたいですが、こうして実際に時間をかけてやってみるとyumコマンドの便利さを思い知らされます。

## 1. リポジトリのクローン
本題に戻り、以下の記事を参考にCakePHP用のコードの入手とdocker-composeのインストールを遂行します。

[Qiita:【爆速】 15分で CakePHP3 実行環境を簡単に構築する by Docker](https://qiita.com/km42428/items/df1d0a1eefddcf771dfa)

今回はこの記事を書いてくれた方のリポジトリのクローンをホームディレクトリで実施します。

```
$ cd ~
$ git clone https://github.com/km42428/docker-cakephp3-template.git
Cloning into 'docker-cakephp3-template'...
remote: Enumerating objects: 38, done.
remote: Total 38 (delta 0), reused 0 (delta 0), pack-reused 38
Unpacking objects: 100% (38/38), done.
Checking connectivity... done.
```
実際にlsみてみるとディレクトリができています。

```
$ ls
anaconda-ks.cfg  docker-cakephp3-template
$ cd docker-cakephp3-template
$ ls
LICENSE  README.md  data  docker-compose.yml
```
## 2. docker-composeのインストール
以下の記事と公式ドキュメントを参考にインストールを実施します。

[Qiita: Docker Compose - インストール](https://qiita.com/zembutsu/items/dd2209a663cae37dfa81)

[公式ドキュメント(英 - Linux): Install Docker Compose](https://docs.docker.com/compose/install/)

念のためsu rootしておきます。大いなる権限には大いなる責任が云々。

そして安定(stable)なリリースと書かれている、公式ドキュメントに記載されたコマンドを実行しました。完了までには時間がかかります。

```
$ su root
# sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```

実行バイナリを許可します。

```
# sudo chmod +x /usr/local/bin/docker-compose
```

これで完了しており、バージョンも表示されました。

```
# docker-compose --version
docker-compose version 1.24.0, build 0aa59064
```

## 3. 初期設定

では早速buildしてみましょう。3分くらいかかります。

```
# docker-compose build
```
できあがったようです。

```
Successfully built 58a46e68225e
Successfully tagged docker-cakephp3-template_host:latest
```

## 4. コンテナの起動

コンテナを立ち上げてみます。

```
# docker-compose up -d
<中略>
Creating docker-cakephp3-template_mysql_1 ... done
Creating docker-cakephp3-template_phpfpm_1 ... done
Creating docker-cakephp3-template_host_1   ... done
Creating docker-cakephp3-template_nginx_1  ... done
```

起動状態を確認してみます。プロジェクトはまだ存在しないのでhostのコンテナが生成されていないようです。

```              
# docker ps
CONTAINER ID        IMAGE                             COMMAND                  CREATED             STATUS              PORTS                                      NAMES
cf2d5161e296        nginx:mainline-alpine             "nginx -g 'daemon of…"   4 days ago          Up 54 seconds       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   docker-cakephp3-template_nginx_1
6677d42b2aac        docker-cakephp3-template_phpfpm   "docker-php-entrypoi…"   4 days ago          Up 53 seconds       9000/tcp                                   docker-cakephp3-template_phpfpm_1
bd0a06a37dc0        docker-cakephp3-template_mysql    "docker-entrypoint.s…"   4 days ago          Up About an hour    33060/tcp, 0.0.0.0:3307->3306/tcp          docker-cakephp3-template_mysql_1

```
phpfpmコンテナに入って、ターミナルを立ち上げます。
今回のidは6677d42b2aacでした。

```
# docker exec -it 6677d42b2aac /bin/sh
```
なんとこれで仮想マシンに入れました。コンテナってこんな感じなのか......

```
/var/www/html #
```

--2019/08/09追記--

いちいちdocker psを叩いてcontainer IDを調べるのが面倒になってきて検索をかけたところ、かなり楽にやれる方法を見つけました。

まず以下のコマンドを入力してやるとdocker-composeでのサービス名がわかります。より正確にいうとdocker-compose.ymlに実際にサービス名が書いてあり、それを出力しているようです。

```
# docker-compose config --service
mysql
phpfpm
nginx
host
```

そしてphpfpmにexecコマンドでコンテナの中に入ります
(最近docker公式ドキュメントのdocker exec をよく読んだら擬似ターミナルだったっぽいがdocker-compose execについてはあまり詳しく言及されていない)。

```
# docker-compose exec phpfpm /bin/sh
/var/www/html #
```

擬似ターミナルでやらないといけないことはCakePHPの場合だとbakeコマンドを打ったりなんかでしょう。とはいえdataディレクトリにいないやつは基本的にdocker-compose downした瞬間に設定が消し飛ぶようにできています。賽の河原エンドよりしんどいことをしたくなければdataディレクトリにあるものだけ操作するか、dataディレクトリにファイルを置けるようにしましょう。

とはいえ今後はcontainer IDを控えずともさくさくやれそうです。

--追記ここまで--


ではcakephpのプロジェクトを作っていこうと思います。その前に、プロジェクト生成に必要となるパッケージ管理ソフト、composerをインストールします。

```
# curl -s https://getcomposer.org/installer | php
```
しかし私の環境だとうまくいきませんでした。-sを外して実行したところこんな結果が出てきました。

--2019/08/09追記--  
たぶんphpのうしろに変な文字が入り込んでいたのが原因だったので修正された上記コマンドで問題ないと思います。

```
# curl https://getcomposer.org/installer | php
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0curl: (6) Could not resolve host: getcomposer.org
/var/www/html #
```
以下の記事を参考にdns設定を変更します。

[qiita:curlで「Couldn't resolve host」エラーが出た場合の対処](https://qiita.com/bz0/items/7d4bac34c6cdada59b94)

```
# vi /etc/resolv.conf
```

```
nameserver 8.8.8.8
```
もう一度実行することでうまくいきました。

```
# curl https://getcomposer.org/installer | php
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100  257k  100  257k    0     0  82280      0  0:00:03  0:00:03 --:--:-- 82280
All settings correct for using Composer
Downloading...

Composer (version 1.8.6) successfully installed to: /var/www/html/composer.phar
Use it: php composer.phar
```

ではsampleプロジェクトを作成します。最後にYを押して終了です。

```
# php composer.phar create-project --prefer-dist cakephp/app sample
```
コンテナから抜けます

```
# exit
```

作成されたsampleプロジェクトでmysqlに接続するためにファイルを一部書き換えます。

```
docker-composeのディレクトリ/data/htdocs/sample/config/app.php
```
```
-   'host' => 'localhost',
+   'host' => 'mysql',
```

--2019/08/09追記--  
win10マシンでどハマりしたのですが、URLにアクセスできない事象が発生しました。win10ではURLに普通にアクセスして403 forbiddenが出て、macで今回再検証でSafariからやってみたらそもそも読み込み中のまま結果が返ってこなくなりました。nginxのアクセスログをみてみるとURLが正しいのに404を返している状態でした。

これを調べてみると、cakePHP3とnginxの設定の問題があったようです。

[cakephp3 公式ドキュメント 構成設定 App.baseUrlのところ](https://book.cakephp.org/3.0/ja/development/configuration.html)

App.baseUrlの項目によると、Apache の mod_rewriteを使わない場合、つまりnginxを使う場合には、以下のコマンドはコメントインする必要があります。

```
-   //'baseUrl' => env('SCRIPT_NAME'),
+   'baseUrl' => env('SCRIPT_NAME'),
```

それと.htaccessも削除する必要があります。このファイルはApache用のファイルで、nginxでは不要であるどころか変なリダイレクトを走らせてしまうのです。

sample直下と、webrootにあるので削除しておきます。

そして、nginxでも再設定が必要です。sampleディレクトリの上の階層、dataディレクトリにあるnginx/conf/conf.d/default.confを開きます。以下のように修正を実施します。

変更前

```
root        /var/www/html;
#root        /var/www/html/bookmarker/webroot;
```

変更後

```
#root        /var/www/html;
root        /var/www/html/sample/webroot;
```

以上を完了させた後でコンテナを再立ち上げします。コンテナは仮想マシンとは異なり、言ってしまえばプロセスそのものなのでプロセスを殺し、そして再度起動する必要があります。

```
# docker-compose restart
Restarting docker-cakephp3-template_host_1   ... done
Restarting docker-cakephp3-template_nginx_1  ... done
Restarting docker-cakephp3-template_phpfpm_1 ... done
Restarting docker-cakephp3-template_mysql_1  ... done
```

-- 追記ここまで --

これで以下のURLにアクセスすると実際にcakephpの画面が表示されました。

```
http://192.168.33.10:8765
```

![スクリーンショット 2019-06-22 07.16.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/674e812c-ccd4-0414-14d8-bac00669ebd0.png)


--2019/08/09追記--

実際にプロジェクトを作成してMVCのスケルトンコードをつくるときはこんな感じでやります。

参考にするのはCakePHP3のブログチュートリアルです。

[CakePHP3公式:ブログチュートリアルパート3](https://book.cakephp.org/3.0/ja/tutorials-and-examples/blog/part-three.html)

まずはexecで入ります。

```
# docker-compose exec phpfpm /bin/sh
/var/www/html #
```

lsするとこんな感じでsampleがみえます。bakeコマンドを打つのでsampleにcdします。

```
# ls
Dockerfile     composer.phar  sample
# cd sample
/var/www/html/sample #
```

cdできたら以下のコマンドを入力してbakeコマンドでArticlesテーブルの雛形(Migrationファイル)をつくります。

```
# bin/cake bake migration CreateArticles title:string body:
text category_id:integer created modified

Creating file /var/www/html/sample/config/Migrations/20190809131508_CreateArticles.php
Wrote `/var/www/html/sample/config/Migrations/20190809131508_CreateArticles.php`
```

次にこのArticlesと関係するCategoriesテーブルの雛形(Migrationファイル)をつくります。

```
# bin/cake bake migration CreateCategories parent_id:intege
r lft:integer[10] rght:integer[10] name:string[100] description:string created m
odified

Creating file /var/www/html/sample/config/Migrations/20190809131618_CreateCategories.php
Wrote `/var/www/html/sample/config/Migrations/20190809131618_CreateCategories.php`
```

チュートリアルに従いparent_id フィールドを 'null' => false を 'null' => true に変更しておきます。ファイルはdocker-cakephp3-template/data/htdocs/sample/config/Migrationsのなかにあります。

テーブルの雛形であるMigrationファイルを適用するのは以下のコマンドです。

```
# bin/cake migrations migrate
```

最後にふたつのテーブルに即したMVCスケルトンコードを作成するのが以下のコマンドです。たったふたつ打ち込むだけで雛形ができてしまいます。便利ですね。

```
# bin/cake bake all Categories
# bin/cake bake all Articles
```

これで以下のURLにアクセスすればほとんどプログラムが作成できていることがわかります。ここからソースコードを加工していけばアプリケーションを作成することができます。

```
http://192.168.33.10/articles
```

--追記ここまで--

最後にコンテナを停止して終了となります。

```
# docker-compose stop
```


--2019/08/09追記--

まっさらにして終了したいときは以下のコマンドです。

```
# docker-compose down
```

## おわりに

とりあえずコンテナを実際に動かすことができました。あとはdocker-compose.ymlのファイル群を自作できるようになればファイルを配って作業ができそうです。

まず私はPythonまわりのファイル群を探してカスタマイズして、早速開発に取り組みつつ、k8sなど基盤まわりに引き続き手を出していこうと思います。

情報系が大の苦手マンを自負して生きていても、こうして単独で楽に基盤構築できるって、考えてみるとすごい時代になったもんですね......