はじめに
Laravel9をFargateで構築する方法を記載します。
下記のソースをそのまま使いますので、クローンしてください。
環境
- fargate
- PHP : 8.1
- Laravel : 9.2.0
- Nginx : 1.20
完成構築図
事前構築
- VPC,インターネットゲートウェイ,サブネット,RDSまで作成済み
- RDSを作成する際、
追加設定
でデータベース名:「laravel_ecs」
を作成してください。マスターユーザー名とパスワードも使いますので、メモしておきましょう。
- RDSを作成する際、
ソースのディレクトリ構造
ソースをクローン後に、ディレクトリ構造を確認します。
laravel-ecs % tree
.
├── docker
│ ├── nginx
│ │ ├── Dockerfile
│ │ ├── default.conf
│ │ └── nginx.conf
│ └── php
│ ├── Dockerfile
│ └── php.ini
└── src
├── README.md
├── app
├── .env.production
├── artisan
├── bootstrap
├── composer.json
├── composer.lock
├── config
├── database
├── lang
├── package.json
├── phpunit.xml
├── public
│ └── index.php
├── resources
├── routes
├── storage
├── tests
└── webpack.mix.js
- dockerディレクトリ配下は、以下のgithubを参考にしています。
- srcディレクトリは、laravel9.2のデフォルトのソースになります。
- .env.productionは、各自設定してください。
-
APP_KEY
は、下記のAPP_KEYを使ってください。APP_KEY=base64:Wya0dp/iTvZJrXW0qM5uSTR2JugldcCMambNZNzR9Kc=
-
オリジナルのAPP_KEY
は、fargate構築後に、fargate内に入って作成できます。作成方法はこちらで説明しています。
-
APP_KEY=すでに作成済みのものか上記のAPP_KEYを入れる
DB_CONNECTION=mysql
DB_HOST=RDSのエンドポイントを記述
DB_PORT=3306
DB_DATABASE=laravel_ecs
DB_USERNAME=RDS作成の際に設定したマスターユーザー名
DB_PASSWORD=RDS作成の際に設定したマスターパスワード
ALBを作成
ALBを以下の項目を適切に選択し、作成します。
他の項目は、全てデフォルトでよいです。
・名前:何でも
・VPC:作成したVPC
・サブネット:作成したパブリックサブネット
・セキュリティーグループ(インバウンド:0.0.0.0に対して、HTTPとHTTPSを許可
します)
・リスナー:HTTP:80
ターゲットグループ作成
Include as pending below
は、押さずに、ターゲットグループを作成
ロードパランサーの作成画面に戻り、他はデフォルトで作成。
ALBのリスナーの確認
ターゲットグループがfargateのみになっているか確認します
fargate用のセキュリティーグループを作成
elbのsgに対して、httpを許可します。
HTTP
:ソース
:albのセキュリティーグループを選択
RDSのセキュリティーグループを修正
fargateのsgに対して、MYSQL/Aurora
を許可するように修正します。
Route53を作成
Route53を作成します。
・ドメイン名:xxxx.com
・タイプ:パブリックホストゾーン
次に、独自ドメインのネームサーバー情報を変更します。
以下の4つのネームサーバー情報を貼り付けます。
ネームサーバー情報の変更方法:お名前ドットコム
ドメイン→ドメイン機能一覧→ネームサーバー設定画面
に移動し、その他
のタブから入力できます。
Route53レコードの設定
Route53を利用して独自ドメインとALBのDNS名を紐づけます。
ホストゾーンxxxx.com
のレコードを作成します
・レコード名:<空白>
・レコードタイプ:A
・エイリアス:選択します
・トラフィックのルーティング先:ALB,東京リージョン、先程作成したALBを選択
・ルーティングポリシー:シンプルルーティング
IAMユーザーの作成
ECRにDockerイメージをプッシュする際、cliを利用するため、事前にIAMユーザーを作成し、アクセスキーを発行しておきましょう。
IAMポリシーは、EC2InstanceProfileForImageBuilderECRContainerBuilds
をアタッチします。
aws configure --profile
コマンドを使用し、アクセスキーとシークレットキーを設定します。
$ aws configure --profile fargate-laravel
AWS Access Key ID [None]: ****************DMH2
AWS Secret Access Key [None]: ****************bHBU
Default region name [None]: ap-northeast-1
Default output format [None]:
// aws cli プロフィール変更
$ export AWS_DEFAULT_PROFILE=fargate-laravel
これでローカルでのcliのセットは完了です。
ECRを作成
AWSのECSのコンソール画面からECRのリポジトリをクリックします
nginx
とapp
リポジトリの2つを作成します。
・可視性設定:プライベート
・リポジトリ名:nginx
・その他はデフォルト設定のまま
・可視性設定:プライベート
・リポジトリ名:php
・その他はデフォルト設定のまま
プッシュコマンドの表示
をクリックすると以下の画面が出てきます。
この4つのコマンドの流れでECRにpushしていきます。
ソースをクローンした後、ソースのルートディレクトリに移動し、ecrのログインをします。
$ cd laravel-ecs
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded
ログインできました。
ログインに失敗した場合、IAMユーザーのアクセスキーIDとシークレットアクセスキーが以下の情報と一致しているか確認してください。
一致していない場合、IAMユーザーから新たにアクセスキーを発行し、~/.aws/credentials
や~/.aws/config
ファイルを修正してください。
// profileの確認
$ cat ~/.aws/credentials
$ cat ~/.aws/config
// profileの確認
$ aws configure --profile fargate-laravel
AWS Access Key ID [None]: ****************DMH2
AWS Secret Access Key [None]: ****************bHBU
Default region name [None]: ap-northeast-1
Default output format [None]:
// aws cli プロフィール変更
$ export AWS_DEFAULT_PROFILE=fargate-laravel
ログイン後、nginxをビルドし、タグ付け後、ECRにpushします。
今回は、タグは、latest
ではなくprod
にします。
実際にサービスを構築する際、タグをprod
・dev
・stg
と、環境別にイメージタグを作成するため、prodにしました。
laravel-ecs $ docker build -t nginx:prod -f ./docker/nginx/Dockerfile .
$ docker tag nginx:prod [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com/nginx:prod
$ docker push [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com/nginx:prod
問題なくpushできれば、ECRのリポジトリにイメージが作成されます。
同様にphp
でもビルドし、タグ付け後、ECRにpushします。
laravel-ecs $ docker build -t php:prod -f ./docker/php/Dockerfile .
$ docker tag php:prod [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com/php:prod
$ docker push [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com/php:prod
phpとnignxのイメージをpushできました。
クラスターを作成
ECSのコンソール画面からクラスターの作成をクリックします。
クラスター名を記入し、作成します。
タスク定義を作成
ECSのコンソール画面のタスク定義タブから新しいタスク定義の作成をクリックします
・起動タイプ:Fargate
次へ
・タスク定義名:laravel-prod
・タスクロール:なし
・ネットワークモード:awsvpc
・タスク実行ロール:ecsTaskExecutionRole
(デフォルト)
コンテナの追加php
-
コンテナ名:
php
-
イメージ:リポジトリの
イメージのURI
-
環境
環境変数APP_ENV:Value:production
を設定すると、env.production
を読み取ってくれます。
コマンドは、以下を参考にしております。
- 他はすべてデフォルトのままです
更新をクリックするとコンテナが作成されます。
コンテナの追加nginx
- コンテナ名:
nginx
- イメージ:リポジトリの
イメージのURI
- ECRのnginxをクリックすると、
イメージのURI
がありますのでコピペしましょう。
- ECRのnginxをクリックすると、
- ポート:
80
- 他はすべてデフォルトのままです
更新をクリックするとコンテナが作成されます。
他はすべてデフォルトのままでタスク定義を作成します。
サービスを作成
-
サービスの設定
-
次のステップ
ターゲットグループを新規で作成する場合は、以下の設定になります。
elbからfargate(task)に対して、ポート80でアクセスされ、task内のnginxのポート80に繋がります。
elbにacm(証明書)を入れている場合、プロダクションリスナーポートは、HTTPS
を選択できるようになります。
次のステップ
・autoscalingなし
サービスが作成されました!
http://xxxx.com/
にアクセスすると、laravelが表示されました!
表示されない場合、以下のエラーの可能性があります。
エラー集
ResourceInitializationError
ResourceInitializationError:
unable to pull secrets or registry auth: execution resource retrieval failed:
unable to retrieve ecr registry auth: service call has been retried 3 time(s):
RequestError: send request failed caused by: Post https://api.ecr....
privateサブネットで起動
fargateをprivateサブネットで起動した場合、以下のエラーが出ます。publicサブネットに変更しましょう。
セキュリティーグループ
sgを確認してください。
- elbのsgは、httpで全開放(0.0.0.0/0)
- fargateのsgは、elbからのhttpで許可
- ACLとセキュリティグループが、サブネットからのポート 443 へのアウトバウンドアクセスを許可
exec /docker-entrypoint.sh: exec format エラー
原因は、M1チップのPCでビルドしたため、ビルドするマシンと実行するマシンのCPUアーキテクチャが異なると起動に失敗するようです。
ビルド時、--platform amd64
をつけるとうまく起動します。
$ laravel-ecs $ docker build -t nginx:prod -f --platform amd64 ./docker/nginx/Dockerfile .
sh: php: not foundエラー
タスクのログを確認すると、phpのコンテナに以下の記載があります。
sh: php: not found
これは、phpのコンテナ内にnginxのイメージが入り、nginxのコンテナ内にphpのイメージが入っていることが原因でした。
コンテナがすぐに停止する場合
コンテナがRunning
となってもすぐにコンテナがStopされる場合、以下の確認をしてみてください
ヘルスチェックに失敗
エラーログが下記の場合、nginxの設定ミスによるもので、default.conf
ファイル、もしくは、ヘルスチェックパス
を修正します。
2022/04/04 16:49:54 [error] 32#32: *2 directory index of "/var/www/html/" is forbidden, client: xx.x.x.xx, server: , request: "GET / HTTP/1.1", host: "xx.x.x.xxx"
default.conf修正
index index.php;
がない可能性があります。ない場合、追加してください
server {
listen 80;
root /var/www/html/public;
error_log /var/log/nginx/error.log;
+ index index.php;
また、ターゲットグループのヘルスチェックパスが/
になっていることを確認しましょう。
LaravelのAPP_KEYがない場合
APP_KEYをenvファイルに記載していない場合、コンテナがRunning時に、http://xxxx.com/
にアクセスすると、以下のエラー表示がされます。
No application encryption key has been specified.
APP_KEYがない、暗号化されていないことが原因です。
とりあえず、envファイルにAPP_KEY=base64:Wya0dp/iTvZJrXW0qM5uSTR2JugldcCMambNZNzR9Kc=
を加えて、再度ビルドしてください。
APP_KEY作成方法
オリジナルのAPP_KEYを作成したい場合、fargate内にアクセスし、key作成コマンドを実行する必要があります。
下記の記事通りに行い、fargate内にアクセスします。
aws ecs execute-command \
--cluster laravel \
--task <タスクID> \
--container php \
--interactive \
--command "/bin/sh"
The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.
Starting session with SessionId: ecs-execute-command-0e408d1fb1cba10cf
# pwd
/var/www/html
# php artisan key:generate --show
base64:Wya0dp/iTvZJrXW0qM5uSTR2JugldcCMambNZNzR9Kc=
Fargate EXEC でコンテナに入りAPIキーを作成するためには、コンテナがRuuning時に、Fargate EXECする必要があります。
今回のAPP_KEYがないエラーの場合、コンテナが起動停止を繰り返しますので、とりあえず、先程のAPP_KEY
を加えビルドし、エラーを解消しましょう。
コンテナが起動で安定した後、Fargate EXECし、APIキーを作成するようにしましょう。
envファイル
にAPP_KEY=base64:Wya0dp/iTvZJrXW0qM5uSTR2JugldcCMambNZNzR9Kc=
を追加し、再ビルドし、pushします。
phpソース内の修正なので、phpコンテナのみで良いです。念の為、nginxも同様にビルドしてもよいかもしれませんが。
laravel-ecs $ docker build -t php:prod -f ./docker/php/Dockerfile .
$ docker tag php:prod [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com/php:prod
$ docker push [アカウントエイリアス12桁].dkr.ecr.ap-northeast-1.amazonaws.com/php:prod
サービス画面に遷移し、強制デプロイにチェックし、更新します。
新しいタスク起動後、http://xxxx.com/
にアクセスすると、laravelが表示されました!
運用や機能追加するTIP集
- Fargateで構築したLaravelを運用にする上で、ポイントまとめています。
- こちらの記事では、Fargate で構築した Laravel の コンテナを 読み取り専用(ReadOnly)にする方法について説明しております。
- こちらの記事では、Fargate で構築した Laravel で Supervisor を導入する方法について説明しております。
参考
エントリーポイントについて
タスク定義