さくらのクラウド + Container Linuxでのプロビジョニング
さくらのクラウドでContainer Linuxを使う場合、プロビジョニングをどうするかは悩みどころです。
さくらのクラウドではプロビジョニングのための仕組みとしてスタートアップスクリプトは用意されているものの、Container Linuxでは利用できないという制限があります。
参考 スタートアップスクリプトは以下のOSに対応しています。
- CentOS
- Debian
- Ubuntu
- FreeBSD
- RancherOS
- VyOS
スタートアップスクリプト以外でプロビジョニングするには?
スタートアップスクリプト以外でプロビジョニングする方法としては以下のようなものが挙げられます。
- Ansibleなどのプロビジョニングツールを利用してサーバ起動後にSSHで操作
- ISOイメージ機能を利用してConfigDrive経由でcloud-configを流し込む
- PXEブート環境を構築しIgnitionを使う
2番目のISOイメージでConfigDriveを使う方法についてはこちらの記事が詳しいです。
3番目の方法は、前回紹介したcybozuさんのsabakanやCoreOS社の提供するMatchboxを使ってDHCPサーバやIgnitionファイルの管理/配布などを行う環境を作るというもので、導入/運用の敷居が少し高めとなっています。
参考: sabakanの紹介記事
もうちょっと楽にPXEブート+Ignitionの管理ができないか、、、
ということで今回の本題の「terraform-sakuracloud-matchbox」というモジュールを公開しました。
Terraform + Matchbox + さくらのクラウド = terraform-sakuracloud-matchbox
terraform-sakuracloud-matchbox
はMatchboxを手軽に導入するためのTerraformモジュールです。
以下のような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の起動/インストール用イメージなどのアセットの提供
このモジュールはMatchboxサーバを提供するのみで、接続するスイッチ(VPC)やPXEブートするサーバなどは別途用意する必要があります。
また、Matchbox自体への設定の投入(IgnitionやMetadataなど)も別途用意する必要があります。
次にこのモジュールを使って実際にPXEブートしてContainerLinuxをブート/ディスクへのインストールまでを行ってみます。
terraform-sakuracloud-matchbox
でContainerLinuxの起動/プロビジョニングまで
実際にどうやって使うのかをみていきます。
準備
以下のものが必要になります。あらかじめ準備しておいてください。
さくらのクラウド/Matchbox向けのTerraformプロバイダーはCommunity ProviderでTerraform本体とは別で配布されており個別にインストールが必要です。
それぞれの最新版をGitHubからダウンロードし、~/.terraform.d/plugins/
配下などに配置しておいてください。
詳細は以下のドキュメントを参照してください。
さくらのクラウドAPIキーは環境変数などに設定しておいてください。
なお、今回は簡便のためモジュールわけなどせずに同じディレクトリ内に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つです。
本来はディスクの作成時にコピー元アーカイブの指定やサーバへの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などを用いて クライアントとプロファイルを結びつけるものです。
と言ってもよくわからないですよね。実物を見るのが早いと思います。
まず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
バージョンをプリフェッチします。
alpha
やbeta
も利用可能です。
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を用いたワークフローにも適合しやすいと思います。
ぜひ使ってみてください。
以上です。