ECSタスク定義をコンソールから作って後悔した後、コード管理するため最速でJSON登録可能にする超愚直な方法

ECSのタスク定義、マネジメントコンソールから登録するの最初はわかりやすいんです。ただ、項目が増えてくるとJSONで管理したくなります。そんなあなたの気持ちに寄り添う記事です。
2020.04.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いつもこってりしたリード文を書く自分ですが、今日はもう、全部タイトルに書いた。

小ネタなのにタイトル長くない?!

  ( ゚д゚) ガタッ
  /   ヾ
__L| / ̄ ̄ ̄/_
  \/   /

せやな。

ECSのタスク定義登録は項目が多くて大変

ECSのタスク定義は、長年のECSの機能拡張に伴い設定可能な項目が非常に多くなっています。そんな複雑なタスク定義ですが、登録方法は大きく分けて3つあります。

  1. マネジメントコンソールから登録
  2. タスク定義のJSONを作成し、AWS CLIからregister-task-definitionを使って登録
  3. CloudFormationなどIaCを使って登録

ECSのタスク定義作成に慣れていない場合、項目の関連性が把握しやすいマネジメントコンソールからの登録を自分はおすすめしています。

JSONからの登録方法もテンプレートが公式で案内(タスク定義テンプレート)されていますが、最初は項目が多すぎていきなりのJSON作成は辛いと思います。

また、CloudFormationも良い選択肢なのですが、いかんせん最新プロパティがCloudFormationに対応するまでのタイムラグが結構あったりします。

最初はマネジメントコンソール⇢必要に応じてJSONに移行するのがわかりやすい

最初、マネジメントコンソールで登録しそれをベースに運用してく方法ももちろんありです。ただ、環境変数や設定項目が多くなっていくに従い、「画面でやるの辛い…し、コード管理したいYO!!」という気持ちがでてくる場合も多いです。

そんなとき、1からJSONを作り直しても良いんですが、既存の登録内容との整合性を確認するのも大変なので、コンソール登録した内容をJSONに反映するこの記事が役に立つってことです。

登録用JSONを作成するのが案外難しい

「そんなん、既存の登録内容からその内容をJSONで出力してそれをそのまま使えばええやん?」と思いますよね。はい。そんなAPIはありません。もちろん、タスク定義の内容を表示するAPIはあるんですが、このdescribe-task-definitionコマンドを使って出力した内容は、そのままではタスク定義登録用には使えないため、何かしらの加工が必要となります。

実はやろうとしていることは、弊社もこのこちらの記事と完全に同じなのですが、実施方法が異なります。

describe-task-definitionで取得したJSONはそのままではregister-task-definitionで登録できないお話 | Developers.IO

ECSタスク定義で利用できるJSONを作る方法

前置き長くなりましたが、ここから実際にマネジメントコンソールに登録しているECSタスク定義から、登録に利用できるJSONの作成方法を解説していきます。

元ネタのJSONを取得する

最初に編集するための元ネタとなるJSONを取得します。今回のJSONはマネジメントコンソールにのみ表示されているので、ものすごい愚直な方法でとってきますYO

マネジメントコンソールのECSタスク定義メニューから該当のタスク定義を開きます。ここで[Create new revision]をクリック。

タスク定義編集画面に遷移するので、ここで、画面一番下にある[Conrigure via JSON]ボタンをクリック。

すると、今回登録の元ネタに利用できるJSONが表示されます。

これをマウスで選択して適当なエディタにコピーしてJSONとして保存します。「マウスで選択!?まじかよ!?」と思うかもですが、マジです。ちょっと見た限りこの内容をCLIから取得する方法はありません。

こんな感じで取得できたでしょうか?ファイル名は、ecs-task.jsonにしています。

ecs-task.json

{
  "ipcMode": null,
  "executionRoleArn": null,
  "containerDefinitions": [
    {
      "dnsSearchDomains": null,
      "logConfiguration": null,
      "entryPoint": null,
      "portMappings": [
        {
          "hostPort": 8000,
          "protocol": "tcp",
          "containerPort": 8000
        }
      ],
      "command": null,
      "linuxParameters": null,
      "cpu": 0,
      "environment": [],
      "resourceRequirements": null,
      "ulimits": null,
      "dnsServers": null,
      "mountPoints": [
        {
            〜〜以下略〜〜
}

余談:タスク定義を表示したとき、画面に別タブで[JSON]があることを知っている人も多いと思います。このJSON使って試してみたんですが、エラーの解消方法がわかりにくかったため、元ネタのJSONは上で案内したものを使っています。

一度登録を試してみてエラーを表示させる

このJSONがそのままCLIから登録できればよいのですが、それができません。試しにaws cliのregister-task-definitionをつかって登録しようとすると、以下の感じのエラーが大量にでます。下の例では、タスク定義fargate-efs-mount-testに、JSONを登録しています。

aws ecs register-task-definition --family fargate-efs-mount-test --cli-input-json file://ecs-task.json

Parameter validation failed:
Invalid type for parameter ipcMode, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
Invalid type for parameter executionRoleArn, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
Invalid type for parameter containerDefinitions[0].dnsSearchDomains, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].logConfiguration, value: None, type: <class 'NoneType'>, valid types: <class 'dict'>
Invalid type for parameter containerDefinitions[0].entryPoint, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].command, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].linuxParameters, value: None, type: <class 'NoneType'>, valid types: <class 'dict'>
Invalid type for parameter containerDefinitions[0].resourceRequirements, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].ulimits, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].dnsServers, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].mountPoints[0].readOnly, value: None, type: <class 'NoneType'>, valid types: <class 'bool'>
Invalid type for parameter containerDefinitions[0].workingDirectory, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
Invalid type for parameter containerDefinitions[0].secrets, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].dockerSecurityOptions, value: None, type: <class 'NoneType'>, valid types: <class 'list'>, <class 'tuple'>
Invalid type for parameter containerDefinitions[0].memory, value: None, type: <class 'NoneType'>, valid types: <class 'int'>
〜〜以下略〜〜

エラーを潰して登録できるJSONを作っていく

あとは、エラー内容を確認しながらJSONを編集していくのみです。エラー内容は大量にありますが、基本的にエラー内容は「プロパティの中身がnullやで」と言っているだけなので、値が設定されていないnullのプロパティをどんどん削除していきます。

ある程度不要な項目削ったら、再度登録してみて、エラーがでたらまたつぶし〜っていうのを繰り返します。

最終的にエラーが無くなって、作成したJSONからregister-task-definitionが実行できたら、あなたの勝ちです! お疲れさまでした。

$ aws ecs register-task-definition --family fargate-efs-mount-test --cli-input-json file://ecs-task.json
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:629895769338:task-definition/fargate-efs-mount-test:16",
        "containerDefinitions": [
            {
                "name": "cloud-commander",
                "image": "coderaiser/cloudcmd:latest",
〜〜以下略〜〜

これをキッカケにECSタスク定義のコード管理に挑戦してみよう!

この記事書いておきながら、「もっと他の方法無いのかなぁ…」と思ったりしましたが、まぁ無さそうでした。ECSのタスク定義、設定項目が非常に多いのですが、マネジメントコンソール自体は非常によくできていると思うので、うまく学習と運用でそれぞれの手段を比較しながら、今回の記事を参考にしていただければと思います。

それでは、今日はこのへんで。濱田(@hamako9999)でした。