ecspresso v1.7.0 をリリースしました

3ヶ月ぶりの ecspresso リリースのお知らせです。

Amazon ECS デプロイツール ecspresso の v1.7.0 をリリースしました。

github.com

新機能

定義ファイル (サービス / タスク / run --overrides-file) で Jsonnet の直接読み込みをサポートしました

これまで JSON 形式が要求されていた各種定義ファイルで、Jsonnet の読み込みがサポートされました。

ファイルの拡張子が .jsonnet の場合、ecspresso 内部で先に Jsonnet を処理して JSON に変換後、これまで通り (テンプレート記法による env, tfstate の展開などが行われて) 読み込まれるようになります。

JSON は人が読み書きするのは不便なことが多いため、 ecspresso advent calendar 2020 day 20 - Jsonnetによる定義ファイル生成 の記事などで Jsonnet 形式をお勧めしていました。これまでは事前に自分で jsonnet コマンドを実行して JSON に変換してから ecspresso を起動する必要がありましたが、その処理が不要になりました。

github.com/google/go-jsonnet をライブラリとして組み込んでいるため、jsonnet コマンドは不要です。CI/CD 環境でも jsonnet のインストールが不要になって嬉しいですね。

各種定義ファイルで使用できない key を発見すると警告を表示するように

ecspresso が使用するタスク/サービス定義のファイルは aws-sdk-go で定義している構造体にマッピングされます。

これまでは JSON ファイル中の要素名(key) を間違った場合など、構造体に対応するものがない場合は、単に無視されていました。そのため要素名を typo した場合など、気が付かないうちに要素自体が省略されてしまい、意図しない構成がデプロイされてしまうことがありました。

v1.7 では、構造体に対応する要素が存在しない場合は warning を表示するようになりました。

f:id:sfujiwara:20211101152937p:plain

タスク定義リビジョンを取り扱う revisions, deregister コマンド追加

revisons コマンドは、存在しているタスク定義のリビジョンを表示できます。 IN USE の欄には、現在サービス内で利用しているタスクの情報が表示されます。単体タスクが使用している場合は RUNNING task, サービスに設定されているものは *** deployment となります。

$ ecspresso revisions
ecspresso --envfile envfile revisions
|        NAME        |       IN USE       |
+--------------------+--------------------+
| ecspresso-test:386 |                    |
| ecspresso-test:387 |                    |
| ecspresso-test:388 |                    |
| ecspresso-test:389 | ACTIVE deployment  |
| ecspresso-test:390 | RUNNING task       |
| ecspresso-test:391 |                    |
| ecspresso-test:392 | PRIMARY deployment |

古い revision を登録解除する、deregsiter コマンドも追加されました。

deregister コマンドでは以下のオプションのどちらかが必要です。

  • --revision=リビジョン番号 を指定すると指定したリビジョンを登録解除します
  • --keeps=保持する数 現在利用中のものを除いて指定した数だけリビジョンを保持し、古いリビジョンを登録解除します
    • 「現在利用中のものを除いて」= revisions コマンドで IN USE の欄が空欄のものが対象

revision が増えすぎて困る!とか、間違って動作しない revision を登録してしまったのでうっかり使わないようにしたい、という場合にご利用ください。

Fargate Windows Containers 対応

先日リリースされたばかりの、Fargate での Windows Containers の起動に対応しました。

aws.amazon.com

タスク定義の image, runtimePlatform を適切に指定すると起動できます。

// せっかくなので Jsonnet 形式で
{
  image: 'mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019',  
  runtimePlatform: {
    operatingSystemFamily: 'WINDOWS_SERVER_2019_CORE',
  },
  // ....
}

f:id:sfujiwara:20211101155543p:plain

バグ修正

サービス定義の desiredCount が設定されている(未定義ではない) 場合に create を行うと、その設定を無視して desiredCount=1 を設定してしまうバグを修正しました。


おしらせ

ecspresso handbook で、コマンドリファレンスの章も追加で無料公開しました。

現在 v1.5 対応版ですが、近日中に v1.7 対応に更新予定です。

zenn.dev

ISUCON11で優勝しました

勝った!!引退!!!

取り乱しました。

ずっと参加してきているWebアプリケーションパフォーマンスチューニングコンテスト ISUCON、ISUCON11本選にチーム「fujiwara組」で参加して、優勝しました。

ISUCON11 まとめ : ISUCON公式Blog

fujiwara組は初回のISUCONから参加している老舗チームで、自分(fujiwara)以外のメンバーは都度入れ替わっているのですが、今回はISUCON10の時と同様に会社(面白法人カヤック)の同僚である acidlemon と macopy とのチームです。

