kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Terraform で「最新の」Amazon ECS タスク定義を追跡できる aws_ecs_task_definition の track_latest オプション

Terraform で Amazon ECS タスク定義を作りつつ,アプリケーションのライフサイクルとして GitHub Actions などの「Terraform 以外で」イメージタグを差し替えて Amazon ECS タスク定義を更新(正確には更新ではなくリビジョン追加)する運用を選択することがあると思う.さらにデプロイを繰り返すと使わなくなった Amazon ECS タスク定義が増えるため,定期的に「登録解除 (INACTIVE)」をすることもあると思う.ちなみに2023年2月からは削除もできるようになっているけど〜 \( 'ω')/

track_latest とは

しかし Amazon ECS タスク定義を登録解除すると Terraform でリソースを追跡できず,terraform plan を実行すると Amazon ECS タスク定義を作り直そうとしてしまう.少し前置きは長くなったけど,2024年2月16日にリリースされた Terraform AWS Provider v5.37.0 aws_ecs_task_definition に新しく track_latest オプションが追加された❗️

track_latest - (Optional) Whether should track latest task definition or the one created with the resource. Default is false.

この track_latest を使うと Terraform 側は常に「最新の」Amazon ECS タスク定義を追跡して比較してくれるため,Amazon ECS タスク定義の作り直しがなくなり,運用しやすくなる可能性がある👏

github.com

とは言え実際に試さないとイメージが沸かず,プルリクエストに書いてあるシナリオを参考に試してみた.

github.com

デフォルト or track_latest = false の場合

Step.1

今回はイメージの例として amazonlinux のタグを 2.0.20231218.02.0.20240109.02.0.20240131.0 と更新する流れを試す.まずは Terraform で Amazon ECS タスク定義(リビジョン1)を作る.

resource "aws_ecs_task_definition" "sandbox_track_latest_false" {
  family                   = "sandbox-track-latest-false"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"

  container_definitions = jsonencode([
    {
      name  = "amazonlinux",
      image = "amazonlinux:2.0.20231218.0"
    }
  ])
}

Terraform で Amazon ECS タスク定義(リビジョン1)を作った

Step.2

次は Terraform 以外(今回は AWS CLI を使う)でイメージタグを更新した Amazon ECS タスク定義を2個を作る(リビジョン2・リビジョン3).この状態でアプリケーションとして稼働する最新の Amazon ECS タスク定義は「リビジョン3」となる.

$ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240109.0.json
$ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240131.0.json

📝 taskdefinition-2.0.20240109.0.json

{
    "family": "sandbox-track-latest-false",
    "networkMode": "awsvpc",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "containerDefinitions": [
        {
            "name": "amazonlinux",
            "image": "amazonlinux:2.0.20240109.0"
        }
    ]
}

📝 taskdefinition-2.0.20240131.0.json

{
    "family": "sandbox-track-latest-false",
    "networkMode": "awsvpc",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "containerDefinitions": [
        {
            "name": "amazonlinux",
            "image": "amazonlinux:2.0.20240131.0"
        }
    ]
}

AWS CLI で Amazon ECS タスク定義(リビジョン2・リビジョン3)を作った

Step.3

ここで使わなくなった Amazon ECS タスク定義(リビジョン1・リビジョン2)を登録解除する.

$ aws ecs deregister-task-definition --task-definition sandbox-track-latest-false:1
$ aws ecs deregister-task-definition --task-definition sandbox-track-latest-false:2

Amazon ECS タスク定義(リビジョン1・リビジョン2)を登録解除した

Step.4

最後に terraform plan を実行すると Amazon ECS タスク定義を作り直そうとする😨 ちなみに個人用の Terraform Cloud のキャプチャを載せている.

terraform plan を実行した

track_latest = true の場合

Step.1

基本的には同じだけど,名前を sandbox-track-latest-true に変更して,track_latest = true も設定した.まずは Terraform で Amazon ECS タスク定義(リビジョン1)を作る.

