Terraform+GitHub Actionsでコミュニティープロバイダーを利用する方法について

さくらのクラウド向けプロバイダーなどのTerraformのコミュニティプロバイダーをGitHub Actionsで利用する際に独自のGitHub Actionsを作成しているケースを見かけました。

ak1ra24.hatenablog.com

qiita.com

私が最近よく使っているhashicorp/setup-terraform+terraform.d配下にプロバイダーのバイナリーを置くという方法だとアクションを自作しなくても済むので今回紹介しておきます。

hashicorp/setup-terraform+terraform.d配下にプロバイダーのバイナリーを置く方法

こちらのリポジトリさくらのクラウドプロバイダーを利用する例を公開しました。

github.com

Terraformで利用するtfファイル郡+GitHub Actionsとしてhashicorp/setup-terraformを利用する構成になっています。 (注: この例ではstateの扱いを手抜きしてます。本番環境で利用する際はTerraform Cloudを使うなどの対応が必要です)

hashicorp/setup-terraform

HashiCorp社が公開しているGitHub Actionsです。 前述の記事ではhashicorp/terraform-github-actionsが参照されていましたが、こちらの後継がhashcorp/setup-terraformです。

www.terraform.io

こちらの記事に新旧比較がありました。

tech.medpeer.co.jp

hashicorp/setup-terraformを利用すれば基本的なTerraformでの操作は行えそうですね。

コミュニティプロバイダーの配置

コミュニティプロバイダーは~/.terraform.d/plugins/配下以外にもいくつか有効な置き場所があります。

www.terraform.io

特にワーキングディレクトリのterraform.d配下に置く方法は

  • tfファイル類と同じリポジトリ内に配置できる -> コードとプロバイダーのバージョン管理が容易
  • プロバイダーのダウンロードが行えないような環境(Air-Gap)でも利用できる

といった利点があります。Terraform Cloudなどでコミュニティプロバイダーを利用する場合もこの方法を利用しますね。

febc-yamamoto.hatenablog.jp

この2つを組み合わせることでGitHub Actionsでコミュニティープロバイダーを利用可能となります。

実行例: https://github.com/yamamoto-febc/terraform-github-action-test/runs/709137993?check_suite_focus=true

おまけ: Terraform v0.13以降では

febc-yamamoto.hatenablog.jp

こちらの記事のようにコミュニティプロバイダーがTerraform Registryに登録されていればプロバイダーのバイナリーをterraform.d配下に置く必要もなくなります。 この辺も楽になりそうですね。

終わりに

ということでTerraform+GitHub Actionsでコミュニティープロバイダーを利用する方法について紹介しました。
コミュニティプロバイダーでも割と簡易な手順で利用できますので是非お試しください。

以上です。

Terraform v0.13開発版でプロバイダーの自動インストール/更新を試す

今年の1月にTerraform Registryでプロバイダー(3rd含む)を配布できるようにするというアナウンスがありました。

www.hashicorp.com

ベータテストへの参加を募集していたので申し込んでおいたのですが、本日(2020/5/15)参加できるようになったとの連絡をいただいたので早速プロバイダーの公開&自動インストールを試しました。

Terraform Registryでのプロバイダーの配布

従来はterraform initを実行してもgithub.com/terraform-providers配下のプロバイダーのみが自動インストールされるだけで、コミュニティが開発しているプロバイダーは~/.terraform.d/plugins/配下に格納しておくなど手動でのインストール作業が必要でした。

これがTerraform Registryにあらかじめプロバイダーの登録を行っておくことで自動でインストール/更新が可能となりました。

試しにさくらのクラウド向けプロバイダーをTerraformRegistryで公開してみました。

f:id:febc_yamamoto:20200515100233p:plain

registry.terraform.io

(ベータテスト中は上記のプロバイダー自体が予告なく削除される可能性もあります)

プロバイダーのインストール/更新

公開したプロバイダーのインストール/更新を試してみます。

Terraform v0.13開発版のビルド

試すにはTerraform v0.13の開発版が必要です。今はビルド済みのバイナリが提供されていないため、GitHubからソースをクローンしてビルドする必要があります。 Goの開発環境を用意して以下でビルドします。

$ git clone https://github.com/hashicorp/terraform.git ; cd terraform
$ make dev

これで$GOPATH/bin/terraformが作成されます。

tfファイルの準備

以下のようなブロックをtfファイルに記述する必要があります。

terraform {
  required_providers {
    sakuracloud = {
      source = "sacloud/sakuracloud"
      version = "~> 2"
    }
  }
}

terraform initの実行

