PC移行に伴い新たな開発環境を構築する必要が出てきたが、XAMPP入れるのも古いかな(nginx使いたいし)、WSL上にごちゃごちゃ入れると何入れたかわからなくなる、と思ったのでDockerでなんとかならないかと試してみることに。
Dockerが動く状況なら移行先でも同様の開発環境がすぐに構築できるようになったはず。
WSLを入れるところから長々書いているので、答えだけdockerのファイルの答えだけ見たい方は、下の方を見るか
https://github.com/miyawa-tarou/docker-test/commit/5d5c78633a6c0e94b0c25849cf683c9a459b891e
あたりを見てください。
WSL2を入れる
Windowsのアップデート
- Windows 10、バージョン 2004、ビルド 19041 以上である必要があるので、アップデートします。
- WindowsUpdateのところからできる場合もあるようですが、ゆっくりと順次配布のためない場合は下記からダウンロードできます
仮想化を有効にする
BIOS
- ここはメーカーによるから細かい方法は置いておくが、BIOSに入って
- Intel Virtualizationとかがdisalbeになっていたらenableにする
Windows
Windowsの仮想化を有効に(GUIからやる方法もあるはず)
PowerShellを管理者モードで開き下記を実行
> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
> Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
再起動
WSL2の設定
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10
再びPowerShellを管理者モードで開き下記を実行
> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
WSLのデフォルトをバージョン2にしておく
powershell
wsl --set-default-version 2
「最新の WSL2 Linux カーネル更新プログラム パッケージ」が必要なこともあるかもしれない。
その場合は下記からダウンロード。
https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-kernel
ディストリビューションを入れる
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#install-your-linux-distribution-of-choice
WindowsStoreから好みを入れる(自分はUbuntuを入れた)
入ったら一回起動しておく(ここは起動しなくて動くか確かめてない)
ディストリビューションをあとからWSL2にする
WSL1で入れてしまった場合は、下記コマンドで変換する
> wsl -l -v
NAME STATE VERSION
* Ubuntu-18.04 Stopped 1
Ubuntu Running 1
> wsl --set-version Ubuntu 2
変換なのでちょい時間がかかる
Docker Desktopを入れる
https://www.docker.com/products/docker-desktop
Enable WSL2 Windows Featuresのチェックは付けたまま
これでDocker環境の準備は整ったはず
既存ファイル郡にDockerのファイルを追加する
ここからはDockerの話
既存コードににDocker設定を入れる
- ドキュメントルートに
docker-composer.yml
- それ以外のDocker関連ファイルを
./docker/
以下に置く
docker-composer.yml
XAMPPからの移行だが、本番はに近づけるため、
nodeサーバー、php-fpm、MariaDBと、XAMPPを意識するという点で今回はphpmyadminを入れる
それぞれ別のコンテナで動かす
version: '3'
services:
test_db:
image: mariadb:latest
volumes:
# データ永続化用
- ./docker/dbdata:/var/lib/mysql
# 初期データ用(ここに置いたsqlファイル等は実行される)
- ./docker/initdb:/docker-entrypoint-initdb.d
environment:
- MYSQL_ROOT_PASSWORD=mariadb
ports:
# Docker外(ローカル)からも3306で繋がるようにしておく
- 3306:3306
test_myadmin:
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
# 上のDBコンテナ名
- PMA_HOST=test_db
# root固定
- PMA_USER=root
# 上のMYSQL_ROOT_PASSWORDの値
- PMA_PASSWORD=mariadb
links:
# DBコンテナにつながるようにする
- test_db
ports:
# ローカルのブラウザからはlocalhost:8080で見られるようにする
- 8080:80
test_nginx:
image: nginx:alpine
depends_on:
- test_php
volumes:
# nginxの設定
- ./docker/nginx/docker.conf:/etc/nginx/conf.d/default.conf
# nginxのrootに合わせる(rootにはpublicを付ける必要がある)
- .:/var/www/test
ports:
- 80:80
environment:
- NGINX_PORT=80
test_php:
# これだけ素のイメージでは足りないのでDockerfileを利用する(Dockfileのパスを指定)
build: ./docker/php
links:
- test_db
volumes:
# php.iniの設定を送る(今回は特にめだった何かはしていない)
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
- .:/var/www/test
ports:
- 9000:9000
Dockerを理解してないがゆえに割と悩んだのが、多くの環境構築系資料で、ここにおいたコードが実行されるでしょみたいの書かれるけど、「え?どうやって編集するの?」ということ
結論としては、volumes以下はコピーされるのではなくマウントされるので、更新すれば自動で反映される。なので
volumes
- .:/var/www/hoge
とかやれば、ファイル全体が自動的にマウントされる、Dockerコンテナ側に反映される
Dockerfile(PHPサーバー)
FROM php:7.3-fpm
RUN apt-get update \
# Laravel実行には必要
&& apt-get install -y zlib1g-dev libzip-dev mariadb-client \
&& docker-php-ext-install zip pdo_mysql \
# XDebug用(今回は不要)
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
COPY --from=composer /usr/bin/composer /usr/bin/composer
composerは必須ではないが、後述のLaravelクソ重い問題で利用する
Docker に Composer をインストールするベストプラクティス(と解説)
Nginxのconf
server {
# nginxコンテナのポートの右側の数値
listen 80;
server_name localhost;
charset utf-8;
# volumesでマウントしているところと一致させる(Laravelなのでこちらはpublicをつける)
root /var/www/test/public;
index index.php;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
# test_phpはdockerのPHPコンテナ名、9000はそのポート(右側の数字)
fastcgi_pass test_php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
初期SQLを置く
docker-compose.yml
のファイル内のコメントに書いたが、データベース系のコンテナだあと
/docker-entrypoint-initdb.d に置かれたファイルは自動でよしなにしてくれるらしい。
ここに .sql
, .sql.gz
をおけばSQLが実行、.sh
を置けばシェルが走るらしい。
artisanでmigrationで行う場合は .sh
で書けば良い
上のdocker-composerで/docker/initdb においたものが/docker-entrypoint-initdb.d にコピーされるのでそこにおいておく
なお、いきなりテーブル作成をしてしまうとエラーになる。ちゃんとdatabaseの作成・指定から行う。
Laravelの.env設定
関係あるのはDB周りだけなので、そこの部分だけ修正する。
DB_CONNECTION=mysql
# DBコンテナ名
DB_HOST=test_db
# DBコンテナで指定したポート(右側)
DB_PORT=3306
# 実際に使っているもの次第(今回は初期データがここに入ってる)
DB_DATABASE=docker_test
DB_USERNAME=root
# 指定したパスワード
DB_PASSWORD=mariadb
起動してみる
composer-docker.ymlのある場所まで移動して
$ docker-compose up -d
Windows側でもWSL側でも動くはずである。
ミスがなければ起動するはず。
DockerDesktop側のDashboardからも起動が確認できる
動作確認
- phpMyAdminへのアクセスは:http://localhost:8080/
- 上でおいたSQLも動いていることを確認
-
http://localhost/
- 表示されるはず
問題点1:Laravelがクソ重い
上のを実行すると気づくとも思うが、何もしてない処理でもクソ重い。
大して何もしてないページなのに表示に数秒かかる・・・。これではさすがに厳しい。
どうやら調べてみると、「マウントするファイルが多いと重くなる」模様
下記が解決策として実行したもの・浮かんだもの
不要なファイルはマウントしない(今回やった解決策)
自分で触ることのないファイルはわざわざ、マウントする必要がない
- vendor以下は依存を変えない限りは不要である
- storage以下は自動で作られるファイルだからこちらかアップすることはない
しかし単にマウントしないだけだと以下の問題が起きる
- vendor以下がないため、composer installをする必要がある
- storage以下のファイルが存在しないからエラーになる
一旦ファイルを送ってからマウントを切るという手もあるが、一発で構築できないという点でイケてない。
構築後に中に入って準備をするのもイケてない。
なので、必要なファイルはDockerfileで取得するようにする
volumes:
# php.iniの設定を送る
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
- .:/var/www/test
# 除外
- /var/www/test/storage
- /var/www/test/vendor
Dockerfileに下記を追加
# storageファイルはマウントしないのでもともと必要なディレクトリは作成する
RUN mkdir -p /var/www/test/storage/app/public
RUN mkdir -p /var/www/test/storage/framework/cache/data
RUN mkdir -p /var/www/test/storage/framework/sessions
RUN mkdir -p /var/www/test/storage/framework/testing
RUN mkdir -p /var/www/test/storage/framework/views
RUN chmod -R 777 /var/www/test/storage
# vendorはマウントしないのでcomposerで入れる
COPY composer.lock /var/www/test/composer.lock
# いらないかも
COPY composer.json /var/www/test/composer.json
# composer.jsonで必須になっているもの(autoloadまわり)
RUN mkdir -p /var/www/test/database/seeds
RUN mkdir -p /var/www/test/database/factories
# cd /var/www/test && composer install でも動きそう
WORKDIR /var/www/test
# scriptsでファイルチェックをしているが、マウント前のこの時点では存在しないのでそれは避ける
RUN composer install --no-scripts
これで再作成
$ docker-compose build --no-cache
表示に1秒かからなくなった!
その他解決策1:docker-syncを使う
WindowsもLinuxもベータ版らしい
Docker for MacのLaravel アプリケーションのが遅い?それ、ファイルをいっぱいマウントしてるからかもです。
Macだとこれが普通に行われている記事をよく見る
その他解決策2:ファイルwatch+rsyncする
上のdocker-syncはrsyncしているだけなので、自分で動かすこともできる気がする。
実際うまく動くかは不明
https://medium.com/@imranhsayed/rsync-using-phpstorm-on-save-b1e73c079db0
問題点2:同じ.envファイルでWSLとDocker上両方動かせない
.env
で DB_HOST=test_db
としているがDocker内での名称であり、WSL側では認識せず動かせない
そのため、開発を行うWSL側から php artisan
などを実行してもDB周りが上手く動かない
- 127.0.0.1だとDockerコンテナからは127.0.0.1ではないため動かない
- Connection refused.
- localhostだとsocketのエラーが出る
- SQLSTATE[HY000] [2002] No such file or directory
Socketファイルを云々している記事もあったがこれじゃない感。
Docker側から見てlocalhostとはなにかというと、 host.docker.internal
であり、これを入れて見るとartisanも動いたし、Dockerホスト側からも動いた
DB_HOST=host.docker.internal
最終形
こちらにLarvelのテストファイルと共に置いてます:https://github.com/miyawa-tarou/docker-test/commit/5d5c78633a6c0e94b0c25849cf683c9a459b891e
docker-compose.yml
version: '3'
services:
test_db:
image: mariadb:latest
volumes:
# データ永続化用
- ./docker/dbdata:/var/lib/mysql
# 初期データ用(DB系イメージだとここに置いたsqlファイル等が実行される)
- ./docker/initdb:/docker-entrypoint-initdb.d
environment:
- MYSQL_ROOT_PASSWORD=mariadb
ports:
# Docker外からも3306で繋がるようにしておく
- 3306:3306
test_myadmin:
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
# 上のDBコンテナのホスト
- PMA_HOST=test_db
# root固定
- PMA_USER=root
# 上のMYSQL_ROOT_PASSWORDの値
- PMA_PASSWORD=mariadb
links:
# DBコンテナにつながるようにする
- test_db
ports:
# ブラウザからはlocalhost:8080で見られるようにする
- 8080:80
test_nginx:
image: nginx:alpine
depends_on:
- test_php
volumes:
- ./docker/nginx/docker.conf:/etc/nginx/conf.d/default.conf
ports:
- 80:80
environment:
- NGINX_PORT=80
test_php:
# これだけ素のイメージでは足りないのでDockerfileを利用する(Dockrfileのパスを指定)
build:
# composer.lockをDockerfile内で使うために実行場所は変えない(通常だとDockerfileの位置からの参照、親ファイルは読めない)
context: .
dockerfile: ./docker/php/Dockerfile
links:
- test_db
volumes:
# php.iniの設定を送る
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
- .:/var/www/test
# 除外
- /var/www/test/storage
- /var/www/test/vendor
ports:
- 9000:9000
docker/php/Dockerfile
FROM php:7.3-fpm
# composer.jsonで必須になっているもの
RUN mkdir -p /var/www/test/database/seeds
RUN mkdir -p /var/www/test/database/factories
RUN apt-get update \
# Laravel実行には必要(多分)
&& apt-get install -y zlib1g-dev libzip-dev mariadb-client \
&& docker-php-ext-install zip pdo_mysql \
# XDebug用
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
COPY --from=composer /usr/bin/composer /usr/bin/composer
# storageファイルはマウントしないのでもともと必要なディレクトリは作成する
RUN mkdir -p /var/www/test/storage/app/public
RUN mkdir -p /var/www/test/storage/framework/cache/data
RUN mkdir -p /var/www/test/storage/framework/sessions
RUN mkdir -p /var/www/test/storage/framework/testing
RUN mkdir -p /var/www/test/storage/framework/views
RUN chmod -R 777 /var/www/test/storage
# vendorはマウントしないのでcomposerで入れる
COPY composer.json /var/www/test/composer.json
COPY composer.lock /var/www/test/composer.lock
# composer.jsonで必須になっているもの(autoloadまわり)
RUN mkdir -p /var/www/test/database/seeds
RUN mkdir -p /var/www/test/database/factories
# cd /var/www/test && composer installでも動きそう
WORKDIR /var/www/test
# scriptsでファイルチェックをしているが、この時点ではないのでそれは避ける(後でマウントされるため)
RUN composer install --no-scripts
docker/nginx/docker.conf
server {
# nginxコンテナのポートの右側の数値
listen 80;
server_name localhost;
charset utf-8;
# volumesでマウントしているところと一致させる
root /var/www/test/public;
index index.php;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
# test_phpはdockerのPHPコンテナ、9000はそのポート(右側の数字)
fastcgi_pass test_php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
.env(差分では.env.exampleに置いてます)
DB_CONNECTION=mysql
DB_HOST=host.docker.internal
DB_PORT=3306
# 実際に使っているもの次第
DB_DATABASE=docker_test
DB_USERNAME=root
DB_PASSWORD=mariadb
Xdebug入れてますが、まだ設定はしていない・・・。