神戸学院大学 経営学部 林坂ゼミ

Docker 入門トップページ

« 戻る 次へ »

Docker 入門

Laravel アプリケーション実行環境を Docker で構築する

Docker を使って Laravel アプリケーションを公開する

ここでは Laravel アプリケーションを本番環境で公開するための実行環境を Docker で構築します.具体的には下図の通り,Web サーバには nginx を利用し http://localhost/ という URL でリクエストを受け付けます.Web サーバへのリクエストは PHP をインストールしたアプリケーションサーバに転送され処理されます.さらに,バックエンドのデータベースは MySQL のコンテナで運用します.

web-502

このページの Docker サンプルコードは GitHub の Laravel02Nginx フォルダで公開しています.また,Laravel のコードも GitHub で公開しています.

目次に戻る

ファイル/フォルダ構成

任意の新規ディレクトリを作成し,その中に次の構成でディレクトリとファイルを設置します.なお,Laravel プロジェクトは laravel ディレクトリに設置します.Docker の Git リポジトリには Laravel プロジェクトのコードが含まれないように laravel/.gitignore を設置しておきます.また,ログファイルも Git に含まれないように logs/nginx/.gitignore も設置しておきます.さらに,.env ファイルには MySQL のユーザ名とパスワードなどを保存しますが,やはりそのファイルが Git のリポジトリに含まれないように .gitignore を設置します.

Laravel02Nginx % tree -a -F ⏎
./
├── .env
├── .env.example
├── .gitignore
├── docker-compose.yml
├── laravel/
│   └── .gitignore
├── logs/
│   └── nginx/
│       └── .gitignore
├── mysql/
│   ├── Dockerfile
│   ├── my.cnf
│   └── script/
│       └── init-db.sql
├── nginx/
│   └── conf.d/
│       └── default.conf
├── php/
│   ├── Dockerfile
│   └── php.ini
└── Readme.md

9 directories, 13 files
Laravel02Nginx %

目次に戻る

全体設計

全体の設計図である docker-compose.yml は次のような内容にします.つまり,3つのサービスと1つのボリュームから構成されます.Web サーバとなる nginx コンテナ,アプリケーションサーバとなる laravel_php コンテナ(サービス名 app),データベースサーバとなる laravel_mysql コンテナ(サービス名 mysql) というコンテナと,データベースを保存するためのボリューム(ボリューム名 mysqlvolume) からなる構成です.

docker-compose.yml
services:
  nginx:
    image: nginx:1.25.5
    container_name: nginx
    ports:
      - 80:80
    volumes:
      - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
      - ./laravel/example-laravel-app:/var/www/html
      - ./logs/nginx:/var/log/nginx
    depends_on:
      - app

  app:
    build:
      context: .
      dockerfile: ./php/Dockerfile
      args:
          IMAGE: ${PHP_IMAGE}
    container_name: laravel_php
    volumes:
      - ./php/php.ini:/usr/local/etc/php/php.ini
      - ./laravel/example-laravel-app:/var/www/html
    depends_on:
      - mysql

  mysql:
    build:
      context: .
      dockerfile: ./mysql/Dockerfile
      args:
          IMAGE: ${MYSQL_IMAGE}
    container_name: laravel_mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
      - mysqlvolume:/var/lib/mysql
      - ./mysql/script:/docker-entrypoint-initdb.d
    ports:
      - 3306:3306
volumes:
  mysqlvolume:

Laravel のプロジェクトは laravel/example-laravel-app に配置しますが,これ自体が Docker の Git リポジトリに含まれないように laravel/.gitignore に次の指定をしておきます.

laravel/.gitignore
*

目次に戻る

Nginx の設定

Nginx は docker-compose.yml の3行目にあるとおり,nginx:1.25.5 イメージをそのまま利用してコンテナを起動します.Nginx の設定ファイルには次のような nginx/conf.d/default.conf を利用することにします.ここで,23行目の appdocker-compose.yml のサービス名 app と一致させていることに注意してください.また,Nginx と FastCGI (php-fpm) という組合せで PHP の実行プロセスを処理することにも注意してください.


server {
  listen 80;

  server_name localhost;
  root /var/www/html/public;

  add_header X-Frame-Options "SAMEORIGIN";
  add_header X-Content-Type-Options "nosniff";

  index 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 app:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_hide_header X-Powered-By;
    include fastcgi_params;
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }
    fastcgi_param HTTP_PROXY "";
    fastcgi_index index.php;
    include fastcgi_params;
  }


  location ~ /\.(?!well-known).* {
    deny all;
  }
}

Nginx のアクセスログ (access.log および error.log) は log/nginx/ に格納されます.これらのログファイルが Git のリポジトリに含まれないように log/nginx/.gitignore は次の内容にします.

log/nginx/.gitignore
*

目次に戻る

PHP-FPM の設定

次に,PHP のアプリケーションサーバとなる Docker イメージを設計します.まず,利用する Docker イメージを .env で指定します.PHP-FPM (FastCGI Process Manager) は負荷の高いサイトに主に役立ついくつかの機能を備えた主要な PHP FastCGI 実装です

.env(抜粋)
# PHP
PHP_IMAGE=php:8.4.14-fpm