あとはterraform initを実行するだけです。

f:id:febc_yamamoto:20200515101128p:plain

インストールされましたね! インストールされたプラグインはカレントディレクトリ配下の.terraform/plugins配下のディレクトリ内に格納されます。

f:id:febc_yamamoto:20200515101353p:plain

これは便利ですね! 3rd プロバイダーは更新が面倒なために一度インストールしたらなかなか更新してもらえないという問題があったのですが、 これで更新も行えるようになるため非常に楽になると思います。 (もちろんバージョンをピンすることもできます)

ということで正式リリースがとても楽しみです!!

プロバイダー開発者向け: Terraform Registryでの配布までの作業

ここからはプロバイダー開発者向けにTerraform Registryでプロバイダーを配布するまでに必要な作業をまとめておきます。

全体的には以下のような作業が必要となります。

  • HashiCorp社にベータテストへの参加を申し込む(こちらの記事を参照)
  • 受付メールがきたら以下をHashiCorp社の担当者さんに伝える
    • ベータテストに参加する人のGitHubのユーザー名(Terraform Registryへのログインに使うアカウント)
    • 署名用GPG公開鍵
  • (HashiCorpさん側でTerraform Registryでのベータテストを有効にしてもらう)
  • プロバイダーのビルド/署名(GoReleaserのテンプレートが提供される)
  • (初回のみ) Terraform Registry上からプロバイダーの登録

Note: これ以外にもプロバイダーのリポジトリ内にドキュメントを指定のフォーマットで準備しておく必要があります。
プロバイダーのテンプレートなどを参考に準備しておきましょう。

これらはベータテスト参加時に提供されるドキュメント(多分一般公開されてるやつ)に書いてありますのでそちらに従って作業していけば大丈夫です。

Terraform Registry上での公開は以下のような感じです。

まず、ベータテストに参加すると右上のPublishメニュー内にProviderというメニューが生えます。

f:id:febc_yamamoto:20200515102956p:plain

これを選ぶと次にGitHub上のオーガニゼーションを選択する画面が出てきます。
プロバイダーのリポジトリがあるオーガニゼーションを選択しましょう。

f:id:febc_yamamoto:20200515103035p:plain

オーガニゼーションを選択すると、公開するプロバイダーのリポジトリを選択する画面になります。

f:id:febc_yamamoto:20200515103140p:plain

あとはPublishボタンを押すだけです。 規約に同意したらチェックを入れてPublishボタンを押せば公開されます。

f:id:febc_yamamoto:20200515103220p:plain

ドキュメントもterraform.ioのように綺麗に表示されてますね。

f:id:febc_yamamoto:20200515103347p:plain

なお、古くからプロバイダーを書いている場合、ドキュメントの手直しが少々必要かもしれません。 具体的には各リソースのドキュメント(.md)の先頭にサブカテゴリー(サイドバー)の定義を書いていく必要があります。 この辺はTerraformのドキュメントを参照の上適切に直しておきましょう。


ということでTerraform v0.13の機能を先取りで試してみました。

従来の3rdプロバイダーは更新が面倒なために、古いバージョンを使っていること起因の問題がよく発生していました。 これを解消できますのでかなり期待しています。

v0.13のリリースが待ち遠しいですね!

以上です。

TerraformerでGmailフィルタプロバイダーのコードをリバース生成する

はじめに: TerraformerへGmailフィルタプロバイダー対応がマージされた

既存の環境からTerraformのコード(tfファイル)+Stateファイル(terraform.tfstate)を生成してくれるTerraformerというツールがあります。

github.com

本日、このTerraformerにGmailフィルタプロバイダー対応を追加するPRがマージされました。

github.com

これにより、既にブラウザからある程度フィルタを作成済みのアカウントでもterraform-provider-gmailfilterを利用しやすくなりました。

背景

terraform-provider-gmailfilterについては以前以下の記事を書きました。

febc-yamamoto.hatenablog.jp

このプロバイダーはgmailfiltersというツールにインスパイアされて作成したものです。
ただ、gmailfiltersには既存のフィルタをエクスポートする機能がありますがこのプロバイダーでは実装していませんでした。

このため、既にGmail上でラベルやフィルタを作成済みのアカウントではGmailフィルタプロバイダーを導入するのが若干面倒でした。 (インポート機能は実装済みなため、tfファイルを書いて個別にインポートしていけば対応できてましたが面倒ですよね)

エクスポートについては、既に既存の環境からTerraformのコード(tfファイル)+Stateファイル(terraform.tfstate)を生成してくれるツールがいくつか存在するため、 プロバイダー側で提供するのではなくそれらを利用した方が良いと考えていたからです。