f:id:sfujiwara:20210921113931p:plain
チーム紹介スライド

過去に ISUCON1, 2, 5 で優勝しているので、6年ぶり4度目の優勝になりました。もう引退していいよね!(というか941さんに出禁って言われた気がする…)

やったこと

リポジトリはこちらです。

github.com

アプリケーションの変更は PR になっているので、それを順に見ると分かりやすいかと思います。 Pull requests · fujiwara/isucon11-f · GitHub

方針としては以下で、結果的には全員のやることがなくなってしまうことがなく、最後まで手を打ち続けられたのが勝因かなと思います。

  • fujiwara がインフラまわりの初期設定とチューニング、モニタリング、複数台構成を組むなどの足回りを整備
  • その間に acidlemon, macopy が大きめのアプリケーション改造に取りかかる
    • GetGrades の SingleFlight 化
    • JOIN はずし
    • 既読管理の Redis 化
  • fujiwara が細かいコードの改善を片付けて露払いする
    • zip生成での外部コマンド呼び出しを archive/zip 化
    • 1行だけ DB を引くような部分をオンメモリキャッシュ化 (メモリになければDBを見てメモリ(sync.Map)に載せる
    • 外部キーを全部やめる
    • echo(フレームワーク) の JSONSerializer を自作して goccy/go-json
    • 参照だけのエンドポイントで無駄にトランザクションを張っていたのをやめる
  • 大きめの改善を merge して伸ばしていく

fujiwara組が負けるときのパターンは、インフラ担当の自分がやることがなくなってしまって手が空いてしまうことが多いのですが、今回は3人がフル回転できてよかったですね。

個人的ハイライトは、archive/zip 化を決意して、10分で一発実装、ベンチ通過できたところでしょうか。AWS Lamba デプロイツールである lambroll を実装したときに Go での zip 生成は経験があったので、それをみながらスッとできました。いろんなコードを書いてみるものですね。

archive/zipにする by fujiwara · Pull Request #5 · fujiwara/isucon11-f · GitHub

スコア推移

やっていて、これだけ苦しい ISUCON は初めてかも知れません。何をしてもスコアに明確に響かない(けどサーバの負荷は僅かに下がる気がする)手を、最後には効くと信じて打ち込み続けるというのが本当にしんどい。

リアルでのパフォーマンスチューニングでは、明確に数字が上がらない施策を無闇に入れるのは避けるべきですよね。得られるパフォーマンスと、コードや運用の複雑さがペイしないと技術負債(しかもメリットなし)まっしぐらなので。競技中、ずっとしんどいしんどいって言ってました。

f:id:sfujiwara:20210921113651p:plain
スコア推移(最終上位3チーム+特別賞)

スコア推移を見ると、リーダーボードで自チーム以外のスコアが閲覧できなくなる17時直前に大きく伸びているのが分かります。

この時点で大きめの改善がマージ済みだったものの、db.SetMaxOpenConns(10) のままで MySQL の負荷が上がりきらないことに気が付いたので、 MaxOpenConns を 10 -> 20 -> 40 -> 60 と調整して最適値を探ってスコアを上げ、最後にダメ押しで今までずっと有効にしていた MySQL の slow query log を無効化して更に数字を伸ばした、というやつでした。

最終的には2位の NaruseJun もこの直後に10万点を超えて来ていたようなので、スコアが公開されている17時前に少しは盛り上げられてよかったかなと思います。

実際のスコアはリポジトリに保存してあります。 isucon11-f/scores.txt at main · fujiwara/isucon11-f · GitHub

最後に

近年の ISUCON ではもう年を食った社会人は若者や学生には勝てないんじゃないか、などといわれたこともありましたが、平均年齢38.7歳のおじさんチームでもまだまだ戦えることが示せてよかったです。

ただ個人的には、競技として洗練されて高度化していく方向が極まってきて、8時間以内に運営が想定したポイントを何個クリアできるか、あらかじめ設定された問題をどれだけ早く正確にこなすかのゲーム、になっているのが多少気になるところではあります。初期の頃の、誰がどんな手を繰り出して何をやってくるのか分からないみたいな空気を多少懐かしく思いつつ、まあこれも業界や時代の流れかなとは思いますが。

最後になりますが、楽しく快適な競技を提供して頂いた運営チーム、作問チーム、アドバイザリーの皆様ほか、スタッフの皆様にお礼申し上げます。本当に快適で楽しい ISUCON でした!(しんどかったけど…)

ISUCON11予選を4位で通過しました

今年もやってきました ISUCON の季節です。

ISUCON は 8 までは(出題を含めて)予選本選の全てに参加できていたのですが、9, 10 では連続で予選落ちしていました。10は予選であと1チーム上回れば、というところで及ばずでしたが、本選には並行参加チームというオープン参加扱いで参加させてもらい、ひっそり全体の3位相当のスコアを出していたんですよね。なのでチームのポテンシャルとしてはまだまだいけるはず!ということで ISUCON 11 にも10と同様、同僚の @acidlemon と @mackee_w (macopy) と参戦しました。

結果、全体の4位のスコアで予選を通過できました!

isucon.net

やったこととか

使用したのは Go 実装です。ミドルウェアは特に変更せず、最後まで nginx + MariaDB のままでした。 3台のうち1台を MySQL(MariaDB)専用、残りの2台を nginx + アプリケーションにしています。

コードの変更については、リポジトリを公開しています。

github.com

最終的に取りこまれた PR のタイトルとスコア、時刻をざっと並べるとこんな感じでした。

  • isu_conditionのorder by狙い #1 by mackee
    • 最初に slowlow をみて index を貼ったやつ。これで初期スコアから 16,168 へ (11:10:12)
  • いつものinterpolateParams=true #2 by acidlemon
    • Go の MySQL ドライバでデフォルトだと server side prepeare をするのをやめるやつ。17,918
  • debugのログをoffにする #3 by mackee
  • generateIsuGraphResponseが全部取るのは意味がないので1日の範囲だけにする #4 by mackee
  • trendは最新だけだからLIMIT 1 #6 by acidlemon
    • このあたりでスコア 30,000 程度 (まだ1台) (12:27:17)
  • isu_character_idx 追加 #7 by fujiwara
  • ログレベルをINFOにしてアクセスログも黙らせる #8 by mackee
  • 9割落としてるのはわかったので静かにしてもらう #9 by acidlemon
  • 9割おじさんから8割おじさんへ #10 by acidlemon
    • dropProbability という数値の調整でスコアの傾向を探っています
    • ここで3台構成にして 39,704 までアップ (13:00:43)
  • 9割に戻しつつpostIsuをbulk insert #11 by mackee
    • 48,346 (13:04:11)
  • initializeでalter #16 by acidlemon
  • image はファイルに書く#17 by fujiwara
    • isu.image カラムに入っていた画像バイナリをファイルで読み書きするよう改修
  • condition_true_countカラムに対応するstruct定義にする #18 by acidlemon
    • 1カラムに文字列で入っていたフラグを分解して true の数を別に持つ改修
  • true_countで絞り込み #19 by mackee
  • userテーブルへのfetchをキャッシュする #23 by mackee
    • オンメモリ化を進めている 73,570 (15:31:31)
  • 全量さばけるようになったので全部コメントアウト!#24 by mackee
    • ここで dropProbability=0 で通るようになったのでスコアが跳ね上がりました。一気に桁が上がって 374,366 (15:41:40)
  • isu nameをオンメモリ #26 by fujiwara
  • isuの画像をNULLで潰す #28 by acidlemon
  • isuを引いてくるところでcacheする #29 by mackee
    • このあたりで並行して Redis branch を作っていました(by acidlemon)がスコアが出ず、取り込みは諦め
  • インデックス1個にまとめて書き込み負荷を下げる #30 by mackee
    • 最後、isu_condition の primary key を変更して復号 pkey にしたのが効果を発揮して 684,959 (18:31:27)
    • id bigint AUTO_INCREMENTid bigint DEFAULT NULL (カラム自体は使わないけど残す)
    • PRIMARY KEY(jia_isu_uuid, timestamp)

再起動試験後、18:38:02 に 704,779 を記録して打ち止めでした。

f:id:sfujiwara:20210823173306p:plain
スコア推移(最終上位4チーム)

感想とお礼

出題はなるほど IoT で時系列データ(今までなかったのでそろそろ来そうだとは思った)、極端なところがなくて、いい問題でしたね。最終的には isu_condition の書き込みをどう捌くかに帰着するので、ここを上手く圧縮できたらもっとブレイクスルーできたのかな…と思います。時系列DBを使ったチームとかあったんでしょうか。

ベンチは大変快適で、例年ありがちな謎 fail に悩まされることがほぼなかったので、競技に集中できてとてもありがたかったです。近年、めきめきと ISUCON 運営力の向上を感じますね。頼もしい限りです。

運営の皆様、大変良い問題をありがとうございました。3大会ぶりの本選参加なので、本選でも楽しみたいと思います。よろしくおねがいします!

ecspresso v1.6.0 をリリースしました

このブログはすっかり ecspresso のリリースノートとなっている昨今ですが、今回もリリースのお知らせです。

Amazon ECS デプロイツール ecspresso の v1.6.0 をリリースしました。

github.com

非互換変更

これまで GitHub で配布しているリリースバイナリのパッケージが .zip 形式でしたが、リリースを GoReleaser で行うようにした関係で、tar.gz 形式に変更になっています。 (追記: GoReleaserでもzipにはできるのですが、パッケージ内部のファイル名を揃えることが難しかったため、どのみちインストーラーなどの対応が必要になるためtar.gzに変更しました)

手動でインストールしている場合は、zip ではなく tar で展開してください。

CircleCI Orb の場合は、 fujiwara/ecspresso@0.0.15 を使用してください。それ以前のバージョンでは、latest や v1.6.0 以降のバージョンが正しくインストールできません。

GitHub Actions の場合は、kayac/ecspresso@v1 で latest, v1.6.0 以降もインストールできるようになっています。もしまだ @v0 を使用している場合は @v1 へ更新をお願いします。

Homebrew でのインストールは今まで通り行えます。

新機能

ECS サービスなしでのコマンド実行

ecspresso はこれまで、一見 ECS にサービスが存在しなくてもよさそうな操作でも、サービスが存在しないと行えない操作がありました。単体タスクの実行 (run)、タスクの一覧 (tasks)、ECS Exec (exec) の各コマンドは、ECS サービスが存在している状態でないと正常に動作しませんでした。

v1.6.0 ではこれらの機能を、ECS にサービスがなくても実行できるようになりました。

  • run については、実行時の networkConfiguration など、ECS サービス定義と同等の情報が必要なため、サービス定義ファイルが必要です
  • tasks, exec については、サービス定義も不要です。タスク定義の family が同一なものを ECS クラスタ内から検索して操作対象とします

tfstate 参照機能で Terraform Cloud, Terraform Enterprise をサポート

Terraform Cloud で管理している tfstate を参照できるようになりました。URL を指定する場合は remote://app.terraform.io/{myorg}/{myworkspace} という形式で指定してください。

認証情報は TFE_TOKEN 環境変数から読み取ります。

--config のデフォルト値として ecspresso.yml が設定されます

これまで ecspresso の設定ファイルを指定する --config オプションの値はデフォルト値が存在しませんでしたが、ecspresso.yml というデフォルト値が設定されました。

バグ修正

exec コマンドでログ出力を KMS 暗号化する設定の場合動作しないのを修正しました

session-manager-plugin の呼び出し方法の問題でした。

CodeDeploy アプリケーションが100個以上ある場合にデプロイできない問題を修正しました

APIで一度に100個しか取得できない関係で、失敗することがありました。世の中にはいっぱいアプリケーションがある環境があるんですね…

tfstate 参照のキーに - が入っていると panic する問題を修正しました

outputs を定義している場合、リソース名には - が含まれる可能性があります。

CodeDeploy で使用する AppSpec に CapacityProviderStrategy を追加しました

ドキュメントの英語の誤りが修正されました

英語がグダグダなのを直していただいて、ありがとうございます!

短い ARN 形式を利用している場合に ecspresso init が失敗する問題を修正しました


パッケージングが変更になった以外は基本的に互換性を保ったリリースとなっています。Pull Requestをお寄せいただいた皆様、ありがとうございました。

どうぞご利用ください。

ECS Execに対応した ecspresso v1.5.0 をリリースしました

Amazon ECS のデプロイツール、ecspresso の v1.5.0 をリリースしたのでお知らせです。

github.com

今回は Amazon ECS Exec という新機能対応が目玉です。ほかにもお送りいただいたPRを取りこんだ各種修正が入ったリリースになります。どうぞご利用ください。

PRをお送りいただいた皆様、ありがとうございました!

新機能

ECS Exec への対応を追加しました

ホストから docker exec するように、Fargate に対しても起動しているコンテナに入ってコマンドを実行できる ECS Exec 機能がリリースされています。

aws.amazon.com

ecspresso v1.5 では exec コマンドを追加して、AWS CLI なしで exec できるようにしました。session-manager-plugin は必要です。

exec を使用するためには、まずサービス定義で enableExecuteCommand を true に設定して create / deploy します。(起動中の ECS サービスに対してもあとから変更可能です)

{
  "enableExecuteCommand": true
}

必要な権限などが揃っているかどうかは amazon-ecs-exec-checker で確認すると便利です。

その後は ecspresso exec コマンドを使用して、起動中のタスクに対して exec ができます。タスクに複数コンテナがある場合は、更に選択肢がでます。

実際に実行してみた様子は以下をご覧ください。

この例ではタスクやコンテナの絞り込みに peco を使っていますが、絞り込みに使うコマンドは設定ファイルの filter_command で指定可能です。未指定の場合は ID / コンテナ名入力するダイアログが表示されます。

タスクを一覧/詳細表示する tasks コマンドを追加

これまで ecspresso ではサービスとタスク定義の管理に主眼を置いていたため、起動済みのタスクの情報を見る手段がありませんでした。

ecspresso tasks を実行すると、サービスから起動されたタスクと、同じタスク定義を持ったタスク(単体で run されたものも含む) を表示します。

$ ecspresso --config config.yaml
|                ID                |   TASKDEFINITION   | INSTANCE |   LASTSTATUS   | DESIREDSTATUS |         CREATEDAT         |         GROUP         |  TYPE   |
+----------------------------------+--------------------+----------+----------------+---------------+---------------------------+-----------------------+---------+
| 28852184e15e48e0aad6b7549f92ed65 | ecspresso-test:274 |          | RUNNING        | RUNNING       | 2021-04-13T13:45:23+09:00 | service:nginx-local   | FARGATE |
| bed89f2e492e44cd82d75776ff2d8a7f | ecspresso-test:276 |          | RUNNING        | RUNNING       | 2021-04-13T13:48:04+09:00 | service:nginx-local   | FARGATE |
| fad8863654f945588273916a3a56bd95 | ecspresso-test:275 |          | DEPROVISIONING | STOPPED       | 2021-04-13T13:46:21+09:00 | family:ecspresso-test | FARGATE |

--find オプションを付けると exec 同様にタスクを絞り込んで、決定するとそのタスクの情報を JSON で出力もできます。

停止したタスクについても API で取得できる時点までは閲覧できるので、なぜか上手く起動できずに落ちてしまったタスクでも詳細を表示すれば、マネージメントコンソールを見に行かずに理由が分かります。

次の例では、"stoppedReason": "Essential container in task exited" などが読み取れます。

$ ecspresso --config config.yaml --id fad8863654f945588273916a3a56bd95 --output json
{
  "attachments": [ ... ],
  "availabilityZone": "ap-northeast-1c",
  "capacityProviderName": "FARGATE",
  "clusterArn": "arn:aws:ecs:ap-northeast-1:123456789012:cluster/ecspresso-test",
  "connectivity": "CONNECTED",
  "connectivityAt": 1618289185.693,
  "containers": [ ... ],
    {
      "containerArn": "arn:aws:ecs:ap-northeast-1:123456789012:container/ecspresso-test/fad8863654f945588273916a3a56bd95/8a04958b-4918-4a15-b6d4-6b40791c4fba",
      "cpu": "0",
      "exitCode": 137,
      "healthStatus": "UNKNOWN",
      "image": "debian:buster-slim",
      "lastStatus": "STOPPED",
      "managedAgents": [
        {
          "lastStatus": "STOPPED",
          "name": "ExecuteCommandAgent"
        }
      ],
      "name": "bash",
      "networkBindings": [],
      "networkInterfaces": [
        {
          "attachmentId": "bcb4aa98-1dfe-4a08-9a29-9db6e15d8334",
          "privateIpv4Address": "10.3.3.161"
        }
      ],
      "runtimeId": "fad8863654f945588273916a3a56bd95-987533343",
      "taskArn": "arn:aws:ecs:ap-northeast-1:123456789012:task/ecspresso-test/fad8863654f945588273916a3a56bd95"
    }
  ],
  "cpu": "256",
  "createdAt": 1618289181.026,
  "desiredStatus": "STOPPED",
  "enableExecuteCommand": true,
  "executionStoppedAt": 1618289229,
  "group": "family:ecspresso-test",
  "healthStatus": "UNKNOWN",
  "lastStatus": "STOPPED",
  "launchType": "FARGATE",
  "memory": "512",
  "overrides": {
    "containerOverrides": [
      {
        "command": [
          "nginx",
          "-V"
        ],
        "name": "nginx"
      },
      {
        "name": "bash"
      }
    ],
    "inferenceAcceleratorOverrides": []
  },
  "platformVersion": "1.4.0",
  "pullStartedAt": 1618289214.039,
  "pullStoppedAt": 1618289223.039,
  "startedAt": 1618289229.039,
  "stopCode": "EssentialContainerExited",
  "stoppedAt": 1618289345.672,
  "stoppedReason": "Essential container in task exited",
  "stoppingAt": 1618289280.886,
  "tags": [],
  "taskArn": "arn:aws:ecs:ap-northeast-1:123456789012:task/ecspresso-test/fad8863654f945588273916a3a56bd95",
  "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/ecspresso-test:275",
  "version": 6
}

