Closed26

Laravelプロダクト Fargate化への道

前提

  • コードリポジトリが docker-compose 化されている
  • AWS を利用している
  • PHP 7 系以上
  • Laravel 5.8 以上
  • セッションストアにRedisを使用
  • フロントエンドは Vue.js で開発

Step 1 アプリケーションのイメージ化

・・・
    build:
      context: 
      dockerfile: 
      args:
・・・

・・・
    image:
・・・

ログ出力をファイルから標準出力へ

composer install を Dockerfile で

docker build 前に Vue.js のビルドを済ませるように

docker build の作業拠点を Amazon Linux Workspaces にしていたことは大きかったはず
(ビルド時間面。 Docker for Mac 辛い)

[躓いていたこと]

  • ディレクトリがない編

    • storage 配下のディレクトリが足りてなくて
      • 特に、 storage/framework/cache/data
    • bootstrap/cache ディレクトリに書き込み権限がなくて
  • build 時には Redis と繋がってないので

    • php artisan cache:clear をDockerfile中でやるとエラーになる
    • php artisan config:clear しないと環境変数が古いまま

ログ出力をファイルから標準出力へ

この点、文化として浸透していない現場がそれなりにありそう
「セッションをファイルで持つ」のを Redis 等の共有ストレージに変えておく、のようなスケールアウトを意識した初動にもしておいた

Step 2 イメージ化したアプリケーションを動かす

  • docker-compose up してコンソール出力とにらめっこ

環境変数の不足

「何が不足しているのかわからないが落ちる」地獄
結局は S3 へのアクセスキー/シークレットキーだった

開発者から環境変数の追加を伝達されない、という問題ケースもあった

Step 3 インフラ構築(ECS は cluster まで)

以下の順に module 化 しつつ順次 apply

  • network

    • vpc
    • subnet
    • nat gateway
    • (vpc endpoint : 後で追加)
      • Gateway
      • Interface
  • security

    • public
    • private
    • storage
    • (vpc_endpoint)
  • ecs-fargate

    • ecs cluster
    • alb
    • iam role
  • data-store

    • rds
    • elasticache

終盤で ECR pull ができなくなって大苦戦
相当焦った

問題のポイントは、プライベートサブネットに 443 ポートの疎通を入れてなかったこと。
Fargate 1.4.0 での VPC Endpoint 設定が必要になったところが腹落ちしてなかった。

ECS cluster のキャパシティプロバイダー、オートスケールはまださわれていない
FARGATE_SPOT 把握したい

サービスディスカバリはチョットできた

Step 4 ecspresso で ECS サービス・タスク定義構築

https://zenn.dev/fujiwara/books/ecspresso-handbook
  • 手始めは maintenance service
    • nginx-proxy
  • 次にDBマイグレーションをする用の artisan service
    • laravel-app
  • そして、年末年始に学習しておいた、nginx - laravel 一体タスクを実装

https://booth.pm/ja/items/2539342

だいたいの流れ

  • init は特に使わず json でサービス定義・タスク定義を記述
  • verify でシンタックスチェック
  • --dry-run でどういうタスク定義が作られるかを最終確認
  • 初回は create でサービス作成
  • 2回目以降は deploy
  • 作り直すときは一旦 scale --tasks=0 -> delete
  • マイグレーションは run --skip-task-definition --overrides="{\"containerOverrides\":[{\"name\":\"laravel-app\",\"command\":[\"make\",\"migrate\"]}]}"

今のところ、rollback --deregister-task-definition は使っていない

古くてもう使わないタスク定義の登録解除は今のところ手動

デプロイ後の整理問題、そこかしこにありそう

Step 5 デプロイ簡素化

今のところ、CircleCI 版のみ。近日中に Bitbucket Pipelines 版が生まれるはず。

だいたいのワークフロー構成
  • check
    • 開発メインストリーム ブランチのみで filter
      • test-fresh-seed
        • local 用の 環境変数を direnv で load
        • Vue.js build
        • docker build
        • DB migrate:fresh --seed を走らせる
          • (なぜか成功しないのでコメントアウト中)
      • 完了時に Slack に通知
  • ecr-update
    • ステージング・本番環境用ブランチのみで filter
    • パラメータ run_push を true にした API からのリクエストのみで発動
      • build
        • staging 用の 環境変数を direnv で load
        • Vue.js build
        • docker build
        • docker tag
      • ECR への push まで
        • docker tag
        • aws ecr login
        • docker push
      • 完了時に Slack に通知
  • ecs-deploy
    • ステージング・本番環境用ブランチのみで filter
    • パラメータ run_deploy を true にした API からのリクエストのみで発動
    • 要承認 : CircleCI の管理画面で実施可能
      • 開始時に Slack に通知
      • ecspresso のインストール
      • make jsonnet (タスク定義 ecs-task-def.json 作成)
      • make verify
      • make dry-deploy
      • make deploy <- デプロイ本体
      • 完了時に Slack に通知
  • ecs-rollback
    • ステージング・本番環境用ブランチのみで filter
    • パラメータ run_rollback を true にした API からのリクエストのみで発動
    • 要承認 : CircleCI の管理画面で実施可能
      • 開始時に Slack に通知
      • ecspresso のインストール
      • make jsonnet (タスク定義 ecs-task-def.json 作成)
      • make verify
      • make dry-rollback
      • make rollback (ecspresso rollback --deregister-task-definition) <- ロールバック本体
      • 完了時に Slack に通知
  • db-migrate
    • ステージング・本番環境用ブランチのみで filter
    • パラメータ run_migrate を true にした API からのリクエストのみで発動
    • 要承認 : CircleCI の管理画面で実施可能
      • 開始時に Slack に通知
      • ecspresso のインストール
      • make jsonnet ( "artisan" タスク定義 ecs-task-def.json 作成)
      • make verify
      • make mg-run (php artisan migrate 実行) <- マイグレーション実行本体
      • 完了時に Slack に通知
  • 意図的に「全自動」にしていない
    • 不測の事態が発生したときの「振られ幅」を小さめに抑える
  • デプロイ用IAMユーザーで運用
    • ベースにした情報は下記 *1

@raki さんから学んだ

https://twitter.com/raki/status/1372201607216033793

記 *1

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs_managed_policies.html
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/ecr_managed_policies.html#AmazonEC2ContainerRegistryPowerUser
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/codedeploy_IAM_role.html

staging 用の 環境変数を direnv で load

↑で微妙にハマったこと

少し変数名を間違えてただけで、画面に期待されていた文字列が載ってこない

Laravel Mix の「左辺と右辺、同じはダメ」制約嫌い。

今後の課題など

  • Vue.js のビルドに時間がかかるのはキャッシュするなどして短縮したい
    • 毎度、デプロイ用のエグゼキューター(Amazon Linux2 をカスタマイズした Docker イメージ)を pull している・・・
  • CloudWatch にヘルスチェック ログが流れないように
    • ノイズ感甚だしい
  • バッチ処理実行コンテナ
  • NGINX の resolver を入れたい
    • サービスディスカバリ機能で DNS キャッシュのために疎通できなくなるのを避けたい
  • ブルーグリーンデプロイ
    • もっと気軽に検証できるように
  • ECS Exec
    • php artisan cache:clear をオンデマンドでしたい!!
  • 接続元IP制限
    • ステージング環境は内部公開にとどめたい場合
このスクラップは2021/03/27にクローズされました
作成者以外のコメントは許可されていません