概要
VSCodeのdevcontainerを使ってLaravel環境構築を解説する記事です。
使用ツールさえ用意すれば高速で環境構築でき、Dockerを使用しているのでチームでの統一された開発環境としても使用できます。
とりあえず動かしたい人はリポジトリリンクからどうぞ。
リポジトリ
https://github.com/naoyayamamoto/laravel-docker-sample
テンプレートリポジトリとして用意しているので、雛形としても使用できます。
使用ツール
- Docker
- Docker-compose
- Visual Studio Code
- Visual Studio Code Remote - Containers
以上のツールを使用します。
Docker
・Visual Studio Code
についてはインストールの詳細を省きます。
Visual Studio Code Remote - Containers
についてはMicrosoft謹製のVSCodeプラグインです。リンクよりVSCodeにインストールできます。
使用方法
リポジトリをVSCodeで開く
$ git clone https://github.com/naoyayamamoto/laravel-docker-sample
$ code laravel-docker-sample
# codeコマンドが入っていなければVSCodeでリポジトリを開いてください
devcontanerを使用してVSCodeを開く
- VSCodeに
Visual Studio Code Remote - Containers
が入っていれば左下にアイコンが追加されているので、それを押してダイアログを開くか、Show All Commandscmd + shift + P
でダイアログを開く。 -
Remote-Containers: Reopen in Container
を実行すると環境の準備が始まります。 - 初回はDockerの準備を行うため時間がかかりますが、2回目以降は高速で立ち上がります。
アクセス確認
http://localhost:8000
へアクセスでLaravel初期ページが表示されるはずです。
解説
devcontainerを開いた際に.devcontainer/docker-compose.yml
を元にDocker環境が構築されます。
以下のコンテナを使用しており、それぞれ解説していきます。
- nginx:alpine (web)
- mysql:8 (db)
- VSCode用にカスタマイズしたphp:7-fpm (app)
nginx:alpine (web)
- デフォルトイメージを使用
- フロントとして常に起動するので、
php artisan serve
なしでアクセス可能 -
.devcontainer/docker/nginx/default.conf
を読み込ませ、php-fpmへ処理を流している
mysql:8 (db)
- デフォルトイメージを使用
-
.devcontainer/docker/mysql/my.cnf
を読み込ませている(日本語基本設定) - 環境変数
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: laravel
を設定しているので、rootパスワードなし、初期テーブルlaravel
が作成される
VSCode用にカスタマイズしたphp:7-fpm (app)
- devcontainerを開いた際の初期接続コンテナ
-
.devcontainer/docker/php/Dockerfile
を使用してビルド -
composer
・node
・npm
・yarn
が使用可能 - php-fpmをsockで実行するために
.devcontainer/docker/php/php-fpm.d/zzz-www.conf
を読み込ませている -
DB_HOST: db
を設定しているので、.envでの設定よりこちらが優先されてdbコンテナに接続されます
おまけ
本番環境用のDockerfile
本番を想定してビルドを行うDockerfileがリポジトリに追加しているので、カスタマイズの元として使用してください。
マルチステージビルドを使用して、jsのコンパイルとcomposerのインストールを先行して行い、最終イメージを極力小さくしています。
GithubActionsでビルドテストだけは通しています。
kubernetesで使用する場合
参考までにkubernetesで使用する場合の設定です。
nginxとphpを1PODとして動かすことを想定しています。
参考deployment.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
default.conf: |
access_log /dev/stdout main;
error_log /dev/stderr warn;
server {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
gzip on;
gzip_http_version 1.0;
gzip_disable "msie6";
gzip_proxied any;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
open_file_cache max=100000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
listen 80;
root /workspace/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
---
kind: Service
apiVersion: v1
metadata:
name: laravel-service
spec:
selector:
app: laravel
ports:
- protocol: TCP
port: 80
targetPort: 80
name: laravel-http
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: laravel
labels:
app: laravel
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: laravel
template:
metadata:
labels:
app: laravel
spec:
containers:
- name: app
image: myimage
volumeMounts:
- mountPath: /var/run/php-fpm
name: php-fpm-socket
- mountPath: /shared
name: public-contents
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "cp -aT /workspace/public /shared"]
- name: web
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/run/php-fpm
name: php-fpm-socket
- mountPath: /etc/nginx/conf.d
name: nginx-conf
- mountPath: /workspace/public
name: public-contents
volumes:
- name: php-fpm-socket
emptyDir: {}
- name: public-contents
emptyDir: {}
- name: nginx-conf
configMap:
name: nginx-conf
items:
- key: default.conf
path: default.conf