【読書メモ】モニタリングでの4大シグナル/USEメソッド/REDメソッド

f:id:febc_yamamoto:20190217131709j:plain

最近、監視やモニタリング熱が自分の中で高まってきてます。
その一環で先月"Prometheus Up & Running"を購入しました。

Prometheus: Up & Running: Infrastructure and Application Performance Monitoring

Prometheus: Up & Running: Infrastructure and Application Performance Monitoring

少し前にようやく届いたので読んでいってます。

今回は読書のメモとして調べたサイトなどを残しておきます。

Prometheus Up & Runningに出てくるUSEメソッド/REDメソッド

とりあえずPrometheus Up & Runningのchapter3まで読みました。
chapter3ではREDメソッドUSEメソッドというものが登場します。

「これモニタリングの文脈でよく見かける気がする…」

と思い、どこで読んだのか思い出してみた(調べた)ら、最近読んだものではこちらの記事にありました。

blog.freshtracks.io

とくにこの連載記事の第2回でUSEメソッドとREDメソッドについて詳しく扱われてます。

blog.freshtracks.io

こちらの記事では、モニタリングの取り掛かりとして複雑で多種多様なメトリクスを抽象化する方法について扱っています。

そのため方法として以下の3つが挙げられています。

  • The Four Golden Signals(4大シグナル)
  • The USE Method(USEメソッド)
  • The RED Method(REDメソッド)

The Four Golden Signals

こちらはみんな大好きSRE本ことSite Reliability Engineeringに載ってるやつです。

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

日本語版だと6章 分散システムのモニタリング - 4大シグナル(P.62)です。

4つのシグナルとは、

  • Latency (レイテンシ)
  • Traffic(トラフィック)
  • Errors (エラー)
  • Saturation(飽和状態)

で、とりあえずこれを見とけって指標ですね。

これらを実際に見ようとした時、どのメトリクスをどのように見ればいいのか悩むかもしれません。(元記事も悩んだと書いてますね)
特にSaturationって難しいですよね。

これを考える際の指針となるのがUSEメソッドだそうです。

The USE Method

The USE MethodとはBrendan Gregg(@brendangregg)氏により提唱されたシステムのパフォーマンス分析の方法論だそうです。

元記事: www.brendangregg.com

一言でまとめると

すべてのリソースについて、使用率(Utilization)、飽和状態(Saturation)、エラー(Errors)を確認する

でしょうか。それぞれの頭文字をとってUSEメソッドと呼んでるのですね。

さらに次の定義が続きます。

  • リソース(Resources):すべての物理サーバーの機能コンポーネント(CPU、ディスク、バスなど)
  • 使用率(Utilization):リソースが処理中でbusyだった時間の平均
  • 飽和状態(Saturation):リソースにサービスできない余分な作業がある度合い。(処理できてないものは大抵キューに入れられいる)
  • エラー(Errors):エラーイベントの数

具体的な指標も例示されてます(ディスクの使用率であればデバイスがビジーな割合を見る、飽和状態であればwatiキューの長さを見る、など)ので元記事は目を通しておいた方が良さそうです。

The RED Method

次にUSEメソッドが対象とする(物理的な)リソースの上で動くアプリケーションをどうモニタリングするかですが、 このためにThe RED Methodが紹介されています。

The RED MethodとはTom Wilkie(@tom_wilkie)氏によるマイクロサービスのモニタリングのための方法論だそうです。

grafana.com

www.weave.works

こちらは全てのマイクロサービスが測定すべき指標を以下のように定義しています。

  • レート(Rate) - 秒あたりのリクエスト数
  • エラー(Errors) - リクエストの失敗数
  • 時間(Duration) - リクエストの処理にかかる時間

USE vs RED ??

“The USE method is for resources and the RED method is for my services”  — Tom Wilkie

だそうで、両方一緒に使うべき、だそうです。

先ほどのGrafanaのブログでもTomの発言が載ってますね。

Tom recommended using the USE and RED Methods together. “It’s like the RED Method is about caring about your users and how happy they are,” Tom said, “and the USE Method is about caring about your machines and how happy they are. It’s really just two different views on the same system. They’re complimentary.”

終わりに

もうちょっと英文読む速度上げないと色々追いきれない。。。

以上です。

入門 監視 ―モダンなモニタリングのためのデザインパターン

入門 監視 ―モダンなモニタリングのためのデザインパターン

さくらのクラウド+Container LinuxでPXEブート+Ignitionを使う

f:id:febc_yamamoto:20190216160328p:plain

さくらのクラウド + Container Linuxでのプロビジョニング

さくらのクラウドでContainer Linuxを使う場合、プロビジョニングをどうするかは悩みどころです。

さくらのクラウドではプロビジョニングのための仕組みとしてスタートアップスクリプトは用意されているものの、Container Linuxでは利用できないという制限があります。

参考 スタートアップスクリプトは以下のOSに対応しています。
- CentOS
- Debian
- Ubuntu
- FreeBSD
- RancherOS
- VyOS

スタートアップスクリプト以外でプロビジョニングするには?

スタートアップスクリプト以外でプロビジョニングする方法としては以下のようなものが挙げられます。

  • Ansibleなどのプロビジョニングツールを利用してサーバ起動後にSSHで操作
  • ISOイメージ機能を利用してConfigDrive経由でcloud-configを流し込む
  • PXEブート環境を構築しIgnitionを使う

2番目のISOイメージでConfigDriveを使う方法についてはこちらの記事が詳しいです。

hnakamur.github.io

3番目の方法は、前回紹介したcybozuさんのsabakanやCoreOS社の提供するMatchboxを使ってDHCPサーバやIgnitionファイルの管理/配布などを行う環境を作るというもので、導入/運用の敷居が少し高めとなっています。

参考: sabakanの紹介記事

febc-yamamoto.hatenablog.jp

もうちょっと楽にPXEブート+Ignitionの管理ができないか、、、

ということで今回の本題の「terraform-sakuracloud-matchbox」というモジュールを公開しました。

Terraform + Matchbox + さくらのクラウド = terraform-sakuracloud-matchbox

terraform-sakuracloud-matchboxはMatchboxを手軽に導入するためのTerraformモジュールです。

registry.terraform.io

以下のようなtfファイルの記述でMatchboxをセットアップすることが可能です。

module "matchbox" {
  source =  "sacloud/matchbox/sakuracloud"

  #Matchboxを稼働させるサーバのパスワード
  server_password = "put-your-server-password"

  #DHCPサーバなどのPXEブート関連機能を動かすためのネットワークに接続するスイッチのID
  switch_id       = "1234556789012"

}

このモジュールは以下のような動きをします。

  • サーバを1台作成
  • サーバをインターネット(共有セグメント)と指定されたスイッチに接続
  • サーバ上でMatchboxとdnsmasqを起動
  • スイッチ側NIC上でMatchboxのHTTP APIエンドポイントを提供
  • DHCPクライアントに対するデフォルトゲートウェイとして構成(ip_forward)
  • MatchboxのgRPC API用にCA証明書、サーバ証明書/秘密鍵、クライアント証明書/秘密鍵を生成(オプションで指定も可能)
  • インターネット側NIC上でMatchboxのgRPCエンドポイントを提供
  • CoreOSの起動/インストール用イメージなどのアセットの提供

f:id:febc_yamamoto:20190216165154p:plain

このモジュールはMatchboxサーバを提供するのみで、接続するスイッチ(VPC)やPXEブートするサーバなどは別途用意する必要があります。
また、Matchbox自体への設定の投入(IgnitionやMetadataなど)も別途用意する必要があります。

次にこのモジュールを使って実際にPXEブートしてContainerLinuxをブート/ディスクへのインストールまでを行ってみます。

terraform-sakuracloud-matchboxでContainerLinuxの起動/プロビジョニングまで

実際にどうやって使うのかをみていきます。

準備

以下のものが必要になります。あらかじめ準備しておいてください。

さくらのクラウド/Matchbox向けのTerraformプロバイダーはCommunity ProviderでTerraform本体とは別で配布されており個別にインストールが必要です。
それぞれの最新版をGitHubからダウンロードし、~/.terraform.d/plugins/配下などに配置しておいてください。 詳細は以下のドキュメントを参照してください。

www.terraform.io

さくらのクラウドAPIキーは環境変数などに設定しておいてください。

sacloud.github.io

なお、今回は簡便のためモジュールわけなどせずに同じディレクトリ内にMatchboxサーバの定義とPXEブートするサーバ/Ignitionの定義などを格納します。
本来はライフサイクルが異なるため別モジュールに分けるべきと思いますので、実際に利用する際はこの辺りも考慮しておいてください。

Matchbox構築

まずはMatchboxを動かすためのサーバとPXEブートで利用するスイッチを作成します。

以下のようなtfファイルmatchbox.tfを作成します。

resource sakuracloud_switch "switch" {
  name = "matchbox-internal"
}

module "matchbox" {
  source             = "sacloud/matchbox/sakuracloud"

  server_password    = "your-password"
  switch_id          = "${sakuracloud_switch.switch.id}"

  server_public_key  = "${file("~/.ssh/id_rsa.pub")}"
  server_private_key = "${file("~/.ssh/id_rsa")}"
}

パスワードは適当なものに置き換えてください。 また、サーバに接続するためのSSH公開鍵/秘密鍵も合わせて指定しています。
~/.ssh/id_rsa~/.ssh/id_rsa.pubが存在しない場合は適当にssh-keygenなどで作成しておいてください。

作成したらterraform initしてterraform applyします。

$ terraform init
...
Terraform has been successfully initialized!
...

$ terraform apply

...
Apply complete! Resources: 17 added, 0 changed, 0 destroyed.

これでサーバが作成されMatchboxが動いている状態となりました。

PXEブートするサーバの作成/Ignitionなどの定義

次にPXEブートするサーバやサーバに適用するIgnitionの定義を行います。

