久しぶりにLaravelで開発することになり、最近のDocker開発環境はどうなってるんだろうと調べてみたら、Laravel 8.xから利用できるようになったLaravel Sailが素敵そうだったので調べてみました。
Laravel Sailとは
Laravel Sail - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/sail#introduction
Laravel Sailは、LaravelのデフォルトのDocker開発環境と対話するための軽量のコマンドラインインターフェースです。Sailは、Dockerの経験がなくても、PHP、MySQL、Redisを使用してLaravelアプリケーションを構築するための優れた出発点を提供します。
基本的に、Sailは、プロジェクトのルートに保存されるdocker-compose.ymlファイルとsailスクリプトです。このsailスクリプトは、docker-compose.ymlファイルで定義されたDockerコンテナーと対話するための便利なメソッドをCLIに提供します。
Laravel Sailは、macOS、Linux、およびWindows(WSL2経由)でサポートされています。
まさか公式が対応してくれているとは!
インストール
Mac、Windows、Linuxそれぞれのインストール手順がありましたが、基本的には同じ手順でしたので、Macで試してみます。
前提
前提としてDockerアプリが必須となります。Dockerアプリのインストールについては割愛します。
Mac
Installation - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/installation#getting-started-on-macos
8.x公式のSailを利用したインストール手順インストール手順にあるコマンドcurl -s https://laravel.build/example-app | bash
について先に調べてみます。
コマンドに含まれるhttps://laravel.build/example-app
へアクセスするとセットアップスクリプトがダウンロードできます。
https://laravel.build/example-app へアクセスしてみると以下のスクリプトが取得できます。
composerのコンテナイメージを取得・起動してそのコンテナ内でlaravel new example-app
を実行してプロジェクト作成しています。なるほどー
docker info > /dev/null 2>&1
# Ensure that Docker is running...
if [ $? -ne 0 ]; then
echo "Docker is not running."
exit 1
fi
docker run --rm \
-v $(pwd):/opt \
-w /opt \
laravelsail/php80-composer:latest \
bash -c "laravel new example-app && cd example-app && php ./artisan sail:install"
cd example-app
CYAN='\033[0;36m'
LIGHT_CYAN='\033[1;36m'
WHITE='\033[1;37m'
NC='\033[0m'
echo ""
if sudo -n true 2>/dev/null; then
sudo chown -R $USER: .
echo -e "${WHITE}Get started with:${NC} cd example-app && ./vendor/bin/sail up"
else
echo -e "${WHITE}Please provide your password so we can make some final adjustments to your application's permissions.${NC}"
echo ""
sudo chown -R $USER: .
echo ""
echo -e "${WHITE}Thank you! We hope you build something incredible. Dive in with:${NC} cd example-app && ./vendor/bin/sail up"
fi
実際に実行してみます。途中、端末のパスワードを求められるので入力します。
$ curl -s https://laravel.build/example-app | bash
Unable to find image 'laravelsail/php80-composer:latest' locally
latest: Pulling from laravelsail/php80-composer
852e50cd189d: Pull complete
0266fc315b01: Pull complete
(略)
Digest: sha256:b387b05f2d55d32d9ab1b861b4bc8347f75b36ca2b259231a3359118682dabad
Status: Downloaded newer image for laravelsail/php80-composer:latest
_ _
| | | |
| | __ _ _ __ __ ___ _____| |
| | / _` | '__/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V / __/ |
|______\__,_|_| \__,_| \_/ \___|_|
Warning: TTY mode requires /dev/tty to be read/writable.
Creating a "laravel/laravel" project at "./example-app"
(略)
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
74 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan key:generate --ansi
Application key set successfully.
Application ready! Build something amazing.
Please provide your password so we can make some final adjustments to your application's permissions.
Password:
Thank you! We hope you build something incredible. Dive in with: cd example-app && ./vendor/bin/sail up
つおい。もう開発環境の準備が整いました。
ディレクトリを覗いてみるといたせりつくせり感満載です。
$ cd example-app
$ ls -al
total 640
drwxr-xr-x 27 kai 339809989 864 2 19 19:53 ./
drwxr-xr-x 3 kai 339809989 96 2 19 19:51 ../
-rw-r--r-- 1 kai 339809989 220 2 17 01:58 .editorconfig
-rw-r--r-- 1 kai 339809989 865 2 19 19:53 .env
-rw-r--r-- 1 kai 339809989 815 2 19 19:53 .env.example
-rw-r--r-- 1 kai 339809989 111 2 17 01:58 .gitattributes
-rw-r--r-- 1 kai 339809989 191 2 17 01:58 .gitignore
-rw-r--r-- 1 kai 339809989 181 2 17 01:58 .styleci.yml
-rw-r--r-- 1 kai 339809989 3780 2 17 01:58 README.md
drwxr-xr-x 7 kai 339809989 224 2 17 01:58 app/
-rwxr-xr-x 1 kai 339809989 1686 2 17 01:58 artisan*
drwxr-xr-x 4 kai 339809989 128 2 17 01:58 bootstrap/
-rw-r--r-- 1 kai 339809989 1646 2 17 01:58 composer.json
-rw-r--r-- 1 kai 339809989 268563 2 19 19:51 composer.lock
drwxr-xr-x 16 kai 339809989 512 2 17 01:58 config/
drwxr-xr-x 6 kai 339809989 192 2 17 01:58 database/
-rw-r--r-- 1 kai 339809989 2614 2 19 19:53 docker-compose.yml
-rw-r--r-- 1 kai 339809989 473 2 17 01:58 package.json
-rw-r--r-- 1 kai 339809989 1202 2 17 01:58 phpunit.xml
drwxr-xr-x 7 kai 339809989 224 2 17 01:58 public/
drwxr-xr-x 6 kai 339809989 192 2 17 01:58 resources/
drwxr-xr-x 6 kai 339809989 192 2 17 01:58 routes/
-rw-r--r-- 1 kai 339809989 563 2 17 01:58 server.php
drwxr-xr-x 5 kai 339809989 160 2 17 01:58 storage/
drwxr-xr-x 6 kai 339809989 192 2 17 01:58 tests/
drwxr-xr-x 45 kai 339809989 1440 2 19 19:53 vendor/
-rw-r--r-- 1 kai 339809989 559 2 17 01:58 webpack.mix.js
.gitignore
用意されているので、Gitリポジトリへのコミットもはまらずにできそうです。
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.phpunit.result.cache
docker-compose.override.yml
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
docker-compose.yml
を眺めてみるとlaravelのDockerfileは./vendor/laravel/sail
以下のファイルを参照していることがわかります。コメントアウトされていますが、seleniumやPostgreSQL、memcachedにも対応しているみたいです。
ポート変更したい場合、環境変数が利用できるようになっているので、例えばlaravel.test
のポートを変更したい場合、.env
ファイルにAPP_PORT=8000
などのように追記すると変更できます。
Laravel SailでDocker環境構築 | RE:ENGINES
https://re-engines.com/2021/01/25/laravel-sail/
# For more information: https://laravel.com/docs/sail
version: '3'
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.0
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.0/app
ports:
- '${APP_PORT:-80}:80'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
# - pgsql
- redis
# - selenium
# selenium:
# image: 'selenium/standalone-chrome'
# volumes:
# - '/dev/shm:/dev/shm'
# networks:
# - sail
mysql:
image: 'mysql:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- 'sailmysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test: ["CMD", "mysqladmin", "ping"]
# pgsql:
# image: postgres:13
# ports:
# - '${FORWARD_DB_PORT:-5432}:5432'
# environment:
# PGPASSWORD: '${DB_PASSWORD:-secret}'
# POSTGRES_DB: '${DB_DATABASE}'
# POSTGRES_USER: '${DB_USERNAME}'
# POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
# volumes:
# - 'sailpostgresql:/var/lib/postgresql/data'
# networks:
# - sail
# healthcheck:
# test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"]
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sailredis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
# memcached:
# image: 'memcached:alpine'
# ports:
# - '11211:11211'
# networks:
# - sail
mailhog:
image: 'mailhog/mailhog:latest'
ports:
- '${FORWARD_MAILHOG_PORT:-1025}:1025'
- '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
networks:
sail:
driver: bridge
volumes:
sailmysql:
driver: local
# sailpostgresql:
# driver: local
sailredis:
driver: local
laravelコンテナのDockerfile
を眺めてみるとタイムゾーンを変更したい場合にカスタマイズしたいかなぁと思う程度です。
FROM ubuntu:20.04
LABEL maintainer="Taylor Otwell"
ARG WWWGROUP
WORKDIR /var/www/html
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update \
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 \
&& mkdir -p ~/.gnupg \
&& chmod 600 ~/.gnupg \
&& echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \
&& apt-key adv --homedir ~/.gnupg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E5267A6C \
&& apt-key adv --homedir ~/.gnupg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C300EE8C \
&& echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu focal main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
&& apt-get update \
&& apt-get install -y php8.0-cli php8.0-dev \
php8.0-pgsql php8.0-sqlite3 php8.0-gd \
php8.0-curl php8.0-memcached \
php8.0-imap php8.0-mysql php8.0-mbstring \
php8.0-xml php8.0-zip php8.0-bcmath php8.0-soap \
php8.0-intl php8.0-readline \
php8.0-msgpack php8.0-igbinary php8.0-ldap \
php8.0-redis \
&& php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
&& curl -sL https://deb.nodesource.com/setup_15.x | bash - \
&& apt-get install -y nodejs \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get install -y yarn \
&& apt-get install -y mysql-client \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.0
RUN groupadd --force -g $WWWGROUP sail
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
COPY start-container /usr/local/bin/start-container
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php/8.0/cli/conf.d/99-sail.ini
RUN chmod +x /usr/local/bin/start-container
EXPOSE 8000
ENTRYPOINT ["start-container"]
./vendor/bin/sail up
コマンドを実行してDockerコンテナを立ち上げます。
docker-compose up
コマンドでも立ち上げることができました。
$ ./vendor/bin/sail up
Creating network "example-app_sail" with driver "bridge"
Creating volume "example-app_sailmysql" with local driver
Creating volume "example-app_sailredis" with local driver
Pulling redis (redis:alpine)...
alpine: Pulling from library/redis
ba3557a56b15: Pull complete
(略)
Digest: sha256:6ea115e574af216b2175f3783bb1119140b24619632e522841c1aac6990f5e79
Status: Downloaded newer image for redis:alpine
Building laravel.test
(略)
Creating example-app_redis_1 ... done
(略)
Creating example-app_laravel.test_1 ... done
Attaching to example-app_mailhog_1, example-app_redis_1, example-app_mysql_1, example-app_laravel.test_1
mailhog_1 | [HTTP] Binding to address: 0.0.0.0:8025
mailhog_1 | 2021/02/19 11:08:44 Using in-memory storage
mailhog_1 | 2021/02/19 11:08:44 [SMTP] Binding to address: 0.0.0.0:1025
mailhog_1 | 2021/02/19 11:08:44 Serving under http://0.0.0.0:8025/
mysql_1 | 2021-02-19 11:08:44+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.21-1debian10 started.
redis_1 | 1:C 19 Feb 2021 11:08:44.329 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 19 Feb 2021 11:08:44.329 # Redis version=6.0.10, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 19 Feb 2021 11:08:44.329 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
mailhog_1 | Creating API v1 with WebPath:
mysql_1 | 2021-02-19 11:08:44+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
redis_1 | 1:M 19 Feb 2021 11:08:44.330 * Running mode=standalone, port=6379.
redis_1 | 1:M 19 Feb 2021 11:08:44.330 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | 1:M 19 Feb 2021 11:08:44.330 # Server initialized
mailhog_1 | Creating API v2 with WebPath:
mysql_1 | 2021-02-19 11:08:44+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.21-1debian10 started.
redis_1 | 1:M 19 Feb 2021 11:08:44.331 * Ready to accept connections
mysql_1 | 2021-02-19 11:08:44+00:00 [Note] [Entrypoint]: Initializing database files
mysql_1 | 2021-02-19T11:08:44.731409Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.21) initializing of server in progress as process 45
mysql_1 | 2021-02-19T11:08:44.739160Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
mysql_1 | 2021-02-19T11:08:45.144394Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
laravel.test_1 | 2021-02-19 11:08:45,721 INFO Set uid to user 0 succeeded
laravel.test_1 | 2021-02-19 11:08:45,726 INFO supervisord started with pid 17
mysql_1 | 2021-02-19T11:08:46.142439Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
laravel.test_1 | 2021-02-19 11:08:46,730 INFO spawned: 'php' with pid 19
laravel.test_1 | 2021-02-19 11:08:47,733 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
mysql_1 | 2021-02-19 11:08:49+00:00 [Note] [Entrypoint]: Database files initialized
mysql_1 | 2021-02-19 11:08:49+00:00 [Note] [Entrypoint]: Starting temporary server
mysql_1 | 2021-02-19T11:08:49.524217Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.21) starting as process 92
mysql_1 | 2021-02-19T11:08:49.538476Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
laravel.test_1 | Starting Laravel development server: http://0.0.0.0:80
mysql_1 | 2021-02-19T11:08:49.706431Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
mysql_1 | 2021-02-19T11:08:49.809603Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: /var/run/mysqld/mysqlx.sock
mysql_1 | 2021-02-19T11:08:49.959222Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
mysql_1 | 2021-02-19T11:08:49.959381Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
mysql_1 | 2021-02-19T11:08:49.961133Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
mysql_1 | 2021-02-19T11:08:49.991284Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.21' socket: '/var/run/mysqld/mysqld.sock' port: 0 MySQL Community Server - GPL.
mysql_1 | 2021-02-19 11:08:50+00:00 [Note] [Entrypoint]: Temporary server started.
laravel.test_1 | [Fri Feb 19 11:08:49 2021] PHP 8.0.2 Development Server (http://0.0.0.0:80) started
mysql_1 | Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
mysql_1 | Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
mysql_1 | Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
mysql_1 | Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
mysql_1 | 2021-02-19 11:08:52+00:00 [Note] [Entrypoint]: Creating database example_app
mysql_1 |
mysql_1 | 2021-02-19 11:08:52+00:00 [Note] [Entrypoint]: Stopping temporary server
mysql_1 | 2021-02-19T11:08:52.783401Z 11 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 8.0.21).
mysql_1 | 2021-02-19T11:08:54.552265Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.21) MySQL Community Server - GPL.
mysql_1 | 2021-02-19 11:08:54+00:00 [Note] [Entrypoint]: Temporary server stopped
mysql_1 |
mysql_1 | 2021-02-19 11:08:54+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
mysql_1 |
mysql_1 | 2021-02-19T11:08:55.019311Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.21) starting as process 1
mysql_1 | 2021-02-19T11:08:55.027315Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
mysql_1 | 2021-02-19T11:08:55.193856Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
mysql_1 | 2021-02-19T11:08:55.297841Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
mysql_1 | 2021-02-19T11:08:55.410836Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
mysql_1 | 2021-02-19T11:08:55.411005Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
mysql_1 | 2021-02-19T11:08:55.413393Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
mysql_1 | 2021-02-19T11:08:55.435750Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.21' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
mailhog_1 | [APIv1] KEEPALIVE /api/v1/events
とくにエラーもなくコンテナが起動しました。素晴らしい。-d
オプションをつけることでバックグラウンドで起動することもできました。-d
オプションで起動した場合、./vendor/bin/sail stop
コマンドでコンテナを終了することができます。
http://localhost/ へアクセスするとLaravelアプリが表示されることが確認できます。
MailHogのコンテナも起動しているので、http://localhost:8025/
でダッシュボードが表示できます。
phpMyAdminが使いたい場合
MySQLに関してはphpMyAdminなどの管理ツールは用意されていないので、必要であれば個別に追加するのがよさそうです。
docker-compose.yml
に以下の定義を追加するとphpMyAdminが利用できるようになります。
How to add phpmyadmin to laravel 8 sail docker-compose.yml - Stack Overflow
https://stackoverflow.com/questions/66195113/how-to-add-phpmyadmin-to-laravel-8-sail-docker-compose-yml
phpmyadmin:
image: phpmyadmin/phpmyadmin
links:
- mysql:mysql
ports:
- 8080:80
environment:
MYSQL_USERNAME: '${DB_USERNAME}'
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
PMA_HOST: mysql
networks:
- sail
初期状態だとユーザー名root
パスワード空でログインできます。
Windows
Installation - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/installation#getting-started-on-windows
Windows Subsystem for Linux 2(WSL2)がインストールされている前提で手順はMacと同じです。
Linux
Installation - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/installation#getting-started-on-linux
Macと同じです。
まとめ
非常に手軽にLaravelの開発環境を構築することができました。Dockerの知識がなくとも利用することができ、開発に集中できるとてもよいツールだったので積極的に利用したいと思います。
参考
Laravel Sail - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/8.x/sail#introduction
Laravel SailでDocker環境構築 | RE:ENGINES
https://re-engines.com/2021/01/25/laravel-sail/
How to add phpmyadmin to laravel 8 sail docker-compose.yml - Stack Overflow
https://stackoverflow.com/questions/66195113/how-to-add-phpmyadmin-to-laravel-8-sail-docker-compose-yml
Laravel Sail なら Docker 開発環境がコマンド 2 撃で構築できる。PHP/MySQLからキューやメール環境までオールインワン
https://www.ritolab.com/entry/217
【Docker】Laravel Sailのインストールと使い方を確認 | アールエフェクト
https://reffect.co.jp/laravel/laravel-sail