PHP の Docker イメージを設計するための Dockerfile は次の内容とします.具体的には php-fpm ベースイメージのアップデートを実施し,いくつかのコマンド (git, curl など) をインストールした後,PHP 拡張モジュールを Docker にインストールするヘルパーコマンド (docker-php-ext-install),PHP から MySQL データベースへのアクセスを可能にするためのドライバ (pdo_mysql) をインストールしています.

php/Dockerfile
ARG IMAGE

FROM ${IMAGE}

RUN apt-get update \
    && apt-get install -y git curl zip unzip \
    && docker-php-ext-install pdo_mysql

WORKDIR /var/www

PHP の設定は次のとおりとします.

php/php.ini
[PHP]
post_max_size = 100M
upload_max_filesize = 100M
variables_order = EGPCS

目次に戻る

MySQL の設定

続いて MySQL の準備を行います.ベースイメージの指定とユーザ名,パスワードは .env に設定します.ここで,管理者パスワード MYSQL_ROOT_PASSWORD とユーザ (docker-user) のパスワード MYSQL_PASSWORD には複雑な文字列を設定するようにしてください.

.env(抜粋)
# MySQL
# MYSQL_IMAGE=arm64v8/mysql:8.4
MYSQL_IMAGE=mysql:8.4

MYSQL_ROOT_PASSWORD=password
MYSQL_USER=docker-user
MYSQL_PASSWORD=secret

MySQL はここここと同じように日本語文字の文字化けが発生しないように Docker イメージのビルドを次のとおり設定します.

mysql/Dockerfile
ARG IMAGE

FROM ${IMAGE}

RUN microdnf install -y glibc-locale-source glibc-langpack-en && \
    microdnf clean all

RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

また,MySQL の設定ファイルも次のとおり準備します.

mysql/my.cnf
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci

[client]
default-character-set=utf8mb4

さらに,MySQL コンテナの初回起動時にはボリュームが生成され,データベースの生成,ユーザ権限の設定を行います.この指示は init-db.sql に記載します.ここでユーザ名 (docker-user) は .env で設定したユーザ名と同じものを設定するようにしてください.また,データベース名 (commentsDB) は Laravel プロジェクトの .env にも同じ名称を設定しなければならないことにも注意してください.

mysql/script/init-db.sql
CREATE DATABASE IF NOT EXISTS `commentsDB`;
GRANT ALL PRIVILEGES ON `commentsDB`.* TO 'docker-user';

.env にはパスワードを記載する必要があるため,Git のリポジトリに .env を含めてはなりません.このため,プロジェクト全体の .gitignore には .env を指定します.(macOS の場合は .DS_Store も入れておくと良いでしょう.)

.gitignore
.env
.DS_Store

目次に戻る

Laravel プロジェクトの準備

次に,Laravel のプロジェクトについて GitHub から (2) のコマンドでクローンを作成します.ここで,プロジェクトは laravel/example-laravel-app/ 以下に設置することがdocker-compose.yml で指定されていることに注意し,(4) ではダウンロードしたディレクトリ名(フォルダ名)を変更しています.

Laravel02Nginx % cd laravel ⏎  # (1) ディレクトリの移動
laravel % git clone git@github.com:rinsaka/laravel-comment-app-2025.git ⏎  # (2) クローンの作成
Cloning into 'laravel-comment-app-2025'...
remote: Enumerating objects: 236, done.
remote: Counting objects: 100% (236/236), done.
remote: Compressing objects: 100% (138/138), done.
remote: Total 236 (delta 78), reused 228 (delta 70), pack-reused 0 (from 0)
Receiving objects: 100% (236/236), 101.37 KiB | 313.00 KiB/s, done.
Resolving deltas: 100% (78/78), done.
laravel % ls ⏎  # (3) ディレクトリ/ファイルの一覧(Windows では dir コマンド)
laravel-comment-app-2025
laravel % mv laravel-comment-app-2025 example-laravel-app ⏎  # (4) ディレクトリ名の変更(Windows では ren / rename コマンド)
laravel % ls ⏎  # (5) ディレクトリ/ファイルの一覧(Windows では dir コマンド)
example-laravel-app
laravel %

クローンを作成した Laravel プロジェクトにはセキュリティの関係で .env は含まれておらず,そのサンプルである .env.example が含まれています.次のコマンドで,.env.example のコピーを .env として作成します.

laravel % cd example-laravel-app ⏎  # (1) ディレクトリを移動
example-laravel-app % cp .env.example .env ⏎  # (2) ファイルをコピー(Windows では copy コマンド)
example-laravel-app %

.env のデータベースに関する設定を次のとおり編集します.ここで,データベース名 (DB_DATABASE) には init-db.sql に指定した名称と同じものを設定するようにしてください.また,ユーザ名 (DB_USERNAME) とパスワード (DB_PASSWORD) には Docker プロジェクトの .env に設定した内容と同じものを設定してください.

laravel/example-laravel-app/.env(抜粋)
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=commentsDB
DB_USERNAME=docker-user
DB_PASSWORD=secret

