Amazon ECSのタスクを常に新鮮に保つ仕組みをStep Functionsで

SREチームの藤原です。今回はAmazon ECSのサービス内のタスクを定期的に再起動することで、日々のメンテナンスコストを削減する話です。SRE連載 3月号になります。

3行でまとめ

  • ECS Fargateのタスクは時々再起動が必要
  • 人間が対応するのは面倒
  • Step Functionsを定期実行して常に新鮮なタスクに入れ換えて予防しよう

ECS Fargateのタスクは時々再起動する必要がある

ECS Fargateでサービスを運用していると、数ヶ月に一度ほどの頻度でこのようなお知らせがやってきます。

[要対応] サービス更新のお知らせ - AWS Fargate で実行されている Amazon ECS サービスの更新が必要です [Action Required] Service Update Notification - Your Amazon ECS Service Running on AWS Fargate Needs an Update

Fargateをホストしている基盤に更新があったりセキュリティパッチが当たった場合、その上で動いているタスクを起動し直す必要があるためです。

このお知らせを放置していても、予告された期限を過ぎると自動的に新しいタスクが起動し、今動いているタスクは終了するため、サービス自体はダウンタイムなく維持されます(されるはずです)。なので基本放置でよいかというと……これが原因で障害を起こした例が過去にありました。

  1. ECSが新しいタスクを起動しようとした
  2. ECR(Elastic Container Registry)からイメージが消えていた1などの理由で、新しいタスクが起動できなかった
  3. ECSは新しいタスクを起動しようとし続けたが、ひっそりと数日間失敗し続け…
  4. 新しいタスクが起動しないまま、ついに古いタスクが終了し、サービスのタスクが全滅した

今動いているタスクと同じタスク定義だとしても、そのタスク定義から新しいタスクが起動できるかは、実際に起動してみるまでは分からないのでした。

人間がやるのは面倒→機械にやらせましょう

サービス内のタスクを再起動するには、例えばaws cliで以下のようなコマンドを実行するだけです。--force-new-deployment オプションによって、サービス内のタスクを強制的に入れ換えます。簡単ですね。

$ aws ecs update-service \
     --service service_name \
     --cluster cluster_name \
     --force-new-deployment

しかしコマンドを一発打つだけの簡単な作業とはいえ、多数のAWSアカウントで多数のECSサービスを運用している場合、それら全てについて一つ一つCLIを実行するのも面倒です。

ECSサービスのタスクはいつ入れ替わってもよいように作られているべきです(そうでなければアプリケーションの作りを見直しましょう)。単にこの作業を自動化し、毎日再起動してしまえばよいでしょう。

デプロイ頻度が少ないサービスではとても長い間、数年間動き続けているタスクがあったりします。このようなサービスでは、実際に再起動が必要になったタイミングでタスクが新しく起動できるか不安になってしまいます(人間が)。

常に新鮮なタスクに入れ換えることで、以下の要因を取り除くことができます。

  • このタスクは起動できるだろうかという不安
  • お知らせが来てからタスクを再起動する作業
  • このようなお知らせに払う関心
    • 古い基盤で動いているタスクがひとつもなければ、更新が必要という通知も来ないはずです

Step FunctionsでECSサービスの再起動を実装

定期的にタスクを再起動する処理を実装する方法はいろいろ考えられますが、この程度の作業にaws cliやSDKを使ったLambdaなどを用意するのも大袈裟です。今回はStep FunctionsのAWS SDK統合を利用して実装してみました。

aws.amazon.com

実装するState Machineはごくシンプルなものです。リトライなどの考慮はありませんが、仮に失敗したところで次回の実行で成功すれば問題ないものなので、シンプルに徹しました。

このState MachineはTerraformで管理しています。

terraformのコードは以下のようになりました。ECSクラスター mycluster に存在しているECSサービス service1, service2 を再起動するState Machineをそれぞれ定義するものです。

locals {
  ecs_services = ["service1", "service2"] // サービス名
}

resource "aws_sfn_state_machine" "refresh-ecs-service" {
  for_each = toset(local.ecs_services)
  name     = "refresh-ecs-${each.value}"
  role_arn = aws_iam_role.refresh-sfn.arn // ecs:UpdateService できる権限を持ったrole
  definition = jsonencode({
    Comment = "ECS Service ${each.value} タスク入れ換え"
    StartAt = "UpdateService"

    States = {
      UpdateService = {
        Comment = "ECS Service ${each.value} refresh"
        End     = true
        Parameters = {
          Cluster            = "mycluster"
          Service            = each.value
          ForceNewDeployment = true  // 強制的にタスクを入れ換える
        }
        Resource = "arn:aws:states:::aws-sdk:ecs:updateService"
        Type     = "Task"
      }
    }
  })
}
  • aws_sfn_state_machineリソースを使います
  • State Machineの定義(definition)は、HCLで書いた定義をjsonencode関数でJSON文字列化して与えます
  • AWS SDK統合でECSのUpdateService APIを呼び出すリソース名は arn:aws:states:::aws-sdk:ecs:updateService です。uが小文字なことに気をつけてください

