search
LoginSignup
80
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

LaravelアプリをDockerfile, ECR, ECS, RDSを使用してデプロイする。

こんにちは。
KENと申します。

簡単な自己紹介

2020年4月から渋谷のとある企業でWebエンジニアをしてます、エンジニア一年生です。
エンジニアの研修でDockerを使用して開発環境を構築し、それをAWSの各種サービスを使用してコンテナデプロイをしました。
初めての経験で、コンテナデプロイ関連の記事も少なかったため、今回は自分の頭の整理を兼ねて記事を書くことにしました。

概要

今回の記事では、Laravelが動く環境をdockerで作成し、簡単なアプリを制作し、それをAWSのECR, ECS, RDS等のサービスを使用してデプロイするまでの流れについて書いていきます。

対象読者

Docker, AWSで何かアプリを制作、デプロイしてみたい人。
Dockerコンテナをデプロイしてみたい人。

環境

Docker version 19.03.8
docker-compose version 1.25.4

DockerでLaravelが動く環境を作る

基本的にこのフェーズはこの記事を参考にさせて頂きましたので、この記事を参考に進めてください。

【初心者向け】20分でLaravel開発環境を爆速構築するDockerハンズオン

一部ファイル構成、docker-compose.ymlの記述が上記サイトと異なる部分がありますので、その点について説明します。

今回の最終的なディレクトリ構成は以下です。

.
├── README.md
├── docker
│   ├── mysql
│   │   └── my.cnf
│   ├── nginx
|   |   |__ Dockerfile
│   │   └── default.conf
│   └── php
│       ├── Dockerfile
│       └── php.ini
├── docker-compose.yml
├── logs
│   ├── access.log
│   ├── error.log
│   ├── mysql-error.log
│   ├── mysql-query.log
│   ├── mysql-slow.log
│   └── php-error.log
└── src(アプリケーションのルートディレクトリ)
    └── readme.md

docker-compose.yml

version: "3"
services:
  app:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
      args:
        - TZ=${TZ}
    ports:
      - ${APP_PORT}:8000
    volumes:
      - ./src:/work
      - ./logs:/var/log/php
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
    working_dir: /work
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_DATABASE=${DB_NAME:-homestead}
      - DB_USERNAME=${DB_USER:-homestead}
      - DB_PASSWORD=${DB_PASS:-secret}
      - TZ=${TZ:-Asia/Tokyo}

  web:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile
    depends_on:
      - app
    ports:
      - ${WEB_PORT:-80}:80
    volumes:
      - ./src:/work
      - ./logs:/var/log/nginx
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      - TZ=${TZ:-Asia/Tokyo}

  db:
    image: mysql:8.0
    volumes:
      - db-store:/var/lib/mysql
      - ./logs:/var/log/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_DATABASE=${DB_NAME:-homestead}
      - MYSQL_USER=${DB_USER:-homestead}
      - MYSQL_PASSWORD=${DB_PASS:-secret}
      - MYSQL_ROOT_PASSWORD=${DB_PASS:-secret}
      - TZ=${TZ:-Asia/Tokyo}
    ports:
      - ${DB_PORT:-13306}:3306

volumes:
  db-store:

docker/php/Dockerfile

FROM php:7.4-fpm-alpine
COPY ./src /work
COPY ./docker/php/php.ini /usr/local/etc/php/php.ini
LABEL maintainer="ucan-lab <info@u-can.tech>"

SHELL ["/bin/ash", "-oeux", "pipefail", "-c"]

# tinker(psysh)
ARG PSYSH_DIR=/usr/local/share/psysh
ARG PSYSH_PHP_MANUAL=$PSYSH_DIR/php_manual.sqlite
ARG PHP_MANUAL_URL=http://psysh.org/manual/ja/php_manual.sqlite

# timezone
ARG TZ=Asia/Tokyo

# composer
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer

