1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[laravel]Dockerマルチステージビルドで環境構築をやってみる

Posted at

はじめに

Dockerで環境構築していると、開発環境のみ必要なライブラリやパッケージなども多く、
イメージサイズに悩まされることがあります。
そんな時、ステージを分けて必要なものだけに絞った構築ができることを知りました。
今回のテーマは「Laravel環境をDockerマルチステージビルドで環境構築したい」です!

ディレクトリ

nginx,php,mysqlという環境で構築していきます。
細かい環境構築の内容については、他の記事を参考にしてください。

dockerディレクトリ配下にコンテナ別でファイルを管理。
laravelアプリ自体のファイルはwwwディレクトリ配下に配置。

.
├── README.md
├── docker-compose.yml
├── .env
├── docker
│   ├── mysql
│   │   └── my.cnf
│   ├── nginx
│   │   └── default.conf
│   └── php
│       ├── Dockerfile
│       └── php.ini
└── www
    ├── README.md
    ├── app
    ・
    ・
    ・

docker-compose.yml と .envを準備

マルチステージビルドは、ymlファイルでtargetを指定することでどのステージをビルドするか選択することができます。
まずはdocker-compose.ymlを準備し、php>build>targetの部分をenvファイルから指定できるようにしていきます。

docker-compose.yml
services:
    php:
        container_name: ${PROJECT_NAME:?err}-php
        build:
            dockerfile: ./docker/php/Dockerfile
            target: ${BUILD_STAGE_TARGET:?err} # ここで指定
        ports:
            - ${DEV_HOST_PORT:?err}:5173
        volumes:
            - ./docker/php/php.ini:/usr/local/etc/php/php.ini
            - ./www:/var/www
            - vendor-store:/var/www/vendor #vendor volume mount
            - node_modules-store:/var/www/node_modules #node_modules volume mount
            - storage-framework-store:/var/www/storage/framework #storage volume mount

    nginx:
        image: ${NGINX_IMAGE:?err}
        container_name: ${PROJECT_NAME:?err}-nginx
        ports:
            - ${WEB_HOST_PORT_HTTP:?err}:80
            - ${WEB_HOST_PORT_HTTPS:?err}:443
        volumes:
            - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
            - ./www/public:/var/www/public
        depends_on:
            - php

    mysql:
        image: ${MYSQL_IMAGE:?err}
        ports:
            - ${DB_HOST_PORT:?err}:3306
        volumes:
            - ./docker/mysql/my.cnf:/etc/my.cnf
            - db-store:/var/lib/mysql
        environment:
            - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:?err}
            - MYSQL_DATABASE=${MYSQL_DATABASE:?err}
            - MYSQL_USER=${MYSQL_USER:?err}
            - MYSQL_PASSWORD=${MYSQL_PASSWORD:?err}
            - TZ=Asia/Tokyo

volumes:
    db-store:
    vendor-store: #vendor
    node_modules-store: #node_modules
    storage-framework-store: #storage

実際は、開発/テスト/ステージング/本番などいくつかに分かれることが多いと思いますが、
今回はお試しということで開発(development)と本番(production)の2つにしています。

.env
PROJECT_NAME=test-app

# php
BUILD_STAGE_TARGET=development  # development / production
DEV_HOST_PORT=5173


# nginx
NGINX_IMAGE=nginx:alpine
WEB_HOST_PORT_HTTP=80
WEB_HOST_PORT_HTTPS=443


# db
MYSQL_IMAGE=mysql:8.0
DB_HOST_PORT=3306
MYSQL_ROOT_PASSWORD=app1
MYSQL_DATABASE=app1
MYSQL_USER=app1
MYSQL_PASSWORD=app1

Dockerfile

・nginxとmysqlは公式のイメージを使い、マルチステージビルドに対応するのはphpのDockerfileとなります。
・今回は3つのステージを作成

1. builderステージ

Laravelのビルドに必要なベース部分を構築するパッケージをインストール
ソースコードもコピーしてcomposer installまで行います。

2. developmentステージ

そのままbuilderステージを引き継いで、開発に必要なパッケージを追加
デバッグ用にXdebugと、フロントエンド開発に必要なのでnode.jsを追加
npm installまで行います。
ここまでであれば、普通に開発環境のDockerfileと変わりません。

3. productionステージ

ここからがマルチステージビルドの目的になります。
・ベースイメージから作り直し
・ランタイムに必要なパッケージだけに絞ってインストール
・必要なファイルはビルドした①のステージからコピーする
こうすることでビルド時だけ使われる余計なファイルを含まない環境を構築してイメージ容量を削減できるというわけです。

Dockerfile
# builderステージ
FROM php:8.2-fpm-alpine as builder

# 必要なパッケージのインストール
RUN apk update && apk add --no-cache \
    oniguruma-dev \
    libxml2-dev \
    libzip-dev \
    bash \
    vim \
    git

# PHP拡張のインストール
RUN docker-php-ext-install -j$(nproc) \
    pdo_mysql \
    bcmath \
    zip

# gd拡張をインストール
# 必要なパッケージを追加:libpng-dev freetype-dev libjpeg-turbo-dev libwebp-dev
RUN apk add --no-cache \
    libpng-dev \
    freetype-dev \
    libjpeg-turbo-dev \
    libwebp-dev
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install gd

# アプリケーションのソースコードをコピー
WORKDIR /var/www
COPY ./www /var/www

# Composerのインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Composerを使用して依存関係をインストール
RUN composer install --no-dev --optimize-autoloader \
    && composer dump-autoload --optimize


# ====================================
# developmentステージ
FROM builder as development

# Xdebugのインストール
RUN apk add --no-cache linux-headers $PHPIZE_DEPS \
    && pecl install xdebug \
    && docker-php-ext-enable xdebug
# 設定ファイルをコピー
COPY ./docker/php/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini

# node.jsのインストール
RUN apk add --no-cache nodejs npm
# npmパッケージのインストール
RUN npm install

# www-dataユーザーに所有権を変更
RUN chown -R www-data:www-data /var/www


# ====================================
# productionステージ
FROM php:8.2-fpm-alpine as production

# 必要なランタイムパッケージのみをインストール
RUN apk add --no-cache \
    oniguruma \
    libxml2 \
    libzip \
    libpng \
    freetype \
    libjpeg-turbo \
    libwebp \
    bash \
    vim \
    git

# ビルダーステージから必要なファイルをコピー
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/bin/composer /usr/bin/composer
COPY --from=builder /var/www /var/www
WORKDIR /var/www

# www-dataユーザーに所有権を変更
RUN chown -R www-data:www-data /var/www

さいごに

  • productionステージで最低限の内容にしたことでイメージサイズがかなり小さくできました!
     development : 675.75MB
     production : 176.44MB

  • 環境毎にDockerfileを分けたりする必要もなく、それぞれ必要なものだけにしておけるのでとても便利でした👏

  • Laravelの記事をあまり書いていませんでしたが、これからは少しずつ書いていこうと思います。

参考

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?