GitHub からクローンを作成した Laravel プロジェクトには vendor ディレクトリ以下のファイルが含まれていません.vendor ディレクトリには PHP Composer 他,Laravel の実行に必要な様々なパッケージをインストールする必要があります.次のコマンドで PHP Composer などをインストールします.

example-laravel-app % docker run --rm \
  -v $(pwd):/opt \
  -w /opt \
  laravelsail/php84-composer:latest \
  bash -c "composer install" ⏎
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 112 installs, 0 updates, 0 removals
  - Downloading doctrine/inflector (2.1.0)
  - Downloading doctrine/lexer (3.0.1)
  - Downloading webmozart/assert (1.11.0)
  - Downloading dragonmantank/cron-expression (v3.4.0)
  - Downloading symfony/deprecation-contracts (v3.6.0)
  - Downloading fakerphp/faker (v1.24.1)
  - Downloading symfony/polyfill-php83 (v1.33.0)
  - Downloading symfony/polyfill-mbstring (v1.33.0)
  - Downloading symfony/http-foundation (v7.3.4)
  - Downloading fruitcake/php-cors (v1.3.0)
  - Downloading psr/http-message (2.0)
  - Downloading psr/http-client (1.0.3)
  - Downloading ralouphie/getallheaders (3.0.3)
  - Downloading psr/http-factory (1.1.0)
  - Downloading guzzlehttp/psr7 (2.8.0)
  - Downloading guzzlehttp/promises (2.3.0)
  - Downloading guzzlehttp/guzzle (7.10.0)
  - Downloading symfony/polyfill-php80 (v1.33.0)
  - Downloading guzzlehttp/uri-template (v1.0.5)
  - Downloading symfony/polyfill-intl-grapheme (v1.33.0)
  - Downloading symfony/string (v7.3.4)
  - Downloading symfony/service-contracts (v3.6.0)
  - Downloading symfony/console (v7.3.4)
  - Downloading nunomaduro/termwind (v2.3.2)
  - Downloading phpoption/phpoption (1.9.4)
  - Downloading graham-campbell/result-type (v1.1.3)
  - Downloading vlucas/phpdotenv (v5.6.2)
  - Downloading symfony/css-selector (v7.3.0)
  - Downloading tijsverkoyen/css-to-inline-styles (v2.3.0)
  - Downloading symfony/var-dumper (v7.3.4)
  - Downloading symfony/polyfill-uuid (v1.33.0)
  - Downloading symfony/uid (v7.3.1)
  - Downloading symfony/routing (v7.3.4)
  - Downloading symfony/process (v7.3.4)
  - Downloading symfony/polyfill-php85 (v1.33.0)
  - Downloading symfony/polyfill-php84 (v1.33.0)
  - Downloading symfony/polyfill-intl-idn (v1.33.0)
  - Downloading symfony/mime (v7.3.4)
  - Downloading psr/event-dispatcher (1.0.0)
  - Downloading symfony/event-dispatcher-contracts (v3.6.0)
  - Downloading symfony/event-dispatcher (v7.3.3)
  - Downloading psr/log (3.0.2)
  - Downloading egulias/email-validator (4.0.4)
  - Downloading symfony/mailer (v7.3.4)
  - Downloading symfony/error-handler (v7.3.4)
  - Downloading symfony/http-kernel (v7.3.4)
  - Downloading symfony/finder (v7.3.2)
  - Downloading ramsey/collection (2.1.1)
  - Downloading brick/math (0.14.0)
  - Downloading ramsey/uuid (4.9.1)
  - Downloading symfony/translation-contracts (v3.6.0)
  - Downloading symfony/translation (v7.3.4)
  - Downloading symfony/clock (v7.3.0)
  - Downloading nesbot/carbon (3.10.3)
  - Downloading monolog/monolog (3.9.0)
  - Downloading league/uri-interfaces (7.5.0)
  - Downloading league/uri (7.5.1)
  - Downloading league/mime-type-detection (1.16.0)
  - Downloading league/flysystem-local (3.30.0)
  - Downloading league/flysystem (3.30.0)
  - Downloading nette/utils (v4.0.8)
  - Downloading nette/schema (v1.3.2)
  - Downloading dflydev/dot-access-data (v3.0.3)
  - Downloading league/config (v1.2.0)
  - Downloading league/commonmark (2.7.1)
  - Downloading laravel/serializable-closure (v2.0.6)
  - Downloading laravel/prompts (v0.3.7)
  - Downloading laravel/framework (v12.34.0)
  - Downloading laravel/pail (v1.2.3)
  - Downloading laravel/pint (v1.25.1)
  - Downloading symfony/yaml (v7.3.3)
  - Downloading laravel/sail (v1.46.0)
  - Downloading nikic/php-parser (v5.6.1)
  - Downloading psy/psysh (v0.12.12)
  - Downloading laravel/tinker (v2.10.1)
  - Downloading hamcrest/hamcrest-php (v2.1.1)
  - Downloading mockery/mockery (1.6.12)
  - Downloading filp/whoops (2.18.4)
  - Downloading nunomaduro/collision (v8.8.2)
  - Downloading staabm/side-effects-detector (1.0.5)
  - Downloading sebastian/version (5.0.2)
  - Downloading sebastian/type (5.1.3)
  - Downloading sebastian/recursion-context (6.0.3)
  - Downloading sebastian/object-reflector (4.0.1)
  - Downloading sebastian/object-enumerator (6.0.1)
  - Downloading sebastian/global-state (7.0.2)
  - Downloading sebastian/exporter (6.3.2)
  - Downloading sebastian/environment (7.2.1)
  - Downloading sebastian/diff (6.0.2)
  - Downloading sebastian/comparator (6.3.2)
  - Downloading sebastian/code-unit (3.0.3)
  - Downloading sebastian/cli-parser (3.0.2)
  - Downloading phpunit/php-timer (7.0.1)
  - Downloading phpunit/php-text-template (4.0.1)
  - Downloading phpunit/php-invoker (5.0.1)
  - Downloading phpunit/php-file-iterator (5.1.0)
  - Downloading sebastian/lines-of-code (3.0.1)
  - Downloading sebastian/complexity (4.0.1)
  - Downloading sebastian/code-unit-reverse-lookup (4.0.1)
  - Downloading phpunit/php-code-coverage (11.0.11)
  - Downloading myclabs/deep-copy (1.13.4)
  - Downloading phpunit/phpunit (11.5.42)
   0/102 [>---------------------------]   0%
  11/102 [===>------------------------]  10%
  22/102 [======>---------------------]  21%
  34/102 [=========>------------------]  33%
  42/102 [===========>----------------]  41%
  53/102 [==============>-------------]  51%
  65/102 [=================>----------]  63%
  74/102 [====================>-------]  72%
  82/102 [======================>-----]  80%
  95/102 [==========================>-]  93%
 102/102 [============================] 100%
  - Installing doctrine/inflector (2.1.0): Extracting archive
  - Installing doctrine/lexer (3.0.1): Extracting archive
  - Installing symfony/polyfill-ctype (v1.33.0): Extracting archive
  - Installing webmozart/assert (1.11.0): Extracting archive
  - Installing dragonmantank/cron-expression (v3.4.0): Extracting archive
  - Installing symfony/deprecation-contracts (v3.6.0): Extracting archive
  - Installing psr/container (2.0.2): Extracting archive
  - Installing fakerphp/faker (v1.24.1): Extracting archive
  - Installing symfony/polyfill-php83 (v1.33.0): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.33.0): Extracting archive
  - Installing symfony/http-foundation (v7.3.4): Extracting archive
  - Installing fruitcake/php-cors (v1.3.0): Extracting archive
  - Installing psr/http-message (2.0): Extracting archive
  - Installing psr/http-client (1.0.3): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing psr/http-factory (1.1.0): Extracting archive
  - Installing guzzlehttp/psr7 (2.8.0): Extracting archive
  - Installing guzzlehttp/promises (2.3.0): Extracting archive
  - Installing guzzlehttp/guzzle (7.10.0): Extracting archive
  - Installing symfony/polyfill-php80 (v1.33.0): Extracting archive
  - Installing guzzlehttp/uri-template (v1.0.5): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.33.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.33.0): Extracting archive
  - Installing symfony/string (v7.3.4): Extracting archive
  - Installing symfony/service-contracts (v3.6.0): Extracting archive
  - Installing symfony/console (v7.3.4): Extracting archive
  - Installing nunomaduro/termwind (v2.3.2): Extracting archive
  - Installing voku/portable-ascii (2.0.3): Extracting archive
  - Installing phpoption/phpoption (1.9.4): Extracting archive
  - Installing graham-campbell/result-type (v1.1.3): Extracting archive
  - Installing vlucas/phpdotenv (v5.6.2): Extracting archive
  - Installing symfony/css-selector (v7.3.0): Extracting archive
  - Installing tijsverkoyen/css-to-inline-styles (v2.3.0): Extracting archive
  - Installing symfony/var-dumper (v7.3.4): Extracting archive
  - Installing symfony/polyfill-uuid (v1.33.0): Extracting archive
  - Installing symfony/uid (v7.3.1): Extracting archive
  - Installing symfony/routing (v7.3.4): Extracting archive
  - Installing symfony/process (v7.3.4): Extracting archive
  - Installing symfony/polyfill-php85 (v1.33.0): Extracting archive
  - Installing symfony/polyfill-php84 (v1.33.0): Extracting archive
  - Installing symfony/polyfill-intl-idn (v1.33.0): Extracting archive
  - Installing symfony/mime (v7.3.4): Extracting archive
  - Installing psr/event-dispatcher (1.0.0): Extracting archive
  - Installing symfony/event-dispatcher-contracts (v3.6.0): Extracting archive
  - Installing symfony/event-dispatcher (v7.3.3): Extracting archive
  - Installing psr/log (3.0.2): Extracting archive
  - Installing egulias/email-validator (4.0.4): Extracting archive
  - Installing symfony/mailer (v7.3.4): Extracting archive
  - Installing symfony/error-handler (v7.3.4): Extracting archive
  - Installing symfony/http-kernel (v7.3.4): Extracting archive
  - Installing symfony/finder (v7.3.2): Extracting archive
  - Installing ramsey/collection (2.1.1): Extracting archive
  - Installing brick/math (0.14.0): Extracting archive
  - Installing ramsey/uuid (4.9.1): Extracting archive
  - Installing psr/simple-cache (3.0.0): Extracting archive
  - Installing symfony/translation-contracts (v3.6.0): Extracting archive
  - Installing symfony/translation (v7.3.4): Extracting archive
  - Installing psr/clock (1.0.0): Extracting archive
  - Installing symfony/clock (v7.3.0): Extracting archive
  - Installing carbonphp/carbon-doctrine-types (3.2.0): Extracting archive
  - Installing nesbot/carbon (3.10.3): Extracting archive
  - Installing monolog/monolog (3.9.0): Extracting archive
  - Installing league/uri-interfaces (7.5.0): Extracting archive
  - Installing league/uri (7.5.1): Extracting archive
  - Installing league/mime-type-detection (1.16.0): Extracting archive
  - Installing league/flysystem-local (3.30.0): Extracting archive
  - Installing league/flysystem (3.30.0): Extracting archive
  - Installing nette/utils (v4.0.8): Extracting archive
  - Installing nette/schema (v1.3.2): Extracting archive
  - Installing dflydev/dot-access-data (v3.0.3): Extracting archive
  - Installing league/config (v1.2.0): Extracting archive
  - Installing league/commonmark (2.7.1): Extracting archive
  - Installing laravel/serializable-closure (v2.0.6): Extracting archive
  - Installing laravel/prompts (v0.3.7): Extracting archive
  - Installing laravel/framework (v12.34.0): Extracting archive
  - Installing laravel/pail (v1.2.3): Extracting archive
  - Installing laravel/pint (v1.25.1): Extracting archive
  - Installing symfony/yaml (v7.3.3): Extracting archive
  - Installing laravel/sail (v1.46.0): Extracting archive
  - Installing nikic/php-parser (v5.6.1): Extracting archive
  - Installing psy/psysh (v0.12.12): Extracting archive
  - Installing laravel/tinker (v2.10.1): Extracting archive
  - Installing hamcrest/hamcrest-php (v2.1.1): Extracting archive
  - Installing mockery/mockery (1.6.12): Extracting archive
  - Installing filp/whoops (2.18.4): Extracting archive
  - Installing nunomaduro/collision (v8.8.2): Extracting archive
  - Installing staabm/side-effects-detector (1.0.5): Extracting archive
  - Installing sebastian/version (5.0.2): Extracting archive
  - Installing sebastian/type (5.1.3): Extracting archive
  - Installing sebastian/recursion-context (6.0.3): Extracting archive
  - Installing sebastian/object-reflector (4.0.1): Extracting archive
  - Installing sebastian/object-enumerator (6.0.1): Extracting archive
  - Installing sebastian/global-state (7.0.2): Extracting archive
  - Installing sebastian/exporter (6.3.2): Extracting archive
  - Installing sebastian/environment (7.2.1): Extracting archive
  - Installing sebastian/diff (6.0.2): Extracting archive
  - Installing sebastian/comparator (6.3.2): Extracting archive
  - Installing sebastian/code-unit (3.0.3): Extracting archive
  - Installing sebastian/cli-parser (3.0.2): Extracting archive
  - Installing phpunit/php-timer (7.0.1): Extracting archive
  - Installing phpunit/php-text-template (4.0.1): Extracting archive
  - Installing phpunit/php-invoker (5.0.1): Extracting archive
  - Installing phpunit/php-file-iterator (5.1.0): Extracting archive
  - Installing theseer/tokenizer (1.2.3): Extracting archive
  - Installing sebastian/lines-of-code (3.0.1): Extracting archive
  - Installing sebastian/complexity (4.0.1): Extracting archive
  - Installing sebastian/code-unit-reverse-lookup (4.0.1): Extracting archive
  - Installing phpunit/php-code-coverage (11.0.11): Extracting archive
  - Installing phar-io/version (3.2.1): Extracting archive
  - Installing phar-io/manifest (2.0.4): Extracting archive
  - Installing myclabs/deep-copy (1.13.4): Extracting archive
  - Installing phpunit/phpunit (11.5.42): Extracting archive
   0/112 [>---------------------------]   0%
  13/112 [===>------------------------]  11%
  26/112 [======>---------------------]  23%
  35/112 [========>-------------------]  31%
  45/112 [===========>----------------]  40%
  57/112 [==============>-------------]  50%
  70/112 [=================>----------]  62%
  79/112 [===================>--------]  70%
  93/112 [=======================>----]  83%
 104/112 [==========================>-]  92%
 110/112 [===========================>]  98%
 112/112 [============================] 100%
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

   INFO  Discovering packages.

  laravel/pail .......................................................... DONE
  laravel/sail .......................................................... DONE
  laravel/tinker ........................................................ DONE
  nesbot/carbon ......................................................... DONE
  nunomaduro/collision .................................................. DONE
  nunomaduro/termwind ................................................... DONE

