チラシ裏日記上等!!新館

Webアプリケーションエンジニアの雑記帳。映画とかアニメとかの記事も書きます。

aws-cliでECSのTaskDefinitionとServiceを更新する

GitHubコントリビュート状況

CIでデプロイするときはコマンドでTaskDefinitionのリビジョンを更新し、更新したTaskDefinitionを使うようにServiceを更新したいと思います。

ECS関連でデプロイするためのOSSは割とあるので、ちゃんとやりたいときはそっちを使ったほうが便利だと思います。aws-cliを使ってやろうとするとちょっと苦労するのですが、そのあたりの情報が少なかったのでメモがてら残そうと思います。

叩くコマンド

叩くコマンドを次に示します。

TaskDefinitionのリビジョンの更新は次のコマンドで実行します。

$ aws ecs register-task-definition --family family名 --cli-input-json "$(aws ecs describe-task-definition --task-definition TaskDefinition名 | jq '.taskDefinition | { containerDefinitions: .containerDefinitions }')"

Serviceの更新は次のコマンドで実行します。

$ aws ecs update-service --cluster cluster名 --service service名 --task-definition TaskDefinition名

aws-cliとjqを使ってなんとか出来ます。jqが必要なのはちょっと悔しいところです。jqでなくてもjsonをよろしく扱えるコマンドがあればそれで代用は可能だと思います。

TaskDefinitionのリビジョンの更新

TaskDefinitionの更新は既存のTaskDefinitionの最新を取得してそれを利用して再度登録することで実現します。

2つのコマンドの組み合わせで実行します。次のコマンドは既存のTaskDefinitionを取得するコマンドです。

$ aws ecs describe-task-definition --task-definition TaskDefinition名

このコマンドを実行すると次のような結果が得られます。

{
    "taskDefinition": {
        "taskDefinitionArn": "arn名",
        "containerDefinitions": [
            {
                // コンテナの定義
            }
        ],
        "family": "family名",
        "revision": 1,
        "volumes": [],
        "status": "ACTIVE",
        "requiresAttributes": [
            {
                "name": "com.amazonaws.ecs.capability.ecr-auth"
            },
            {
                "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
            },
            {
                "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
            },
            {
                "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
            }
        ],
        "placementConstraints": [],
        "compatibilities": [
            "EC2"
        ]
    }
}

このjsonからTaskDefinitionを登録するための containerDefinitions をjqを使って取り出します。

$ aws ecs describe-task-definition --task-definition TaskDefinition名 | jq '.taskDefinition | { containerDefinitions: .containerDefinitions }'

ここで出力した文字列をTaskDefinitionの登録コマンドで使用します。登録するコマンドは次の通りです。

$ aws ecs register-task-definition --family family名 --cli-input-json TaskDefinitionのJSON

family名を指定すればリビジョンのみを更新したTaskDefinitionが作成されます。--cli-input-json に先ほど取り出した containerDefinitions を指定すれば良いです。

以上のコマンドを組み合わせて作ったワンライナーをもう一度示します。

$ aws ecs register-task-definition --family family名 --cli-input-json "$(aws ecs describe-task-definition --task-definition TaskDefinition名 | jq '.taskDefinition | { containerDefinitions: .containerDefinitions }')"

Serviceの更新

TaskDefinitionを更新するだけではServiceは更新されないのでServiceを更新するコマンドを叩きます。Serviceを更新するコマンドは次です。

$ aws ecs update-service --cluster cluster名 --service service名 --task-definition TaskDefinition名

これに関しては特に難しいことはなく update-service を実行しているだけです。このコマンドを実行すると新しいTaskが実行されデプロイが完了します。

まとめ

以上TaskDefinitonとServiceを更新するコマンドを見ていきました。出来ればaws-cliだけで実現したかったのですが、JSONを扱う都合上jqに頼らざる終えませんでした。ひょっとしたらもっとスマートな方法が他にもあるような気がしましたが、とりあえずリビジョンの更新と新しいリビジョンを使用したServiceの更新はできました。

Taskの更新とかはAWSでしか使わない知識なので学習コストとしては微妙な感じですね。デプロイの仕組みも自前でなんとかする必要があるので、もうちょっとちゃんとやるならkubernetesを使ったほうがいいんだろうなと思いました。