LoginSignup
21
22

More than 1 year has passed since last update.

【AWS】AWS超初心者が、頑張ってDockerで作ったLaravelプロジェクトをECR、ECS、EC2を使ってAWS上で動かしてみた

Last updated at Posted at 2021-02-24

皆さんこんにちは!

巷で有名なDockerとAWS

2つともつい2,3週間前に学習を始めたのですが、最初は苦労したものの少し慣れてくると便利だなと感じました。

あと、Amazonってすごい!

今回はそんなDockerで作ったLaravelプロジェクトをAWS上で動かしてみたいと思います!

DockerでLaravelプロジェクトを作成する方法は下記の記事を参考にして作成してください!

【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン

Dockerに触れたことがない人でも簡単に作れるのでおススメの記事です!

IAMユーザー権限の追加

IAMユーザーの場合、以下の権限を追加しておいてください。

・AmazonRDSFullAccess
・AmazonEC2FullAccess
・IAMFullAccess
・AmazonEC2ContainerRegistryFullAccess
・AmazonECS_FullAccess
・ComputeOptimizerReadOnlyAccess

ディレクトリ構成

├─backend
│  └─laravel
│      ├─app
│      ├─bootstrap
│      ├─config
│      ├─database
│      ├─public
│      ├─resources
│      ├─routes
│      ├─storage
│      ├─tests
│      └─vendor
├── logs
│   ├── access.log
│   ├── error.log
│   ├── mysql-error.log
│   ├── mysql-query.log
│   ├── mysql-slow.log
│   └── php-error.log
├── docker
│   ├── mysql
│   │   └── my.cnf
│   ├── nginx
|   |   |__ Dockerfile
│   │   └── default.conf
│   └── php
│       ├── Dockerfile
│       └── php.ini
├── docker-compose.yml

Docker設定

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/php/php.ini

zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese

docker/nginx/Dockerfile

FROM nginx:1.17-alpine
COPY ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY ./backend /work

EXPOSE 80

docker/nginx/default.conf

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

    location / {
        root /work/laravel/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;
    }
}

めちゃめちゃ長いので気合い入れていきましょう!

それでは説明していきます!!

DockerイメージをECRにプッシュ

まず最初にECRと言う場所にDockerイメージをプッシュします。

イメージ的にはGithubにソースコードをプッシュするときと同じ感覚です。

コンテナのビルド

以下のコマンドでappコンテナとwebコンテナをビルドしてください。

docker build -t app -f docker/php/Dockerfile .
docker build -t web -f docker/nginx/Dockerfile .

ECRのリポジトリ作成

まず最初にECR用のプロファイルを作成してください。

aws configure --profile ecr

これでアクセスキー、シークレットキを入力してください。

リージョンはap-northeast-1

Default output formatにはtextと入力してください。

もしシークレットキーを忘れてしまった方や、アクセスキーの場所が分からない方は下記の記事が参考になるかと。

DockerプロジェクトをAWSのECRにプッシュしようとしたらエラーが起きたときに話

そしたら下記のコマンドを入力しECRへログインしてください。

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [aws_account_id].dkr.ecr.ap-northeast-1.amazonaws.com

Login Successdedが表示されたらOK

次はリポジトリの作成を行います。

今回はappコンテナ用とwebコンテナ別々に作成していきます。

aws ecr create-repository --repository-name app --image-scanning-configuration scanOnPush=true --region ap-northeast-1
aws ecr create-repository --repository-name web --image-scanning-configuration scanOnPush=true --region ap-northeast-1

「ECS」→「AmazonECR Repositories」に以下のように作成されてたら成功です。

image.png

Dockerイメージをプッシュ

先ほどビルドしたイメージをECRへプッシュします

#appコンテナをappディレクトリにプッシュ
docker tag app:latest 905806622013.dkr.ecr.ap-northeast-1.amazonaws.com/app:latest
docker push 905806622013.dkr.ecr.ap-northeast-1.amazonaws.com/app:latest

#webコンテナをwebディレクトリにプッシュ
docker tag web:latest 905806622013.dkr.ecr.ap-northeast-1.amazonaws.com/web:latest
docker push 905806622013.dkr.ecr.ap-northeast-1.amazonaws.com/web:latest

無事プッシュされたら成功です。

また、時間がかかる場合があり時間がかかりすぎてしまうと、タイムアウトになりプッシュが中断されるのですが、その場合はもう一度プッシュすればOKです!

ECSの設定

次は先ほどECRにプッシュしたイメージをECSで使っていきます。

その前にまずは、PCからECSへ接続するためにSSHキーが必要なるのでSSHキーの作成を行います。

