sakuracloud_exporter v0.7.0 − コレクターごとの無効化/fakeモードの追加 など
Prometheusのさくらのクラウド向けExporterであるsakuracloud_exporterのv0.7.0をリリースしました。
v0.7.0での主な変更/修正点は以下の通りです。
- コレクターごとの有効/無効切り替え機能
- Go言語向けさくらのクラウドAPIライブラリ libsacloud v2対応
- さくらのクラウドAPI呼び出しの代わりにローカルファイルから値を取得する「fakeモード」
- その他細かなバグ/パフォーマンス問題の修正
今回の修正はちょっと特殊な状況向けではありますが、ハマれば非常に便利なものだと思います。 順に紹介します。
コレクターごとの有効/無効切り替え
sakuracloud_exporterではさくらのクラウドAPIでリソース一覧を取得〜必要に応じて各リソースごとに詳細取得のためにさらにAPI呼び出し、という処理を行なっています。 このため、さくらのクラウド上に大量のリソースを持つようなケースでは一連のAPI呼び出しに長い時間がかかってしまうことがあります。
そこでこの問題への対応の一環としてコレクターごとに有効/無効を指定できるようになりました。
以下のフラグを用いて各コレクターごとに設定が可能となっています。
--no-collector.auto-backup
: 自動バックアップ--no-collector.coupon
: クーポン--no-collector.database
: データベース--no-collector.internet
: スイッチ+ルータ--no-collector.load-balancer
: ロードバランサ--no-collector.mobile-gateway
: モバイルゲートウェイ--no-collector.nfs
: NFS--no-collector.proxy-lb
: エンハンスドロードバランサ--no-collector.server
: サーバ--no-collector.sim
: SIM--no-collector.vpc-router
: VPCルータ--no-collector.zone
: ゾーン情報
デフォルトでは全コレクターが有効となっています。
特定のコレクターだけ無効にするようなケースや、特定のコレクターだけ有効にして複数のexporterを起動するようなケースなどにご利用いただけると思います。
さくらのクラウドAPI呼び出しの代わりにローカルファイルから値を取得する「fakeモード」
このバージョンからGo言語向けさくらのクラウドAPIライブラリ libsacloud v2.0が利用されるようになりました。
libsacloud v2.0では主にテスト用の機能として、さくらのクラウドAPI呼び出しをラップしてダミーの応答を返す「fakeドライバー」という仕組みが導入されました。fakeドライバーはステートフルな処理(リソースの登録〜登録したリソースを後から参照、など)を行うためにステートを保持しています。ステートは保存先をインメモリ or ファイルから選べるようになっています。
このfakeドライバーを利用することでsakuracloud_exporterでサーバがダウンした状況やメンテナンスがスケジュールされた状況などを意図的に作り出すことを容易にするのが今回導入された「fakeモード」です。
fakeモードはibsacloudのfakeドライバーを利用してさくらのクラウドAPI呼び出しの代わりにステートファイルから値を取得してメトリクスを算出するモードです。
fakeモードの有効化
fakeモードの有効化は
- 起動時のオプション
--fake-mode
の指定 - 環境変数
FAKE_MODE
の指定
の何れかで可能です。
値はステートファイルのパスを指定します。
例えばカレントディレクトリのfake-store.json
というファイルを利用する場合は以下のように指定します。
$ sakuracloud_exporter --fake-mode fake-store.json
ファイルが存在しない場合は新規作成されます。 (とはいえその状態だと何もリソースが存在しないためあまり意味はないでしょうが)
fakeモードではこのファイルからサーバやディスクといったリソースの情報を読み取ってメトリクスを出力します。
ステートファイルはJSONとなっており、以下のようなものです。
[ { "Availability": "available", "CPU": 1, "CreatedAt": "2019-08-05T11:35:39.075614+09:00", "Description": "desc", "ID": "100000000022", "InstanceHostInfoURL": "", "InstanceHostName": "sac-is1a-svXXX", "InstanceStatus": "up", "InterfaceDriver": "virtio", "Interfaces": [ { "HostName": "", "ID": 100000000028, "IPAddress": "", "MACAddress": "00:00:5e:00:53:01", "PacketFilterID": "", "PacketFilterName": "", "PacketFilterRequiredHostVersion": 0, "SubnetBandWidthMbps": 0, "SubnetDefaultRoute": "", "SubnetNetworkAddress": "", "SubnetNetworkMaskLen": 0, "SwitchID": 100000000008, "SwitchName": "", "SwitchScope": "", "UpstreamType": "", "UserIPAddress": "", "UserSubnetDefaultRoute": "", "UserSubnetNetworkMaskLen": 0 } ], "MemoryMB": 1024, "Name": "example", "ResourceType": "Server", "ServerPlanCommitment": "standard", "ServerPlanGeneration": 100, "ServerPlanID": 100001001, "ServerPlanName": "世代:100 メモリ:001 CPU:001", "Tags": [ "example", "server" ], "ZoneName": "is1a" } ]
ステートファイルの例として、sakuracloud_exporterが利用する各種リソースが登録されているものを以下に用意しています。
sakuracloud_exporter/example-fake-store.json at 0.7.0 · sacloud/sakuracloud_exporter · GitHub
ステートファイルはテキストファイルですのでエディタなどで編集することができるようになっています。
fakeモードの利用例: サーバのメンテナンス情報の登録
ここでは通常だと手動で発生させるのが難しい、サーバのメンテナンス情報の登録をfakeモードで行なってみます。
さくらのクラウドでのメンテナンス情報とは?
さくらのクラウドではサーバが稼働しているホストの不調などでサーバの再起動が必要になる場合があります。 (再起動することで別のホストで稼働させる)
メンテナンスは通常事前に通知され、期限までにユーザーが任意のタイミングでサーバの再起動を行うことが可能となっています。 また、メンテナンス情報はウェブサイト上で公開されているほか、APIからも参照できるようになっています。
これを利用してsakuracloud_exporterではメンテナンス情報を取得するためのメトリクスを提供しており、これらを利用して独自に監視/通知の仕組みを整えることができます。 (詳しくは以下で紹介させていますので参照ください)
このメンテナンス情報ですが、当然ながらメンテナンスを任意に発生させるというのは困難です。
たまたまメンテナンス対象のサーバが手元にあればよいですが、そうでない場合がほとんどだと思います。
このためPrometheusでメンテナンス情報を監視/通知する仕組みを用意しても動作確認がすぐには出来ません。 これは困りますよね。
このような場面でfakeモードが役に立ちます。
ということでfakeモードでのexporterの起動〜メンテナンス情報の登録までをやってみます。
fakeモードを有効にしてexporterを起動
まずはfakeモードでexporterを起動してみます。 ステートファイルは先ほど紹介したGitHub上に公開されている例を用います。
# exampleステートファイルをGitHubからダウンロード $ curl -sLO https://raw.githubusercontent.com/sacloud/sakuracloud_exporter/0.7.0/examples/fake/generate-fake-store-json/example-fake-store.json # fake-modeオプションを指定してexporterを起動 $ sakuracloud_exporter --fake-mode example-fake-store.json
Prometheusのコンソールからサーバの情報を参照(sakuracloud_server_info
)すると2台のサーバが存在することが確認できるはずです。
ID: 100000000022
と ID: 100000000035
の2台ですね。
また、メンテナンス情報は sakuracloud_server_maintenance_info
で確認できます。
ID:100000000035
にはすでにメンテナンス情報が登録されていますね。
これはメンテナンス確認用として最初から登録されているやつです。
単にメンテナンス情報としてどのようなメトリクスが参照できるか確認したいだけの場合はこちらを利用すればOKです。
今回はメンテナンス情報の登録されていないID: 100000000022
の情報を操作してメンテナンス情報を登録してみます。
ステートファイルを操作してメンテナンス情報を登録
次にステートファイルexample-fake-store.json
をエディタなどで修正してメンテナンス情報を登録します。
JSON内のID: 100000000022
のサーバの部分を探し出し、InstanceHostInfoURL
というフィールドにhttp://support.sakura.ad.jp/mainte/mainteentry.php?id=26595
という値を設定します。
JSONは以下のようになっているはずです。
// 該当部分だけ抜粋 { "ID": "100000000022", "InstanceHostInfoURL": "http://support.sakura.ad.jp/mainte/mainteentry.php?id=26595",
ファイルを編集して保存するとexporterにより自動で再読み込みが行われます。
その後(Prometheusによるスクレイピングの後に)Prometheusのコンソールで再度メンテナンス情報を確認するとID: 100000000022
のサーバにもメンテナンス情報が登録されたことが確認できます。
これでメンテナンス情報を登録することができました。 逆にメンテナンス情報のクリアもできますのでアラートルールの確認などに便利にお使いいただけると思います。
終わりに
sakuracloud_exporter v0.7.0の紹介でした。 徐々に便利になってきてますのでぜひご利用&フィードバックいただけると嬉しいです。
以上です。
入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング
- 作者: Brian Brazil,須田一輝,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2019/05/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
【小ネタ】Terraformで子リソースに分割されたリソース定義をdynamic blockを使って書き直す例
GitHubで質問もらったやつが例として手頃だったのでブログ書いておきました。
やりたいこと
Terraform v0.11以前までの親リソース/子リソースに分けて定義していたリソースをv0.12で導入されたdynamic blockに書き直す
v0.11以前
ここではrke_cluster
リソースの子リソースとしてdata rke_node_parameter
を定義しています。
# locals to allow us to control which nodes get assigned manager roles vs. controlplane and workers locals { mgr_roles = ["controlplane","etcd"] worker_roles = ["worker"] } # rke_clusterリソースに対する子リソース(node)の定義 data rke_node_parameter "nodes" { count = "${var.NODE_COUNT}" address = "${azurestack_public_ip.vmpip.*.ip_address[count.index]}" user = "myuser" role = "${split(",", count.index < var.nbr_managers ? join(",", local.mgr_roles) : join(",", local.worker_roles))}" ssh_key = "${file("path/to/sshkey")}" } resource rke_cluster "cluster" { depends_on = ["azurestack_public_ip.vmpip", "azurestack_virtual_machine.vm"] # 子リソースの定義 nodes_conf = ["${data.rke_node_parameter.nodes.*.json}"] }
v0.12のdynamic blockを使って書き直し
子リソースdata rke_node_parameter
をrke_cluster
のnodes
にdynamic blockを使って書き直してます。
# locals to allow us to control which nodes get assigned manager roles vs. controlplane and workers locals { mgr_roles = ["controlplane","etcd"] worker_roles = ["worker"] } resource rke_cluster "cluster" { depends_on = ["azurestack_public_ip.vmpip", "azurestack_virtual_machine.vm"] dynamic nodes { for_each = azurestack_public_ip.vmpip.* content { address = nodes.value.ip_address user = "myuser" role = split(",", nodes.key < var.nbr_managers ? join(",", local.mgr_roles) : join(",", local.worker_roles)) ssh_key = file("path/to/sshkey") } } }
ポイント
まずはこちらのドキュメントには目を通しておきましょう。
その上で書き換えのポイントとしては、
for_each
にはvariable以外にもresourceやdataも指定できるfor_each
にリスト要素を指定した場合、content
ブロック内で<element>.key
とすればインデックスを、<element>.value
で値を参照できる
あたりでしょうか。
content
ブロック内でイテレート対象の値を参照する際は<element>.value
とvalueをつける必要がある点に注意です。(よく間違える)
なお、書き直しするにはプロバイダー側で親リソース内に子リソースの定義を書けるようになっていることが必要です。
(例: azurerm_virtual_machine
リソースのstorage_data_disk
みたいにブロックでもリソースでも定義できるようになっていること)
終わりに
この類の書き換えはterraform 0.12upgrade
で自動置き換えできないので手動で書き換える必要があります。
(書き換える必要があるかは別問題として)
dynamic blockを使えばより簡潔に書ける or 処理が早くなる(反映処理時のロックが不要になったり)などの恩恵を受けられる可能性もありますので使いすぎに注意しつつどんどん使いましょう
以上です。
さくらのクラウド: k3OSパブリックアーカイブなら手軽にRioが使える
k3OSがパブリックアーカイブに
さくらのクラウドにk3OSのパブリックアーカイブが追加されましたね!
ISOイメージと違い、パブリックアーカイブであれば「ディスクの修正」という機能でIPアドレスの設定やSSH公開鍵の設定が行えるようになります。
これを使えば非常に手軽にk3sによるKubernetes環境が手に入りますね。
さらにk3sが動くということはRioが動くということです。
Rioが動かせればKnative/Istio/Prometheus/Grafana/Kiali/BuildKit/イメージレジストリなどを内包していますのでこれらも使えるようになります。
(Rioについては以下スライドを参照ください)
ということで早速試してみました。
パブリックアーカイブからk3OSをインストールしてみる
早速k3OSパブリックアーカイブを用いてサーバ作成を行ってみます。
CLIであるUsacloudは本日リリースされたv0.25.0からk3OSに対応しましたのでこちらを利用します。
$ export PASSWORD=your-password $ usacloud server build --os-type k3os --core 2 --memory 4 --password "$PASSWORD" --name k3os -y
もちろんコンパネから作成してもOKです。
SSHで接続
作成したらSSHで接続してみます。rancherユーザーで接続できるはずです。
$ usacloud server ssh --user rancher k3os
接続できたら各種コンポーネントが動いているのが確認できるはずです。
$ kubectl cluster-info $ kubectl get cs
これでKubernetesが使えるようになりましたね。
Rioのダウンロード
次にRioをインストールします。まずrio
コマンドをダウンロードします。
$ sudo curl -L -o /usr/local/bin/rio https://github.com/rancher/rio/releases/download/v0.1.1/rio-linux-amd64 $ sudo chmod +x /usr/local/bin/rio
これでrio
コマンドが使えるようになります。
rio install
の実行
次にRioの各コンポーネントをKubernetes上にデプロイします。
$ rio install
しばらく待つと以下のようなメッセージが表示されデプロイが完了するはずです。
Welcome to Rio! Run `rio run https://github.com/rancher/rio-demo` as an example
Rioを動かしてみる
まずはRioの各コンポーネントがデプロイされているか確認してみます。
確認はrio -s ps
を用います。
(-s
または--system
オプションはRioのシステムコンポーネントを表示するためのオプションです。)
$ rio -s ps
手元の環境では以下のように表示されました。
動いているようですね!GrafanaとKialiについては表示されたURLをブラウザで開けるようになってます。
(Grafana/Kialiともユーザー名とパスワードはadmin
になってます)
あとはrio run
などをお好みで試してみましょう!
片付け
使い終わったら不要な課金を防ぐために以下のコマンドでサーバの削除を忘れずに行っておきましょう。
$ usacloud server rm -f k3os
終わりに
k3OS+パブリックアーカイブで非常に手軽にKubernetes環境を使えるようになりましたね!
k3sが動けばRioのようなKubernetes上で動くプロダクトもちゃんと使えるはずです。
夢が広がりますね!!
ぜひお試しください!
以上です。
UsacloudでエンハンスドロードバランサのLet's Encrypt設定を行う
昨日の記事ではTerraformでエンハンスドロードバランサのLet's Encrypt設定を行えるようになったことを紹介しました。
昨日に続き、本日Usacloud v0.24.0がリリースされ、UsacloudにてエンハンスドロードバランサのLet's Encrypt設定が行えるようになりました。
本日はUsacloud v0.24で行われたエンハンスドロードバランサ関連の機能拡充について紹介します。
Usacloud v0.24.0
v0.24.0では以下のようなエンハンスドロードバランサ関連の機能拡充が行われました。
- 100/500CPS対応
- HTTPSへのリダイレクト対応
- HTTP/2のサポート
- Let's Encrypt対応
100/500CPS対応
enhanced-load-balancer create
またはplan-change
で100/500CPSプランを指定可能となりました。
$ usacloud enhanced-load-balancer create --plan 100 ...
HTTPSへのリダイレクト対応
公開ポートの設定時にリダイレクトの有効化ができるようになりました。
$ usacloud enhanced-load-balancer bind-port-add --mode http --port 80 --redirect-to-https <ID or Name>
--mode
がhttpの時のみ指定可能ですのでご注意ください。
HTTP/2のサポート
公開ポートの設定時にリダイレクトの有効化ができるようになりました。
$ usacloud enhanced-load-balancer bind-port-add --mode https --port 443 --support-http2 <ID or Name>
こちらは--mode
がhttpsの時のみ指定可能ですのでご注意ください。
Let's Encrypt対応
Let's Encrypt設定の有効化/証明書取得が行えるようになりました。
# Let's Encrypt設定の有効化 $ usacloud enhanced-load-balancer acme-setting --accept-tos --common-name www.example.com <ID or Name> # 証明書の取得/更新 $ usacloud enhanced-load-balancer acme-renew <ID or Name> # 証明書の確認 $ usacloud enhanced-load-balancer cert-info <ID or Name>
Let's Encrypt設定を有効化するには--accept-tos
というフラグを指定する必要がある点に注意してください。
これはLet's Encrypt側の利用規約に同意するというフラグで、明示的に指定しないと有効化出来ないようにしています。
また、証明書発行対象のコモンネームが名前解決できるようになっている必要があります。
この辺りの詳細はさくらのクラウドのマニュアルを参照してください。
ということでUsacloudでのエンハンスドロードバランサ関連機能拡充について紹介しました。 Terraformと上手く使い分けてみてくださいね。
以上です。
TerraformでさくらのクラウドのエンハンスドロードバランサのLet's Encrypt設定を行う
Terraform for さくらのクラウド v1.13.0リリース
本日リリースのTerraformさくらのクラウド向けプロバイダー v1.13.0にてエンハンスドロードバランサ関連の機能拡充が行われました。
- 100/500CPSプランのサポート
- HTTPSへのリダイレクト機能
- HTTP/2のサポート
- Let's Encrypt設定
Release v1.13.0 · sacloud/terraform-provider-sakuracloud · GitHub
新プラン/HTTPSへのリダイレクト/HTTP2のサポート
これらについては以下のようなtfファイルで利用可能となっています。
resource "sakuracloud_proxylb" "foobar" { name = "terraform-test-proxylb-acme" # 100CPSプランを利用 plan = 100 vip_failover = true health_check { protocol = "http" delay_loop = 10 host_header = "usacloud.jp" path = "/" } bind_ports { proxy_mode = "http" port = 80 # HTTPSへのリダイレクトを有効化 redirect_to_https = true } bind_ports { proxy_mode = "https" port = 443 # HTTP/2サポートの有効化 support_https = true } servers { ipaddress = "${sakuracloud_server.server01.ipaddress}" port = 80 } }
Let's Encryptの利用
Let's Encryptを利用するには新設されたリソースsakuracloud_proxylb_acme
を利用する必要があります。
# エンハンスドロードバランサでのLet's Encrypt設定 resource sakuracloud_proxylb_acme "foobar" { proxylb_id = sakuracloud_proxylb.foobar.id accept_tos = true # 規約への同意 common_name = "www.example.com" update_delay_sec = 120 }
注意点としてはさくらのクラウドのマニュアルに記載の条件を満たす必要があるという点があります。
2番目の条件である、DNSレコードの設定を含めたtfファイルの例は以下の通りです。
# エンハンスドロードバランサの定義 resource "sakuracloud_proxylb" "foobar" { name = "terraform-test-proxylb-acme" plan = 100 vip_failover = true health_check { protocol = "http" delay_loop = 10 path = "/" } # Let's Encryptを利用するにはhttp/https両方のbind_portsが必要 bind_ports { proxy_mode = "http" port = 80 redirect_to_https = true } bind_ports { proxy_mode = "https" port = 443 support_https = true } servers { ipaddress = "${sakuracloud_server.server01.ipaddress}" port = 80 } } # エンハンスドロードバランサでのLet's Encrypt設定 resource sakuracloud_proxylb_acme "foobar" { proxylb_id = sakuracloud_proxylb.foobar.id accept_tos = true # 規約への同意 common_name = "www.example.com" update_delay_sec = 120 } resource sakuracloud_server "server01" { name = "terraform-test-server01" graceful_shutdown_timeout = 10 } # エンハンスドロードバランサのVIP/FQDNを解決するためのDNSレコード設定 data sakuracloud_dns "zone" { name_selectors = ["example.com"] } resource "sakuracloud_dns_record" "record" { dns_id = data.sakuracloud_dns.zone.id name = "www" type = "CNAME" value = "${sakuracloud_proxylb.foobar.fqdn}." ttl = 10 }
この例ではエンハンスドロードバランサのFQDNを証明書発行対象のFQDNのCNAMEとして登録しています。
注意点として、DNSレコード登録直後は証明書発行対象のFQDNが解決できない場合があります。
このためにsakuracloud_proxylb_acme
にはupdate_delay_sec
という項目を設けています。
これはリソース作成時に指定秒数待つための項目です。手元の環境では120秒くらいに設定すると上手くいっていました。
終わりに
TerraformからLet's Encryptの設定〜設定を行うためのレコードの登録まで一括して行えるのは非常に楽だと思います。
ぜひご活用ください。
以上です。
ConftestでOpenPolicyAgent/Regoを使いTerraformのコードにポリシーを適用してみる
今日はConftestを用いてTerraformでのインフラコードにポリシーを適用してみます。
TerraformでのインフラコードのUnitTest
terraform validate
での構文チェック
Terraformではtfファイルの構文チェックを行ってくれるterraform validate
コマンドが提供されています。
実行するとtfファイルの構文誤りやパラメータ名間違いなどを検出してくれます。
$ terraform validate Error: Unsupported argument ← パラメータ名間違い on test.tf line 6, in data "sakuracloud_server" "server": 6: name_selectorsa = ["sakura-dev"] An argument named "name_selectorsa" is not expected here. Did you mean "name_selectors"?
これを利用すれば最低限tfファイルとして正しく書けているかのテストが行えます。
特にTerraform v0.12からは以下のように変数に型情報を与えることが出来るようになっており、モジュール利用時などにより厳密なチェックが行えるようになりました。
# var.nodesはaddressとuserというフィールドを持つオブジェクトのリストしか指定できない variable "nodes" { type = list(object({ address = string, user = string, })) }
ポリシーの適用
テストの際、terraform validate
での構文チェック以外にも様々な制約を課したい/ポリシーを適用したいことが多々あります。
例えば、
といった場合です。
Terraform EnterpriseであればSentinelを用いてポリシーの適用が行えるのですが、OSS版の場合、現時点ではSentinelを利用できません。
そこで今回はConftestを用いてポリシーの適用を行ってみました。
Conftest
Conftestについてはこちらの記事が詳しいです。
ConftestはYAMLあるいはJSONで定義された設定ファイルに対してテストを書けるというツールです。
面白いのは、テストに使うのがOpen Policy AgentのRegoというポリシー用の言語だという点です。
ConftestでOpenPolicyAgent/Regoを用いてポリシーを定義しておいてCIでConftestを実行すればポリシーの適用/強制ができそうです。
ConftestのリポジトリにはTerraformのコードをテストする例がありますのでそちらを参考にポリシーを書いてみます。
conftestでのterraformインフラコードのテスト
Conftestはコマンドラインツールとなっており、以下のように実行することでYAML/JSONファイルのテストが行えます。
$ conftest test <file>
デフォルトではカレントディレクトリのpolicy
ディレクトリ配下を参照するようになっていますのでこちらにポリシーファイル(.rego)を作成していきます。
(この挙動は-p
または--policy
オプションで変更可能です)
tfファイルをどうやってテストするの?
TerraformでのインフラコードはJSONでも記載できますが、通常はHCL(.tf)で記載していると思います。 conftestはHCLを読んでくれませんのでどうにかしてJSON/YAMLに変換する必要があります。
ConftestのリポジトリにあるTerraformの例ではplanファイルを出力した上でterraform show
にJSON出力オプションを指定して実行することでtfファイルを間接的にテストするという方法を取っています。
例えば、以下のようなtfファイルがある場合、
resource sakuracloud_server "server" { name = "example" core = 1 memory = 1 }
これを元にplanファイル生成〜terraform show
をJSON出力すると以下のようになります。
# planファイルを出力 $ terraform plan --out plan.tfplan # terraform showをJSONで出力 $ terraform show -json plan.tfplan | jq . { "format_version": "0.1", "terraform_version": "0.12.1", "planned_values": { "root_module": { "resources": [ { "address": "sakuracloud_server.server", "mode": "managed", "type": "sakuracloud_server", "name": "server", "provider_name": "sakuracloud", "schema_version": 1, "values": { "additional_nics": null, "commitment": "standard", "core": 2, "description": null, "disable_pw_auth": null, "graceful_shutdown_timeout": 60, "hostname": null, "icon_id": null, "interface_driver": "virtio", "memory": 4, "name": "test", "nic": "shared", "note_ids": null, "password": null, "private_host_id": null, "ssh_key_ids": null } } ] } }, "resource_changes": [ { "address": "sakuracloud_server.server", "mode": "managed", "type": "sakuracloud_server", "name": "server", "provider_name": "sakuracloud", "change": { "actions": [ "create" ], "before": null, "after": { "additional_nics": null, "commitment": "standard", "core": 2, "description": null, "disable_pw_auth": null, "graceful_shutdown_timeout": 60, "hostname": null, "icon_id": null, "interface_driver": "virtio", "memory": 4, "name": "test", "nic": "shared", "note_ids": null, "password": null, "private_host_id": null, "ssh_key_ids": null }, "after_unknown": { "additional_display_ipaddresses": true, "cdrom_id": true, "disks": true, "display_ipaddress": true, "dns_servers": true, "gateway": true, "id": true, "ipaddress": true, "macaddresses": true, "nw_address": true, "nw_mask_len": true, "packet_filter_ids": true, "private_host_name": true, "tags": true, "vnc_host": true, "vnc_password": true, "vnc_port": true, "zone": true } } } ], "configuration": { "root_module": { "resources": [ { "address": "sakuracloud_server.server", "mode": "managed", "type": "sakuracloud_server", "name": "server", "provider_config_key": "sakuracloud", "expressions": { "core": { "constant_value": 2 }, "memory": { "constant_value": 4 }, "name": { "constant_value": "test" } }, "schema_version": 1 } ] } } }
これをconftestコマンドに読ませることでテストを行います。
ポリシーの作成
今回は試しにサーバのコア数は2以上、メモリは4GB以上を指定しないといけないというポリシーにしてみます。
ポリシーファイルは以下の内容でpolicy/instance_type.rego
というファイルを作成します。
package main # コア数は2以上であること deny[msg] { resource := input.resource_changes[index] resource.type == "sakuracloud_server" resource.change.after.core < 2 msg = "sakuracloud_server.core must be greater than 2" } # メモリは4GB以上であること deny[msg] { resource := input.resource_changes[index] resource.type == "sakuracloud_server" resource.change.after.memory < 4 msg = "sakuracloud_server.memory must be greater than 4" }
テスト実行(ポリシー適用)
それでは早速conftestでテストを実行(ポリシーを適用)してみます。
Makefileの作成
プランファイルの出力~JSONへの変換は毎回コマンド入力するのも大変なのでMakefileでまとめておきます。
NAME := myproject COMMAND := terraform PLAN = $(NAME)-plan.tfplan SHOW = $(NAME)-show.json CODE = $(NAME).tf all: test plan: $(PLAN) $(PLAN): $(CODE) $(COMMAND) plan -out $(PLAN) show: $(SHOW) $(SHOW): plan $(COMMAND) show -json $(PLAN) > $(SHOW) test: show cat $(SHOW) | conftest test - clean: @rm -f $(PLAN) $(SHOW) .PHONY: plan show test all clean
これでmake
するだけでテスト可能になります。
なお、このMakefileだと中間ファイルが作成されますので必要に応じてcleanを実行したり.gitignoreに追記したりしておいてください。
実行
現時点でのtfファイルは以下の通りです。
resource sakuracloud_server "server" { name = "example" core = 1 memory = 1 }
ポリシーである2コア以上かつ4GBメモリ以上に反しているのでエラーとなるはずです。
$ make # [中略] cat example-show.json | conftest test - sakuracloud_server.core must be greater than 2 sakuracloud_server.memory must be greater than 4 make: *** [test] Error 1
エラーになりましたね!
今度はtfファイルを修正して実行してみます。
resource sakuracloud_server "server" { name = "example" core = 2 memory = 4 }
# [中略] cat example-show.json | conftest test -
今度はエラーとなりませんでしたね。
あとは必要に応じてポリシーを充実させ、CIに組み込めば良さそうです。
終わりに
Open Policy Agent/Regoを初めて使ってみましたがなかなか面白いですね。 TerraformのようなインフラコードのテストでShift left testing出来ると効率がグッと上がりますのでどんどん活用していきたいです。
以上です。
参考情報
- Conftest: https://github.com/instrumenta/conftest
- Open Policy Agent: https://www.openpolicyagent.org/
- Rego Deep Dive: https://www.slideshare.net/TorinSandall/rego-deep-dive
- Open Policy Agentを始めてみよう: https://kenfdev.hateblo.jp/entry/2019/03/19/092927
- Unit Test好きにはたまらない!Conftestで設定ファイルのテストをしてみた: https://kenfdev.hateblo.jp/entry/2019/05/31/194614
TerraformでのプロビジョニングにVNCを使う
TerraformでVNCでのプロビジョニングを行えるようにするプラグインterraform-provisioner-vncを公開しました。
Terraformでのプロビジョニング
Terraformではリソースの初期設定や削除時のクリーンアップ処理などを行えるようにプロビジョナーという仕組みが用意されています。
Terraform v0.12.1の時点では以下のようなプロビジョナーが利用可能となっています。
- chef Provisioner
- file Provisioner
- habitat Provisioner
- local-exec Provisioner
- remote-exec Provisioner
- salt-masterless Provisioner
SSH/WinRMが利用できないリソースのプロビジョニングは?
プロビジョナーのうちlocal-exec以外はSSHまたはWinRM(SSHのみの場合もある)でリモートに接続してなんらかの処理を行うようになっています。 これはSSH/WinRMが利用できないリソース、例えば初期状態ではリモート接続を許可していないようなリソースではこれらを利用できないということです。
この問題の解決方法の一つとして、VNC経由でコマンドを実行するのが今回公開したterraform-provisioner-vnc
です。
Packerでいうboot_commandを実行するものとなっており、主にSSH/WinRM出来るまでの環境を整えることを目的としています。
terraform-provisioner-vncの使い方
通常のプロビジョナーと同じく、対象のリソースやnull_resourceにprovisionerブロックを記載することで利用します。 例えばさくらのクラウドのサーバだと以下のように使います。
resource sakuracloud_server "example" { name = "example" # ...中略 provisioner vnc { host = self.vnc_host port = self.vnc_port password = self.vnc_password boot_wait = "10s" # ここに実行したいコマンドを記載していく inline = [ "<tab><wait>", "text ks=http://${var.ip}:${var.port}/anaconda-ks.cfg<enter>", ] } }
remote-execと同じく、inline
(文字列リストで指定)、script
(スクリプトファイルのパスで指定)、またはscripts
(ファイルパスのリストで指定)で実行するスクリプトを指定できます。
記載できる内容はPackerでのboot_commandと互換性があり、<enter>
などの特殊キーもサポートしています。(入力処理はPackerそのものを利用してます)
指定できるスクリプトについてはPackerのQEMU Builderのboot_commandについてのドキュメントを参照してください。
terraform-provisioner-vncのインストール
リリースページからバイナリファイルをダウンロードし~/.terraform.d/plugins
配下に配置すればOKです。
利用例
利用例として、さくらのクラウド上のサーバでk3OSを起動〜ディスクへのインストールまでを行う例を挙げておきます。
参考: k3os on さくらのクラウド - febc技術メモ
k3OSをISOイメージから起動した場合、公開鍵を登録する or rancherユーザーのパスワードを設定するまでSSH接続できません。
このため、VNCプロビジョナーを用いてOSのインストール処理〜GitHubから公開鍵の取得/登録などを行います。
OSのインストール後はSSHプロビジョナーで接続して任意のプロビジョニングが実行できます。
この例ではkubectl
コマンドを実行してみています。
variable server_name { default = "example" } variable github_username { default = "yamamoto-febc" } provider sakuracloud { zone = "is1b" } data sakuracloud_cdrom k3os { name_selectors = ["k3OS"] } resource sakuracloud_disk "disk" { name = var.server_name } resource sakuracloud_server "k3os" { name = var.server_name core = 2 memory = 4 disks = [sakuracloud_disk.disk.id] cdrom_id = data.sakuracloud_cdrom.k3os.id # VNC経由でOSのインストール処理 provisioner vnc { host = self.vnc_host port = self.vnc_port password = self.vnc_password boot_wait = "40s" inline = [ "rancher<enter>", "<wait5>", "sudo os-config<enter>", "<wait5>", "<enter>", "<wait5>", "<enter>", "<wait5>", "y<enter>", "<wait5>", "${var.github_username}<enter>", # terraformの$記法も使えるしコメントも書ける "<wait10s>", "<enter>", "<wait5>", "<enter>", "<wait5>", "<enter>", "<wait10s>", "y<enter>", "<wait5>", ] } # VNCでプロビジョニング後はSSHで接続してプロビジョニング connection { type = "ssh" host = self.ipaddress user = "rancher" private_key = file("/Users/kaz/.ssh/id_rsa") script_path = "/home/rancher/bootstrap.sh" } provisioner "remote-exec" { inline = [ "echo ${self.ipaddress} `hostname` | sudo tee -a /etc/hosts", # /etc/hostsに自身のホスト名を追記 "kubectl cluster-info", "kubectl get cs", "kubectl version", ] } }
終わりに
使い所は限られますが、Packerを使うまでもないちょっとしたコマンドを実行しておきたいケースに便利だと思います。
なお、TerraformでのCustom Provisionerの仕組みはこちらにコメントされているように将来的に大きく変わる可能性もある点は注意しておいてください。
(利用する側としてはあまり関係ないかもしれませんが)
以上です。