81 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
example-laravel-app %

さらに,Laravel の実行時,storage フォルダにファイルが出力されます.書き込み権限が必要になるため,アクセス権を変更します(この作業はスキップしても良いかもしれません).

example-laravel-app % ls -l | grep storage ⏎  # (1) アクセス権を確認
drwxr-xr-x   5 rinsaka  staff     160 11月 13 16:21 storage
example-laravel-app % chmod -R 777 storage ⏎  # (2) アクセス権の変更
example-laravel-app % ls -l | grep storage ⏎  # (3) アクセス権を確認
drwxrwxrwx   5 rinsaka  staff     160 11月 13 16:21 storage
example-laravel-app % cd ../../

目次に戻る

コンテナの起動

ようやく準備ができたのでコンテナを起動します.最初の起動時は --build オプションを付与してイメージのビルドを行います.

Laravel02Nginx % docker compose up -d --build ⏎
[+] Building 19.7s (18/18) FINISHED
 => [internal] load local bake definitions                                 0.0s
 => => reading from stdin 900B                                             0.0s
 => [mysql internal] load build definition from Dockerfile                 0.0s
 => => transferring dockerfile: 276B                                       0.0s
 => WARN: InvalidDefaultArgInFrom: Default value for ARG ${IMAGE} results  0.0s
 => [app internal] load build definition from Dockerfile                   0.0s
 => => transferring dockerfile: 191B                                       0.0s
 => WARN: InvalidDefaultArgInFrom: Default value for ARG ${IMAGE} results  0.0s
 => [app internal] load metadata for docker.io/library/php:8.4.14-fpm      2.6s
 => [mysql internal] load metadata for docker.io/library/mysql:8.4         1.6s
 => [auth] library/php:pull token for registry-1.docker.io                 0.0s
 => [auth] library/mysql:pull token for registry-1.docker.io               0.0s
 => CACHED [app internal] load .dockerignore                               0.0s
 => => transferring context: 2B                                            0.0s
 => [mysql 1/3] FROM docker.io/library/mysql:8.4@sha256:b306273d4d36bc1a7  0.0s
 => CACHED [mysql 2/3] RUN microdnf install -y glibc-locale-source glibc-  0.0s
 => CACHED [mysql 3/3] RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8         0.0s
 => [mysql] exporting to image                                             0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:dbf6a819532a16dc9da7d948948187f286d9232949867  0.0s
 => => naming to docker.io/library/laravel02nginx-mysql                    0.0s
 => [mysql] resolving provenance for metadata file                         0.0s
 => [app 1/3] FROM docker.io/library/php:8.4.14-fpm@sha256:95876d81a4cbc8  5.8s
 => => resolve docker.io/library/php:8.4.14-fpm@sha256:95876d81a4cbc86f8e  0.0s
 => => sha256:fc5665bd22995935b24c5d8766394552c6720fb813a 3.25kB / 3.25kB  0.0s
 => => sha256:a979881ca2aa8febe2abb6661daf602b292984efb 10.87kB / 10.87kB  0.0s
 => => sha256:1a28af7603cdf6004d302424db9853fb489926eababed22 225B / 225B  0.4s
 => => sha256:95876d81a4cbc86f8e2aa49b5c417697092521c9c 10.30kB / 10.30kB  0.0s
 => => sha256:f2731e5164d54ee6e46123f5188c4200070cceb 110.16MB / 110.16MB  2.5s
 => => sha256:b263042dc7dd327e9f48c2e5bf784f51e4a1c866753a34b 224B / 224B  0.8s
 => => extracting sha256:1a28af7603cdf6004d302424db9853fb489926eababed22c  0.0s
 => => sha256:d2b3c84f2838cff64ff8bafbde54f4267231d7835 13.79MB / 13.79MB  1.4s
 => => sha256:2d415c0a35ffcdcd2cdd9cbdfbbe4e8759207ff3dec7e32 488B / 488B  1.3s
 => => sha256:2952f26b621e51373a10b32d1730c92d9adb91d72 13.33MB / 13.33MB  2.0s
 => => sha256:c97ad7844b63e2d81e4e0a4a6356bd62aa4149cbabc 2.45kB / 2.45kB  1.8s
 => => sha256:f7ddcb1ce63088e30d61bf426cef5ce7b8ad1cf0e3cec1b 251B / 251B  2.3s
 => => sha256:15ca1bbcbfd2ecdd1d25a2cb18d209bcd52a86476da3f1d 245B / 245B  2.5s
 => => sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d 32B / 32B  2.6s
 => => extracting sha256:f2731e5164d54ee6e46123f5188c4200070cceb2705e6dd4  2.5s
 => => sha256:a59d5459d17e4321f99c6aa9f1f8fc8a0c883b6340a 9.20kB / 9.20kB  2.7s
 => => extracting sha256:b263042dc7dd327e9f48c2e5bf784f51e4a1c866753a34b8  0.0s
 => => extracting sha256:d2b3c84f2838cff64ff8bafbde54f4267231d7835dd6ce8d  0.1s
 => => extracting sha256:2d415c0a35ffcdcd2cdd9cbdfbbe4e8759207ff3dec7e324  0.0s
 => => extracting sha256:2952f26b621e51373a10b32d1730c92d9adb91d72b4c20bd  0.3s
 => => extracting sha256:c97ad7844b63e2d81e4e0a4a6356bd62aa4149cbabc4b043  0.0s
 => => extracting sha256:f7ddcb1ce63088e30d61bf426cef5ce7b8ad1cf0e3cec1bd  0.0s
 => => extracting sha256:15ca1bbcbfd2ecdd1d25a2cb18d209bcd52a86476da3f1d6  0.0s
 => => extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6  0.0s
 => => extracting sha256:a59d5459d17e4321f99c6aa9f1f8fc8a0c883b6340a11b01  0.0s
 => [app 2/3] RUN apt-get update     && apt-get install -y git curl zip   10.9s
 => [app 3/3] WORKDIR /var/www                                             0.0s
 => [app] exporting to image                                               0.2s
 => => exporting layers                                                    0.2s
 => => writing image sha256:d58d4b10c52cd32b07310adab055df621c3bc5ff164b4  0.0s
 => => naming to docker.io/library/laravel02nginx-app                      0.0s
 => [app] resolving provenance for metadata file                           0.0s