rollback コマンドが CodeDeploy に対応

これまで ecspresso rollback は CodeDeploy でデプロイされた場合には機能しませんでしたが、機能するようになりました。 Feature Request: Rollback by CodeDeploy by cohalz · Pull Request #261 · kayac/ecspresso · GitHub

タスク定義へのタグ付けに対応

これまではタスク定義ファイルに tags を記述してもタグを付与することができませんでしたが、タグをつけられるようになりました。

これに伴って、タスク定義ファイルを取り扱うときに AWS SDK Go の ecs.TaskDefinition を使用していた部分が、ecs.RegisterTaskDefinitionInput を使用するように変わっています。JSON ファイルとして扱う場合には互換性を持たせていますが、もし何か問題がありましたらお知らせください。

{
  "tags": [
     {
        "key": "TagKey",
        "value": "TagValue"
     }
   ]
}

Feature Request: Support add Tags to TaskDefinition by Hirofumi-Narita · Pull Request #256 · kayac/ecspresso · GitHub

Support tagging for task definition. by fujiwara · Pull Request #260 · kayac/ecspresso · GitHub

バグ修正

init コマンド実行時に ECS サービスの propagateTags 属性を扱えるように

これまでは init コマンドで既存 ECS サービスを定義ファイル化した時点で propagateTags 属性が消えていましたが、保持するようになりました。