このために、それらのツールの中でも個人的に1番のお気に入りであるTerraformerGmailフィルタプロバイダー対応を行い、本日無事にマージされました。

使い方

Terraformerのビルド

今はまだマージされたばかりでこの変更を含めたリリースが行われていない状態ですので、利用するにはソースからビルドする必要があります。
README.mdを参考に手元でビルドします。

今回はDocker上でビルドしてみました。

# ソース一式をクローン
$ git clone https://github.com/GoogleCloudPlatform/terraformer.git; cd terraformer

# ビルド用コンテナ起動
$ docker run -it --rm -v $PWD:$PWD -w $PWD golang:1.14

# 依存モジュールのダウンロード
$ go mod download

# ビルド(ここではmacos向けにビルドしてます)
$ GOOS=darwin GOARCH="amd64" go build -v

これでカレントディレクトリにterraformer実行ファイルが生成されます。

Gmailフィルタプロバイダーのインストール

次にGmailフィルタプロバイダーをインストールしておきます。 こちらのリリースページから実行ファイルをダウンロードし、~/.terraform.d/plugins/darwin_amd64/配下(macosの場合)に配置しておきます。

Gmail APIの認証(Gmailフィルタプロバイダーを利用したことがない方)

次にGmail APIを有効にし、APIを利用するための認証設定を行なっておきます。 今回はApplication Default Credentialsを利用します。

まずは以下に従いAPIコンソールからGmail APIを有効化します。

support.google.com

次にクレデンシャルの作成、OAuthクライアントの作成、シークレットファイルのダウンロードを行います。 ダウンロードしたファイルはclient_secret.jsonという名前で保存しておきます。

保存したら以下のコマンドを実行します。

gcloud auth application-default login \
  --client-id-file=client_secret.json \
  --scopes \
https://www.googleapis.com/auth/gmail.labels,\
https://www.googleapis.com/auth/gmail.settings.basic

実行するとブラウザでアクセスを許可しても良いか尋ねる画面が開きますので画面に従い許可していきます。

これで準備完了です。

Terraformerの実行

あとはTerraformerを実行するだけです。
以下のコマンドで既存のラベルとフィルタからtfファイル+terraform.tfstateファイルを生成できます。

$ ./terraformer import gmailfilter -r label,filter

デフォルトだとカレントディレクトリ配下のgenerated/gmailfilter/{filter,label}ディレクトリに以下のようなファイルが生成されます。

例: generated/gmailfilter/filter/filter.tf

resource "gmailfilter_filter" "tfer--ANe1BmgZqKtSU0e8o24MkdHlWUd6JsoQ9PRIug" {
  action {
    add_label_ids    = ["${data.terraform_remote_state.label.outputs.gmailfilter_label_tfer--Google_id}"]
    remove_label_ids = ["INBOX"]
  }

  criteria {
    exclude_chats  = "false"
    has_attachment = "false"
    query          = "from:mail-noreply@google.com"
    size           = "0"
  }
}

resource "gmailfilter_filter" "tfer--ANe1BmiABTbNsxNxhKfdIlJN-002D-2BJRicNJdqRYQ" {
  action {
    add_label_ids    = ["${data.terraform_remote_state.label.outputs.gmailfilter_label_tfer--parent_child_id}"]
    remove_label_ids = ["INBOX"]
  }

  criteria {
    exclude_chats  = "false"
    from           = "foobar@example.com"
    has_attachment = "false"
    size           = "0"
  }
}

# ...

例: generated/gmailfilter/label/label.tf

resource "gmailfilter_label" "tfer--Google" {
  label_list_visibility   = "labelShow"
  message_list_visibility = "show"
  name                    = "Google"
}

resource "gmailfilter_label" "tfer--parent" {
  label_list_visibility   = "labelShow"
  message_list_visibility = "show"
  name                    = "parent"
}

resource "gmailfilter_label" "tfer--parent_child" {
  label_list_visibility   = "labelShow"
  message_list_visibility = "show"
  name                    = "parent/child"
}

リソース名が若干長いのが気になりますが、1からtfファイルを書くよりこれを編集していく方が楽だと思います。

注意点

生成されるコードではサブラベルでの親ラベルへの依存の設定がうまくいかないです。 サブラベルを利用している場合は適宜tfファイルを書き換える(label.tfのnameなど)必要がありますのでご注意ください。

# 変更前
resource "gmailfilter_label" "tfer--parent_child" {
  label_list_visibility   = "labelShow"
  message_list_visibility = "show"
  name                    = "parent/child"
}

