nokoのブログ

こちらは暫定のメモ置き場ですので悪しからず

ECSを復習してみた

構築手順・CICD設定

0. 全体構成

f:id:noko_htn:20211218215326p:plain AmazonECS / Fargate 本番運用のための構築とデプロイ方法まとめから引用

1-1. Clusterの構築

  • Cluster: TaskとServiceをグルーピングする概念。アプリケーションごと、環境ごとに用意する。
  • Fargateだとネットワーキングのみ

1-2. DockerImageを作成し、ECRにpush

  • ディレクトリ構成は要検討。アプリと分けるのもあり?DockerfileとTaskDefinitionをアプリごとにどこにおくか。
# イメージビルド
$ docker build ./ -t ecr-cicd-example
# ローカルで確認
$ docker run ecr-cicd-example
# ECRリポジトリを作成しておく
# ログイン
aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin XXX.dkr.ecr.us-east-2.amazonaws.com
# タグ付け(ローカルで)
docker tag ecr-cicd-example:latestXXX.dkr.ecr.us-east-2.amazonaws.com/ecr-cicd-example:latest
# プッシュ
docker pushXXX.dkr.ecr.us-east-2.amazonaws.com/ecr-cicd-example:latest

1-3. TaskDefinitionの作成

  • Task: コンテナの集合体
  • TaskDefinition: docker-compose的なもの
  • TaskDefinitionで定義するもの: タスクメモリ、CPU、コンテナ1のイメージURI・ポートマッピング・ログ設定

1-4. Serviceの作成と実行

  • Serviceを作成せずTaskを実行することも可能(バッチ処理など)
  • Service: 指定したtaskDefinitionからtaskを生成する
  • Serviceで定義するもの: ネットワーク、VPC、タスク定義
  • ネットワークモードで awsvpc を使う場合はプライベートサブネットを使いましょう
  • ECS Serviceを作成する際に「deployment_controller」の設定で「type = "CODE_DEPLOY"」の指定

2-1. (手動)Dockerfileを更新し、ソースリポジトリにpush

2-2. (GitLab)DockerImageをビルドし、ECRにpush

  • Docker Image TagとしてGitのCommit Hashを利用することでイメージを一意に特定できるようにします.
  • TaskDefinitionも、コンテナイメージのURIを書き換えてS3にアップロードする
  • AWS CLIのオプションで全てパラメータを渡すのは大変なので手元に「taskdef.json」というファイルを作成し, CLI Skeltonとして利用します
  • S3バケットの「appspec.yaml」を更新します.。CodeDeployでDeploymentを作成する際にS3バケットにあるAppspecを指定して作成します.。なので事前に用意したS3バケットに上記で作成したTask Definitionの新しいリビジョンを指定した「appspec.yaml」を保存します。
# Task Definitionを登録する
$ aws ecs register-task-definition \
  --cli-input-json file://path/to/taskdef.json

# appspec.yaml更新
aws s3 cp /path/to/appspec.yaml s3://YOUR_BUCKET_NAME/appspec.yaml

2-3. (CodeBuild)Greenをデプロイ

  • テストポートで動作確認する

2-4. (CodeBuild)切り替え

  • 確認が完了したらCodeDeploy画面で『トラフィックの再ルーティング』を実行する。→ロールバックの必要がないと判断したら『元のタスクセットの終了』を選択する。

3. コンテナログイン

  • AppコンテナのRoleに対して、ecs-exec用のIAMポリシーを新たに追加
$ aws --profile=adachin ecs execute-command  \
    --region ap-northeast-1 \
    --cluster adachin \
    --task xxxxxxxxxxxxxxxxxxxxxx \
    --container adachin-app \
    --interactive \
    --command "/bin/bash"

シェルスクリプト化する

ポイント

ネットワーク

  • VPCエンドポイントが色々必要
    • S3, CloudWatchLogs, ECR, etc
      • ecr.dkr, ecr.api, logs
    • セキュリティーグループはエンドポイントに接続するプライベートサブネットのインバウンド通信(ポート443)を許可すること(タスク実行でSGを指定するが、それがエンドポイントにhttpsで許可されているか)
    • -> fargate1.4から変わっているので注意
    • S3はインターフェース型もゲートウェイ型もどちらも必要?