Support tags&propagateTags to `init` & `create` by cohalz · Pull Request #270 · kayac/ecspresso · GitHub

verify コマンド実行時に ELB の検証をタスク実行ロールではなく ecspresso の実行権限で行うように

これまでは verify コマンド実行時の ELB (target group) の検証を、タスク実行ロール(にAssumeRoleした状態)で行っていましたが、ecspresso 自体の実行権限で行うように変更しました。

タスク実行ロールには最小限の権限しか持たせない方が望ましい、という理由です。v1.5 の時点ではecspresso の実行権限での検証に失敗した場合、タスク実行ロールでの検証にフォールバックしますが、この挙動は移行措置として次のリリースで削除する予定です。

Don't require `elasticloadbalancing:DescribeTargetGroups` in task execution role to `verify` by cohalz · Pull Request #262 · kayac/ecspresso · GitHub

ecspresso handbook も改訂予定です

すみません、v1.4.0 リリース時に改訂予定としていましたが、まだ handbook は v1.3 対応のままです。v1.4, 1.5 での変更について加筆予定ですので、引き続きよろしく願いします。

zenn.dev

GitHub Sponsors はじめました

github.com

One-time のスポンサーもできるようになっていますので、よろしければこちらもご検討ください。

ecspresso v1.4.0 をリリースしました