[+] Running 7/7
 ✔ mysql                                Built                              0.0s
 ✔ app                                  Built                              0.0s
 ✔ Network laravel02nginx_default       Created                            0.0s
 ✔ Volume "laravel02nginx_mysqlvolume"  Created                            0.0s
 ✔ Container laravel_mysql              Start...                           0.2s
 ✔ Container laravel_php                Started                            0.3s
 ✔ Container nginx                      Started                            0.4s
Laravel02Nginx %

念のため,コンテナの起動状況を確認します.

Laravel02Nginx % docker container ls ⏎
CONTAINER ID   IMAGE                  COMMAND                   CREATED          STATUS          PORTS                                         NAMES
bc701969547f   nginx:1.25.5           "/docker-entrypoint.…"   25 seconds ago   Up 24 seconds   0.0.0.0:80->80/tcp, [::]:80->80/tcp           nginx
184a54790146   laravel02nginx-app     "docker-php-entrypoi…"   25 seconds ago   Up 24 seconds   9000/tcp                                      laravel_php
969ddaa17d4b   laravel02nginx-mysql   "docker-entrypoint.s…"   25 seconds ago   Up 24 seconds   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp   laravel_mysql
Laravel02Nginx %

目次に戻る

アプリケーションの初期設定

はじめてコンテナを起動したのでいくつかの初期設定を行う必要があります.これにはアプリケーションサーバのコンテナ(サービス名 app,コンテナ名 laravel_php)に入り以下の作業を行う必要があります.まず,コンテナにログインします.