サーバの定義

まずはサーバの定義を行います。以下のようなtfファイルservers.tfを作成してください。

locals {
  node_count = 1
}

resource sakuracloud_server "server" {
  name   = "node-${count.index+1}"
  core   = 2
  memory = 2 # Container Linuxは2GB以上のメモリが必要
  nic    = "${sakuracloud_switch.switch.id}" # 先ほど作成したスイッチに接続
  disks  = ["${sakuracloud_disk.disk.*.id[count.index]}"]

  count  = "${local.node_count}"
}

resource sakuracloud_disk "disk" {
  name  = "node-${count.index}"
  size  = 20
  count = "${local.node_count}"
}

注意点は以下2つです。

  • サーバのメモリは2GB以上にする(Container Linuxの要件)
  • サーバのNICは先ほど作成したスイッチに接続する

本来はディスクの作成時にコピー元アーカイブの指定やサーバへのIPアドレスの指定などが必要なのですが、 今回はOSの入っていないブランクディスク、設定類はIgnitionで行うためこの指定となっています。

次にMatchboxで配布するIgnitionなどの定義を行います。

Matchboxの設定

Matchboxプロバイダーへのパラメータ指定

Ignitionなどの定義はMatchboxが提供するgRPC APIを用いて行います。
これをTerraformから行えるようにしてくれるのがTerraformのMatchboxプロバイダーです。

まずは先ほど作成したMatchboxサーバを利用するようにMatchboxプロバイダーへのパラメータ指定を行います。

以下のようなtfファイルをprovider_matchbox.tfという名前で作成してください。

provider "matchbox" {
  endpoint    = "${module.matchbox.matchbox_grpc_api_endpoint}"
  client_cert = "${module.matchbox.client_cert}"
  client_key  = "${module.matchbox.client_key}"
  ca          = "${module.matchbox.ca_cert}"
}

接続するための情報は先ほどのterraform-sakuracloud-matchboxモジュールが提供してくれますので、tfファイル上でモジュールの値を参照するように指定しています。

MatchboxのProfile/Group作成

次にMatchboxのProfileとGroupを作成します。

MatchboxでのProfileとは名前付きの設定テンプレートのことです。
Profileは iPXEやGRUB、Ignition configなどを保持します。

GroupとはMatchboxクライアントから提示されるMACアドレスやシリアル、UUIDなどを用いて クライアントとプロファイルを結びつけるものです。

coreos.com

と言ってもよくわからないですよね。実物を見るのが早いと思います。

まずProfileとして

  • PXEブートした時に適用するProfile
  • ディスクにOSをインストールした後に適用するProfile

の2種類を作成します。

以下のようなtfファイルをprofile.tfとして作成します。

UPDATE: 2019/2/17 00:25 argsの誤りを修正

// Create a CoreOS-install profile
resource "matchbox_profile" "coreos-install" {
  name = "coreos-install"

  kernel = "${module.matchbox.matchbox_assets_coreos_kernel_path[0]}"
  initrd = ["${module.matchbox.matchbox_assets_coreos_initrd_path[0]}"]
  args = [
    "initrd=coreos_production_pxe_image.cpio.gz",
    "coreos.config.url=${module.matchbox.matchbox_http_api_endpoint}/ignition",
    "coreos.first_boot=yes",
    "ipv6.disable=1",
    "console=tty0",
    "console=ttyS0",
  ]

  container_linux_config = <<EOF
---
systemd:
  units:
    - name: installer.service
      enable: true
      contents: |
        [Unit]
        Requires=network-online.target
        After=network-online.target
        [Service]
        Type=simple
        ExecStart=/opt/installer
        [Install]
        WantedBy=multi-user.target
storage:
  files:
    - path: /opt/installer
      filesystem: root
      mode: 0500
      contents:
        inline: |
          #!/bin/bash -ex
          curl --retry 10 "{{.ignition_endpoint}}?os=installed" -o ignition.json
          coreos-install -d /dev/vda -C stable -V current -i ignition.json {{if index . "baseurl"}}-b {{.baseurl}}{{end}}
          udevadm settle
          systemctl reboot
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - {{.ssh_authorized_key}}
EOF
}

// Create a simple profile which just sets an SSH authorized_key
resource "matchbox_profile" "simple" {
  name                   = "simple"
  container_linux_config = <<EOF
---
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - {{.ssh_authorized_key}}
EOF
}

ちょっと長いですが順番にみていきましょう。

まずPXEブートした時に適用するProfileがmatchbox_profile.coreos-installです。
ここではiPXEブート時に必要になるvmlinuzとinitrdのダウンロードURL、起動時のカーネルパラメータ、起動時に渡すcontainer_linux_config(Ignition)の内容を指定しています。

container_linux_configではcoreos-installコマンドを用いたディスクへのOSインストールとユーザーcoreの作成、SSH用の公開鍵の登録を行っています。

次にディスクにOSをインストールした後に適用するProfileがmatchbox_profile.simpleです。
こちらはユーザーcoreの作成とSSH用の公開鍵を登録しているだけです。

ここでcontainer_linux_configの中で{{.xxx}}のようなパラメータ指定をしているのに気づかれた方もいらっしゃるかもしれません。
これは後述するGroupから渡されるパラメータです。Profileとしては設定のテンプレートを用意しておき、Groupから渡されるパラメータを反映することで具体的なcontainer_linux_config(Ignition)の内容となるということですね。

次にGroupです。
以下のようなtfファイルをgroup.tfとして作成します。

// Default matcher group for machines
resource "matchbox_group" "default" {
  name    = "default"
  profile = "${matchbox_profile.coreos-install.name}"

  # セレクタ未指定のため、パラメータ指定のない全てのマシンにマッチする

  metadata {
    ignition_endpoint  = "${module.matchbox.matchbox_http_api_endpoint}/ignition"
    ssh_authorized_key = "${file("~/.ssh/id_rsa.pub")}"
    baseurl            = "${module.matchbox.matchbox_http_api_endpoint}/assets/coreos"
  }
}

// Match machines which have CoreOS Container Linux installed
resource "matchbox_group" "node1" {
  name    = "node1"
  profile = "${matchbox_profile.simple.name}"

  selector {
    os = "installed"
  }

  metadata {
    ssh_authorized_key = "${file("~/.ssh/id_rsa.pub")}"
  }
}

上の方がPXEブート時に利用されるGroup、下の方がディスクにOSインストール後に利用されるGroupです。 先ほどのProfile定義では以下のような記述がなされていました。

  • PXEブート時のカーネルパラメータ: coreos.config.url=${module.matchbox.matchbox_http_api_endpoint}/ignition
  • coreos-installコマンドに渡すIgnition.jsonの取得コマンド: curl --retry 10 "{{.ignition_endpoint}}?os=installed" -o ignition.json

どちらもMatchboxサーバの/ignitionに対してHTTPでリクエストしてignition.jsonを取得しています。
後者はパラメータとしてos=installedが指定されていますので、これを元にどののGroupなのか? -> どのProfileなのか? -> どのignition.jsonを返すか、をMatchboxが判定してくれます。

ここまできたらあとはterraform applyを実行するだけです。

applyするとブランクディスクからサーバが作成され、PXEブート〜ディスクへのOSインストールが行われるはずです。

Profileの定義を変えることで様々なプロビジョニングが行えますね!

その他の機能: OS起動/インストールイメージのプリフェッチ

デフォルトではContainerLinuxのPXEブート/ディスクへのインストール用イメージをMatchbox上にプリフェッチするようになっています。
以下のパラメータを指定することでプリフェッチを無効化したり、異なるバージョンのイメージをプリフェッチしておくことが可能です。

  # 対象のContainerLinuxのバージョン("1967.6.0"みたいに指定する)
  prefetch_coreos_assets_keys = ["current"]

  # 対象のChannel(https://coreos.com/releases/を参照)
  prefetch_coreos_assets_channel = "stable" # allowed values are: current/beta/alpha/custom

  # カスタムイメージを使う場合のダウンロードURL
  prefetch_coreos_assets_custom_url = ""

デフォルトはstableチャンネルのcurrentバージョンをプリフェッチします。
alphabetaも利用可能です。
prefetch_coreos_assets_keysに空を指定することでプリフェッチを無効化可能です。

なお、プリフェッチを無効化した場合はMatchboxのProfile/Groupで各種ダウンロード先を変え忘れないように注意してください。

その他の機能: ゲートウェイ機能のON/OFF

デフォルトではMatchboxサーバはIPフォワードが有効化され、DHCPクライアントからの外部へのリクエストをSNATするようになっています。

この挙動は以下のパラメータで制御可能です。

  # フォワードの有効/無効
  server_enable_forward = true

例えば既存のVPC内に配置したり、デフォルトゲートウェイとしてVPCルータを利用すると言った場合にはこの設定を変更する必要があります。

また、この設定を変えた場合、DHCPで配布するデフォルトゲートウェイの設定も変える必要があります。
以下のあたりのパラメータを合わせて変更してください。

  # Matchboxサーバ自身のプライベート側IPアドレス
  matchbox_ipaddress     = "192.168.0.1"

  # Matchboxサーバのネットワークマスク長
  matchbox_nw_mask_len   = "24"

  # MatchboxのHTTP APIが利用するポート番号
  matchbox_http_api_port = 8080

  # MatchboxのgRPC APIが利用するポート番号
  matchbox_grpc_api_port = 8081

  # DHCPで配布するデフォルトゲートウェイのアドレス
  matchbox_gateway       = "192.168.0.1"

  # DHCPで配布するアドレス範囲
  dhcp_start             = "192.168.0.101"
  dhcp_end               = "192.168.0.200"

終わりに

このモジュールを利用することでTerraform + MatchboxでPXEブート + Ignitionの管理が行えるようになります。
Terraformで完結していますので既存のTerraformを用いたワークフローにも適合しやすいと思います。
ぜひ使ってみてください。