Amazon ECS のデプロイツール、ecspresso の v1.4.0 をリリースしたのでお知らせです。

github.com

今回はそこまで大きな機能追加はないのですが、地味に嬉しい機能が入っております。どうぞご利用ください。

run コマンドに --overrides-file が追加

単体タスクを実行する run コマンドに、--overrides-file オプションが追加されました。

タスク実行時に上書きするコマンドや環境変数は、これまで --overrides オプションでJSON文字列として渡す必要がありましたが、これが結構複雑な構造をしているので組み立てが面倒でした。

{
    "containerOverrides": [
        {
            "name": "foo",
            "command": ["my-command"]
        }
    ]
}

こんな構造なので、CLI で渡すのはだいぶ煩雑です。ということで、あらかじめファイルとして JSON を記述しておいて、それを --overrides-file で指定することができるようになりました。また、このファイルは他の ecspresso の定義ファイルと同様、テンプレートとして解釈されます。

{
    "containerOverrides": [
        {
            "name": "foo",
            "command": ["{{ must_env `COMMAND` | json_escape }}"]
        }
    ]
}

このように環境変数COMMAND という値を展開するように定義しておけば、コマンドだけを変更したい場合に以下のように実行できます。便利!

$ COMMAND="echo hoge" ecspresso run --overrides-file overrides.json ...

