とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど

開催予定の勉強会

読者登録と各種SNSのフォローもよろしくお願いいたします。

ECSでGitOps

私が関わっている案件ではK8s(っというかEKSやGKE)をよく使っています。K8sを使っていればArgoCDを使えるので、デプロイの仕組みをあまり意識する必要はありません。一方でAWS ECSで運用したい要望が出てくると自分でデプロイの仕組みを作る必要がでてくるので話は複雑になります。たまたまそんな機会があり、色々手法を検索しているとAWSのサンプルでECSをGitOpsで管理するサンプルがでてきました。今回はこれを動かしてみます。

gitops-amazon-ecs-sample

github.com

AWSのサンプルが色々置いてあるOrgで、その中の一つにGitOpsでECSを管理するサンプルが転がっていました。仕組みは以下の図です。

https://github.com/aws-samples/gitops-amazon-ecs-sample/raw/main/docs/gitops-ecs.png

処理の流れを見ていくと

  1. CodeCommitにdeployment.yamlをPush
  2. CodePipelineが発火
  3. CodePipelineがCodeBuildをキック
  4. CodeBuildがdeployment.yamlをdeployment.jsonに変換
  5. CodePipelineがStep Functionsをキック、inputにdeployment.json

Step Functionsの中の処理は以下

https://github.com/aws-samples/gitops-amazon-ecs-sample/raw/main/docs/deploy-stepfunction.png

なんやかんやした後、デプロイの成功失敗を通知しているようです。

必要なツール

以下のツールをインストールします。

もしこれだけで動かない場合は以下のREADMEに必要なツールが記載されているので全部いれてみてください。

README.md:Prerequisites

はじめ方

公式のサンプルはバグというか想定している処理が抜けているようなので、私のGitHubアカウントにフォークして一部修正しました。このリポジトリを使っている前提で話を進めます。

サンプルを適当なディレクトリにクローンします。

git clone https://github.com/vtj-ttanaka/gitops-amazon-ecs-sample.git
cd gitops-amazon-ecs-sample

GitOps環境をデプロイします。

sam build
sam deploy --guided --capabilities CAPABILITY_NAMED_IAM
  1. sam deployをすると色々聞かれますが、全てデフォルトで問題ありません。もし、変更したい部分があれば変更してください。
  2. Deploy this changeset? [y/N]:っと聞かれた時だけyを入力してください。それでデプロイが開始されます。

デプロイが完了すると色々なリソースが作成されています。CloudFormationのスタックに「sam-app」というのができていると思うので確認してみてください。1.の手順で「Stack Name」を変更していたらここの値は変わっています。

CloudFormationのOutputにCodeCommitの情報が出力されています。

このリポジトリをCloneします。私はgit-remote-codecommitを使用しているので、こちらのツールで進めます。

git clone codecommit::ap-northeast-1://config-repo-sam-app

空のリポジトリがCloneされるので、gitops-amazon-ecs-sample/deployment.yamlをリポジトリにコピーします。

cp /path/to/gitops-amazon-ecs-sample/deployment.yaml /path/to/config-repo-sam-app

deployment.yamlの中身はコンテナをスケジュールで実行するtasksと、コンテナをサービスとして実行するservicesに分かれています。tasksはオプショナルなので、登録してもしなくてもOKです。

tasks:
  - service: コンテナ名
    cwRuleName: CloudWatch Events Rule名で、定期実行をするためのもの
    image: デプロイするコンテナイメージURL
services:
  - service: コンテナ名
    clusterName: ECSクラスター名
    serviceName: ECSにデプロイされているサービス名
    image: デプロイするコンテナイメージURL

こんな感じでdeployment.yamlを修正します。今回は簡単に以下のようにしました。

release: 4.0
services:
  - service: echoserver
    clusterName: vtj-poc
    serviceName: vtj-poc
    image: "gcr.io/google_containers/echoserver:1.3"

いざデプロイヤー

git add deployment.yaml 
git commit -am 'add deployment.yaml'                      
git push origin main                

deployment.yamlをリポジトリにコミットするとCodePipelineが動き出します。

CodeBuildが完了してStep Functionsまでいけたら中身を見てみましょう。

今どんな処理が行われているかWeb UIから図としてみることができます。

ECSの画面も見てみてください。リビジョンが変わっていると思います。

リビジョンをクリックして中身をみるとどんなコンテナがデプロイされたのかを確認できます。

Gitを起点にデプロイすることができました。

Step Functionsで何をやっているのか

Step Functionsの中の動作が少し複雑なので説明します。

sam deployをすると4つのLambdaがデプロイされます。

  • InitConfigFunction
  • DeployTaskFunction
  • DeployEcsFunction
  • ValidateDeployFunction

1 InitConfigではInitConfigFunctionを実行します。InitConfigFunctionはsrc/init/lambda.pyがデプロイされています。このLambdaはdeployment.yamlに指定されたtasksとservicesに実行権限の情報を追加します。45行目48行目が該当の処理です。

2 Step FunctionsのChooseTaskOrServiceが実行され、tasksにサービスが指定されていればDeployTasksに飛びます。tasksが定義されていなければDeployTasksはスキップされ、DeployEcsに行きます。 1. DeployTasksはDeployTaskFunctionを実行します。DeployTaskFunctionはsrc/task/lambda.pyがデプロイされています。このLambdaはデプロイされているコンテナイメージとdeployment.yamlで指定されているコンテナイメージを比較して、コンテナイメージに変更があれば新しいタスク定義を登録しCloudWatch Event Ruleを書き換えて、 次のスケジュールで実行されるサービスを更新します。デプロイを行ったサービスはdeployment_neededフラグが立てられます。

3 DeployEcsはDeployEcsFunctionを実行します。DeployEcsFunctionはsrc/deploy/lambda.pyがデプロイされています。このLambdaはデプロイされているコンテナイメージとdeployment.yamlで指定されているコンテナイメージを比較して、コンテナイメージに変更があれば新しいタスク定義を登録し新しいリビジョンを登録します。デプロイを行ったサービスはdeployment_neededフラグが立てられます。

4 Step FunctionsのWaitForDeploymentが実行され、デプロイの完了を待ちます。ここは決め打ちで300秒待機させられます。

5 ValidateDeployはValidateDeployFunctionを実行します。ValidateDeployFunctionはsrc/validate/lambda.pyがデプロイされています。deployment_neededフラグの立てられたサービスでタスクをカウントし、0だったらfailed、1以上であればsuccessの処理に流れていきます。

片付け

CodePipelineで使うためのArtifactバケットがそのままだと削除できません。CloudFormationの画面からバケット名と特定しバケットをからにしてください。

バケットを空にできたらいよいよリソースの削除です。

sam delete

すべての質問にyで答えて削除は完了です。

まとめ

gitops-amazon-ecs-sampleはECSなどを起動しない代わりに、既存のECSクラスターでGitOpsを始められるようになっていました。まだECSでGitOpsできていない環境では試してみる価値はあるかもしれません。少し気になったのはデプロイの方法です。Blue/Greenやローリングアップデートではなく、コンテナが単純に置き換えられていくので、タイミング次第ではサービス断が発生するかもしれません。Blue/Greenデプロイの仕組みをいれようと思うとLambdaで自前実装する必要があり、この辺の仕組みを考え実装できるだけのスキルが必要になりそうです。