RUN apk update && \
  apk add --update --no-cache --virtual=.build-dependencies \
    autoconf=~2.69 \
    gcc=~9.2 \
    g++=~9.2 \
    make=~4.2 \
    tzdata=2020a-r0 \
    git=~2.24 && \
  apk add --update --no-cache \
    icu-dev=~64.2 \
    libzip-dev=~1.5 \
    oniguruma-dev=~6.9 && \
  cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
  echo ${TZ} > /etc/timezone && \
  pecl install xdebug && \
  git clone https://github.com/phpredis/phpredis.git /usr/src/php/ext/redis && \
  apk del .build-dependencies && \
  docker-php-ext-install intl pdo_mysql mbstring zip bcmath redis && \
  docker-php-ext-enable xdebug && \
  mkdir $PSYSH_DIR && curl $PHP_MANUAL_URL -o $PSYSH_PHP_MANUAL && \
  curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && \
  composer config -g process-timeout 3600 && \
  composer config -g repos.packagist composer https://packagist.jp && \
  composer global require hirak/prestissimo

docker/nginx/Dockerfile

FROM nginx:1.17-alpine
COPY ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY ./src /work
EXPOSE 80

docker/nginx/default.conf

server {
    listen 80;
    root /work/public;
    index index.php;
    charset utf-8;
    error_log /var/log/nginx/error_test.log;

    location / {
        root /work/public;
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

ECRのリポジトリを作成

AWSのコンソール画面にログインして、次の画像の画面にアクセスしてください。
ここで2つのリポジトリを作ります。

nginxのイメージを保存するリポジトリとphp-fpmのイメージを保存するリポジトリの二つです。

スクリーンショット 2020-05-04 17.39.05.png

ECRにDockerイメージをPushする

次にそれぞれのリポジトリにDockerイメージをPushしていきます。
下の画像のように、プッシュコマンドの表示というボタンがあるので、それを押して出てきたコマンドに従って進めてください。
AWS CLIがインストールされていることが前提です。

スクリーンショット 2020-05-04 17.40.03.png

スクリーンショット 2020-05-04 17.40.33.png

ECSのタスク定義を作成

次にタスク定義を作成します。
タスク定義とは、アプリケーションを構成する 1 つ以上(最大 10 個)のコンテナを記述するJSON形式のテキストファイルです。
アプリケーションの設計図のようなものです。

下記の画面で新しいタスク定義の作成をクリックしてください。
スクリーンショット 2020-05-04 17.54.02.png

今回はタスクの起動タイプをEC2に指定します。
スクリーンショット 2020-05-04 17.54.17.png

続いてタスク定義名を決め、コンテナの追加をクリックします。
スクリーンショット 2020-05-04 18.22.24.png
スクリーンショット 2020-05-04 18.22.54.png

下の画像のようにappコンテナとwebコンテナを作成してください。
まずはappコンテナの定義です。
スクリーンショット 2020-05-04 18.28.42.png

コマンドの蘭に、コンテナ起動時に実行したいコマンドを入力しておきます。
あとは環境変数も指定します。私は本番環境では.env.productionを使用しているので、APP_Env=productionと指定しています。
スクリーンショット 2020-05-04 18.28.53.png

続いてWebコンテナを定義しましょう。
スクリーンショット 2020-05-04 18.37.03.png

こちらも作業ディレクトリと環境変数を指定します。
スクリーンショット 2020-05-04 18.37.34.png

Webコンテナのネットワーク設定のリンクにはapp(appコンテナのこと)と記述しましょう。
docker/nginx/default.confでfastcgi_pass app:9000;という記述があるので、ここと合わせるためappと記述します。
スクリーンショット 2020-05-04 18.40.25.png

これでタスク定義を作成してください!

ECSのクラスターを作成

次にクラスターを作成します。
今回はEC2Linux + ネットワーキングを選択して作成します。

スクリーンショット 2020-05-04 18.45.34.png

EC2インスタンスタイプはt2.micro、後はご自身のキーペアを選択してください。
スクリーンショット 2020-05-04 18.46.23.png

スクリーンショット 2020-05-04 18.47.56.png

これでクラスターを作成します。

タスクの起動

先ほど作成したタスク定義の画面に行ってください。
そこからアクションをクリックして、タスクの実行をクリックします。
スクリーンショット 2020-05-04 18.55.03.png

次の画面でタスク定義とクラスターをそれぞれご自身が先ほど作成したものを選択し、実行をクリックします。
スクリーンショット 2020-05-04 18.55.33.png

(すみません、この画像ではタスク定義とクラスター名がsample-appになっていません。この記事の流れではこの二つは本来sample-appという名前になります。)

続いてクラスターの画面に行き、先ほど実行したタスクのステータスがRUNNINGになっていることを確認してください。
スクリーンショット 2020-05-04 19.01.19.png

これでEC2インスタンスのパブリックIPアドレスにアクセスすれば/srcディレクトリ以下に作成したアプリのトップページが表示されるはずです。

RDSの作成 

データベースを使用するアプリの場合はRDSを作成しましょう。
RDSの画面を開いたらデータベースの作成をクリックします。
スクリーンショット 2020-05-04 21.10.08.png

標準作成で今回はMySQLを使用します。(Dockerの開発環境もMySQlを使用しているので)
スクリーンショット 2020-05-04 21.11.44.png

無料利用枠で、マスターユーザー名マスターパスワードを決めます。
スクリーンショット 2020-05-04 21.11.57.png

追加設定でアプリに利用するデータベースも作成しておきましょう。
今回はsample_appという名前でデータベースを作成しておきます。
スクリーンショット 2020-05-04 21.13.12.png

これで作成をクリックしてください!

作成されたデータベースは、RDSダッシュボードの「データベース」で確認できます。

RDSの設定

EC2インスタンスからDBインスタンスにアクセスするために、
「セキュリティグループのルール」から使用中のセキュリティーグループをクリックし、インバウンドの編集でアドレス入力の箇所にEC2のプライベートIPアドレス/32を入力してください。

RDSで構築したMySQLは、日本語の保存ができないそうです。
日本語で保存できるように設定を変更します。パラメータグループの設定を、日本語データを保存できるように変更する必要があるみたいです!
詳しくはググってみてください。ここでは割愛します。

PHPのコンテナ内でマイグレーション

では最後です。
/srcディレクトリの下に、env.productionを作成します。
ECSのタスク定義で、appコンテナ、webコンテナ両方にAPP_ENV=productionという記述をしたので、本番環境ではこの.env.productionが参照されます。
記述は.envの内容とほとんど同じで大丈夫ですが、一部変更します。
下記を参考に記述してください。

DB_CONNECTION=mysql
DB_HOST=RDSのエンドポイントを記述
DB_PORT=3306
DB_DATABASE=sample_app(RDSの追加設定で作成したデータベース名)
DB_USERNAME=root
DB_PASSWORD=RDS作成の際に設定したマスターパスワード

ではsshでEC2インスタンスに接続してください。
ssh接続するには、EC2インスタンスのセキュリティーグループのインバウンドで22番ポートのアクセスを受け入れる設定ができている必要があります。
下記手順で進めていってください。

sshが機能するには、キーが公開されていないことが必要なので、キーペアのアクセス権を変更する。

chmod 400 xxx.pem(ご自身のキーペア)

sshでEC2インスタンスのパブリックDNSに接続する

ssh -i "xxx.pem" ec2-user@ec2-xx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

EC2インスタンスに接続できたら、MySQLのソフトウェアをインストールする。

sudo yum -y install mysql

MySQLに接続する(rootは今回のマスターユーザー名、xxxの所にはエンドポイントを記述する)

mysql -u root -p -h XXX.xxx.ap-northeast-1.rds.amazonaws.com

MySQLへ接続できたことが確認できたら、:qで接続を終了します。

次にdocker psで今起動しているコンテナのIDを確認し、下記のコマンドでapp(phpが動いているコンテナ)の内部に入りましょう。

docker exec -i -t コンテナID

そして下記コマンドでマイグレーションを実行します。

php artisan migrate

無事マイグレーションが完了し、テーブルが作成されていることが確認できたら、EC2インスタンスのパブリックIPアドレスにアクセスしてみましょう。
トップページが表示されるだけでなく、新規登録機能など、DBが絡む機能も動くようになっているはずです。

以上が、LaravelアプリをECR, ECS, RDSを使用してデプロイする手順です。

最後までお付き合いくださりありがとうございました!!

補足

説明が至らない所、私の認識が間違っていて、おかしな説明がされている所があるかもしれません。
何かありましたらコメント等で教えて頂きますと幸いです。

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
What you can do with signing up
80
Help us understand the problem. What are the problem?