resource "aws_ecs_task_definition" "sandbox_track_latest_true" {
  family                   = "sandbox-track-latest-true"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  track_latest             = true

  container_definitions = jsonencode([
    {
      name  = "amazonlinux",
      image = "amazonlinux:2.0.20231218.0"
    }
  ])
}

Step.2

Step.2 も基本的には同じ.Amazon ECS タスク定義を2個作る(リビジョン2・リビジョン3).

$ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240109.0.json
$ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240131.0.json

📝 taskdefinition-2.0.20240109.0.json

{
    "family": "sandbox-track-latest-true",
    "networkMode": "awsvpc",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "containerDefinitions": [
        {
            "name": "amazonlinux",
            "image": "amazonlinux:2.0.20240109.0"
        }
    ]
}

📝 taskdefinition-2.0.20240131.0.json

{
    "family": "sandbox-track-latest-true",
    "networkMode": "awsvpc",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "containerDefinitions": [
        {
            "name": "amazonlinux",
            "image": "amazonlinux:2.0.20240131.0"
        }
    ]
}

Step.3

ここで使わなくなった Amazon ECS タスク定義(リビジョン1・リビジョン2)を登録解除する.

$ aws ecs deregister-task-definition --task-definition sandbox-track-latest-true:1
$ aws ecs deregister-task-definition --task-definition sandbox-track-latest-true:2

Amazon ECS タスク定義(リビジョン1・リビジョン2)を登録解除した

Step.4

track_latest = true を設定してると Step.4 から挙動が変わってくる💡ここで terraform plan を実行すると Amazon ECS タスク定義を作り直しではなく「最新の」Amazon ECS タスク定義を追跡して比較してくれる.実際に containerDefinitions.image の値を最新の amazonlinux:2.0.20240131.0 から,Terraform コードで指定している amazonlinux:2.0.20231218.0 に戻すような差分が出ている❗️

terraform plan を実行した

次に Terraform コードを修正して最新の Amazon ECS タスク定義と一致させる📝

resource "aws_ecs_task_definition" "sandbox_track_latest_true" {
  family                   = "sandbox-track-latest-true"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  track_latest             = true

  container_definitions = jsonencode([
    {
      name  = "amazonlinux",
      image = "amazonlinux:2.0.20240131.0"
    }
  ])
}

もう一度 terraform plan を実行すると No changes で差分なしになる👌

なるほどー \( 'ω')/

terraform plan を実行した

まとめ

2024年2月16日にリリースされた Terraform AWS Provider v5.37.0 で追加された aws_ecs_task_definition の新しいオプション track_latest オプションを試してみた❗️ドキュメントを読むだけではイメージが沸かず,実際に試してみて良かった.とは言え track_latest = true を設定するとアプリケーションを頻繁にデプロイするときに変更の追随も大変そうなので ignore_changes で変更を無視する運用も引き続き残りそう.まずは track_latest = true の存在を覚えておこうー💡

位置情報や地図を仕事で使う前のキャッチアップに最適な「現場のプロがわかりやすく教える位置情報エンジニア養成講座」を読んだ

「現場のプロがわかりやすく教える位置情報エンジニア養成講座」を読んだ📕

今まで GIS: Geographic Information System など位置情報を取り扱うための技術的な知識や経験がなく,地図アプリケーションを使うと「便利だな〜w」という感想しか出てこないようなレベルだった💨

本書を読んで,そして本書の後半では実際にアプリケーションを写経しながら実装したことによって,位置情報を取り扱うための最低限の知識と開発の流れを把握できるようになった❗️本書の冒頭には「これから位置情報を扱うエンジニア」が読者層だと書いてあったけど,まさにその通りだと思った.位置情報や地図を仕事で使う前のキャッチアップに最適な一冊だった🗾