あとは、このState Machineを適宜EventBridgeから定期実行してやるだけです。

まとめ

今回は些細な工夫ですが、Amazon ECSサービス内のタスクを定期的に再起動する作業を自動化し、対応コストを減らす取り組みを紹介しました。

クラウドで動いているコンピューティングリソース(ECSタスク、オートスケールしているEC2のインスタンスなど)はあまり長期間動かしたままにせず、定期的に新しいものに交換していくことをお勧めします。結果的に人間が手を動かして対応するコストを減らすことに繋がることが多いためです。

カヤックでは楽をするためのに手を動かすことが好きなエンジニアを募集しています!


  1. ECRのライフサイクルルールで使用中のイメージが削除されてしまう問題とその対策については ecrm - Amazon ECRから不要イメージを安全に削除するOSSを作った も参照してください

3/9(木) Google Cloud 主催 Innovators Live Japan に市川が登壇します!

SREチーム(新卒)の市川恭佑です。

Google Cloud が主催するオンライン形式のイベント Innovators Live Japan につきまして、この度、3月9日(木)開催のウェビナー「実録!SRE」の1コーナーを担当することになりました。

cloudonair.withgoogle.com

最年少なのに何故かトリですが、たぶん特別な理由はないので、リラックスして当日を迎えたいと思っています。

発表概要

タイトルは「SRE の目的に立ち返った Infrastructure as Code の再考察」というものです。

イベントの紹介ページには書かれていない背景の補足も含めて、発表内容を軽く紹介いたします。

なぜ Infrastructure as Code の話?

SRE 文脈で Infrastructure as Code(IaC)と聞くと「あくまでもツールの話だよね」という印象を抱く方が少なくないと思います。 それ自体は至極当然なことで、そもそも IaC は「SRE の要求に応じて台頭した」といった歴史的順序を持っていないからです。

しかしながら、SRE として活動している人の多くが触れていることも間違いないでしょう。 我々にとっては、当たり前にある大前提のツールと化しているのです。

当たり前にあるものほど、その意義については、曖昧な認識を放置してしまいがちです。 その上に、自分にとっては当たり前に使えるものでも、他人にはハードルが高いものと認識されてしまってコラボレーションが阻害されることも多々あります。

これは、最近発売されたオライリー・ジャパンの「オブザーバビリティ・エンジニアリング」においても、モニタリングを題材として同じような教訓が記されています。

www.oreilly.co.jp

本書の冒頭で紹介されている「社会技術的(Socio-technical)」という用言は SRE や DevOps にも当てはまるものです。 他種多様な背景でシステムの開発・運用に携わる多くのメンバーに参加してもらうために、特定の取り組みにおいて当然のように利用される技術への再考察は、決して無駄なものにならないでしょう。

全体的に、どんな話?

これまで、学生エンジニアとしてのアルバイト時代を含めて、基本的に Amazon Web Services(AWS)を利用した自社 Web サービスに関わっていた私ですが、 最近の人事異動の結果、Google Cloudを利用した受託開発のモバイルゲーム案件に配属されました。

これにより、IaC に関連する分野で、以下のような問題が顕著になりました。

  • 大人の事情で操作できないサービス
  • 特定のツールと噛み合わせの悪い API
  • ツールの管理外で作成・操作されるリソース

もちろんこれらは以前の座組・スタックでも存在しましたが、例外的なものとして扱うことが可能でした。 それに対して、現在の環境ではこれらの問題がより恒常的に発生して、SRE の活動をする前提として無視できないレベルに達したため、IaC との関わり方を根本的に見つめ直しました。

具体的にどのような帰結を導いたかについては当日のお楽しみとさせてください。 SLI/SLOなどを題材としていない点で、毛色の違う発表にはなりますが、皆さんの業務を考える上でのお力添えになれば幸いです。 (以下のリンクは再掲です)

cloudonair.withgoogle.com

ブログの宣伝

今回、カヤックSRE連載という企画で公開したブログをきっかけに登壇のお話をいただきました。

自分の登壇告知と同時にブログの宣伝までするのは大変に恐縮ですが、結構しっかり書いた自信作です。 ちょうど OIDC で Google Cloud と良い感じに Federation したい気持ちが高ぶっている方がいらっしゃいましたら、CircleCI 以外でも参考になる部分が多いと思いますので、是非ご一読ください。

techblog.kayac.com

また、Google Cloud の文脈では、去年末にアドベントカレンダー企画で書いた記事も激しくオススメです。 これまた手前味噌ですが、すごく自信があるので「これからGoogle Cloudに入門する人はどうするべきか」以降だけでも読んでもらえると喜びます。 こちらについては、より多くの方に楽しんでいただけると思います。

techblog.kayac.com

技術ブログや登壇といったアウトプットは、業界では皆さん当然のようにこなしている印象がありますが、実際やってみると大変な労力を要していることを実感しています。最近は他の人のそれを参考にする度に、ありがたさを噛み締めています。

ということで、イベント当日に会いましょう。👋

カヤックではSREを募集しています!

hubspot.kayac.com