Laravel02Nginx % docker compose exec app /bin/bash ⏎
root@184a54790146:/var/www#

(1) でディレクトリの一覧を確認し,(2) では html ディレクトリに移動します.(3) では Laravel プロジェクトのソースがあることを確認します.(4) では PHP のバージョン番号を表示して php コマンドが利用できることを確認しています.さらに (5) では artisan のバージョン番号を表示して php artisan コマンドが動作することを確認しています.

root@184a54790146:/var/www# ls ⏎  # (1) 
html
root@184a54790146:/var/www# cd html ⏎  # (2) 
root@184a54790146:/var/www/html# ls ⏎  # (3) 
README.md  compose.yaml   database	resources  vendor
app	   composer.json  package.json	routes	   vite.config.js
artisan    composer.lock  phpunit.xml	storage
bootstrap  config	  public	tests
root@184a54790146:/var/www/html# php --version ⏎  # (4) 
PHP 8.4.14 (cli) (built: Nov  4 2025 01:23:04) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.4.14, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.14, Copyright (c), by Zend Technologies
root@184a54790146:/var/www/html# php artisan --version ⏎  # (5) 
Laravel Framework 12.34.0
root@184a54790146:/var/www/html#

次のコマンドで Laravel プロジェクトの .env ファイルの先頭を表示します.ここで,アプリケーションキー (APP_KEY) がまだ設定されていないことを確認します.