さらに OpenStreetMap / 国土数値情報 / 地理院タイルなど,地図関連の公開データ(ライセンスには注意)が多くあることも今までは全然知らなかった.

www.openstreetmap.org

nlftp.mlit.go.jp

maps.gsi.go.jp

目次

どの章も良かったけど,特に「第2章」で位置情報の知識を整理できたことと「第5章」でアプリケーションを一歩一歩動かしながら実装できたところが良かった👌

  • 第1章: 位置情報の世界
    • 1-1 位置情報とは
    • 1-2 位置情報アプリケーション
    • 1-3 位置情報アプリケーションの特徴
    • 1-4 自由に使える位置情報データ
  • 第2章: 位置情報の基本
    • 2-1 位置を表す方法:経緯度
    • 2-2 丸い地球をどう地図にするか:地図投影法
    • 2-3 位置情報のデータ形式
    • 2-4 位置情報のファイル形式
    • 2-5 位置情報の配信方法
    • 2-6 サーバーレスの潮流:Cloud Optimized
  • 第3章: 位置情報データの取得・加工
    • 3-1 QGISとは
    • 3-2 QGISのダウンロードとインストール
    • 3-3 位置情報データの取得
    • 3-4 位置情報データの表示
    • 3-5 位置情報データの加工:ベクトルデータ編
    • 3-6 位置情報データの加工:ラスターデータ編 
  • 第4章: 位置情報アプリケーション開発:入門編
    • 4-1 位置情報ライブラリの紹介
    • 4-2 テーマ別ハンズオン
    • 4-3 その他の位置情報技術
  • 第5章: 位置情報アプリケーション開発:実践編
    • 5-1 入門編との違い
    • 5-2 実践編Part1:「防災マップ」を作成する
    • 5-3 実践編Part2:スマートフォンで利用できるようにする

目次の詳細は出版社サイトを見てもらえればと!

www.shuwasystem.co.jp

実装したアプリケーション

「第4章」では Leaflet を使って,多くの地図表現を実装しながら学ぶ.そして「第5章」では MapLibre GL JS を使って,地図アプリケーション(防災マップ)を実装する.以下のような特徴がある👏

  • 背景の地図は OpenStreetMap のデータを使う
  • ハザードマップ(洪水浸水想定区域・津波浸水想定区域など)は「ハザードマップポータルサイト」のデータを使う
  • 指定緊急避難場所は「国土地理院」のデータを使う
  • etc

今回はできる限り写経しながら進めつつ,コピペで十分なところは本書のコードが公開されている GitHub リポジトリを参考にした.

github.com

そして実際にデプロイしたアプリケーション(一部)のキャプチャを紹介する❗️

防災マップ: 初期表示

防災マップ: 津波浸水想定区域と津波の指定緊急避難場所

防災マップ: 3D 表示

防災マップ: 指定緊急避難所の詳細情報など

本書のデモサイトも GitHub Pages にデプロイされていて実際に試せる👌ちなみに僕は GitHub Pages ではなく Vercel にデプロイして動作確認をしていた.

ちなみにキャプチャを載せたアプリケーションは完成後に復習も兼ねて Mapbox Controls の inspect と zoom を追加で導入してるので,右下のボタンは少しカスタマイズしてある💡

github.com

その他メモ

誤植

読みながら気付いたところをメモしておく📕

  • P.195: 開発実践編朱>開発実践編
  • P.233: 5-2-6 が2個ある

まとめ

「現場のプロがわかりやすく教える位置情報エンジニア養成講座」を読んだ📕

GIS: Geographic Information System や位置情報に関する知識がなかった僕にとってはとてもおもしろく勉強になる一冊だった.ユーザーとしては日々地図アプリケーションを使う機会があるため,今後は「どういう技術を使っているのかな〜」という目線で考えながら使ってみたいと思う.本当に読んで写経して良かった❗️

ちなみに本書には出てこなかったけど,AWS 関連で調べていたら Registry of Open Data on AWS に地理空間データが公開されていたり,事例もあったりして,今後はこのあたりの領域もウォッチしよう〜 \( 'ω')/

