構築手順・CICD設定
0. 全体構成
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)切り替え
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エンドポイントが色々必要
デプロイ
- 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することになる?
- コンテナごとにログが分かるか→ログタスクさえわかればログインできる
- 一台だけ異常があった場合に、それだけ落とすとかできるか。
- 環境ごとの適用状況の差分確認をどうするか