84
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

LaravelのインフラをDockerで作ってみた

Last updated at Posted at 2020-01-27

Laravelのインフラ構築をDockerでやってみました。

この記事ではLaravelのアプリケーションをコンテナ化するのではなく、
インフラだけをコンテナにして、アプリケーションはDockerの外でデプロイするようにしています。

ここに至る経緯として、最初はECSでの運用なども視野に入れていたのですが、
最終的に現在のチームのスキルなどを考慮して、コンテナの知識がそれほど高くないエンジニアでも気軽にデプロイできることを目指しました。

今回やりたいことはAnsibleなどを使えばいいんでしょうが、あんまり知識がないのでとりあえず多少知識のあるDockerを採用しました。

構築対象はまっさらのEC2インスタンスを想定しており、phpなどが入ってない想定です。
なので、Dockerでそのあたりも構築していきます。

というわけで、まずは構成を紹介して、後半で環境構築手順を説明していきます。

コンテナ構成

  • web
    • nginxを実行するコンテナ
  • fpm
    • php-fpmを実行するコンテナ
  • php
    • phpコマンドを実行するためのコンテナ
  • worker
    • キューワーカとして動作させるコンテナ
  • scheduler
    • スケジューラとして動作させるコンテナ
  • db
    • develop環境でのdbコンテナ
  • phpmyadmin
    • db管理用のPHPMyAdminコンテナ
  • redis
    • develop環境でのredisコンテナ
  • composer
    • composerを実行するためのコンテナ
  • npm
    • npmを実行するためのコンテナ

ファイル構成

laravel-project以下に必要なファイルを追加します。

ファイル構成
+ laravel-project
  + docker
    + composer
      - Dockerfile
    + fpm
      - Dockerfile
    + npm
      - Dockerfile
    + web
      - Dockerfile
      - default.conf
  - .env.development
  - docker-compose.yml

webコンテナ

webコンテナはnginxのイメージからdefault.confを書き換えて、phpの実行をfpmコンテナに渡すようにします。
ここではdefault.confはそれ以外何もしないシンプルなものとします。

docker/web/default.conf
server {
    listen  80;
    server_name  localhost;
    index  index.php
    charset  utf-8;
 
    location / {
        root  /usr/share/nginx/html;
        try_files  $uri $uri/ /index.php$is_args$args;
    }
 
    location ~ \.php$ {
        root  /var/www/html/public;
        fastcgi_pass   fpm:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/html/public$fastcgi_script_name;
        include        fastcgi_params;
    }
}
docker/web/Dockerfile
FROM nginx:alpine

COPY default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

fpmコンテナ

fpmコンテナはphp-fpmイメージをベースに諸々インストールします。

docker/fpm/Dockerfile
FROM php:7.2.17-fpm-alpine

RUN apk add --update --no-cache git openssh

RUN apk add --no-cache \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    openssl-dev \
 && docker-php-ext-configure gd \
    --with-freetype-dir=/usr/include/ \
    --with-jpeg-dir=/usr/include/ \
 && docker-php-ext-install \
    gd \
    mbstring \
    pdo_mysql

WORKDIR /var/www/html

phpコンテナ、workerコンテナ、schedulerコンテナ

これらのコンテナはfpmのイメージを使います。

dbコンテナ、phpmyadminコンテナ、redisコンテナ

これらのコンテナはOfficialやPublicのイメージのまま使います。

composerコンテナ

Laravelではcomposerコマンドが必要になるのでcomposerのためのイメージを作成します。

docker/composer/Dockerfile
FROM php:7.3.3-alpine
 
RUN apk add --update --no-cache git unzip && \
    curl -sL https://getcomposer.org/installer | php && \
    mkdir /usr/local/src && \
    mv composer.phar /usr/local/src && \
    ln -s /usr/local/src/composer.phar /usr/local/bin/composer
 
RUN mkdir -p /laravel-project
VOLUME ["/laravel-project"]
WORKDIR /laravel-project
 
ENTRYPOINT ["composer"]
CMD ["--help"]

npmコンテナ

npmコマンドを使うためのイメージを作成します。

docker/npm/Dockerfile
FROM node:12.7-alpine
 
RUN apk add --update --no-cache pkgconfig autoconf automake libtool nasm build-base zlib-dev libpng-dev
 
RUN mkdir -p /laravel-project
VOLUME ["/laravel-project"]
WORKDIR /laravel-project
 
ENTRYPOINT ["npm"]
CMD ["help"]

docker-compose.yml

docker-compose.ymlを定義します。
ここでは1ノードで完結できる環境として構築します。

各コンテナに必要なディレクトリをマウントできるようにVolumeを設定します。

また、Laravelで必要な環境変数は.env.developmentファイルに書いておいて、コンテナに渡します。