registry.opendata.aws

aws.amazon.com

Habitify API で習慣データを取得しよう

2024年から Habitify で個人的な習慣化の管理をしていて,もうとにかく便利で毎日の習慣化を支えてもらっている❗️朝活・読書・サプリメントなどを記録しつつ,Habitify のチャレンジ機能を使って毎日プランクを続けていたりもする💪Habitify は無料でも十分使えるけど,僕は Premium に課金して使っている〜 \( 'ω')/

www.habitify.me

実は Habitify を使うまでは数年間 Google Sheets で習慣化の管理をしていて,例えば朝活を例にすると「その日に取り組んだこと」を必ず記録していた.Habitify にも「習慣メモ」という機能があって記録はしてるけど,振り返りのために定期的に集計したく,今回は Habitify API を試してみた❗️API ドキュメントには以下にある.

docs.habitify.me

準備

まず Habitify API の API Key を取得する.ドキュメントにはウェブとアプリで取得できると書いてあったけど,現時点だとウェブでは取得できなさそうだった.Habitify をウェブで使うことはほとんどなく,普段使っているアプリ (Android) から API Key を取得した.

API: 習慣を取得する

/habits API (GET) で習慣化の一覧を取得できる👌(id は省略)今は4種類の習慣を登録している.ちなみにチャレンジ機能のデータは Habitify API では取得できなさそうだった.

$ curl -s -H "Authorization: ${API_KEY}" \
    https://api.habitify.me/habits | jq -r '.data[] | {id, name, goal: {periodicity: .goal.periodicity}}'
{
  "id": "wwwwwwwwwwwwwwwwwwww",
  "name": "ビタミンを摂る",
  "goal": {
    "periodicity": "daily"
  }
}
{
  "id": "xxxxxxxxxxxxxxxxxxxx",
  "name": "朝活をする",
  "goal": {
    "periodicity": "daily"
  }
}
{
  "id": "yyyyyyyyyyyyyyyyyyyy",
  "name": "1週間を振り返る",
  "goal": {
    "periodicity": "weekly"
  }
}
{
  "id": "zzzzzzzzzzzzzzzzzzzz",
  "name": "本を読む",
  "goal": {
    "periodicity": "daily"
  }
}

docs.habitify.me

API: 習慣メモを取得する

/notes API (GET) で習慣メモを取得できる👌パスパラメータには /habits API (GET) で取得した habit_id を設定する.クエリパラメータには Date Formatfromto を設定する.ただし普通にクエリパラメータを設定すると Only accept the format of from is YYYY-MM-DDThh:mm:ss±hh:mm というエラーになってしまうため,URL エンコードを忘れずに❗️

習慣メモを取得できるのは特に嬉しくて,今日までだと以下のような結果(数値は合計日数)だった.Start building with Next.js に取り組んだり,現場のプロがわかりやすく教える位置情報エンジニア養成講座を読み進めている結果を確認できた👏

$ curl -s --get -H "Authorization: ${API_KEY}" \
    --data-urlencode "from=2024-01-01T00:00:00+09:00" \
    --data-urlencode "to=2024-02-14T23:59:59+09:00" \
     https://api.habitify.me/notes/xxxxxxxxxxxxxxxxxxxx | jq -r '.data[].content' | sort | uniq -c | sort --reverse
  17 Start building with Next.js
  15 位置情報エンジニア養成講座
   8 Bedrock ワークショップ
   2 amazon-s3-multipart-upload-transfer-acceleration
   1 Hasura Tutorial PostgreSQL
   1 CDK x EventBridge Pipes
   1 Bedrock デジタルトレーニング

docs.habitify.me

まとめ