SSHキーの作成

  1. サービス検索で「EC2」と検索
  2. 「ネットワーク&セキュリティ」の「キーペア」
  3. 「キーペアを作成」をクリック
  4. キーペアキーを入力(なんでもいい)
  5. ファイル形式はpemを選択
  6. 「キーペアを作成」をクリック
  7. キーペアを作成すると自動でそのファイルが保存されるので、わかりやすいところに置いておく(後で使うため)

タスク定義

次にサービス検索欄で「ECS」と入力し、左のメニューバーの「タスク定義」をクリック

1.「新しいタスク定義の作成」をクリック
2.「EC2」を選択
3. 「タスク定義名」を適当に入力
4. ネットワークモードは「default」
5. 少し下に行き「コンテナの定義」で「コンテナの追加」をクリック

以下の表を参考にコンテナを作成してください。

appコンテナ

コンテナ名 app
イメージ イメージURL(ECR→app→イメージURLをコピーしてここに貼り付け)
メモリ制限 ハード制限(300)
環境
エントリポイント sh,-c
コマンド php artisan config:cache && chmod -R 777 storage/* && php-fpm
作業ディレクトリ /work/laravel
環境変数 Key→APP_ENV,TYPE→Value,値→production

webコンテナ

コンテナ名 web
イメージ イメージURL(ECR→web→イメージURLをコピーしてここに貼り付け)
ポートマッピング ホストポート→80,コンテナポート→80,プロトコル→tcp
メモリ制限 ハード制限(300)
環境
作業ディレクトリ /work/laravel
環境変数 Key→APP_ENV,TYPE→Value,値→production
ネットワーク設定
リンク app

環境変数.envファイルではなく.env.productionを読み込むために行っている作業です。

コンテナ追加を終えたら「作成」をクリック

クラスターの作成

次に左のメニュー欄から「クラスター」選択。

1.「クラスターの作成」をクリック
2.「EC2 Linux + ネットワーキング」を選択
3.「クラスター名」を入力
4.「インスタンスの設定」は以下のように設定

インスタンスの設定
プロビジョニングモデル オンデマンドインスタンス
EC2インスタンスタイプ t2.micro
インスタンス数 1
キーペア 先ほど作成したキーペアを選択

5.「作成」をクリック

無事クラスターが作成されればOK

ALBの作成

ここで一旦、今作ったクラスターを元にALBというものを作成していきます。

まずは今作ったクラスターの画面に行き、「ECSインスタンス」をクリック

するとコンテナインスタンス、EC2インスタンスなどの項目が書いてあると思います。

その中の「EC2インスタンス(例:i-123456789abs)」をクリック

image.png

ページ先の「インスタンスID」をクリック

すると、パブリックアドレス、プライベートアドレスなどが表示される画面たどり着きます。(以下、ページ①とします)

このページは残しておいて、別のタブでサービス検索欄で「EC2」と検索。

左のメニューから「ロードバランシング」にある「ロードバランサー」をクリック

そこから「ロードバランサーの作成」をクリック

  1. 「ApplicationLoadBalancer(HTTP,HTTPS)」を選択
  2. 適当に名前を入力
  3. アベイラビリティーゾーンにページ①の「VPC ID」と同じものを選択

image.png

  1. 次の手順を2回押し「3. セキュリティグループの設定」画面へ
  2. 新しいセキュリティグループを作成する(名前は適当に)

image.png

  1. 「ルーティングの設定」で名前だけ適当に入力し次の画面へ
  2. 「ターゲットの登録」で下のインスタンスからページ①のインスタンスを選択し「登録済みに追加」クリックし次の画面へ
  3. 「作成」をクリック

無事作成されればOK!

タスクの実行

左のメニューの「クラスター」画面に行き、先ほど作ったクラスターの画面に行ってください。

そこから「タスク」→「タスクの実行」をクリック

image.png

タスクの実行
起動タイプ EC2
タスク定義 先ほど作成したタスクを選択
タスクの数 1

「タスクの実行」をクリック

image.png

このように「ステータス」が「RUNNING」になれば成功です!

ここが「STOPPED」になる場合は、おそらくタスク定義の設定ミスかDocker自体に問題があります。

もう一度見直してみてください。

ページの表示

最後にサービス検索欄から「EC2」と検索

左のメニューから「ロードバランシング」にある「ロードバランサー」をクリック

先ほど作成したALBの「説明」にあるDNS名をコピーしてアクセスするとLaravelのトップ画面が表示されます!!

もし、下記のような画面が出ても大丈夫です!

気にせず先へ進んでください!

無題.png

502エラー

ここで、502エラーが表示される場合は、「ターゲットグループ」から先ほどALBを作成する際に作成したグループを選択し、「Targets」の欄が空の状態になっていると思います。

なので、ページ①のインスタンスを追加してあげてください。

すると表示されます!

SSH接続

SSH接続を行うためには、22番ポートからのアクセスを許可しなければいけません。

まずはその設定を行います。

22番ポートの受付

ページ①のセキュリティタブをクリックしてください。

image.png

その中のセキュリティグループをクリック

「インバウンドルールを編集」をクリック

image.png

このようにして「SSH」を追加してください。

※注意 HTTPの設定も残してください!

そしたらコマンドプロンプトにて以下のコマンドを実行。

ただし、Macユーザーは先ほどダウンロードしたキーファイルの権限を変更してください。

chmod 400 xxx.pem

Windowsユーザーの方はこの動作はいりません。

ssh -i "C:~\example-ec2-key.pem" ec2-user@ec2-xxx.ap-northeast-1.compute.amazonaws.com

ec2-xxx.ap-northeast-1.compute.amazonaws.comは、ページ①の「パブリック IPv4 DNS」をコピペしてください。


   __|  __|  __|
   _|  (   \__ \   Amazon Linux 2 (ECS Optimized)
 ____|\___|____/

For documentation, visit http://aws.amazon.com/documentation/ecs
6 package(s) needed for security, out of 13 available
Run "sudo yum update" to apply all updates.

このような画面がでればOK!!

試しにコンテナにアクセスしてみましょう!

docker ps

appコンテナのCONTAINER IDをコピーしてください。

そして以下のコマンドを実行

docker exec -it CONTAINER ID bash
root@***:/work/laravel#

こんな感じでコンテナには入れたらOK!

試しにph artisanコマンドを打って見て下さい!

root@61e66fbbc18e:/work/laravel# php artisan list

ちゃんと表示されましたか??

抜け出すにはexitと入力して下さい。

番外編

No application encryption key has been specifiedエラー

無題.png

先ほどこのような画面になってもOKと言いました。

でも実際はダメですよね(笑)。

なので、このエラーを解決しましょう!!

まず、このエラーはAPP_KEYが無いよと言う意味です。

Laravelを振れたことがある方は一度は見たことのあるエラーですね。

じゃあキーを発行してあげましょう!

まずはコンテナに入るためにSSH接続

ssh -i "C:~\example-ec2-key.pem" ec2-user@ec2-xxx.ap-northeast-1.compute.amazonaws.com
root@61e66fbbc18e:/work/laravel# php artisan key:generate --show
base64:***

ここで、タスク定義を行うときに環境変数を設定したのを覚えていますか?

AWS上では.envファイルではなく、.env.productionを読み込ませるために.env.productionを作成しましょう!

root@61e66fbbc18e:/work/laravel# touch .env.production

そしたら、.env.exampleの内容を.env.productionにコピペしてAPP_KEYのところだけ今発行したキーを貼り付けましょう。

最後にビルドしてプッシュしてください!

docker build -t app -f docker\php\Dockerfile .
docker tag app:latest 905806622013.dkr.ecr.ap-northeast-1.amazonaws.com/app:latest
docker push 905806622013.dkr.ecr.ap-northeast-1.amazonaws.com/app:latest

appコンテナだけで大丈夫です!

無事プッシュが完了したら、クラスターから先ほどと同じようにタスクの実行を行い(前のタスクは停止してください)、「ロードバランサー」のDNSに接続して見て下さい!

image.png

見慣れた画面。。。

ここまで長かった。。。。。。

2021/02/27 追記 RDS(MySQL)への接続

作成したLaravelとMySQLのデータベースの連携方法を以下の記事にまとめたので、興味のある方は是非ご覧ください!

【AWS】EC2インスタンスで作成したLaravelとRDS(MySQL)を連携させる方法

いかがだったでしょうか???

大変ですよね(笑)

ただこの記事を参考にして少しでも時間を削って皆様のお役に立てればなと思います。

ページの最後に参考記事を載せておくので、なにか分からない点がありましたらそちらの記事をご覧ください。

また、何かご不明な点があれば遠慮なくコメント欄にてお申し付けください。

大変でしたが達成感はあると思います!!

これを励みに皆さん勉強頑張りましょう!!!!!

つい最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。

気になる方はぜひ一度ご相談ください!

以上、「【AWS】Dockerで作ったLaravelプロジェクトをECR、ECS、EC2を使ってAWS上で動かしてみた」でした!

良ければ、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

Thank you for reading

参考記事

【AWS】初めてのECR
【Docker × ECS入門】docker compose upでECSデプロイ
LaravelアプリケーションをローカルでもAWSでもDockerで動かす
ALB(Application Load Balancer)を導入する
LaravelアプリケーションをAWS上のDockerで動かす
LaravelアプリをDockerfile, ECR, ECS, RDSを使用してデプロイする。

21
22
2

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
21
22