# 変更後
resource "gmailfilter_label" "tfer--parent_child" {
  label_list_visibility   = "labelShow"
  message_list_visibility = "show"
  name                    = "${gmailfilter_label.tfer--parent.name}/child"
}

終わりに

ということでTerraformerを併用することでGmailプロバイダーのコードを書くのが少し楽になりそうです。
是非お試しください。

以上です。

Gmailのフィルタを管理するためのTerraformプロバイダーを作った

少し前にこちらの記事でgmailfiltersというツールを知りました。

kakakakakku.hatenablog.com

github.com

gmailfiltersはとても良さそうなのですが、なんでもTerraformおじさん的にはTOMLよりHCLで設定を書きたいなと思ったので この土日でTerraformプロバイダーを実装してみました。

github.com

Gmailのフィルタ/ラベルを設定するTerraformプロバイダー terraform-provider-gmailfilter

Gmail APIでフィルタやラベルの登録/更新/削除が行えます。

例えばfoobar@example.comから来たメールをexampleラベルに振り分けるには以下のようなHCLコードとなります。

# ラベル"INBOX"を参照するためのデータソース
data gmailfilter_label "INBOX" {
  name = "INBOX"
}

# ラベル"example"を作成
resource gmailfilter_label "example" {
  name = "example"
}

# フィルタの登録
resource gmailfilter_filter "example" {
  criteria {
    from = "foobar@example.com"
  }
  action {
    add_label_ids    = [gmailfilter_label.example.id]
    remove_label_ids = [data.gmailfilter_label.INBOX.id]
  }
}

フィルタには以下のような項目が指定可能です。

resource gmailfilter_filter "example" {
  criteria {
    from            = "foobar@example.com"
    exclude_chats   = false
    has_attachment  = false
    negated_query   = "from:someuser@example.com rfc822msgid: is:unread"
    query           = "from:someuser@example.com rfc822msgid: is:unread"
    size            = 1000
    size_comparison = "larger"
    subject         = "example"
    to              = "example@"
  }
  action {
    add_label_ids    = [gmailfilter_label.example.id]
    remove_label_ids = ["INBOX"]
    forward          = "destination@example.com"
  }
}

利用例: 入れ子になったラベル(サブラベル)の管理

サブラベルも作成できます。

resource gmailfilter_label "top" {
  name = "top-level"
}

resource gmailfilter_label "child1" {
  name = "${gmailfilter_label.top.name}/child1"
}

resource gmailfilter_label "child2" {
  name = "${gmailfilter_label.child1.name}/child2"
}

これをterraform applyすると以下のようになります。

f:id:febc_yamamoto:20200426173455p:plain

利用例: 添付メールに Attachment ラベルを付ける

元記事にで紹介されてた例です。 こちらは以下のようなコードになります。

# Attachmentラベルの作成
resource gmailfilter_label "attachment" {
  name = "Attachment"
}

# フィルターの作成
resource gmailfilter_filter "attachment" {
  criteria {
    has_attachment  = true
  }
  action {
    add_label_ids    = [gmailfilter_label.attachment.id]
  }
}

利用例: Amazon 購買メールに Amazon ラベルを付ける

こちらも元記事で紹介されていた例です。
元記事ではqueryOrを用いてますが、このプロバイダーではqueryOrに相当するものは提供していません。
代わりにHCL上で利用できる、Terraformに組み込みのFunctionsを利用してクエリを組み立てていきます。

# 対象のメールアドレスのリスト
locals {
  addresses = [
    "from:shipment-tracking@amazon.co.jp",
    "from:auto-confirm@amazon.co.jp",
    "from:order-update@amazon.co.jp",
  ]
}

# Amazonラベルの作成
resource gmailfilter_label "amazon" {
  name = "Amazon"
}

# フィルターの作成
resource gmailfilter_filter "amazon" {
  criteria {
    query = join(" OR ", local.addresses) # joinでqueryを組み立てる
  }
  action {
    add_label_ids    = [gmailfilter_label.amazon.id]
    remove_label_ids = ["INBOX"]
  }
}

おまけ: 実装について

gmailfiltersではqueryToなどの便利機能を提供していますが、このプロバイダーではその辺を提供せず、GmailAPIをそのままTerraformでラップしたような形としました。
入力/編集できる項目や値はAPIドキュメントを見ればわかるようになっています。

Terraformを使う層であれば自分でAPIドキュメントを読むくらいするだろうという想定です。
なので出来ることの詳細はGmailAPIをみていただくのが一番早いと思います。