Habitify API の基本的なリソース HabitsNotes の取得を試してみた❗️個人的には習慣メモを取得できるのは助かる👌他にも実装されてる API はあるけど,取得できるデータが微妙に不足してたり,開発が止まってるように見えるのはちょっと気になる😨例えば習慣の「連続記録」などは API では取得できなかったりする💨

docs.habitify.me

今後も Habitify を毎日使っていくぞー \( 'ω')/

GitHub Actions から AWS CodeBuild のビルドを実行できる「aws-actions/aws-codebuild-run-build」

AWS CodeBuild Run Build for GitHub Actions (aws-actions/aws-codebuild-run-build) を使うと GitHub Actions から AWS CodeBuild のビルドを実行できる👌

github.com

シンプルに AWS CodeBuild のビルドを実行するだけなら project-name パラメータを指定すれば良くて簡単〜 \( 'ω')/

name: Start AWS CodeBuild build

on:
  workflow_dispatch:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ap-northeast-1
      - name: Start AWS CodeBuild build
        uses: aws-actions/aws-codebuild-run-build@v1
        with:
          project-name: sandbox

ちなみに GitHub Actions で AWS アカウントの権限を取得する仕組みは以下の記事にまとめてある!

kakakakakku.hatenablog.com

もし GitHub リポジトリをモノリポ構成(例えば Yarn Workspaces など)で運用していて,アプリケーションごとに AWS CodeBuild を作らず共有するという選択肢もあると思う.

buildspec-override パラメータに packgages/app1/buildspec.yml などアプリケーションごとの buildspec.yml を設定すれば OK👌 さらにアプリケーションごとにビルド環境に必要なスペックが異なる場合は compute-type-override パラメータで BUILD_GENERAL1_SMALLBUILD_GENERAL1_MEDIUM などの環境タイプを設定すれば OK👌柔軟に AWS CodeBuild のビルドを実行できて便利❗️

docs.aws.amazon.com

name: Start AWS CodeBuild build

on:
  workflow_dispatch:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ap-northeast-1
      - name: Start AWS CodeBuild build / app1
        uses: aws-actions/aws-codebuild-run-build@v1
        with:
          project-name: sandbox
          buildspec-override: packgages/app1/buildspec.yml
      - name: Start AWS CodeBuild build / app2
        uses: aws-actions/aws-codebuild-run-build@v1
        with:
          project-name: sandbox
          buildspec-override: packgages/app2/buildspec.yml
      - name: Start AWS CodeBuild build / app3
        uses: aws-actions/aws-codebuild-run-build@v1
        with:
          project-name: sandbox
          buildspec-override: packgages/app3/buildspec.yml
          compute-type-override: BUILD_GENERAL1_MEDIUM

Dependabot で AWS CDK を自動的にアップデートしよう

Dependabot version updates を使うと package.json に指定しているパッケージのアップデートを自動化できる❗️設定は比較的簡単で package-ecosystemnpm を設定して,あとは必須の directoryschedule.interval でアップデートの対象ディレクトリとスケジュールを決めれば OK👌個人的な AWS CDK 検証用プライベートリポジトリに設定して数週間試してみた \( 'ω')/

docs.github.com

ちなみに以下の AWS CDK ドキュメントでは Dependabotnpm-check-updates が紹介されていた.他には reviewdog を使うという選択肢もあると思う🐶

docs.aws.amazon.com

🤖 .github/dependabot.yml

version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: daily
    open-pull-requests-limit: 2
    target-branch: master
    groups:
      aws-cdk-dependencies:
        patterns:
          - aws-cdk
          - aws-cdk-lib
        update-types:
          - minor
          - patch
    ignore:
      - dependency-name: "*"
        update-types: ["version-update:semver-major"]

ちなみに aws-cdk と aws-cdk-lib に関しては同じプルリクエストにまとめるために groups を設定している👌 groups は2023年8月にリリースされている❗️

github.blog

動作確認

AWS CDK の aws-cdkaws-cdk-lib を自動的にアップデートするプルリクエストが作れたー👏