この土日にあーでもないこーでもないって楽しんでたんだけど、たぶんできたと思う。結構色々あったな。というか、今日の日記長い。
## 今日のコード
github.com
## 発端:Dockerでできそうじゃない?
CakePHPを勉強しようと思って、PHPBrewでPHPのバージョンを切り替えられる環境を作って
PHPに入門してみる。phpbrewとIDEA+PHPプラグインでCakePHP3の準備。 - Mitsuyuki.Shiiba
IDEとしてIntelliJ IDEA(+各種PHPプラグイン)を触って
JetBrainsのPhpStormワークショップをひととおりざっくりやってみてメモ - Mitsuyuki.Shiiba
その後にごにょごにょ触ったり色んな記事を見たりしてたら「あれ?Dockerの中のPHPを使えばホスト側にPHPなくても大丈夫そう?」と思ってしまった。
なので、PHPとPHPBrewをアンインストールして、Dockerで環境を構築してみることにした。
## 注意
1) 分かりやすいようにと思って「PhpStorm」って書いてるけど、実際はPhpStormじゃなくてIDEAにPHP系のプラグインを追加してやってる。設定画面やメニューの場所などがちょこちょこ違うけど、機能はだいたい同じなんじゃないかと思う。
IntelliJ IDEA 2018.2.3 EAP (Ultimate Edition)
Build #IU-182.4323.6, built on August 22, 2018
2) OSはUbuntuの18.04
3) PHP自体を勉強し始めたばっかりなので変なところとかあるかも
## できたこと
ホストマシンにはPHPをインストールせずに、PhpStormでApache+PHPのDockerイメージを使って、
## 感想
- 気に入った
- Dockerなので一度準備が整ってしまえばお手軽で良い
- けど、最初に考えてたよりは複雑になっちゃった
- DockerやPhpStormの仕様や、まだサポートされてない機能とかの影響で素直に実現できない部分があって、それを回避する必要があったし、実現できない機能もあった
- もう何年かしたら色々サポートされててもっと楽なのかもしれない
- Vagrantは今回は使わない方向でがんばったけど、使う方がシンプルになるかもなぁという気もした
- それと、速度が心配
- プロジェクトルートをそのままマウントして使うので、色々ファイルが増えても問題ないスピードで動くのかどうかがが心配
## shin1x1さんの記事
shin1x1さんの記事を何度も読んで、実際にやってみて、最初は「う、動くぞ!(←分かってない」って感じだったんだけど、何度か触ってるうちに仕組みがだんだん分かってきた。
blog.shin1x1.com
## PhpStormワークショップのDockerブランチ
それから、前回はPhpStormワークショップのVagrantバージョンをやったのだけど、Dockerバージョンのブランチがあるのでそっちも触ってみた。shin1x1さんのはDocker Composeだったけど、こっちはDockerなんだなーって思いながら。
https://github.com/JetBrains/phpstorm-workshop/tree/docker#getting-started
## やりたいこと
やりたいのはこういうこと
で、それとは別に
### アプリケーション実行用のイメージ
- アプリケーションの実行とリモートデバッグをするためのphp-webイメージがあって
- これは常に起動しておく
- こっちにもプロジェクトのルートディレクトリーとphp.iniがマウントされてる
という感じ。
### 2つイメージをそれぞれ管理するのも面倒なので
1つのDockerイメージで両方をカバーしてしまおうと思う。こんな感じ。
それと、Volumeマウントとかの設定をコードとして書いておきたいのでdocker-composeを使う。
## Docker関係の準備
### Dockerfile
色々あってDockerfileはこうなった。順番に説明してく。
FROM php:7.2.9-apache
↑PHP7 + Apacheのイメージを使用。
# Xdebug
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug
↑Xdebugを入れて有効化。
# For CakePHP
RUN apt-get update && apt-get install -y \
git \
libicu-dev \
libzip-dev \
zip \
&& rm -rf /var/lib/apt/lists/* \
&& a2enmod rewrite \
&& NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) \
&& docker-php-ext-configure zip --with-libzip \
&& docker-php-ext-install -j${NPROC} zip \
&& docker-php-ext-install -j${NPROC} intl \
&& docker-php-ext-install -j${NPROC} pdo_mysql
↑CakePHP動かすのにこんな感じかなぁ?と思いながら書いた。実際に動かしてみたら他にも必要なのがあるかもしれない。
# Composer
ENV COMPOSER_HOME /tmp
COPY --from=composer:1.7.2 /usr/bin/composer /usr/bin/composer
↑Copmoserは、https://github.com/docker-library/docs/tree/master/composer#suggestionsのnoteのところを参考にした。マルチステージビルドの外部からとってくるやつなんやね。
# Change DocumentRoot
WORKDIR /app
ENV APACHE_DOCUMENT_ROOT /app/webroot
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
&& sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
↑DocumentRootの変更は、https://github.com/docker-library/docs/blob/master/php/README.md#changing-documentrootを参考にした。CakePHPのプロジェクトをこの後生成するのでwebrootディレクトリにした。
# Change uid & gid of www-data
RUN usermod -o -u 1000 www-data && groupmod -o -g 1000 www-data
↑昨日の記事でも書いたけど、Linuxの場合はVolumeマウントしたときにuid:gidをホスト側のユーザーと揃えておかないと面倒なので1000:1000固定にしておいた。本当は実行時にuidとgidを外から設定するほうがキレイだけど自分用だし良いかなと思って。
# To switch user on runtime
RUN apt-get update && apt-get -y install \
gosu \
&& rm -rf /var/lib/apt/lists/*
COPY entrypoint.sh /usr/local/bin/docker-php-entrypoint
↑php-webとしてApacheを動かすときは最初のプロセスをrootで起動する必要があるのだけど、php-cliでComposerとかのコマンドラインツールを使いたいときはwww-dataユーザーを使いたいので、gosuを入れてエントリーポイントのファイルを上書きしといた。
### entrypoint.sh
そのエントリーポイント。
#!/bin/sh
set -e
# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
set -- apache2-foreground "$@"
fi
if [ "$1" = "apache2-foreground" ]; then
exec "$@"
else
# use www-data for cli
echo "gosu user to www-data"
exec gosu www-data "$@"
fi
元々のイメージのエントリーポイント https://github.com/docker-library/php/blob/e92dfe4847c9fe74ea309e66f9d3ef0217f8525d/7.2/stretch/apache/docker-php-entrypoint にgosuの処理を加えた。
### docker-compose.yml
次はdocker-compose。
docker-compose.ymlはプロジェクトルートに置いて、Dockerfileとphp.iniはdockerディレクトリーに置いた。
❯ tree
.
├── docker
│ ├── Dockerfile
│ ├── entrypoint.sh
│ └── php.ini
└── docker-compose.yml
1 directory, 4 files
docker-compose.ymlはこんな感じ。
version: '3'
services:
php-cli:
build: ./docker
command: php -v
volumes:
- .:/app
- ./docker/php.ini:/usr/local/etc/php/php.ini
php-web:
build: ./docker
volumes:
- .:/app
- ./docker/php.ini:/usr/local/etc/php/php.ini
ports:
- "8000:80"
CLIの方はビルドをしておきたいだけで起動しておく必要はないので適当にコマンドを指定しておいた。
### php.ini
んで、php.iniはまだ勉強してなくて全然分からないので、shin1x1さんのをコピーさせていただきました。で、2ヶ所だけ変更。
1) xdebug.remote_autostart
をOff
にした。理由はリモートデバッグのところで書く。
2) xdebug.remote_host
を172.17.0.1
(コンテナから見たホスト側のIPアドレス)にしておいた。今だとMacはdocker.for.mac.localhost
からhost.docker.internal
に変わってるから、Macの場合はそっちにしといたらいいかな。Linux版にもそういう機能入れといてくれたらいいのにね。
; timezone
date.timezone = Asia/Tokyo
; error reporing
log_errors = On
error_log = /dev/stderr
; xdebug
xdebug.remote_enable = On
xdebug.remote_autostart = Off
xdebug.remote_connect_back = Off
xdebug.remote_host = 172.17.0.1
;xdebug.remote_port=9000
;xdebug.idekey=phpstorm
### ビルド
以上でファイルが揃ったのでビルド。いったんupして成功することを確認してからCTRL+Cで停止しておく。
❯ docker-compose build
❯ docker-compose up
CTRL + C
ちなみに、docker-composeを使うときは親ディレクトリの名前がイメージIDに使われる。今回僕はプロジェクトのディレクトリ名をphpstorm-docker-cakephp
にしたので、イメージ名はこうなった(ちょっと長かったなって後で思ったけど)。
❯ docker-compose images
Container Repository Tag Image Id Size
------------------------------------------------------------------------------------------------
phpstormdockercakephp_php-cli_1 phpstormdockercakephp_php-cli latest 92565eef7208 490 MB
phpstormdockercakephp_php-web_1 phpstormdockercakephp_php-cli latest 92565eef7208 490 MB
ビルドが終わったので、こんな感じでコマンドが使える。
❯ docker-compose run --rm php-cli whoami
gosu user to www-data
www-data
じゃ、CakePHPプロジェクトを生成しよう。
## ComposerでCakePHPのプロジェクトを生成
### プロジェクトを作成
Composerが使えるようになったのでCakePHPのプロジェクトを生成する。
❯ docker-compose run --rm php-cli composer \
create-project --prefer-dist cakephp/app
しばらく待って、最後に「フォルダーのパーミッションセットする?」って聞かれたのでYにしといた。
### 生成したプロジェクトのファイルを移動
appってディレクトリに生成されてるので、その中身をカレントに移動することにする。
❯ mv app/* .
❯ mv app/.* .
❯ rmdir app
❯ tree -L 1
.
├── bin
├── composer.json
├── composer.lock
├── config
├── docker
├── docker-compose.yml
├── index.php
├── logs
├── phpunit.xml.dist
├── plugins
├── README.md
├── src
├── tests
├── tmp
├── vendor
└── webroot
10 directories, 6 files
### モジュールの追加
んで、PHPCS, PHPMD, PHPUnitを入れておく。PHPUnitはCakePHP指定のバージョンで。
❯ docker-compose run --rm php-cli composer require --dev \
"squizlabs/php_codesniffer" \
"phpmd/phpmd" \
"phpunit/phpunit:^5.7|^6.0"
### 起動して見とく
これでアプリは動く状態なので、docker-composeでphp-webを立ち上げて見てみる。
❯ docker-compose up -d
でブラウザで localhost:8000
(∩´∀`)∩ワーイ。準備はこんなとこかな。じゃ、PhpStormを起動しよう。
## PhpStorm
やるのは4つ:
ここでもう一度伝えておくと、僕が実際に使ってるのはIDEAなので、PhpStormとはちょこちょこ場所が違うかも。
プロジェクトをインポートしたら、Settingsを開いて
Build, Execution, Deployment > Dockerで「+」を押してDockerの設定。Unix socketを選ぶとConnection sucessfulの文字が出る。
次に、PHPのCLI Interpreterを追加する。Language & Frameworks > PHPから、CLI Interpreterの右側の「…」をクリックして
「+」ボタンを押して出たポップアップから「From Docker, Vagrant, VM, Remote...」を選ぶとこんなダイアログが表示される。
ここで今回僕が選んだのは、Docker ComposeじゃなくてDocker。理由は、PhpStormがPHPCSとPHPMDを実行するのにDocker Composeだと対応してなくて、Dockerだったら対応してたから。
さっきDocker Composeでビルドしたので、イメージが作られてる。それを選択「phpstormdockercakephp_php-cli:latest」
んで、OK押したら、こんな感じになるので、OKを押して
PHPの設定画面で、今度は「Docker Container」という項目の一番右側のフォルダアイコンをクリックして
ボリュームマウントの設定を行う。docker-compose.ymlで設定してたのと同じにしてOKを押す。
これでCLIの設定終わり。
Language & Frameworks > PHP > Test Frameworkの設定をこんな感じにして
実行したら動くー!
デバッグ実行もできるー!(∩´∀`)∩ワーイ
## PHPCSとPHPMDのコードインスペクションができた
Code Snifferは、Language & Frameworks > PHP > Code Sniffer でConfigurationの一番右側の「…」のとこを押して
開いた画面の左側の「+」の部分からさっき作成したCLIを選ぶだけ。
んで、Validateボタンを押してOKとなるのを確認しておく。
### Mess Detectorの設定
phpmdもLanguage & Frameworks > PHP > Mess Detectorで同じことをやる。
### Inspectionの設定
は、PHPCSとPHPMDのことをまだよく分かってないので、PHPCSはPSR2を選んで
PHPMDは全部チェック入れてみた
### 変なコードを書くと
ちゃんと指摘してくれる!(∩´∀`)∩ワーイ
だけど、メニューからの一括実行には対応してないみたい。残念。ま、そこはターミナルからやればいっか。
https://youtrack.jetbrains.com/issue/WI-33088
最後にリモートデバッグをやったらおしまい!
### PHP Remote Debugの設定
RunメニューのEdit Configurations…で開いたRun/Debug Configurationsから「+」を押して「PHP Remote Debug」を追加して、「Filter debug connection by IDE key」をチェックしたら右側の「…」を押して、こんな風に設定。パスのマッピングが必要なので、Use path mappingのチェックを入れて、プロジェクトルートを/appにマッピングする。
「PHP Remote Debug」の設定に戻って、IDE key(session id)のところを「PHPSTORM」にしておく。
OKを押す。
JetBrainsの「Xdebug & Zend Debugger bookmarklets generator for PhpStorm」を使う。
www.jetbrains.com
XdebugのIDE keyに 初期値の「PHPSTORM」が入力された状態で「Generate」ボタンを押して表示された「Start debugger」と「Stop debugger」をブックマークバーにドラッグ&ドロップ。
### いよいよデバッグー
Runメニューの下の方にある「Start Listening for PHP Debug Connections」を実行。それと、分かりやすさのために今回は「Break at first line in PHP scripts」を有効にしておく。
その後、http://localhost:8000/ をブラウザで開いて、さっきブックマークした「Start debugger」をクリックして、画面をリロードすると
index.phpに入ってきたところで止まって、デバッグ情報も見れたー(∩´∀`)∩ワーイ
### remote_autostart
最初はXdebugのremote_autostartをOnにしてたんだけど、そうするとCLI系のツールが全部動かなくなってしまったので、OffにしてちゃんとIDE keyを指定するようにしたのだ。
## まとめ
ホストマシンにはPHPをインストールせずに、PhpStormでApache+PHPのDockerイメージを使って、
現在のPhpStormでは対応されていないこと
- Docker ComposerインタープリターによるPHPCS、PHPMDの実行はできない
- メニューからInspectionを一括実行した場合には、PHPCS、PHPMDは動作しない
- それと、PhpStormのComposer連携はRemote Interpreter非対応みたい
感想