verify コマンドに --no-get-secrets オプションが追加

ecspresso verify でのタスク定義の検証時に、これまでは secrets の値が SSM パラメータストアや SecretsManager に存在して読み取れる必要がありました。権限的に読み取れない場合は verify が失敗してしまいますが、値によっては verify を行う環境からは読ませたくない、という要望がありました。

--no-get-secrets オプションを指定すると、secrets が読み取れるかどうかの検証をskipします。

--envfile オプションが追加

ecspresso の各種定義ファイルでは環境変数を展開できる機能があり、動作のカスタマイズには欠かせない機能です。

しかし、複数の環境に対するデプロイを1つの定義ファイルで行う場合には ecspresso 実行環境変数を定義し直す必要があります。これはちょっと面倒な場合があるため、あらかじめ環境変数を定義した envfile を指定できるようにしました。

指定できるファイルは一般的な .env 形式で、export は付いていてもいなくても同様に動作します。

export FOO=foo
BAR=bar

envfile のパースには hashicorp/go-envparse を使用しています。hashicorp のライブラリ、いつもながら渋いけど便利ですね。

github.com

init コマンドに --force-overwrite オプションが追加

指定すると、init コマンドでの定義ファイル出力時に、既にファイルが存在していても確認なしで上書きします。

ecspresso の構成管理ファイルをバックアップ目的でリポジトリ管理していて、それを自動化する場合には確認なしで上書きしたいことはありますね。