以上です。

ベアメタル環境でのサーバ構築/管理ツール 「sabakan」を試した

ベアメタル環境でのサーバ構築のためのツールや管理情報、APIなどを提供するsabakanを試してみましたのでメモを残しておきます。

sabakanとは

サイボウズさんのインフラ刷新プロジェクトNecoで用いられている機材管理ツールとのことです。

github.com

blog.cybozu.io

サーバの構成情報などを保持しておくインベントリ機能とそれらを用いてネットワークブート/プロビジョニングを行う機能を提供してくれます。
データストアとしてはetcdが用いられており、sabakan自体を複数起動して冗長構成にすることもできるようです。

f:id:febc_yamamoto:20190209115153p:plain
(画像引用元: https://github.com/cybozu-go/sabakan)

使い方としては、サーバのシリアル情報や持たせたい役割を構成情報として投入し、スイッチに繋いだ上でサーバの電源を入れるとアプリケーションがデプロイできる状態になる、という感じなようです。

次にもう少し詳しく機能をみてみます。

sabakanの持つ機能

sabakanのREADMEによると以下のような機能を持っているとのことです。

sabakanの機能(一部抜粋):

  • サーバの構成情報のインベントリ / IPアドレスの割り当て管理
  • DHCP(UEFI/iPXE HTTPでのネットワークブート用)サービス
  • HTTPサービス(OSイメージや任意のアセットの提供)
  • サーバのライフサイクル管理用APIの提供

(詳しくはREADMEのFeaturesを参照してください)

サーバのOSにはContainer Linuxを想定しており、Ignitionでプロビジョニングを行うためのjsonを組み立てたりHTTPで配信する機能も持っています。

また、サーバの状態(まだ初期化してないよ、とか動いてるよ、とか退役する/したとか)も保持してます。

参考: sabakan/lifecycle.md at master · cybozu-go/sabakan · GitHub

注意点として、サーバの状態は保持するだけでその変更はAPIなどを用いて外部から行う必要ということがあります。
ヘルスチェックなどを通じて状態を操作するコントローラー的なものは必要に応じて別途用意しないといけないということですね。

類似プロダクト

類似のプロダクトとしてはCoreOSのMatchboxがあります。

coreos.com

Kubernetes環境の構築/管理ツールであるTectonicで足回りの構築に使われているものです。

coreos.com

Matchboxはsabakanと同じくiPXEなどでのネットワークブート、Ignitionによるプロビジョニングに対応しています。

違いとしてはsabakanの方はより物理的なインフラを意識している(ラックの指定とかBMC周りとか)点とサーバの状態管理を行なっている点があります。
Matchboxの方はMetadata APIやTerraformプロバイダーの提供を行なうなど、クラウドを含めより汎用的なインフラ環境上で動かせることを目指しているように感じてます。

どちらも単体で動かすようなものではなく、ビルディングブロックとして他のシステムと協調して動かすものとなっていますので やりたいことに応じて使い分ければ良さそうですね。

sabakanでサーバ構築してみる

概要を押さえたところで早速sabakanを試してみます。

動かし方はGitHub上にGetting startedがありますのでこちらを参考にします。

github.com

また、個人的な好みにより今回はさくらのクラウドで動かします。
さくらのクラウドはOSなしでサーバ作成が出来ますしPXEブートも可能なのでsabakanが使えるはずです。

インフラの準備

まずsabakanを動かすためのサーバ/スイッチなどをさくらのクラウド上で作成します。
今回は以下のような構成にします。

構成:

f:id:febc_yamamoto:20190209121111p:plain

  • sabakan用サーバ
    • 作業用(ssh)にインターネット(共有セグメント)に接続
    • スイッチ(VPC)に接続、sabakanはVPC向けセグメントで動かす
  • VPCでは192.168.150.0/24を用いる

今回はsabakanをDocker上で動かすつもりですので、サーバのOSはContainer LinuxかRancherOSを入れとくのが楽だと思います。
サーバは作成後にスイッチへの接続、スイッチと接続したNIC(eth1)ヘのIPアドレス設定を行なっておきます(今回は192.168.150.1/24にします)。

sabakanの実行

インフラの準備ができたら早速sabakanを実行してみましょう。
以下はsabakan用サーバにssh接続して作業します。

sabakan用のconfigの作成

まずsabakan用のconfigファイルを用意します。
以下の内容をsabakan.ymlという名前で作成します。

etcd:
  endpoints:
    - http://localhost:2379
dhcp-bind: 192.168.150.1:67
advertise-url: http://192.168.150.1:10080

sabakanはconfigファイルだけでなくコマンドラインオプションで各種設定を指定可能ですが、configファイルとコマンドラインオプションを併用した場合はconfigファイルが優先され コマンドラインオプションでの指定が無視されますのでご注意ください(最初気付かずに数分悩みました)。

etcdとsabakanを起動

次にetcdとsabakanをDockerで起動します。
本来は各種オプションをしっかり指定しておくべきだとは思いますが今回はお試しということで色々手を抜いてます。

# etcd
$ docker run -d --rm --name etcd --network=host --uts=host quay.io/cybozu/etcd:3.3

# sabakan
$ docker run -d  --name sabakan --network=host -v $PWD:/work -w /work quay.io/cybozu/sabakan:1.1 -config-file sabakan.yml      

ネットブート用の設定類を投入

sabakanが起動したら次にネットブートを行うための各種設定を投入していきます。

sabakanのCLIクライアントsabactlの準備

sabakanの操作を行うためのCLIクライアントsabactlを準備しておきます。
今回はdocker execでsabakanコンテナ上でsabactlを実行するように以下のエイリアスを利用します。

$ alias sabactl='docker exec -it sabakan sabactl'

IPAM

まずIPアドレスの割り当て定義を投入します。 jsonファイルを作成してsabactlというsabakanのCLIクライアントを用いて投入します。

以下のファイルをipam.jsonという名前で作成してください。

{
   "max-nodes-in-rack": 8,
   "node-ipv4-pool": "192.168.150.0/24",
   "node-ipv4-range-size": 4,
   "node-ipv4-range-mask": 24,
   "node-index-offset": 1,
   "node-ip-per-node": 1,
   "bmc-ipv4-pool": "192.2.0.0/24",
   "bmc-ipv4-offset": "0.0.0.1",
   "bmc-ipv4-range-size": 1,
   "bmc-ipv4-range-mask": 24,
   "bmc-ipv4-gateway-offset": 1
}

作成したら以下のコマンドで投入します。

$ sabactl ipam set -f ipam.json

投入できたかは以下のコマンドで確認できます。

$ sabactl ipam get

ipam.jsonで定義している項目については以下のドキュメントを参照してください。

sabakan/ipam.md at master · cybozu-go/sabakan · GitHub

なお、こちらもとりあえず動けば良いため値は適当にしてます。

DHCPサーバの設定

次にDHCPサーバの設定を投入します。 IPAMと同じくファイルを作ってsabactlで投入します。

以下のファイルをdhcp.jsonとして作成します。

{
   "gateway-offset": 1,
}

投入は以下のコマンドです。

$ sabactl dhcp set -f dhcp.json

設定項目についてのドキュメントはこちらです。

sabakan/dhcp.md at master · cybozu-go/sabakan · GitHub

PXEブート用のイメージ

次にPXEブートを行うためのイメージをCoreOSのWebサイトから取得してsabakanに投入します。
イメージはcurlコマンドで以下のように取得します。

$ curl -o kernel -Lf http://stable.release.core-os.net/amd64-usr/current/coreos_production_pxe.vmlinuz
$ curl -o initrd.gz -Lf http://stable.release.core-os.net/amd64-usr/current/coreos_production_pxe_image.cpio.gz

取得したらsabactlで投入します。

$ sabactl images upload current kernel initrd.gz

なお、ここで指定しているcurrentは各イメージにつけるIDで任意の名前をつけれるようになっています。

sabakanは複数のイメージを登録しておくことが出来、PXEブート時に自動的に最新のイメージを利用するという仕組みになっています。

サーバの定義投入〜サーバ起動

ここまででsabakanの準備が整いました。後はサーバの定義を投入した上でサーバの電源を入れるだけです。
ということで早速定義の投入を行なってみます。

サーバのシリアル(ID)を取得

sabakanにサーバの定義情報を登録する際にサーバのシリアルが必要になります。
物理サーバであれば購入時の保証書などに記載されていると思いますのでそれを利用します。

今回はさくらのクラウドで動かしますので、単純にサーバのIDがあればOKです。

cloud-news.sakura.ad.jp

こちらの記事にあるように、さくらのクラウドではシリアル番号=IDとなります。
なのでさくらのクラウド上でサーバを作成してIDを控えましょう。

サーバの作成(さくらのクラウド)

さくらのクラウドでサーバ作成を行います。

ここでは以下の条件でサーバ作成してください。

  • サーバに接続するディスクはブランクディスクとする
  • サーバのNICはスイッチに接続する
  • 作成後すぐに起動のチェックは外しておく

こんな構成になるはずです。

f:id:febc_yamamoto:20190209150839p:plain

作成したらサーバのIDを控えましょう。

サーバの定義ファイルを作成

サーバのID(シリアル)が用意できましたので、sabakanに投入するサーバの定義ファイルを作成していきます。

まず以下のファイルをmachines.jsonとして作成します。

[
  {
    "serial": "先ほど控えたサーバのID",
    "rack": 0,               
    "role": "test",          
    "bmc": {                
      "type": "IPMI-2.0",
      "ipv4": ""         
    }                    
  }                      
]  

ここでは役割(role)をtestとしました。後ほどこのロール名を用いてIgnition設定を投入していきます。
また、今回はBMCは利用しませんので空にしています。

投入は以下のコマンドです。

$ sabactl machines create -f machines.json

サーバのプロビジョニング用にIgnition設定

次にこのサーバをプロビジョニングするためのIgnitionの設定を投入します。

プロビジョニングでは本来はディスクへのインストールなどを行うべきところですが、 今回はユーザー名core、パスワードがpasswordのユーザーを追加するだけとします。

まず以下のファイルをpasswd.ymlという名前で作成します。

users:      
  - name: core                                                                                                      
    passwordHash: "$1$2OsV8nCL$AaaGvkomzT5c/D6zApaMG0"                                                              
groups:                                               
  - name: sacloud      
    gid: 10000

次に以下のファイルをignision.ymlという名前で作成します。

passwd: passwd.yml

次にsabactlで投入します。

$ sabactl ignitions set -f ignision.yml test サーバのID

これで準備が整いました。

サーバの電源投入

いよいよプロビジョニングしてみます。サーバの電源をONにしコンソールを眺めましょう。

さくらのクラウド CLI usacloudをご利用の方は以下のコマンドでVNCコンソールを開くことが可能です。

$ usacloud server vnc サーバのID

f:id:febc_yamamoto:20190209161940p:plain

うまく設定出来ていればiPXEブートされている様子が見えるはずです。

起動したらユーザー名:core、パスワード:passwordでログインしてみましょう。

f:id:febc_yamamoto:20190209162507p:plain

ログインできれば成功です。

今回はプロビジョニングの設定が適当でしたが、きちんと設定すればすぐにアプリケーションをデプロイできる状態にまで持っていけますね!!

おまけ: sabactlでサーバの状態を変えてみる

前述の通りsabakan自体はサーバの状態を変えることはなく、外部から何らかの形で変えてあげる必要があります。
本来はサーバのプロビジョニングの完了を検知して適切にハンドリングするなどが必要ですが、ここではsabactlで手動で状態を変えてみます。

まず、初期状態ではサーバの状態はuninitializedになっています。

$ sabactl machines get-state サーバのID

uninitialized 

状態を変えるにはsabactl machines set-stateを使うようです。

# healthyにする
sabactl machines set-state サーバのID healthy

# retiringにする
sabactl machines set-state サーバのID retiring

# retiredにする!?
sabactl machines set-state サーバのID retired
Error: Bad Request: invalid request: invalid state: retired

retiredにするにはsabactl crypts deleteしなきゃいけないようです。

参考: sabakan/lifecycle.md at master · cybozu-go/sabakan · GitHub

$ sabactl crypts delete --force サーバのID

# ちゃんとretiredになってるはず
$ sabactl machines get-state サーバのID

retired

終わりに

ということで今回はsabakanを試してみました。 周りのコントローラーを工夫すれば色々出来そうですね。

以上です。

Prometheus さくらのクラウド向け Exporter 「sakuracloud_exporter」

f:id:febc_yamamoto:20190204175049p:plain

さくらのクラウド上のリソースの監視を行うためのPrometheusのExporter「sakuracloud_exporter」をリリースしました。

github.com

この記事ではsakuracloud_exporterの機能や実践的な利用例を紹介します。

もしPrometheusになじみの薄い方は以下の連載記事などをあらかじめ読んでおくことをお勧めします。

knowledge.sakura.ad.jp

sakuracloud_exporterの概要

sakuracloud_exporterPrometheusのExporterです。さくらのクラウドAPIを利用して各種メトリクスを収集します。

さくらのクラウドでのメトリクス関連API

さくらのクラウドではCPU-TIMEやディスクのread/write、NICのreceive/sendなどをAPIを通じて取得できるようになっています。
例えばCPU-TIMEであれば、GET /server/:serverid/monitorというAPIで以下のようなJSONが取得可能です。

{
  "Data": {
    "2019-02-03T14:50:00+09:00": {
      "CPU-TIME": 0.046666666667
    },
    "2019-02-03T14:55:00+09:00": {
      "CPU-TIME": 0.05
    },
    "2019-02-03T15:00:00+09:00": {
      "CPU-TIME": 0.053333333333
    },
    "2019-02-03T15:05:00+09:00": {
      "CPU-TIME": 0.05
    },
    "2019-02-03T15:10:00+09:00": {
      "CPU-TIME": 0.05
    }
  },
  "is_ok": true
}

さくらのクラウドのコントロールパネルではこれを利用した「アクティビティ」という機能が提供されていますね。

f:id:febc_yamamoto:20190204144948p:plain

sakuracloud_exporterではこれらのAPIを用いてPrometheus向けに各種メトリクスの収集/公開を行うようになっています。

sakuracloud_exporterでサポートしているメトリクス

以下のようなリソース関連のメトリクスをサポートしています。
(各メトリクスの詳細はGitHub上のREADMEに記載されています。)

さくらのクラウドのメトリクス関連APIに加え、自動バックアップの状況やクーポン残高なども取得できるようになっています。

どんなことが出来るの?

Grafanaなどのツールを組み合わせての可視化や、AlertManagerを用いてのアラート機能など、 Prometheusを活用した様々な機能が利用できるようになります。 いくつかこのExporterで出来るようになることの例を挙げてみます。

グラフ作成

まずは王道的にGrafanaなどのツールを用いて各種メトリクスをグラフ化することが可能になります。
さくらのクラウドのコントロールパネルのアクティビティ機能ではサーバごとという風にある程度決まった単位での表示しか出来ませんが、 このExporterを用いることで柔軟に対応することが可能です。

例えば複数サーバを並べて比較したり(この辺はnode_exporterで取得することが多いと思いますが)、サーバと接続されているロードバランサやルータのトラフィックも合わせて確認するといった使い方も出来ますね。

複数サーバのCPU-TIMEを並べてみた例:
f:id:febc_yamamoto:20190204150647p:plain

アラート機能

さくらのクラウドではシンプル監視で簡単なアラート機能を利用できますが、 例えばVPC内のサーバのように直接インターネット経由でアクセスできないようなサーバは監視できないといった制限があります。

そういった場合にこのExporterを利用することでさくらのクラウドAPIで取得した情報を元にアラートをあげるということが可能です。

例えば、このExporterではサーバの起動状況をsakuracloud_server_upというメトリック名で公開しています。 これを利用してサーバがシャットダウンした際にアラートをあげることができます。

AlterManagerでサーバがシャットダウンされた時にアラートをあげる例:

  - alert: server_down
    expr: sakuracloud_server_up == 0 # 起動していたら1、以外の場合は0となるため、0の時を条件にする
    for: 1m 
    labels:
      severity: page
    annotations:
      summary: "Server {{ $labels.name }}(ID:{{ $labels.id }}) down"
      description: "{{ $labels.name }} of job {{ $labels.job }} has been down for more than 1 minutes."

工夫次第で色々便利に使えると思います。

sakuracloud_exporterでサポートしているメトリクスの詳細

ここからはsakuracloud_exporterがサポートしているメトリクスについて各リソースごとに詳しくみてみます。

全体で共通的な項目

各リソースには*_infoという、末尾に_infoがつく名前のメトリクスが用意されています。 これは情報参照用のメトリクスで、常に1を返すようになっています。

PrometheusではLabelの値が変更されると違う系列とみなされるため、頻繁に変更されるような項目は各項目のLabelには入れずinfoにまとめて入れると言う形にしています。 各メトリクスの参照時に対象リソースの詳しい情報が必要になった場合に*infoを利用するのが良いでしょう。

例えばサーバのCPU-TIME用のメトリクスsakuracloud_server_cpu_timeは以下のような値を持っています。

sakuracloud_server_cpu_time{id="000000000001",instance="localhost:9542",job="sakuracloud",name="example",zone="tk1a"} 0.5

ラベルはサーバを識別するための最低限の情報しかありません。 ここにサーバのCPU数をラベルとして付与しておきたい場合、以下のようなクエリを用いて*_infoから情報を引っ張ってくる、というようなことができます。

sakuracloud_server_cpu_time * on (zone,id) group_left(cpus) sakuracloud_server_info

このクエリの結果は以下のようになります。

{cpus="2",id="000000000001",instance="localhost:9542",job="sakuracloud",name="example",zone="tk1a"} 0.5

次にリソースごとに利用可能なメトリクスを見てみます。

自動バックアップ関連

Metric Description Labels
sakuracloud_auto_backup_info 自動バックアップ情報の参照用 id, name, disk_id, max_backup_num, weekdays, tags, descriptions
sakuracloud_auto_backup_count この自動バックアップで作成されたアーカイブの現在の数 id, name, disk_id
sakuracloud_auto_backup_last_time 最終バックアップ作成日時(UnixTime) id, name, disk_id
sakuracloud_auto_backup_archive_info この自動バックアップで作成されたアーカイブ情報 id, name, disk_id, archive_id, archive_name, archive_tags, archive_description

例えばこんな感じでバックアップがちゃんと取れているか確認するのに使えると思います。

f:id:febc_yamamoto:20190204172920p:plain

クーポン関連

Metric Description Labels
sakuracloud_coupon_discount クーポン残高 id, member_id, contract_id
sakuracloud_coupon_remaining_days 有効な残日数 id, member_id, contract_id
sakuracloud_coupon_exp_date クーポン期限切れ日時(UnixTime) id, member_id, contract_id
sakuracloud_coupon_usable クーポンが利用可能(有効期限内、かつ残高が1円以上)の場合に1 id, member_id, contract_id

後ほど実践的な例としてこのクーポン情報を利用したアラートの例を扱います。

データベース関連

Metric Description Labels
sakuracloud_database_info データベース情報参照用 id, name, zone, plan, host, database_type, database_revision, database_version, web_ui, replication_enabled, replication_role, tags, description
sakuracloud_database_up 起動している場合は1 id, name, zone
sakuracloud_database_cpu_time CPU-TIME (単位:ms) id, name, zone
sakuracloud_database_memory_used メモリ使用量(単位:GB) id, name, zone
sakuracloud_database_memory_total 総メモリサイズ(単位:GB) id, name, zone
sakuracloud_database_nic_info NIC情報参照用 id, name, zone, upstream_type, upstream_id, upstream_name, ipaddress, nw_mask_len, gateway
sakuracloud_database_nic_receive NIC受信(単位: Kbps) id, name, zone
sakuracloud_database_nic_send NIC送信(単位: Kbps) id, name, zone
sakuracloud_database_disk_system_used システムディスク使用量(unit:GB) id, name, zone
sakuracloud_database_disk_system_total 総システムディスクサイズ(unit:GB) id, name, zone
sakuracloud_database_disk_backup_used バックアップディスク使用量(unit:GB) id, name, zone
sakuracloud_database_disk_backup_total 総バックアップディスクサイズ(unit:GB) id, name, zone
sakuracloud_database_binlog_used binlogのディスク使用量(unit:GB) id, name, zone
sakuracloud_database_disk_read ディスク Read (unit: KBps) id, name, zone
sakuracloud_database_disk_write ディスク Write(unit: KBps) id, name, zone
sakuracloud_database_replication_delay レプリケーション遅延時間(unit:second) id, name, zone

スイッチ+ルータ

Metric Description Labels
sakuracloud_internet_info スイッチ+ルータ情報参照用 id, name, zone, switch_id, bandwidth, tags, description
sakuracloud_internet_receive 受信(unit: Kbps) id, name, zone, switch_id
sakuracloud_internet_send 送信(unit: Kbps) id, name, zone, switch_id

ロードバランサ

Metric Description Labels
sakuracloud_loadbalancer_info ロードバランサ情報参照用 id, name, zone, plan, ha, vrid, ipaddress1, ipaddress2, gateway, nw_mask_len, tags, description
sakuracloud_loadbalancer_up 起動している場合は1 id, name, zone
sakuracloud_loadbalancer_receive NIC 受信(unit: Kbps) id, name, zone
sakuracloud_loadbalancer_send NIC 送信(unit: Kbps) id, name, zone
sakuracloud_loadbalancer_vip_info VIP情報参照用 id, name, zone, vip_index, vip, port, interval, sorry_server, description
sakuracloud_loadbalancer_vip_cps VIPごとの秒あたりのコネクション数 id, name, zone, vip_index, vip
sakuracloud_loadbalancer_server_info 実サーバ情報参照用 id, name, zone, vip_index, vip, server_index, ipaddress ,monitor, path, response_code
sakuracloud_loadbalancer_server_up 実サーバが稼働している場合は1 id, name, zone, vip_index, vip, server_index, ipaddress
sakuracloud_loadbalancer_server_connection 実サーバごとのコネクション数 id, name, zone, vip_index, vip, server_index, ipaddress
sakuracloud_loadbalancer_server_cps 実サーバごとの秒あたりのコネクション数 id, name, zone, vip_index, vip, server_index, ipaddress

モバイルゲートウェイ

Metric Description Labels
sakuracloud_mobile_gateway_info モバイルゲートウェイ 情報参照用 id, name, zone, internet_connection, inter_device_communication, tags, description
sakuracloud_mobile_gateway_up 起動している場合は1 id, name, zone
sakuracloud_mobile_gateway_nic_receive NIC 受信(unit: Kbps) id, name, zone, nic_index, ipaddress, nw_mask_len
sakuracloud_mobile_gateway_nic_send NIC 送信(unit: Kbps) id, name, zone, nic_index, ipaddress, nw_mask_len
sakuracloud_mobile_gateway_traffic_control_info トラフィックコントロール情報参照用 id, name, zone , traffic_quota_in_mb, bandwidth_limit_in_kbps, enable_email, enable_slack, slack_url, auto_traffic_shaping
sakuracloud_mobile_gateway_traffic_uplink トラフィック(UP) (unit: KB) id, name, zone
sakuracloud_mobile_gateway_traffic_downlink トラフィック(DOWN) (unit: KB) id, name, zone
sakuracloud_mobile_gateway_traffic_shaping 通信制限が行われている場合は1 id, name, zone

NFS

Metric Description Labels
sakuracloud_nfs_info NFS情報参照用 id, name, zone, plan, host, tags, description
sakuracloud_nfs_up 起動している場合は1 id, name, zone
sakuracloud_nfs_free_disk_size 空きディスク容量(unit: GB) id, name, zone
sakuracloud_nfs_nic_info NIC情報参照用 id, name, zone, upstream_id, upstream_name, ipaddress, nw_mask_len, gateway
sakuracloud_nfs_receive NIC 受信(unit: Kbps) id, name, zone
sakuracloud_nfs_send NIC 送信(unit: Kbps) id, name, zone

サーバ

Metric Description Labels
sakuracloud_server_info サーバ情報参照用 id, name, zone, cpus, disks, nics, memories, host, tags, description
sakuracloud_server_up 起動している場合は1 id, name, zone
sakuracloud_server_cpu_time CPU-TIME (unit: ms) id, name, zone
sakuracloud_server_disk_info ディスク情報参照用 id, name, zone, disk_id, disk_name, index, plan, interface, size, tags, description
sakuracloud_server_disk_read ディスク Read (unit: KBps) id, name, zone, disk_id, disk_name, index
sakuracloud_server_disk_write ディスク Write (unit: KBps) id, name, zone, disk_id, disk_name, index
sakuracloud_server_nic_info NIC情報参照用 id, name, zone, interface_id, index, upstream_type, upstream_id, upstream_name
sakuracloud_server_nic_bandwidth NIC帯域(unit: Mbps) id, name, zone, interface_id, index
sakuracloud_server_nic_receive NIC 受信(unit: Kbps) id, name, zone, interface_id, index
sakuracloud_server_nic_send NIC 送信(unit: Kbps) id, name, zone, interface_id, index

この中でもsakuracloud_server_nic_bandwidthは頑張って実装したものでなかなか便利だと思います。
さくらのクラウドではプランやサーバの搭載メモリで帯域が変わってくると言う仕様となっています。

manual.sakura.ad.jp

sakuracloud_server_nic_bandwidthはこの仕様を考慮して帯域幅を算出するようになっています。 sakuracloud_server_nic_receivesakuracloud_server_nic_sendと組み合わせて、どのくらい帯域を食っているかを見ることが可能です。

SIM

Metric Description Labels
sakuracloud_sim_info SIM情報参照用 id, name, imei_lock, registerd_date, activated_date, deactivated_date, ipaddress, simgroup_id, carriers, tags, description
sakuracloud_sim_session_up セッション中であれば1 id, name
sakuracloud_sim_current_month_traffic 当月通信量 (unit: Kbps) id, name
sakuracloud_sim_uplink Uplink トラフィック (unit: Kbps) id, name
sakuracloud_sim_downlink Downlink トラフィック (unit: Kbps) id, name

VPCルータ

Metric Description Labels
sakuracloud_vpc_router_info VPCルータ情報参照用 id, name, zone, plan, ha, vrid, vip, ipaddress1, ipaddress2, nw_mask_len, internet_connection, tags, description
sakuracloud_vpc_router_up 起動している場合1 id, name, zone
sakuracloud_vpc_router_session セッション数 id, name, zone
sakuracloud_vpc_router_dhcp_lease DHCPリースの現在の数 id, name, zone
sakuracloud_vpc_router_l2tp_session L2TP/IPsecのセッション数 id, name, zone
sakuracloud_vpc_router_pptp_session PPTPのセッション数 id, name, zone
sakuracloud_vpc_router_s2s_peer_up サイト間VPNのピアとのセッションが確立している場合に1 id, name, zone, peer_address, peer_index
sakuracloud_vpc_router_receive NIC 受信(unit: Kbps) id, name, zone, nic_index, vip, ipaddress1, ipaddress2, nw_mask_len
sakuracloud_vpc_router_send NIC 送信(unit: Kbps) id, name, zone, nic_index, vip, ipaddress1, ipaddress2, nw_mask_len

ゾーン情報

Metric Description Labels
sakuracloud_zone_info ゾーン情報参照用 id, name, description, region_id, region_name

GrafanaのDashboardのVariablesで利用したいために追加したものです。 こんな感じで使ってます。

f:id:febc_yamamoto:20190204170420p:plain

Exporter自身の情報

Metric Description Labels
sakuracloud_exporter_start_time Exporterの起動時間 -
sakuracloud_exporter_build_info Exporterのビルド情報 version, revision, goversion
sakuracloud_exporter_errors_total コレクターごとのエラー数 collector

特にsakuracloud_exporter_errors_totalは重要です。
API呼び出しで予期せぬエラーがあった場合などにこの項目の値が増えていきます。
本番環境で利用する際はこの項目も監視しておき、急激に増えた場合にアラートを出すようにしておいた方が良いでしょう。

実践的な使い方: クーポンの監視

最後に実践的な例としてクーポンの監視を行う例を紹介します。

さくらのクラウドのクーポンはイベントなどでよく配布されており、利用したとこのある方も多いと思います。
このクーポンには利用期限/金額が設定されており、利用期限をすぎたり利用額がクーポンの金額を超過した場合には実際に請求が発生してしまいます。

これを防ぐには以下のようなメトリクスを利用すればOKです。

  • sakuracloud_coupon_remaining_days: クーポン有効期限までの日数
  • sakuracloud_coupon_remaining_discount: クーポンの残高

AlertManagerでこれらの値が閾値を超えた場合にアラートを出したい場合は以下のようにします。

この例では有効期限1週間前、または残高が2000円を下回った場合にアラートをあげるようになっています。

- alert: coupon_expiration
  expr: sakuracloud_coupon_remaining_days <= 7
  labels:
    severity: page
  annotations:
    summary: "クーポン (ID:{{ $labels.id }})はあと{{ $value }}日で有効期限が切れます"
    description: "クーポン (ID:{{ $labels.id }})はあと{{ $value }}日で有効期限が切れます"

- alert: coupon_discount
  expr: sakuracloud_coupon_discount < 2000
  labels:
    severity: page
  annotations:
    summary: "アカウント({{ $labels.member_id}})のクーポン残高が2000円以下になりました。"
    description: "アカウント({{ $labels.member_id}})のクーポン残高が2000円以下になりました。"

終わりに

Prometheusとsakuracloud_exporterを使うことでさくらのクラウドの監視が手軽に行えますね。
便利だと思いますのでぜひご利用ください。

なお使い方がわからないなどの場合は以下のSlackなどに質問を投げてもらえればできる限り回答しますのでこちらもあわせてご利用ください。

slack.usacloud.jp

以上です。

入門 監視 ―モダンなモニタリングのためのデザインパターン

入門 監視 ―モダンなモニタリングのためのデザインパターン

Prometheus: Up & Running: Infrastructure and Application Performance Monitoring

Prometheus: Up & Running: Infrastructure and Application Performance Monitoring

usacloudでクーポン残高を監視してSlackへ通知する

さくらのクラウドで待望のクーポン残高取得APIが公開されましたね!!

cloud-news.sakura.ad.jp

これまではいつのまにか使いすぎてた、とか有効期限が切れてる、なんてこともあったかと思いますが、このAPIを利用すれば残高や有効期限を監視できますのでバッチリですね!!

[UPDATE] スクリプトの誤りを修正しました 2018/1/26 17:10

クーポン残高取得APIの使い方

APIドキュメントはこちらにあります。

developer.sakura.ad.jp

今回はcurlコマンドを使う方法とさくらのクラウド CLI usacloudを使う方法を紹介します。

curlコマンドを使う場合

curlコマンドで直接APIを叩く場合は以下のようにします。

$ TOKEN=APIトークン
$ SECRET=APIシークレット
$ ACCOUNT_ID=アカウントID
$ curl --user "$TOKEN":"$SECRET" \
     https://secure.sakura.ad.jp/cloud/zone/is1a/api/system/1.0/coupon/$ACCOUNT_ID

APIキー(トークン/シークレット)はコントロールパネルのAPIキー画面からコピペでOKです。 アカウントIDはアカウント画面のリソースIDというやつです。

f:id:febc_yamamoto:20190126112504p:plain

レスポンスは以下のようになります。

{
  "AllCount": 1,
  "CountPerPage": 1,
  "Coupons": [
    {
      "AppliedAt": "2019-01-10T11:12:13+09:00",
      "ContractID": "111111111111",
      "CouponID": "xxxxxxxxxxxxxxxx",
      "Discount": 999999,  // クーポン残高
      "MemberID": "abc99999",
      "ServiceClassID": 50122,
      "UntilAt": "2019-03-31T23:59:59+09:00" // クーポン有効期限
    }
  ],
  "Page": 1,
  "is_ok": true
}

あとはこれを加工すれば良いですね。

さくらのクラウド CLI usacloudを使う場合

usacloudにおいてもv0.18からクーポンAPIに対応しました。

github.com

usacloudの場合、アカウントIDは実行時にAPIキーに紐付いたアカウントの情報を参照して設定しますので、APIキーだけ用意すればOKです。

ということで早速試してみます。

今回はこちらのUsacloud Sandboxを利用して実行してみます。

sandbox.usacloud.jp

こちらを開いて適当にウィンドウ内(黒い部分)をクリックするとusacloudが使えるようになります。

まずusacloud configコマンドを実行してAPIキーを入力します。

f:id:febc_yamamoto:20190126113635p:plain

デフォルトゾーン/出力タイプも聞かれますが何も入力しなくてOKです。

その後 usacloud couponコマンドを実行するとクーポン一覧が表示されます。

f:id:febc_yamamoto:20190126113900p:plain

(このアカウントには有効なクーポンが適用されてないためDiscount列が表示されてませんが、本来はDiscount列に残高表示されます。)

出力をJSONにする-o jsonオプションやJSONの加工が行える--queryオプションなどもありますので色々と試してみてください。

定期的にクーポン残高を取得してSlackに通知する

APIを直接叩いたりusacloudコマンドを使うことでクーポン残高の取得ができました。
次にこれを応用して定期的にクーポン残高を取得して、閾値を下回っていた場合にはSlackに通知するようにしてみます。

クーポン残高を取得してSlackに通知するスクリプト

ということでこんなスクリプトにしてみました。

#!/bin/bash

# パラメータ
URL=${SLACK_WEBHOOK_URL}
REMAINING=${COUPON_MIN_REMAINING}

# バリデーション
if [[ -z "${URL}" ]]; then
  echo "SLACK_WEBHOOK_URL is empty. exit(2)"
  exit 2
fi

expr "$REMAINING" + 1 > /dev/null 2>&1
RET=$?
if [[ $RET -gt 1 ]]; then
  echo "COUPON_MIN_REMAINING is not a number. exit(2)"
  exit 2
fi

# クーポン残高取得
DISCOUNT=`usacloud coupon --usable -o json --query 'sum([].Discount)' 2>/dev/null`
if [[ -z "$DISCOUNT" ]]; then
  JSON="{ \"text\": \"さくらのクラウドに有効なクーポンが登録されていません。\" }"
  curl -s -X POST -H 'Content-Type: application/json' -d "$JSON" $URL
  exit 0
fi

expr "$DISCOUNT" + 1 > /dev/null 2>&1
RET=$?
if [[ $RET -gt 1 ]]; then
  echo "'usacloud coupon' command returns invalid value: '${DISCOUNT}'"
  exit 2
fi

# 残高が閾値を下回っているか判定
if [[ "$DISCOUNT" -le "$REMAINING" ]]; then
  # SlackのWebHookを叩く
  JSON="{ \"text\": \"さくらのクラウドのクーポン残高が${DISCOUNT}円になりました。\" }"
  curl -s -X POST -H 'Content-Type: application/json' -d "$JSON" $URL
fi

ポイントはusacloudコマンドを実行してる部分です。 以下のように実行しています。

    usacloud coupon --usable -o json --query 'sum([].Discount)' 

まず--usableオプションをつけることで、残高があり有効期限内のクーポン情報のみ取得するようにしています。 その後-o json--queryでクーポン残高を算出しています。 ここでは単純に各クーポン情報のDiscount列を合計するようにJMESPathでsum([].Discount)と指定しています。

これを適当なファイル名で保存/実行権付与して実行してみます。ここではusacloud-coupon-monitor.shとしました。 SlackのWebhookURLは適当に取得しておきます。

$ export SAKURACLOUD_ACCESS_TOKEN=APIトークン
$ export SAKURACLOUD_ACCESS_TOKEN_SECRET=APIシークレット
$ export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxxx/xxxx/xxxxxxxx" # SlackのWebhookURL
$ export COUPON_MIN_REMAINING=3000 # クーポン残高の閾値

$  ./usacloud-coupon-monitor.sh

これを実行するとSlackに以下のような通知が届くはずです。 (アイコンなどは適当にSlackのWebhook管理画面で編集してます)

クーポンが登録されていない/有効期限が切れた場合:
f:id:febc_yamamoto:20190126115853p:plain

残額が閾値を下回った場合:
f:id:febc_yamamoto:20190126115315p:plain

これでうっかりクーポンの有効期限切れ/使いすぎを防げますね!

あとはこれをcronなりlaunchdなりに登録して毎日実行するようにすればOKです。

終わりに

今回はクーポンAPIを試してみました。

今回のスクリプトでは期限が切れたら or 残額が閾値を下回ったら通知をしていますが、 少し工夫すれば有効期限が残りn日になったら通知、といったこともできると思います。

usacloudではjson以外にもcsvやtsv、Goテンプレートによるカスタム出力にも対応してますのでお好みの方法で色々試してみてください。

以上です。

さくらのクラウド 新プランとプラン移行ツール cloud-plan-migrate

昨年9月にさくらのクラウド 石狩第1ゾーンの新規申し込み受付が再開されました。
それに伴いサーバ/ディスクの新しいプランが提供され、同一性能のプランで比較すると新プランの方が安く提供されるようになりました。

今回はこの新プランを活用すべく、旧プランから新プランへの変更を行うためのツールcloud-plan-migrateを作成しましたのでご紹介いたします。

github.com

石狩第1ゾーンの新規申し込み受付再開

2018/9/27に石狩第1ゾーンでの新規申し込みの受付が再開されました。

www.sakura.ad.jp

これまでは2016/7/1以降に新規作成されたアカウントでは石狩第1ゾーンを利用することができませんでした。

cloud-news.sakura.ad.jp

これが新規申し込み受付が再開されたことにより、アカウントの新旧問わずに石狩第1ゾーンが利用可能となりました。

新規申し込み受付再開と同時に新プランも提供開始

また、新規申し込みの再開と同時にサーバとディスクに新プランが提供されました。
新プランはプラン数が従来の石狩第2/東京第1ゾーンと同等にまで拡充され、同一性能のプランにおいては旧プランよりも低価格になるとのことです。

この新プランについて詳しく追ってみます。

新プランの特徴

新プランについての詳細は以下のさくらのクラウド マニュアルに記載されています。

manual.sakura.ad.jp

これらによると、新プランの特徴として以下のようなものがあるとのことです。

  • 選択できるプランの拡大(東京第1ゾーンとおなじく全94プランに)
  • 同一性能プランにおいて値下げ
  • 以下のディスクサイズが選択可能に
    • SSD 40GB
    • SSD 1TB
    • SSD 2TB
    • SSD 4TB
    • 標準プラン 8TB
    • 標準プラン 12TB

旧プランも継続利用可能(ただし前提条件あり)

また、これまで石狩第1ゾーンでサーバ/ディスクを利用していた場合(2016/7/1以前に作成されたアカウント)、 現在でも旧プランでサーバ/ディスクを作成することが可能です。
現時点でコントロールパネルにて石狩第1ゾーンのサーバ or ディスクの一覧画面を開いたときに、旧プランという表示がされたリソースが1つでもあれば旧プランを継続利用可能になっているはずです。

コントロールパネルでの新旧プラン表示の例:

f:id:febc_yamamoto:20190121100245p:plain

新プランを利用する場合の注意点

注意点として、サーバとディスクを接続する場合はどちらも同じ世代(新/旧)のプランでないといけないという点があります。
例えば、新プランで作成したサーバに旧プランのディスクを接続することはできません。

同一性能プランでの新旧の価格比較

ディスクの価格については新旧プランで違いはないようです。
サーバについては同一性能プラン(コア数/メモリサイズが同一)で比較したところ以下のように新プランの方は全体的に値下げされていました。

新旧プラン価格比較:

コア数 メモリサイズ(GB) 旧プランとの価格差分
1 1 〜 5 ¥-10 〜 ¥-357
2 2 〜 6 ¥0 〜 ¥-648
3 3 〜 12 ¥-810 〜 ¥-2,268
4 4 〜 16 ¥-1,620 〜 ¥-3,564
5 8 〜 24 ¥-2,916 〜 ¥-5,508
6 12 〜 32 ¥-4,212 〜 ¥-7,452
8 16 〜 48 ¥-6,156 〜 ¥-11,340
10 24 〜 64 ¥-8,748 〜 ¥-13,500
12 48 〜 128 ¥-2,700 〜 ¥-14,796

個々のコア数/メモリサイズでの価格比較については以下の画像を参照ください。

f:id:febc_yamamoto:20190118184132p:plain

注: この表/画像は2019/1/18時点で独自に調べたものです。もし誤りなどありましたらコメントください。最新の情報は公式サイトなどを参照ください。

2コア2GBメモリのプランでは新旧で価格の差がないですが、それ以外のプランは全て値下げされています。
特にハイスペックなプランほど値下げ幅が大きいですね。最大で12コア/64GBメモリで¥14,796の値下げです。
また、ここでは月額で比較しましたが、さくらのクラウドでは時間単位/日単位/月単位で課金額が変わります(その時点での最安値となる)。
時間単位/日単位の金額も月額と同じように新プランで値下げされていますので気になる方は比較してみると良いかもしれません。 (旧プランを継続利用している方はあまり時間単位/日単位での利用はしないのではないかという気もしますが)

旧プランから新プランへの移行

前述のマニュアルによると、プラン移行には以下の方法があるようです。

  • コントロールパネル/APIなどでプラン変更を行う(要シャットダウン)
  • 旧サーバをクローンして新サーバを作成する

これ以外にも、自前で新規サーバを作成&プロビジョニングして必要なデータ類をコピーして移行といった方法も考えられますが、 この方法はプラン変更としては本質的にクローンする処理と同じですので説明は割愛します。

それぞれの方法をもう少し詳しくみてみます。

コントロールパネル/APIでプラン変更を行う

さくらのクラウドではサーバのプラン変更を行うためのAPIPUT /server/:serverid/planが提供されています。

このAPIは新プラン提供開始に伴いPlanIDの指定方法が変わりました。
APIのドキュメント: https://developer.sakura.ad.jp/cloud/api/1.1/server/#put_server_serverid_to_plan_planid

APIを利用する際は以下のプラン変更API利用時の注意を参照してください。
プラン変更API利用時の注意: https://manual.sakura.ad.jp/cloud/support/is1a-gen2.html#api

コントロールパネルからプラン変更を行うことでこのAPI経由でプラン変更が行えます。

f:id:febc_yamamoto:20190118184330p:plain

コントロールパネルからサーバのプラン変更を行なった場合、サーバのプランのみが変更されディスクのプランは変更されない点にご注意ください。
前述の通り、新プランのサーバに旧プランのディスクを接続したままの利用はできないため、このままだと起動時に以下のようなエラーが出ます。

f:id:febc_yamamoto:20190118184350p:plain

このため、サーバのプラン変更時にはディスクのプラン変更も合わせて行う必要があります。

ディスクについてはディスクの新規作成時に旧プランのディスクをソースとして選択した上で新プランで作成するという形になります。

f:id:febc_yamamoto:20190118184416p:plain

新プランでのディスクの作成後はサーバに対して旧ディスクの切り離し/新ディスクの接続という作業も必要になりますので忘れないようにしましょう。 また、ディスクソースとした旧プランのディスクは不要になりますので、新旧で2重に課金されないようにこちらも忘れずに削除しましょう。

コントロールパネル/APIでプラン変更を行う際の作業まとめ

ここまでをまとめると、コントロールパネル/APIでプラン変更を行うには以下のような作業が必要ということです。

  • サーバのシャットダウン
  • 旧プランのディスクをコピーして新プランのディスク作成(※1)
  • サーバを新プランに変更
  • 旧プランのディスクをサーバから切り離し(※1)
  • 新プランのディスクをサーバに接続(※1)
  • サーバの起動
  • 旧プランのディスクを削除(※1)

※1: 複数のディスクを接続している場合は各ディスクに対して作業が必要

コントロールパネル/APIでプラン変更を行う際の注意点(特にTerraform関連)

この方法でプラン変更を行う場合、プラン変更後はサーバ/ディスクのIDが変更される点に注意が必要です。

これは特にリソースマネージャーTerraform for さくらのクラウドを利用して構成管理している場合に問題になります。
Terraform for さくらのクラウドでは作成したリソースのIDを状態として保持(terraform.tfstateファイルなど)しておき、それを元にさくらのクラウドAPIを呼び出しています。
IDが変わってしまうとterraform apply時に処理対象のリソースが見つからないということでリソースの新規作成を行おうとしてしまいます。
これを防ぐにはterraform.tfstateファイルの編集といった作業が必要になります。

Terraformをご利用中の場合は対応作業が発生する可能性を考慮しておいてください。 (不安な方はさくらのクラウドユーザーコミュニティ向けのSlackワークスペースなどでご相談ください)

旧サーバをクローンして新サーバを作成する

旧ディスクをコピーして新プランのディスクを作成、新たに作成したサーバと接続することでプラン移行する方法です。
これを行うために、コントロールパネルにて クローン機能 が提供されています。

manual.sakura.ad.jp

クローン機能を用いることでサーバ/ディスクを同時に新プランへ移行することが可能です。
(なお、さくらのクラウド CLIであるusacloudではクローン機能に該当する機能は提供しておりません…クローン機能はコンパネが提供している便利機能なんですよね)

ただし、クローン機能を利用する場合、以下の点に注意が必要です。

  • サーバは新規作成されるため、共有セグメントを利用してグローバルIPを割り当てている場合にグローバルIPが変更される
  • 追加NICや2つ目以降のディスクのコピーは行われない

プラン変更APIの場合は共有セグメント利用時に割り当てられたグローバルIPを保持したままプラン変更できますが、クローンの場合はサーバの新規作成となるためグローバルIPが変更されます。
スイッチ+ルータ(固定のIPアドレスブロックを確保するサービス)を利用している場合などは問題ないと思いますが、そうでない場合は注意が必要です。

また、追加NICや2つ目以降のディスクについても個別に対応が必要になります。

移行方法まとめ

それぞれの方法の特徴や注意点をまとめると以下のようになります。

移行方法 特徴 注意点
プラン変更API コンパネなどからプラン変更用のAPIを利用する - あらかじめサーバのシャットダウンが必要
- サーバ/ディスクで個別に作業が必要
- プラン変更後はサーバのIDが変わる
クローン機能 旧ディスクをコピーして新規作成したサーバに接続する - サーバのグローバルIPが変更される場合がある
- 追加NIC/追加ディスクがある場合は個別に作業が必要

旧プランから新プランに移行すべきか?

今の所は旧プランも(旧プランのリソースが残ってる限りは)継続して利用可能ですのですぐに移行する必要はないと思います。
しかし、新プランでは全体的に値引きされており、継続的に利用するサーバであれば新プランへ移行してしまった方がおトクです。

移行にはサーバの停止や移行作業(これらに伴う準備/検証などの作業も)が必要となりますので、それらの工数も考慮して移行すべきか決定すると良いでしょう。

このため基本的な方針としては、

  • 一時的に止めても良いサーバであればプラン変更APIで移行する
  • サーバを止められない場合は個別に検討する

といった形になるとおもいます。

移行する決定をした場合、出来るだけ速やかに移行した方が料金的におトクですのであまり手間をかけずサッと作業してしまいたいところですね。

プラン移行ツール cloud-plan-migrate

ということでやっと本題です。
前述の通り、プラン変更APIを利用するには結構手間がかかる & クローン機能を使うとグローバルIPが変わる、追加NIC/ディスクは個別に対応が必要、とどちらを選んでも結構手間がかかります。 1〜2台であれば手作業でも良いですが、それ以上、場合によっては数10〜数100台にもなった場合に手作業を行うのは大変です。

個別にAPIを叩くスクリプトを組んでも良いですが、今回限りのソリューションとなるため作り込むことをためらう方も多いと思います。

そこで、さくらのクラウド関連のOSSを集めたsacloudオーガニゼーション配下にcloud-plan-migrateというツールを公開しておきました。

github.com

cloud-plan-migrateについて

Go言語で書かれたCLIツール

cloud-plan-migrateはGo言語で書かれた、プラン変更に特化したCLIツールです。
シングルバイナリでインストールは実行ファイルをダウンロードするだけ、さらにWindows/Linux/macOSなどの各種プラットフォームをサポートしています。

処理の流れ

cloud-plan-migrateは前述のプラン変更APIを用いる方式を採用しています。
具体的にはさくらのクラウドAPIを用いて以下のような処理を行います。

  • サーバのシャットダウン
  • サーバに接続されたディスクをコピーして新プランのディスクを作成
  • サーバに接続されたディスクの切り離し
  • サーバのプラン変更
  • 新プランのサーバに新プランのディスクを接続
  • サーバの起動(オプションで無効化できる)
  • 旧プランのディスクの削除(デフォルトで無効、オプションで有効化できる)

複数台のサーバを一気に処理することができるようになっており、 最大で同時に10サーバ分の処理を平行で行うようになっています。 (処理対象は10サーバ以上を指定可能です。)

プラン変更APIを利用しますので、以下の点は注意が必要です。

  • 処理中はサーバがシャットダウンされる
  • プラン変更後はサーバのIDが変更になる

その代わりにグローバルIPは保持したままとなりますので、プラン変更後にサーバ起動を起動した後はプラン変更前と変わらずご利用いただけるようになっています。
停止時間が許容できる、かつ複数台を一括でプラン変更したい場合などでご利用いただけるかと思います。

インストール

以下のGitHubリリースページから各プラットフォーム向けのバイナリをダウンロードするだけです。

github.com

使い方

実行時にさくらのクラウドAPIキー(トークンとシークレット)が必要です。
APIキーには作成・削除権限が必要となりますので忘れずに権限を設定しておいてください。

APIキーが準備できたら以下のように実行します。

$ cloud-plan-migrate <オプション> <対象サーバのID or 名称>

実行すると以下のようにAPIキーの入力が求められますので用意しておいたAPIキーを入力してください。

$ cloud-plan-migrate <ID or 名称>

Your API AccessToken is not set
    Enter your token: <トークンを入力>
Your API AccessTokenSecret is not set
    Eneter your secret: <シークレットを入力>

実行中は以下のようにサーバ/ディスクごとに処理状況が表示されます。

f:id:febc_yamamoto:20190118185115p:plain

ディスクのコピー処理に時間がかかりますが、それ以外は数秒〜数10秒で終わるはずです。
ディスクのコピー処理はディスクサイズやクラウドAPI側の負荷状況にもよりますが数時間かかることもあります。

参考までに、コントロールパネルのディスクコピーを行う画面には 【完了までの目安時間】2TB: 約6時間, 4TB: 約12時間と書かれています。
実行するタイミングでも結構上下していた感触です(私の手元のマシンで実行した際は20GBのディスクで2〜3分しかかからなかったこともありました。)。
実際に本番環境で実行する際はあらかじめ数回テスト用のサーバなどで試してどれくらいの時間がかかるか試しておくことをお勧めします。

(オプション) 環境変数でのAPIキーの指定

APIキーはコマンド実行時に対話入力する方法以外に、コマンドラインオプションで渡す or 環境変数で指定する方法もあります。

環境変数で指定する場合は以下のようにします。 (usacloudやTerraform/Packer for さくらのクラウドなどと共通の環境変数です)

$ export SAKURACLOUD_ACCESS_TOKEN="APIトークン"
$ export SAKURACLOUD_ACCESS_TOKEN_SECRET="APIシークレット"

パラメータ/オプションについて

コマンドの引数としてプラン変更対象サーバのIDまたは名称を指定します。
名称を指定した場合、部分一致する全ての旧プランサーバが対象となります。

また、ID/名称以外にも--selectorオプションでサーバにつけられたタグを用いて対象を指定可能です。
例えば以下のようにした場合、app=webというタグを持つサーバのみ対象とできます。

なおサーバの名称を指定する場合と異なり、完全一致するタグを持つサーバのみが対象となる点に注意してください。

$ cloud-plan-migrate --selector "app=web"

その他のオプションは以下のものが指定可能です。

APIキー関連

  • --token: [必須] APIキー(トークン)、環境変数 SAKURACLOUD_ACCESS_TOKENでも指定可能です。
  • --secret: [必須] APIキー(シークレット)、環境変数 SAKURACLOUD_ACCESS_TOKEN_SECRETでも指定可能です。

これらを省略した場合、実行時に入力を促すダイアログが表示されます。

マイグレーションの動作関連

  • --selector: 対象サーバをタグで指定する
  • --disable-reboot: プラン変更後にサーバの起動を行わない
  • --cleanup-disk: プラン変更後に旧ディスクを削除する

その他

  • --assumeyes/-y: 実行前の確認を省略する

コマンド実行のログ出力

コマンドを実行するとカレントディレクトリにmigrate-[日付].logというファイル名でログ出力されます。
エラー発生時のトラブルシューティングなどにご利用ください。

エラー時の挙動について

API呼び出しでエラーが発生した場合、エラーが発生した対象のサーバの処理はスキップされます。 それ以外のサーバについては処理が続行されます。

Dockerでの実行

Docker向けのイメージも用意しています。
以下のようにすることでDockerを用いてcloud-plan-migrateを実行できます。

# カレントディレクトリにログ出力されるため-vオプションを指定
$ docker run -it --rm -v $PWD:/work sacloud/cloud-plan-migrate <ID or 名称>

まとめ

今回は石狩第1ゾーンでの新プランについてと旧プランからの移行ツールcloud-plan-migrateを紹介しました。
複数台のサーバ/ディスクのプラン変更を行う際に便利だと思いますのでぜひご活用ください。

皆様のお役に立てば幸いです。

もしプラン変更作業にお悩みの際はユーザーコミュニティ向けのSlackワークスペースでQAなどを行なっておりますので是非ご活用ください。 以下のURLから参加できます。

https://slack.usacloud.jp/

以上です。

external-dnsをさくらのクラウドで使う

kubernetes-incubator/external-dnsって何?

KubernetesでServiceやIngressなどの作成/更新を検知してDNSレコードを動的に設定してくれるexternal-dnsというプロダクトがkubernetes-incubator配下にあります。

github.com

例えば以下のようなIngressを作成するとnginx.example.orgというホスト名に対応するAレコードを作成してくれます。

kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: nginx.example.org
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

external-dnsの特徴的な点として、データソース(ServiceやIngressなど)とレコード作成先(プロバイダーと呼ばれている)が分離されており、 それぞれを任意の組み合わせで利用することが可能という点があります。 これにより様々なプラットフォームを統一的な手段でサポートできるようになっています。

データソースとしてはService/Ingressだけでなく、istio-gateway独自のCRD(Custom Resource Definitions)などがあり、 レコードの作成先については以下のような様々なプラットフォームがサポートされています。

external-dns v0.5時点で対応しているプロバイダー

これがさくらのクラウドに対応していませんでしたので今回forkして対応してみました。

github.com

当記事ではさくらのクラウドでのexternal-dnsの使い方について紹介します。
(なお今の所はupstreamへのマージは考えてません。使いたいという方が増えたら考えます。)

external-dnsさくらのクラウドで使う

準備作業

まずはKubernetesクラスターの準備やさくらのクラウドDNSに管理対象のゾーンを登録しておく必要があります。

KubernetesクラスターについてはRancher2セットアップというスタートアップスクリプトが提供されていますのでそちらを利用して準備しておきます。

以下の記事などが参考になるかと思います。

febc-yamamoto.hatenablog.jp

qiita.com

また、さくらのクラウドへのDNSゾーン登録も必要です。
こちらは以下のスライドなどが参考になるかと思います。

www.slideshare.net

sacloud/external-dnsのデプロイ

準備が出来たらexternal-dnsをデプロイします。

manifestは以下のようになります。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions"] 
  resources: ["ingresses"] 
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: default
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: sacloud/external-dns:latest
        args:
        - --source=service 
        - --source=ingress
        - --domain-filter=example.com # (optional, but we highly recommended to set this) limit to only example.com domains; change to match the zone created above.
        - --provider=sakuracloud
        env:
        - name: SAKURACLOUD_ACCESS_TOKEN
          value: "YOUR_API_KEY"
        - name: SAKURACLOUD_ACCESS_TOKEN_SECRET
          value: "YOUR_API_SECRET"

上の方がRBACの設定、Deploymentのcontainersの部分がexternal-dnsのコンテナの定義となっています。

RBACを使わない場合については以下のドキュメントを参照してください
external-dns/sakuracloud.md at master · sacloud/external-dns · GitHub

external-dnsのコンテナ定義部分だけ抜粋

      containers:
      - name: external-dns
        image: sacloud/external-dns:latest
        args:
        - --source=service 
        - --source=ingress
        - --domain-filter=example.com # (optional, but we highly recommended to set this) limit to only example.com domains; change to match the zone created above.
        - --provider=sakuracloud
        env:
        - name: SAKURACLOUD_ACCESS_TOKEN
          value: "YOUR_API_KEY"
        - name: SAKURACLOUD_ACCESS_TOKEN_SECRET
          value: "YOUR_API_SECRET"

以下の部分は各自で任意の値を設定してください。

この例では以下のような指定を行なっています。

動作確認

動作確認のためnginxコンテナをデプロイし、Ingressで外部からアクセスできるようにします。

まずはPodとServiceをデプロイします。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

続いてIngressをデプロイします。
ここではFQDNとしてexternal-dns.example.comを指定しています。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-example
  namespace: default
spec:
  rules:
  - host: external-dns.example.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

しばらく待つと対象のゾーンにAレコードとTXTレコードが追加されているのがコントロールパネルなどで確認できます。 後は指定したFQDNに対してアクセスするとNGINXのデフォルトページが表示されるはずです。

後片付け

Ingressを削除すると対応するDNSレコードも削除されるようになっています。
(この動作はexternal-dnsのオプション--policyにデフォルトでsyncが指定されているためです)

終わりに

external-dnsを利用することでKubernetes側の操作だけでDNSレコードの登録/変更/破棄が行えます。
頻繁にアプリケーションのデプロイ/DNSレコードの更新を行うけど、 さくらのクラウドのコントロールパネル/APIヘのアクセスは集中管理したい/触れる人を限定したい、といった場合などで便利だと思います。

ぜひご利用ください。

以上です。