注意事項

このプロバイダーでは転送先アドレスの管理は実装していません。 もしフィルタで転送を行いたい場合はあらかじめWebブラウザなどから転送先アドレスを登録しておく必要があります。 参考: Gmail のメールを他のアカウントに自動転送する

また、フィルタを作成しても既存のメールには適用されないようでした。
APIで出来るのかもしれないのですがまだちゃんと調べてないです。

もし適用方法をご存知の方がいらっしゃいましたら教えてもらえると嬉しいです。 (PRもらえるともっと嬉しいです)

終わりに

G Suiteにも対応しておりなかなか便利だと思います。
Terraform好きな方はぜひお試しくださいー。

以上です。

HashiCorp Certified: Terraform Associateを受験した

本日(2020/4/22)HashiCorpの認定試験であるHashiCorp Cloud Engineer Certification Programが一般公開され、Terraform/Vaultのアソシエイトレベルの試験が開始されました。

去年のHashiConfでベータ版としてアナウンスされてたやつですね。

受験費用は$70.5(税別)となんとか手が出る価格だったので早速受験してみました。

結果

無事合格しました。満点取れるかなと思ったのですがいくつか取りこぼしちゃいましたね。。。

f:id:febc_yamamoto:20200423000343p:plain

ひとまず安心しました。

www.youracclaim.com

今後受験する人向けに書ける範囲でメモを残しておきます。

試験の概要/試験範囲

www.hashicorp.com

受験までの流れ

  • 上記サイトから申し込み
  • 申込サイト(ondemand.questionmark.com)にてアカウント作成
  • 同サイトにてシステム要件のチェック(Webカメラ、スピーカー、マイクなど。専用のチェックページがログイン後の画面にある)
  • Buy ExamというタブがあるのでそこからHashiCorp Certified: Terraform Associateを購入
  • 同サイトから受験する日時をスケジューリングする(多分PDTなのでJSTの日中は選べない)
  • (重要) 案内メールが来る
    このメールに受験のルールなどの詳細が記載されているので必ず目を通す
  • 時間になったら同サイトから試験開始

事前に用意しておくもの

国が発行した写真付きの身分証明書(パスポートなど)

勉強した内容

とりあえず試験範囲をざっと眺めて、Terraformのドキュメントを通読しました。

www.terraform.io

このドキュメントにはTerraform v0.12以前/以降両方のドキュメントが含まれるのですが、今回の試験はTerraform v0.12以降が対象ですのでv0.12以前のバージョンについて書かれたドキュメントについては無視して構いません。

また、試験用の教材として以下の2つが用意されていますのでこれらを読むのも良いかもしれません。

learn.hashicorp.com

learn.hashicorp.com

合格後の特典

Credly’s Acclaim platformの提供するデジタルバッジがもらえるとのことでした。

↓↓こんなやつです。

f:id:febc_yamamoto:20200423002531p:plain

出典: https://www.youracclaim.com/org/hashicorp/badge/hashicorp-certified-terraform-associate

合格後10日以内に案内のメールが来るらしいです。

4/29 追記: その後無事に届きました。

www.youracclaim.com

感想

内容よりも英語が大変でした。
記憶力だけを問う意地の悪い問題はなかったので、丁寧に試験範囲のドキュメントを読んでおけば十分じゃないかなと感じました。

終わりに

次はVaultを受けてみます。。。お小遣いが貯まったら。

以上です。

Zabbix+さくらのクラウドAPIでクラウド上のリソースを監視する

はじめに

先日teratailに以下のような質問が投稿されていました。

teratail.com

回答を書きながらいくつか資料を探してみたのですが、さくらのクラウド+Zabbix 4系の記事があまり見当たりませんでしたので自分で試した時のメモを残しておくことにしました。

この記事で扱う内容

この記事ではさくらのクラウド上のリソースをZabbix+さくらのクラウドAPIを利用して監視する方法について取り扱います。
具体的には以下のような内容となっています。

Zabbixのインストールや、そもそもの監視設計(監視対象の選択や通知の設計など)については扱いませんので他サイトなどを参照してください。

それでは早速本題に入っていきます。

ZabbixでさくらのクラウドAPIを通じてクラウド上のリソースを監視する

ZabbixからさくらのクラウドAPIを通じてクラウド上のリソースを監視するにはいくつかの方法があります。

  • 1: 外部チェック/ユーザーパラメータ
  • 2: HTTP agent(Zabbix 4.0以降)
  • 3: PrometheusのExporter + Prometheusチェック(Zabbix 4.2以降)