テンプレート関数に tfstatef が追加

Terraform state file をテンプレートから参照する機能で tfstate 関数がありますが、tfstatef という関数が追加されました。これは要するに print に対する printf です。resource.name["foo"].id のような参照を行う場合に、部分的に文字列を変数から組み立てたい場合に便利です。

例えば環境変数 AZ を使用して aws_subnet.public['$AZ'].id というリソース名を tfstate から参照したい場合、従来は printf で組み立てた文字列を tfstate 関数で渡す、という若干のテンプレート芸が必要でした。

{{ printf `aws_subnet.public['%s'].id` (must_env `AZ`) | tfstate }}

これが、以下のように分かりやすく記述できます。

{{ tfstatef `aws_subnet.public['%s'].id` (must_env `AZ`) }}

verify 時にタスク実行ロールに assume できない場合の警告を warning から info に変更

verify コマンド実行時、ecspresso はタスク実行ロールに assume role を試みて、成功したらタスク実行ロールで、失敗したら現在の権限で検証を行います。

タスク実行ロールに assume することでより確実な検証が行えるのですが、assume role できる設定をわざわざ行わない場合は毎回以下のような警告が(黄文字で)出力されてしまいます。

WARNING: failed to assume role to taskExecutuionRole.

実際にはこれは害があるとまでは言い切れない警告だったため、ログレベルを INFO に変更しました。

作者の周囲でも、この警告が出ていてもほとんど全員が無視するという結果が観測されたため、WARNING を無視させる習慣を付けてしまうのは望ましくない、という理由もあります。

リリースバイナリを Go 1.16 でビルド

Go 1.15 から Go 1.16 に変更しました。今回から、M1 macdarwin むけ arm64 バイナリも同時にビルドしています。


ecspresso handbook も改訂予定です

zenn.dev

v1.4.0 で追加、変更された機能については、ecspresso handbook でも順次改訂予定です。

ecspresso で CloudFormation のリソース読み込みに対応 + その他機能追加した v1.3.0 をリリースしました

あけましておめでとうございます。Amazon ECS デプロイツール ecspresso の v1.3.0 をリリースしたのでお知らせです。

[2021-01-16 追記] v1.3.0 は init コマンドでクラッシュする問題があります。v1.3.1 をご利用ください。

今回は機能追加が盛り盛りなので、まとめて紹介します。

Release v1.3.0 · kayac/ecspresso · GitHub

【新機能】 cloudformation プラグインを追加

これまで ecspresso は Terraform tfstate を読み込んでそのリソース名から属性値を解決できる機能を持っていましたが、CloudFormation でも同様の処理ができるようになりました。

README に例がありますが、次のように Output と Export を定義したテンプレートで構築された、Stack 名が ECS-ecspresso という CloudFormation stack がある場合に

Outputs:
  SubnetAz1:
    Value: !Ref PublicSubnetAz1
  SubnetAz2:
    Value: !Ref PublicSubnetAz2
  EcsSecurityGroupId:
    Value: !Ref EcsSecurityGroup
    Export:
      Name: !Sub ${AWS::StackName}-EcsSecurityGroupId

ecspresso の設定ファイルで cloudformation plugin を指定すると

plugins:
  - name: cloudformation

定義ファイルで cfn_outputcfn_export という関数が使用可能になります。cfn_output スタック名 OutputKey で Outputs の値を名前で解決できます。cfn_export エクスポート名 で、エクスポートされた値を名前で解決できます。