root@184a54790146:/var/www/html# cat .env | head ⏎
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

APP_LOCALE=ja
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=ja_JP

root@184a54790146:/var/www/html#

次のコマンドでアプリケーションキーを生成します.

root@184a54790146:/var/www/html# php artisan key:generate ⏎

   INFO  Application key set successfully.

root@184a54790146:/var/www/html#

アプリケーションキーが生成されたことを上と同じコマンドで確認します.

root@184a54790146:/var/www/html# cat .env | head ⏎
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:EMLfrZ3CxpugLAZhmh+UhcQRx/TENF036kUYqW0EKNQ=
APP_DEBUG=true
APP_URL=http://localhost

APP_LOCALE=ja
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=ja_JP

root@184a54790146:/var/www/html#

次に,(1) でデータベースにテーブルを生成し,(2) でテストデータを投入します.(3) ではコンテナからログアウトしています.

root@184a54790146:/var/www/html# php artisan migrate ⏎  # (1) 

   INFO  Preparing database.

  Creating migration table ...................................... 12.62ms DONE

   INFO  Running migrations.

  0001_01_01_000000_create_users_table .......................... 35.53ms DONE
  0001_01_01_000001_create_cache_table .......................... 11.38ms DONE
  0001_01_01_000002_create_jobs_table ........................... 26.42ms DONE
  2025_10_19_110214_create_comments_table ........................ 6.17ms DONE