順番にみていきます。

1. 外部チェック/ユーザーパラメータ

Zabbixサーバ上、またはエージェント上でスクリプト/バイナリを実行じその結果を受け取る方法です。
少々古いバージョンのZabbix(2.2とか)でも利用できます。

参考:

標準出力に何か出力しておけばそれをZabbixから参照できるということですね。

さくらのクラウドAPIを叩く場合はcurlコマンド、またはCLIであるUsacloudを利用し、 出力をjqコマンドなどで加工してあげると良いと思います。

単純な値をcurlで取得する

# curlでサーバのメモリサイズを取得
$ export TOKEN="さくらのクラウドAPIトークン"
$ export SECRET="さくらのクラウドAPIシークレット"
$ export ZONE=is1a
$ export SERVER_ID=123456789012 # サーバのID
$ curl --user "$TOKEN":"$SECRET" https://secure.sakura.ad.jp/cloud/zone/$ZONE/api/cloud/1.1/server/$SERVER_ID | jq ".Server.ServerPlan.MemoryMB"
4096

2020/01/23 コード誤りを修正

アクティビティグラフの値をcurlで取得する

スペックなどを取得する場合はjqコマンドが単純で済むのですが、アクティビティグラフAPIを使用してCPU利用時間やディスクの読み書き量を取得するとなるとちょっと難易度が上がります。

具体的には、アクティビティグラフAPIは以下のようなJSONを返します。

# サーバのCPU-TIMEを取得
$ curl -s --user "$TOKEN":"$SECRET" https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/server/$SERVER_ID/monitor | jq .
{
    "Data": {
        "2020-01-17T16:45:00+09:00": {
            "CPU-TIME": 0.043333333333
        },
        "2020-01-17T16:50:00+09:00": {
            "CPU-TIME": 0.046666666667
        },
        "2020-01-17T16:55:00+09:00": {
            "CPU-TIME": null
        },
        "2020-01-17T17:00:00+09:00": {
            "CPU-TIME": null
        },
        "2020-01-17T17:05:00+09:00": {
            "CPU-TIME": null
        },
        "2020-01-17T17:10:00+09:00": {
            "CPU-TIME": null
        },
        "2020-01-17T17:15:00+09:00": {
            "CPU-TIME": null
        },
        "2020-01-17T17:20:00+09:00": {
            "CPU-TIME": null
        }
    },
    "is_ok": true
}

日付がキーとなっていること、値にnullが入っていることでjqコマンドの書き方が難しいですね。
これを処理する場合、

  • Data配下の要素からCPU-TIMEの値を抜き出し
  • nullを除去
  • 配列の最後の値を取得(昇順になっているため、最新の値は末尾にある)

という感じになります。面倒ですね…
ひとまず手元で確認したところ、jq '[.Data[]["CPU-TIME"]] | del(.[] | nulls) | .[-1]'でいけました。

# curlでアクティビティグラフAPIを叩き値を抽出
$ curl --user "$TOKEN":"$SECRET" https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/server/$SERVER_ID/monitor | jq '[.Data[]["CPU-TIME"]] | del(.[] | nulls) | .[-1]'
0.046666666667

これで外部チェック/ユーザーパラメータからアクティビティグラフAPIの値を活用できそうですね。

アクティビティグラフの値をusacloudで取得する

usacloudコマンドを利用すればさらに楽に値を抽出できます。 というのも、usacloudコマンドは以下のようにAPIから返されるJSONを変換し、単純な配列にしてから出力するからです。null値のフィルタリングもしてくれてます。
こちらの形の方がjqなどで加工しやすいですよね。

$ usacloud server monitor-cpu -o json $SERVER_ID
[
  {
    "CPUTime": "0.043333333333",
    "Key": "sakuracloud.server.123456789012.cpu",
    "TimeStamp": "2020-01-17 16:45:00 +0900 JST"
  },
  {
    "CPUTime": "0.046666666667",
    "Key": "sakuracloud.server.123456789012.cpu",
    "TimeStamp": "2020-01-17 16:50:00 +0900 JST"
  }
]

これを利用すると、先ほどのcurlコマンドの例は以下のように書き直せます。

# usacloudでアクティビティグラフAPIを叩き値を抽出
$ usacloud server monitor-cpu -o json $SERVER_ID | jq '.[-1].CPUTime|tonumber'
0.046666666667

2. HTTP agent(Zabbix 4.0以降)

Zabbix 4.0以降で利用できるHTTP agentを利用する方法です。

参考:

とりあえずAPIを叩くだけであれば簡単にできます。