fpmのイメージにlaravel_project_phpと名前を付けてphp、worker、schedulerで使いまわします。
php、worker、schedulerコンテナはentrypointを指定してartisanコマンドを実行することで、目的の動作をさせます。

docker-compose.yml
version: "3"
services:
  web:
    build: ./docker/web
    restart: always
    ports:
      - "80:80"
    links:
      - "fpm:fpm"
    volumes:
      - ./public:/usr/share/nginx/html:ro
      - ./storage/app/public:/usr/share/nginx/html/storage:ro
  fpm:
    build: ./docker/fpm
    image: laravel_project_php
    restart: always
    expose:
      - "9000"
    links:
      - "db:db"
      - "redis:redis"
    volumes:
      - .:/var/www/html
    env_file: ./.env.development
  php:
    image: laravel_project_php
    volumes:
      - .:/var/www/html
    env_file: ./.env.development
    working_dir: /var/www/html
    entrypoint:
      - php
  worker:
    image: laravel_project_php
    restart: always
    links:
      - "db:db"
      - "redis:redis"
    volumes:
      - .:/var/www/html
    env_file: ./.env.develop
    working_dir: /var/www/html
    entrypoint:
      - php
      - artisan
      - queue:work
      - redis
      - --tries=3
  scheduler:
    image: laravel_project_php
    links:
      - "db:db"
    volumes:
      - .:/var/www/html
    env_file: ./.env.develop
    working_dir: /var/www/html
    entrypoint:
      - php
      - artisan
      - schedule:run
  db:
    image: mysql:5.7
    restart: always
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_USER=db_user
      - MYSQL_PASSWORD=db_password
      - MYSQL_DATABASE=db_database
    command: --innodb-use-native-aio=0
  redis:
    image: redis:alpine
    restart: always
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    restart: always
    ports:
      - "8080:80"
    links:
      - "db:db"
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=db
      - PMA_USER=root
      - PMA_PASSWORD=root
  composer:
    build: ./docker/composer
    volumes:
      - .:/laravel-project
  npm:
    build: ./docker/npm
    volumes:
      - .:/laravel-project

.env.developmentでLaravelの設定をしていきます。
今回セッションやキューはredisを使います。

.env.development
APP_ENV=staging
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost/
 
LOG_CHANNEL=stack
LOG_LEVEL=debug
 
SMS_DISABLE=false
 
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=db_database
DB_USERNAME=db_user
DB_PASSWORD=db_password
 
BROADCAST_DRIVER=log
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_DRIVER=redis
 
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
 
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=
MAIL_PASSWORD=

環境構築

まずはこのあたりを参考にDockerとDocker Composeをインストールします。

AWS EC2 Amazon LinuxでDocker, Docker Composeをインストールする
https://qiita.com/shinespark/items/a8019b7ca99e4a30d286

インストールが済んだら、本記事の前半でご紹介したファイル構成を含んだlaravel-projectを配置します。

git clone laravel-project
cd laravel-project

Dockerイメージをビルドします。

docker-compose bulid

phpコマンドやcomposerコマンドはコンテナ上で実行するので、
コマンドのエイリアスを作っておくと便利です。

~/.bashrc
alias php='docker-compose run --rm php'
alias composer='docker-compose run --rm composer'
alias npm='docker-compose run --rm npm'

ここから先は上のエイリアスを定義している前提でお読みください。

Laravel環境構築

Laravelの環境構築をしていきます。

Composerを実行します。

composer install

ディレクトリのパーミッションを設定します。

chmod -R 777 storage bootstrap/cache

アプリケーションキーを生成します。

php artisan key:generate

.envファイルにキーが生成されるため、.env.developmentにコピーします。

public/storageのシンボリックリンクも作っておきます。

php artisan storage:link

Dockerコンテナを起動します。

docker-compose up -d

DBのマイグレーションをします。

php artisan migrate

npmビルドします。

npm install
npm run dev

スケジューラをcronに登録します。

sudo crontab -e
crontab
* * * * * /usr/local/bin/docker-compose -f /path-to-laravel-project/docker-compose.yml run --rm scheduler >> /dev/null 2>&1

一応これで起動はするはずですが、問題が少しあるので対策します。

問題:ログのパーミッション

この構成だと、ログがWebから書き込まれた場合と、スケジューラやワーカから書き込まれた場合でパーミッションが違ってしまいます。
本来ならパーミッションをそろえるなどすればいいのですが、妥協してcronで毎分ログファイルのパーミッションを変更してます。

sudo crontab -e
crontab
* * * * * chmod -R 777 /path-to-laravel-project/storage/logs >> /dev/null 2>&1

アプリケーションのデプロイ

laravel-projectディレクトリのファイルを更新するだけです。コンテナの再起動などは必要ありません。

今回は以上となります。

84
92
3

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
84
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?