◆問題
CodePipelineでECSのFargateにDeploy時、DockerHubのRateLimitに引っかかった。何度かやると成功する時もあるけど、正直何度も実行するのが面倒なので渋々対策することに。
◆解決方法
基本的には以下のページにあった内容の通りで行けた。
1点付け加えるとすれば、CodeBuildの実行ロールでSSMの読み込み権限をPolicyアタッチしないと権限エラーとなる。アタッチするPolicyは以下の通り。
CodePipelineでECSのFargateにDeploy時、DockerHubのRateLimitに引っかかった。何度かやると成功する時もあるけど、正直何度も実行するのが面倒なので渋々対策することに。
基本的には以下のページにあった内容の通りで行けた。
1点付け加えるとすれば、CodeBuildの実行ロールでSSMの読み込み権限をPolicyアタッチしないと権限エラーとなる。アタッチするPolicyは以下の通り。
ECSのFargateでLaravelのプロジェクトを立ち上げた時に掲題のエラーが発生。storageのフォルダはDockerfileで以下の通り権限変更しており、同じDockerイメージでローカルで立ち上げた時は何事もなく動くのになぜ??
RUN chmod -R 775 storage
色々試してみて分かったのだが、どうやらルートからの絶対パスで書かないとダメだったのと、AWS環境の場合はフォルダの所有者も「www-data」に変更する必要がある模様。
自分のケースの場合は「/var/www/html」配下にLaravelのプロジェクトソースを展開しているので、以下のような形でDockerfile内の権限部分を変更するとうまくいった。
RUN chmod -R 775 /var/www/html/storage && \ chown -R www-data:www-data /var/www/html/storage
掲題の通りなのだが、自分でECSのFargateを立てて、CodePipelineでDeploy自動化を実装した際、ECS側のTargetGroupは切り替わるけど、ALBのTargetGroupが2つのうち1つ(Green側だけ)が固定となり切り替わらず、CodePipelineでGreen側にDeployした時だけ(2回に1回)しかリクエストが通らない問題が発生した。
結局ALBへのTargetGroupの設定方法に問題があった。ALBとTargetGroupの紐付ける際、他にも色んなエラーが出ていたので、TargetGroupを個別で作成して、それをALBやECSのサービスに紐付けたりしていたけど、そのやり方が不味かった。
正解のやり方として、ALBにTargetGroupが何も紐づいていない状態で、ECSのサービスを作成する際にALBを指定し、TargetGroupを新規作成して紐付ける必要があった。こういう方法でTargetGroupを紐づけることで、CodePipelineでDeployしてうまく切り替えられるようになり、想定通りの挙動になった。
MacでローカルでDockerイメージをビルドしてAWSのECRにpush。ECR上のイメージでECSのFargateを作って起動させた時に以下エラーが発生してコンテナが起動してはすぐに落ちるのループ状態に。
standard_init_linux.go:228: exec user process caused: exec format error
同じイメージでローカルでコンテナを起動したらうまく行くのになんでやねん!と思ってハマってたところ、以下のような記事を見つけた。
はい、ここにある通り、M1チップ搭載のMacでDockerイメージをビルドしたのが原因でした。ビルドするマシンと実行するマシンのCPUアーキテクチャが異なると起動に失敗する、とのことです。Cloud9とかEC2, CodeBuildなど、AWSのサービス上でビルドすれば問題なかったようですが、まさかM1チップが原因だとは思いつきませんでした。
イメージビルド時にplatformを指定やれば、Macローカルビルドしたイメージでも問題なくコンテナ起動しました。
docker build --platform amd64 ./
Laravelかどうかに関係なく、ECS Fargate上のアプリのログをCloudWatchに表示させるには、ログを標準出力させればOK。Laravelの場合、config/logging.phpの「channel」部分を以下のように調整してあげるだけでよい。
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['single', 'stderr', 'stdout'], 'ignore_exceptions' => false, ], 'single' => [ 'driver' => 'single', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', 'days' => 14, ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => 'critical', ], 'papertrail' => [ 'driver' => 'monolog', 'level' => 'debug', 'handler' => SyslogUdpHandler::class, 'handler_with' => [ 'host' => env('PAPERTRAIL_URL'), 'port' => env('PAPERTRAIL_PORT'), ], ], 'ecs' => [ 'driver' => 'stack', 'channels' => ['stderr', 'stdout'], ], 'stdout' => [ 'driver' => 'monolog', 'handler' => StreamHandler::class, 'formatter' => env('LOG_STDERR_FORMATTER'), 'formatter_with' => [ 'dateFormat' => '%Y-%m-%d %H:%M:%S' ], 'with' => [ 'stream' => 'php://stdout', ], ], 'stderr' => [ 'driver' => 'monolog', 'level' => 'error', 'handler' => StreamHandler::class, 'formatter' => env('LOG_STDERR_FORMATTER'), 'formatter_with' => [ 'dateFormat' => '%Y-%m-%d %H:%M:%S' ], 'with' => [ 'stream' => 'php://stderr', ], ], 'syslog' => [ 'driver' => 'syslog', 'level' => 'debug', ], 'errorlog' => [ 'driver' => 'errorlog', 'level' => 'debug', ], 'null' => [ 'driver' => 'monolog', 'handler' => NullHandler::class, ], 'emergency' => [ 'path' => storage_path('logs/laravel.log'), ], ],
何をしているかというと、デフォルト設定になっている「'stack'」に標準出力となる「'stderr'」と「'stdout'」を追加してあげているだけ。「'stdout'」に関してはLaravelのバージョンによっては記述がないかもしれないが、その場合は追記してやればよい。ちなみに「'single'」は見ての通りLaravelプロジェクトフォルダ内にログを出力する設定項目。この設定でCloudWatchにLaravelのログを出力させることができる。とっても簡単。
LaravelにはデフォルトでBasic認証の仕組みが実装されているので、基本的には「route/api.php」で以下のようにmiddlewareを追加してあげるだけ。
Route::get('sampleapi', 'SampleApiController@index')->middleware('auth.basic');
これだけで「User」テーブルの「email」と「password」でBasic認証が実装される。
ただ、この「User」テーブルを参照しに行くのに、configフォルダ内の「auth.php」の以下の部分を見ているので、
自分もそうなのだが、このUserモデルのパスを変更している場合、その変更したパスに合わせてここも調整してやる必要がある。
これでGood to Go
storageフォルダは777に権限していて、welcome画面とかは普通に表示できているのに、apiのURLを呼び出すとなぜかこのエラーが発生。storageフォルダのオーナーを変更すると治るとのこと。
chown -R www-data:www-data storage