まずアイテム作成画面でタイプがHTTPエージェントなアイテムを作成します。 この時、URLにはさくらのクラウドAPIのURLを入力し、http認証をBasicにしてユーザー名/パスワード欄にそれぞれAPIトークン/シークレットを入力します。

f:id:febc_yamamoto:20200123224743p:plain

f:id:febc_yamamoto:20200123224956p:plain

次にこのアイテムをマスターにした依存アイテムを作成します。

f:id:febc_yamamoto:20200123225035p:plain

ポイントは「保存前処理」を追加する部分ですね。 単純なJSONならJSONPathが使えるのですが、前述のアクティビティグラフAPIのレスポンスのような複雑なものを扱う場合はJavaScriptを使うのが良いと思います。

ここでは取得したJSONからCPU-TIMEの値を抜き出し、nullでない末尾の値を抽出するスクリプトを記載しておきます。

f:id:febc_yamamoto:20200123225306p:plain

// コピペ用
const data = JSON.parse(value).Data;
return Object.keys(data).map(function(v){return data[v]["CPU-TIME"]}).filter(function(v){ return v}).pop()

少々回りくどい書き方になっているのはZabbix 4.4の時点でもES6/ES7は部分的なサポートのみだからです。
なのでObject.values()アロー関数が使えないんですよね。。。

これはZabbixが採用しているJavaScriptのエンジンDuktape由来です https://duktape.org/

ともあれこれでHTTP agentを利用してアクティビティグラフAPIを叩くことができました。 テンプレート化して汎用化する必要はありますが、単体のリソースを監視する程度であればこの方法だけでも十分使えると思います。

PrometheusのExporter + Prometheusチェック(Zabbix 4.2以降)

Zabbix 4.2以降というのをクリアできれば正直この方法が一番楽だと思います。

さくらのクラウド向けのPrometheus Exporterであるsakuracloud_exporterと組み合わせる方法です。

github.com

設定自体も簡単で、以下の記事などを参考にすれば設定で迷うことはないと思います。

blog.zabbix.com

tech-lab.sios.jp

Exporterを別途起動しておく必要がある点には注意してください。


ということでZabbix+さくらのクラウドAPIを利用するための3つの方法について紹介しました。

終わりに

今回はZabbix+さくらのクラウドAPIクラウド上のリソースを監視する方法を紹介しました。
これだけで全ての監視を賄えるわけではないですが、多様な角度から監視する上での選択肢の1つにはなると思います。

以上です。

作業メモ: TeamCity on さくらのクラウド+エンハンスドロードバランサ

JetBrainsのTeamCityをさくらのクラウド上に構築した時のメモです。

www.jetbrains.com

概要

構成

f:id:febc_yamamoto:20191218174908p:plain:w500

  • サーバ1台(パケットフィルタ込み)
  • エンハンスドロードバランサ(100cps プラン)
    • SSL終端
    • Let's Encryptでの証明書取得/更新
  • TeamCityはDockerで起動

サーバ上で直接証明書取得 & SSL終端してもよかったのですが、環境構築がめんどくさかったのでエンハンスドロードバランサを利用します。
また、サーバへのアクセスはエンハンスドロードバランサに限定するためにパケットフィルタも合わせて利用します。