サービス定義での使用例は次のようになります。

{
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "subnets": [
        "{{ cfn_output `ECS-ecspresso` `SubnetAz1` }}",
        "{{ cfn_output `ECS-ecspresso` `SubnetAz2` }}"
      ],
      "securityGroups": [
        "{{ cfn_export `ECS-ecspresso-EcsSecurityGroupId` }}"
      ]
    }
  }
}

ご意見をくださった @torics さん、@hamako9999 さん、@_sisisin さん、ありがとうございました!

【新機能】scale コマンドを追加

これまでサービスのタスク数を変更するためには deploy --no-update-service --skip-task-definition --tasks タスク数 を指定していましたが、これをショートカットにした scale コマンドを追加しました。

$ ecspresso --config config.yaml scale --tasks 10

これで ecspresso --config config.yaml deploy --no-update-service --skip-task-definition --tasks 10 とおなじ意味になります。

タスク数だけを変えたい場合でも指定するオプションが多いため、うっかりサービスやタスクを更新してしまう事例がありました。scale コマンドを使用すると必要なのは --tasks のみ(必須) になるため、事故を防げます。

【新機能】tfstate plugin が URL を直接読み込めるようになりました

これまで tfstate plugin はローカルファイルの読み込みのみが可能でしたが、直接 s3, http(s) URL からも読み込めるようになりました。デプロイする環境に terraform.tfstate が存在していない場合、これまではわざわざ aws s3 cp などでローカルにコピーする必要がありました。

plugins:
  - name: tfstate
    config:
      url: s3://my-bucket/terraform.tfstate

tfstate-lookup コマンドも v0.1.0 で URL からの tfstate 読み込みをサポートしています。 https://github.com/fujiwara/tfstate-lookup/releases/tag/v0.1.0

【新機能】設定ファイルで required_version が使用可能に

特定のバージョン以降で追加された機能を要求する場合など、ecspresso のバージョンに制約を持たせたい場合に設定ファイルで使用できる機能です。

required_version: ">= v1.3.0, < v2"

このように semver で指定することで、条件を満たしていないバージョンの ecspresso で実行しようとするとエラーになります。hashicorp/go-version を使用しています。

この機能をサポートしていない v1.3.0 未満のバージョンでは無視されるため、v1.3.0 がリリースされた時点では指定する意味はありません。将来新しいバージョンがリリースされ、その時点で入った機能や修正に依存した処理があるためそれ未満のバージョンでは実行させたくないような場合に役に立つ予定です。

PR を送ってくださった mashiike さん (同僚) ありがとうございました!

【新機能】run コマンドでタスクにタグが付けられるように

ecspresso run --tags Foo=Bar で、実行するタスクに Foo という名前のタグが Bar という値で設定されます (複数指定可能)。

ecspresso run --propagate-tags=(SERVICE|TASK_DEFINITION) で、実行するタスクに付けるタグをサービス定義もしくはタスク定義から引き継ぐことができます。

実は現状では、ecspresso でタスク定義を登録する際にはタグを附与することができません。これは定義ファイルを SDKecs.TaskDefinitionマッピングしていて、この構造体にはタグの定義がないためです。(サポート方法を悩みつつ、具体的な需要が今のところないので何もしていません)

その他修正いろいろ

  • [Fix] Unable to update platformVersion and networkConfiguration for CodeDeploy services. #209
    • CodeDeploy でデプロイする際に、--update-service を付けていても platformVersion と networkConfiguration が変更できなかった問題を修正しています。
  • [Fix] diff command becomes to compare local task definition and remote task definition. #218
    • diff コマンドが比較するタスク定義のリモート(ECS)側が、これまで latest (一番リビジョンが大きい) のものになっていましたが、サービスが現在使用しているリビジョンのものと比較するようになりました。
  • [Fix] Support to Docker Registry V2 API. Enables to read any public image repository using V2 API. (public.ecr.aws, gcr.io, ghcr.io and etc.) #214 #213
    • ECR Public repo など、一般の公開 image を verify できなかった問題を修正しています。Docker Registry API V2 を利用している任意の公開リポジトリの image が存在検証できます。
    • この修正に伴って、verify に 必要な IAM 権限から ecr:ListImages が不要になりました。

ecspresso handbook も改訂予定

昨年末に公開した ecspresso handbook ですが、こちらも v1.3.0 の新機能へ追従して近日改訂予定です。ご購入の方はそのままお読みいただけます。まだの方は是非この機会にお求めください。

zenn.dev