root@184a54790146:/var/www/html# php artisan db:seed ⏎  # (2) 

   INFO  Seeding database.

  Database\Seeders\CommentsTableSeeder ............................... RUNNING
  Database\Seeders\CommentsTableSeeder ............................. 5 ms DONE

root@184a54790146:/var/www/html# exit ⏎  # (3) 
exit
Laravel02Nginx %

本番環境の場合,.env は次のとおり変更すると良いでしょう.

laravel/example-laravel-app/.env(抜粋)
APP_NAME=Laravel
APP_ENV=production
APP_KEY=base64:EMLfrZ3CxpugLAZhmh+UhcQRx/TENF036kUYqW0EKNQ=
APP_DEBUG=false
APP_URL=http://localhost

目次に戻る

動作確認

準備ができたので Web ブラウザで http://localhost/ にアクセスします.

docker-2025-laravel-03

「コメント掲示板」に進むとコメントの一覧が表示されました.

docker-2025-laravel-04

「Title」と「Body」に入力して「投稿」をクリックします.

docker-2025-laravel-05

新たなコメントが投稿できました.

docker-2025-laravel-06

投稿内容の詳細ページにもアクセスできます.

docker-2025-laravel-07

目次に戻る

MySQL の利用方法

続いて,MySQL コンテナへの接続と利用方法を確認します.次の一連のコマンドでは (1) で mysql コンテナにログインしたあと,(2) で docker-user というユーザ名で mysql に接続しています.

Laravel02Nginx % docker compose exec mysql /bin/bash ⏎  # (1) 
bash-5.1# mysql -u docker-user -p ⏎  # (2) 
Enter password:   # (3) パスワードの入力内容は表示されません
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 16
Server version: 8.4.7 MySQL Community Server - GPL

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW DATABASES; ⏎  # (4) データベースの一覧
+--------------------+
| Database           |
+--------------------+
| commentsDB         |
| information_schema |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

mysql> USE commentsDB; ⏎  # (5) データベースの変更(指定)
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SHOW TABLES; ⏎  # (6) テーブル一覧
+-----------------------+
| Tables_in_commentsDB  |
+-----------------------+
| cache                 |
| cache_locks           |
| comments              |
| failed_jobs           |
| job_batches           |
| jobs                  |
| migrations            |
| password_reset_tokens |
| sessions              |
| users                 |
+-----------------------+
10 rows in set (0.00 sec)

mysql> DESC comments; ⏎  # (7) テーブル定義の確認
+------------+-----------------+------+-----+---------+----------------+
| Field      | Type            | Null | Key | Default | Extra          |
+------------+-----------------+------+-----+---------+----------------+
| id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| title      | varchar(255)    | NO   |     | NULL    |                |
| body       | text            | NO   |     | NULL    |                |
| created_at | timestamp       | YES  |     | NULL    |                |
| updated_at | timestamp       | YES  |     | NULL    |                |
+------------+-----------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM comments; ⏎  # (8) データの表示
+----+----------------------------+--------------------------------------------------------------+---------------------+---------------------+
| id | title                      | body                                                         | created_at          | updated_at          |
+----+----------------------------+--------------------------------------------------------------+---------------------+---------------------+
|  1 | 最初のコメント             | 最初のコメントです!                                         | NULL                | NULL                |
|  2 | 2つ目                      | 2つ目のコメントです!                                        | NULL                | NULL                |
|  3 | <三個目>のコメント         | シーダによってテストデータを設定します.                     | NULL                | NULL                |
|  4 | docker                     | Nginx+PHP+MySQLで動いています                                | 2025-11-13 16:34:14 | 2025-11-13 16:34:14 |
+----+----------------------------+--------------------------------------------------------------+---------------------+---------------------+
4 rows in set (0.00 sec)

mysql> exit ⏎  # (9) mysql の終了
Bye
bash-5.1# exit ⏎  # (10) コンテナからのログアウト
exit
Laravel02Nginx %

MySQL には root ユーザ(管理者)でログインすることも可能です.なお,root ユーザのパスワードは .envMYSQL_ROOT_PASSWORD で指定したものを入力してください.管理者で MySQL にログインした場合は利用可能なデータベースが一般ユーザよりも多いことが分かります.

Laravel02Nginx % docker compose exec mysql /bin/bash ⏎  # (1) 
bash-5.1# mysql -u root -p ⏎  # (2) 
Enter password:   # (3) 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 8.4.7 MySQL Community Server - GPL

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW DATABASES; ⏎  # (4) データベースの一覧
+--------------------+
| Database           |
+--------------------+
| commentsDB         |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> exit ⏎  # (5) 
Bye
bash-5.1# exit ⏎  # (6) 
exit
Laravel02Nginx %

目次に戻る

コンテナの終了

本番環境ではほとんど利用する機会がないかもしれませんが,コンテナを停止するには docker compose stop,コンテナを停止したうえで破棄する場合は docker compose down を実行します.

Laravel02Nginx % docker compose stop ⏎
[+] Stopping 3/3
 ✔ Container nginx          Stopped                                        0.2s
 ✔ Container laravel_php    Stopped                                        0.1s
 ✔ Container laravel_mysql  Stopped                                        1.7s
Laravel02Nginx %