デプロイ

  • CodeDeployと連動させて、ローリング or Blue/Green
    • Blue/Greenがおすすめ
    • ターゲットグループを二つ作っておいて切り替える
  • 環境ごとにリポジトリ・デプロイのルールを変える(リポジトリポリシー、CodeDeploy)
    • 開発:手動プッシュを許可
    • ステージング:CI/CDからのプッシュのみ許可
    • 本番: ステージングデプロイ済モデルのみデプロイ可能
  • 環境ごとに固有のタグ識別文字を付与し、タグごとのライフサイクルポリシーを指定する
  • タグは、環境識別子+コミットIDがおすすめ
  • イメージの上書き禁止設定をする。(IMMUTABLE設定)
    • pushはできるが更新されない?ので注意
  • デプロイ前に承認アクションを設定する
  • パスワードとかはSecret Managerでsecure stringとして管理する
  • 今回追加されたDAEMONタイプ: ホストの増減に合わせて1コンテナずつ実行する。 従来のルールベースのECSサービス: REPLICAタイプ
  • CI/CDをどこで実行するかを早めに決める。Jenkinsジョブなど。

監視

  • SNSからChatbotに連携してSlack通知
  • FireLensでログ運用する
    • -> CloudWatch Logsよりおすすめ
    • サイドカーパターンで配置する(設定をONにするだけ?)
  • prefix-name/container-name/ecs-task-id
    • ecs/ecr-cicd-example/aeecde8XXX
  • nginxなどは、ログ出力先に「/dev/stdout」を設定する
  • (コンテナとしてよくないが)ログが複数出るなら、awslogsで個別に設定する?
  • CloudWatch Container Insightsを活用する
    • CloudWatchLogs InsigthsでALBのログを見やすくする

セキュリティ

  • ECS/FargateはPCI DSS準拠
  • 金融サービスに関するWell-Architectedフレームワークレンズを参考にする
  • ECRによる脆弱性スキャン+Trivyによる脆弱性スキャン
  • dockleでベストプラクティスチェック
  • -> CIの中でTrivy+dockle
  • WAFをALBと連携させる
  • コンテナレジストリの暗号化(作成時)

性能

  • オートスケールはステップスケーリング or ターゲット追跡スケーリング
    • ターゲット追跡スケーリングがおすすめ

踏み台

  • SSMのセッションマネージャ
    • SSMエージェントを仕込んでおく?
  • →または、Amazon ECS Exec(最近はこちら?)

運用

  • ECSはAWSの完全なサポートを受けられる(オーケストレータ部分含めて)
  • FargateはEC2よりも割高なので注意
  • FargateはOSのセキュリティパッチ適用や各種ライブラリのアップデート作業が不要になる(運用工数削減)
  • 開発・ステージング環境はLambdaで稼働時間帯を調整する
  • 切り分け
$ aws ecs list-clusters --region us-east-2
$ aws ecs list-tasks --cluster [クラスター名] --desired-status STOPPED --max-items 3 --region us-east-2
$ aws ecs describe-tasks \
    --cluster MyCluster \
    --tasks arn:XXX \
    --region us-east-2

その他

  • sshでない。execを使う。踏み台を経由する?証跡の観点から。
  • ログが分かれるので、標準出力だけでは運用できない?ファイルごとにさらに出力先を分けたい?
    • →awslogsでやるしかない?awslogsのロググループ等どうするか
  • 開発フローどうするか。アプリ側にどう案内するか。CI/CDは必要。コンテナのテストは必要(Fargate上での切り分けが辛いので)
    • →さらに、EC2モードでデプロイする準備もしておく
  • Jenkinsサーバをどこにおくか。DEVとPRD。どっちにどのジョブを作るか。
  • ビルドもFargate?kanikoでビルドはできそうだが実行できるか?pushを挟んでGitLab runnerの他ステップで実行する?→DEVにもSTGにもpushすることになる?
  • コンテナごとにログが分かるか→ログタスクさえわかればログインできる
  • 一台だけ異常があった場合に、それだけ落とすとかできるか。
  • 環境ごとの適用状況の差分確認をどうするか

参考