構築手順

  • サーバ作成/Dockerインストール
  • エンハンスドロードバランサ作成
  • エンハンスドロードバランサで発行されたVIP or FQDNDNS登録(A or CNAMEレコード)
  • エンハンスドロードバランサの設定(待ち受けポート/実サーバ/Let's Encryptなど)
  • パケットフィルタ作成 & サーバにアタッチ
  • TeamCityをDocker上で起動
  • TeamCityのエージェントをDocker上で起動

各手順の詳細

サーバ作成/Dockerインストール

まずはサーバを作成します。今回は2CPU/4GBメモリ/共有セグメントに接続、というスペックで作成しました。
サーバ作成後はDockerがインストールされていない場合はインストールしておきます。

エンハンスドロードバランサ作成

次にエンハンスドロードバランサを作成します。
VIPフェイルオーバを有効にする/しないでこの後作成するDNSレコードの種別が変わりますのでご注意ください。

f:id:febc_yamamoto:20191218180325p:plain:w800

エンハンスドロードバランサで発行されたVIP or FQDNDNS登録(A or CNAMEレコード)

エンハンスドロードバランサを作成したらFQDN or VIPが払い出されます。この値をDNS登録しておきます。
前述の通りVIPフェイルオーバの有効/無効に応じて登録するDNSレコード種別が変わります。

VIPフェイルオーバを有効にした場合

FQDNが発行されますのでCNAMEレコードを登録します。

f:id:febc_yamamoto:20191218181219p:plain

VIPフェイルオーバを無効にした場合:

VIP(Virtual IP Address)が発行されますのでAレコードを登録します。

f:id:febc_yamamoto:20191218194905p:plain

エンハンスドロードバランサの設定

次にエンハンスドロードバランサの設定を行います。

待ち受けポート

以下のように2つ登録します。

f:id:febc_yamamoto:20191218181817p:plain:w800

(1) HTTP
  • プロキシ方式: http
  • 待受ポート番号: 80
  • httpsへのリダイレクト: 有効
(2) HTTPS
  • プロキシ方式: https
  • 待受ポート番号: 443
  • HTTP/2のサポート: 無効

実サーバ

IPアドレスに先ほど作成したサーバのIPを入力して登録します。
ポート番号は8111、サーバグループは空のままとします。

f:id:febc_yamamoto:20191218182449p:plain:w800

Let's Encryptの設定

次に右上のSSH証明書の設定 -> Let's Encryptの設定に進み、Let's Encryptでの証明書自動取得/更新を有効化します。

f:id:febc_yamamoto:20191218182754p:plain:w800

先ほどCNAMEレコードまたはAレコードを登録したFQDNを指定してください。 (エンハンスドロードバランサから払い出されたFQDNではありません)

パケットフィルタ作成 & サーバにアタッチ

次にサーバへのアクセスをエンハンスドロードバランサからだけに絞るためにパケットフィルタを作成してサーバにアタッチします。

まず、エンハンスドロードバランサが実サーバにアクセスする際のアクセス元IPレンジをメモしておきます。
エンハンスドロードバランサの詳細画面のプロキシ元ネットワークという項目です。

f:id:febc_yamamoto:20191218183630p:plain:w800

次にパケットフィルタを作成し、エンハンスドロードバランサからのアクセスだけ許可、以外は拒否するルールを設定します。
(この例では管理用にtcp/10022ポートの許可を追加してます)

f:id:febc_yamamoto:20191218183827p:plain:w800

作成したらサーバの詳細画面からNICに対してパケットフィルタを接続(アタッチ)しておきましょう。サーバを起動したままでアタッチ可能です。

TeamCityをDocker上で起動

ようやくTeamCityのインストールです。 以下のマニュアルからDockerでのインストール周りへと辿ります。

pleiades.io

余談ですが、日本語版マニュアルがjetbrains.comじゃなくてpleiades.ioなのが気になって調べたら↓↓が出てきました。
https://blog.jetbrains.com/jp/2018/10/18/1355
Pleiadesは昔大変お世話になりました。

今回は以下のように起動しました。

# bridgeネットワークを作成しておく
$ docker network create teamcity

# TeamCityサーバ起動
$ docker run -d --name teamcity-server-instance \
    -v teamcity-data:/data/teamcity_server/datadir \
    -v teamcity-log:/opt/teamcity/logs \
    -p 8111:8111  \
    --network teamcity \
    jetbrains/teamcity-server

面倒だったのでDocker ComposeやKubernetesを使わずにDockerコマンドを直接使ってます。

TeamCityのエージェントをDocker上で起動

次にTeamCityのエージェントをDocker上で起動します。 (リスクのある方法ですので以下のドキュメントをちゃんと読んでおきましょう)

https://hub.docker.com/r/jetbrains/teamcity-agent/

今回は以下のように起動しました。

$ docker run -d --name teamcity-agent-01 \
    -e SERVER_URL="http://teamcity-server-instance:8111" \
    -e AGENT_NAME="agent-01" \
    -v teamcity-agent-data:/data/teamcity_agent/conf \
    --network teamcity \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /opt/buildagent/work:/opt/buildagent/work \
    -v /opt/buildagent/temp:/opt/buildagent/temp \
    -v /opt/buildagent/tools:/opt/buildagent/tools \
    -v /opt/buildagent/plugins:/opt/buildagent/plugins \
    -v /opt/buildagent/system:/opt/buildagent/system \
    jetbrains/teamcity-agent

アクセスしてみる

ブラウザでAレコード or CNAMEレコードを登録したFQDNにアクセスするとTeamCityの画面が開くはずです。

f:id:febc_yamamoto:20191218191231p:plain:w800

あとは画面の指示/マニュアルを参考に進めていけばOKなはずです。

終わりに

今回はバックアップなど運用面をあまり気にしてませんので実運用の際はオプションの精査などをしっかり行ってください。

以上です。