LoginSignup
5
11

More than 3 years have passed since last update.

WSL2+Docker+Laravel既存コードでの開発環境作成(XAMPPからの移行)

Posted at

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を入れる

それぞれ別のコンテナで動かす

docker-composer.yml
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サーバー)

docker/php/Dockerfile
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

docker/nginx/docker.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の作成・指定から行う。

Docker で MySQL 起動時にデータの初期化を行う

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からも起動が確認できる

動作確認

問題点1:Laravelがクソ重い

上のを実行すると気づくとも思うが、何もしてない処理でもクソ重い。
大して何もしてないページなのに表示に数秒かかる・・・。これではさすがに厳しい。
どうやら調べてみると、「マウントするファイルが多いと重くなる」模様
下記が解決策として実行したもの・浮かんだもの

不要なファイルはマウントしない(今回やった解決策)

自分で触ることのないファイルはわざわざ、マウントする必要がない

  • vendor以下は依存を変えない限りは不要である
  • storage以下は自動で作られるファイルだからこちらかアップすることはない

しかし単にマウントしないだけだと以下の問題が起きる

  • vendor以下がないため、composer installをする必要がある
  • storage以下のファイルが存在しないからエラーになる

一旦ファイルを送ってからマウントを切るという手もあるが、一発で構築できないという点でイケてない。
構築後に中に入って準備をするのもイケてない。

なので、必要なファイルはDockerfileで取得するようにする

docker-compose.yml
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に下記を追加

docker/php/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上両方動かせない

.envDB_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ホスト側からも動いた

.env
DB_HOST=host.docker.internal

最終形

こちらにLarvelのテストファイルと共に置いてます:https://github.com/miyawa-tarou/docker-test/commit/5d5c78633a6c0e94b0c25849cf683c9a459b891e

docker-compose.yml

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

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

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に置いてます)

.env
DB_CONNECTION=mysql
DB_HOST=host.docker.internal
DB_PORT=3306
# 実際に使っているもの次第
DB_DATABASE=docker_test
DB_USERNAME=root
DB_PASSWORD=mariadb

Xdebug入れてますが、まだ設定はしていない・・・。

5
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
11