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の仕組みはこちらにコメントされているように将来的に大きく変わる可能性もある点は注意しておいてください。
(利用する側としてはあまり関係ないかもしれませんが)
以上です。
Rioにビルトインされているサービスを確認する - GrafanaとKiali
前回はRioでGitリポジトリを指定してのRunを試してみました。
rio run
の引数としてGitリポジトリを指定するだけでリポジトリの変更検知〜イメージのビルド〜公開という仕組みが利用できました。
今回はそれらを実現している、Rioにビルドインされているサービスを確認していきます。
なお、今回はこちらのTerraformモジュールを使ってさくらのクラウド+RKEクラスタ上にRioをインストールしました。
Rioでどのようなサービスが動いているか確認する。
RioはKubernetes上にデプロイされるため、kubectl
などでワークロードを確認(例えばkubectl get pod -n rio-system
を実行)することでどのようなサービスが動いているか調べることができます。
が、より簡単に確認できるコマンドrio --system ps
が提供されていますので今回はこちらを利用します。
(なお、この--system
オプションは省略形(-s
)も利用可能です。またrio logs
などにも対応しています。)
ということで早速確認してみます。
rio --system ps
の実行
実行結果は以下の通りでした。
$ rio --system ps NAME CREATED ENDPOINT REVISIONS SCALE WEIGHT DETAIL rio-system/autoscaler 3 minutes ago v0 1 100% rio-system/build-controller 2 minutes ago v0 1 100% rio-system/buildkit 3 minutes ago v0 1 100% rio-system/cert-manager 2 minutes ago v0 1 100% rio-system/grafana 2 minutes ago https://grafana-rio-system.6y9oo6.on-rio.io:9443 v0 1 100% rio-system/istio-citadel 2 minutes ago v0 1 100% rio-system/istio-gateway 2 minutes ago v0 1 100% rio-system/istio-pilot 2 minutes ago v0 1 100% rio-system/istio-telemetry 2 minutes ago v0 1 100% rio-system/kiali 2 minutes ago https://kiali-rio-system.6y9oo6.on-rio.io:9443 v0 1 100% rio-system/prometheus 3 minutes ago v0 1 100% rio-system/registry 2 minutes ago https://registry-rio-system.6y9oo6.on-rio.io:9443 v0 1 100% rio-system/webhook 2 minutes ago https://webhook-rio-system.6y9oo6.on-rio.io:9443 v0 1 100%
ENDPOINTにURLが表示されているものがありますね。
Grafana
まずは試しにgrafanaのENDPOINTをブラウザで開いてみます。
お、grafanaのダッシュボードが表示されましたね。
Istio関連のダッシュボードがありますね。
いい感じです。
kiali
kialiはIstio向けの可視化ツールです。
これもENDPOINTをブラウザで開いてみます。
これも表示できましたね。早速ログインしてみましょう。
ユーザー名/パスワードともadmin
でログインできます。
いい感じですね。
その他のENDPOINT
他にはイメージレジストリとWebhookにENDPOINTが表示されてますね。 レジストリは試したらイメージのpushなどもできました。
# 適当なイメージをビルド $ docker image build -t registry-rio-system.6y9oo6.on-rio.io:9443/test . # pushしてみる $ docker push registry-rio-system.6y9oo6.on-rio.io:9443/test
Webhookは試そうとしたのですが疲れちゃったのでまた今度。
終わりに
今回はここまで。以上です。
sakura-cloud-controller-managerのデプロイ&トラブルシューティング
さくらのクラウドでKubernetesを利用する場合、マネージドなLBなどを扱うためのcloud-controller-manager実装として sakura-cloud-controller-managerというものがあります。
こちらのデプロイでよく引っかかる点やトラブルシューティング方法についてメモを発掘したので整理がてら残しておきます。
さくらのクラウド上のリソースの構成
Kubernetesクラスタで利用するさくらのクラウド上のリソースの構成は以下の点に注意が必要です。
- ネットワーク構成
- スイッチ(ルータ)への
@k8s
タグ設定
ネットワーク構成
sakura-cloud-controller-managerはサーバをスイッチ+ルータ or スイッチに接続する必要があります。
共有セグメント(共有回線)はサポートしていませんので注意してください。
スイッチ(ルータ)への@k8s
タグ設定
sakura-cloud-controller-managerはさくらのクラウドAPIで取得したスイッチ(ルータ)の情報を元にどのスイッチを利用するかを決定します。
その際に@k8s
タグの付けられたリソースかで判定を行なっています。
タグの付け忘れにご注意ください。
クラスタの構成
次にKubernetesクラスタの構成についてですが、以下2点に注意する必要があります。
順番にみていきます。
--cloud-provider
オプションを適切に指定すること
Kubernetesでexternalなcloud-controller-managerを起動するには--cloud-provider
オプションを適切に指定する必要があります。
参考: Kubernetes Cloud Controller Manager - Kubernetes
具体的には以下2点です。
- kubeletのパラメータとして
--cloud-provider=external
を指定しておくこと - kube-apiserverとkube-controller-managerには
--cloud-provider
を指定しないこと
kubeadmを利用してクラスタのデプロイを行う場合は/var/lib/kubelet/kubeadm-flags.env
ファイルや/etc/default/kubelet
ファイルなどで適切に指定しましょう。
参考: Installing kubeadm - Kubernetes
Nodeに付与されるtaintsへの対応
先ほどの参考ドキュメントに書いてありますが、kubeletに--cloud-provider=external
を指定するとノードに対し以下のようなtaintsが設定されます。
- apiVersion: v1 kind: Node spec: taints: - effect: NoSchedule key: node.cloudprovider.kubernetes.io/uninitialized value: "true"
sakura-cloud-controller-managerをデプロイする際はこのtaintsに対するtolerationsが適切に設定されている必要があります。
# tolerationsの設定例 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sakura-cloud-controller-manager namespace: kube-system spec: replicas: 1 template: spec: containers: - name: sakura-cloud-controller-manager image: "sacloud/sakura-cloud-controller-manager:0.3.0" tolerations: # tolerationsを設定しておく - key: node.cloudprovider.kubernetes.io/uninitialized value: "true" effect: NoSchedule
もしkubeletに--cloud-provider
を指定しなかったらどうなるの?
この場合でもsakura-cloud-controller-managerのデプロイ自体はうまくいくように見えます。
が、ノードのExternalIPが適切に設定されないため、type: LoadBalancer
なサービスを作ってもロードバランサが作成されるものの実サーバが登録されないという状態になります。
serviceは作成されるけど、、、
実サーバは登録されていない
クラスタ内のノード名とさくらのクラウド上でのサーバ名が一致していること
これはsakura-cloud-controller-manager側の制約です。
sakura-cloud-controller-managerではノード名を条件にさくらのクラウドAPIで対象サーバの情報を取得しています。
このため、ノード名とサーバ名が異なるとうまくいきません。
kubeletの--hostname-override
オプションなどで適切に設定しましょう。
(kubeadmの場合は--node-name
フラグが利用できます。 参考: kubeadm init - Kubernetes)
もしノード名とサーバ名が違うとどうなるの?
sakura-cloud-controller-managerでのノード情報の取得が行えず、ノードのtaintsが残り続けます。
このためPodを起動しようとしてもPendingのままとなります。
(まずkube-dnsなどの主要コンポーネントについてもPendingのままとなっているはずです。)
# Podを起動しようとしてもPendingのまま $ kubectl get pod NAME READY STATUS RESTARTS AGE nginx-7cdbd8cdc9-8g8mw 0/1 Pending 0 3m1s # 主要コンポーネントもPendingのまま $ kubectl get pod -n kube-system --selector k8s-app=kube-dns NAME READY STATUS RESTARTS AGE kube-dns-58bd5b8dd7-swrlg 0/3 Pending 0 7m39s
さらにこの状態だとノードのInternalIP/ExternalIPが設定されず、kubectl logs
を実行するとError from server: no preferred addresses found; known addresses: []
などというエラーになります。
sakura-cloud-controller-managerのデプロイ
DeploymentまたはDaemonSetとしてデプロイしてください。
(現在Helmでデプロイする場合はDaemonSetのみサポートしています)
Deploymentとする場合のマニフェスト例は以下の通りです。 (この例はRKEを使ってデプロイしたKubernetesクラスタを利用しています。tolerationsやnodeSelectorsは環境に応じて適切に指定してください)
apiVersion: v1 kind: Secret metadata: name: sakuracloud-api-keys namespace: kube-system type: Opaque data: access-token: "<APIアクセストークン>" access-token-secret: "<APIアクセスシークレット>" --- --- apiVersion: v1 kind: ServiceAccount metadata: name: sakura-cloud-controller-manager namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" name: system:sakura-cloud-controller-manager rules: - apiGroups: - "" resources: - events verbs: - create - patch - update - apiGroups: - "" resources: - nodes verbs: - '*' - apiGroups: - "" resources: - nodes/status verbs: - patch - apiGroups: - "" resources: - services verbs: - list - patch - update - watch - apiGroups: - "" resources: - services/status verbs: - list - patch - update - watch - apiGroups: - "" resources: - serviceaccounts verbs: - create - apiGroups: - "" resources: - persistentvolumes verbs: - get - list - update - watch - apiGroups: - "" resources: - configmaps verbs: - get - list - watch - apiGroups: - "" resources: - endpoints verbs: - create - get - list - watch - update --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: system:sakura-cloud-controller-manager roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:sakura-cloud-controller-manager subjects: - kind: ServiceAccount name: sakura-cloud-controller-manager namespace: kube-system --- apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: k8s-app: cloud-controller-manager name: sakura-cloud-controller-manager namespace: kube-system spec: replicas: 1 selector: matchLabels: k8s-app: cloud-controller-manager template: metadata: labels: k8s-app: cloud-controller-manager spec: dnsPolicy: Default hostNetwork: true serviceAccountName: sakura-cloud-controller-manager containers: - name: sakura-cloud-controller-manager image: "sacloud/sakura-cloud-controller-manager:0.3.0" resources: requests: cpu: 100m memory: 128Mi limits: cpu: 256m memory: 256Mi command: - /usr/local/bin/sakura-cloud-controller-manager - --cloud-provider=sakuracloud - --allocate-node-cidrs=false - --configure-cloud-routes=false env: - name: SAKURACLOUD_ACCESS_TOKEN valueFrom: secretKeyRef: name: sakuracloud-api-keys key: access-token - name: SAKURACLOUD_ACCESS_TOKEN_SECRET valueFrom: secretKeyRef: name: sakuracloud-api-keys key: access-token-secret - name: SAKURACLOUD_ZONE value: "<対象ゾーン(is1a or is1b or tk1a)>" - name: SAKURACLOUD_CLUSTER_ID value: "default" tolerations: - key: node.cloudprovider.kubernetes.io/uninitialized value: "true" effect: NoSchedule - key: "CriticalAddonsOnly" operator: "Exists" nodeSelector: node-role.kubernetes.io/controlplane: "true"
実行時によくあるトラブル
よくあるトラブルとして、Serviceを作成してもいつまでもPendingのままというものがあります。
この場合、sakura-cloud-controller-managerのログを参照すると何かヒントが得られることがあります。
# ログの参照例 $ kubectl logs -f -n kube-system sakura-cloud-controller-managerのpod名
私も引っかかったことがあるのは次のようなエラーメッセージが出るケースです。
Improper request. The parameters of the specified error or input rule violation. Please check your entries.\n実サーバのIPアドレス(xxx.xxx.xxx.xxx)は同一ネットワークである必要があります
このケースは@k8s
タグのついたスイッチ+ルータが複数存在している場合に発生します。
複数のスイッチ+ルータを使い分けたい場合はそれぞれのスイッチに対し識別用のタグを付与した上でk8s.usacloud.jp/router-selector
アノテーションをServiceに対して指定するようにすればOKです。
おまけ: RKEでデプロイするTerraformモジュール
こちらにTerraformのさくらのクラウドプロバイダー+RKEプロバイダーでクラスタ構築やsakura-cloud-controller-managerのデプロイまで行うモジュールを置いておきます。
以上です。
k3OSのISOイメージがさくらのクラウドに追加された
さくらのクラウドのパブリックISOイメージにk3OSが追加されましたね!
前回の記事ではk3OSのISOイメージをダウンロード&アップロードして試しました。
これが本日パブリックISOイメージが追加されたことでISOイメージのダウンロード/アップロードが不要となりより簡単にk3OSを試せるようになりました。
パブリックISOイメージから起動してみる(ディスクレス)
前回はCLIを利用した方法を紹介しましたので、今回はコントロールパネルからの操作を紹介します。
前回はディスクにインストールする手順でしたが、今回はディスクレスでISOイメージから起動してそのまま使う方法にしてみました。
(ディスクを作成しない分お安くなっています)
コントロールパネルからサーバの追加
まずコントロールパネルからサーバ追加画面へ移動します。
サーバ追加画面ではシンプルモード
のチェックを外すのがポイントです。
(サーバ作成時にISOイメージを挿入するには非シンプルモードである必要があります)
その後、ディスクレス
を選択した上で挿入するISOイメージとしてk3OS v0.2.0 amd64
を選択します。
もしディスクを接続したい場合は新規ディスクを作成
を選択し、ディスクソースにブランク
を指定すればISOイメージ選択欄が出てきます。
次のNICの設定はデフォルトのインターネットに接続
を選択しておきます。
これは共有セグメント(共有回線)経由でインターネット接続を行うという指定です。 共有セグメントではDHCPによるグローバルIPの割り当てが利用可能となっています。
なお、k3OSのドキュメントによると、サーバのコア数/メモリはデフォルトの1コア/1GBで大丈夫なようです。
Live install (boot from ISO) requires at least 1GB of RAM.
GitHub - rancher/k3os: Purpose built OS for Kubernetes, fully managed by Kubernetes.
しかし1GBメモリだとイメージのpullなどでエラーになる場合があったため手元の環境ではメモリ2GBで試しました。 (他の要因もあるかもしれませんが調べてません)
参考: CLIでサーバ作成する場合
CLIの場合は以下のコマンドでOKです。
$ usacloud server build --name k3os --disk-mode diskless --iso-image-id `usacloud iso-image read -q k3OS` --memory 2
起動してコンソール接続
サーバを作成&起動後、コントロールパネルからコンソールを開きます。
後は前回と同じくユーザー名rancher
(パスワードなし)でログイン可能です。
ログイン後の設定
SSH
このまま試しても良いのですが、コンソール接続だとコピペができない(ペーストはコンパネ経由でできる)など色々不便なのでSSH接続できるようにします。
今回はGitHubからユーザーの公開鍵を取得して利用します。
以下のコマンドをコンソールで実行します。ユーザー名部分は任意のものに変更してください。
# GitHubのユーザー名が"yamamoto-febc"の場合 $ curl -L -o /home/rancher/.ssh/authorized_keys https://github.com/yamamoto-febc.keys $ chmod 0600 /home/rancher/.ssh/authorized_keys
なお、コンソール接続している時点ではキーボードがUS配列になっていると思います。 普段US配列以外をお使いの場合は記号の入力の際にご注意ください。
この後SSHで接続できるようになっているはずです。
$ ssh rancher@サーバのグローバルIPアドレス
なお公開鍵を用意するのが面倒な方は以下のコマンドでrancherユーザーにパスワードを設定する方法もあります。
$ sudo passwd rancher
/etc/hosts
/etc/hostsを編集し自身のホスト名を解決できるようにします。
ホスト名はhostname
コマンドなどで、IPアドレスはip a show dev eth0
コマンドなどで確認しておきます。
今回は/etc/hostsを以下のようにしました。
127.0.0.1 localhost localhost.localdomain 127.0.1.1 k3os-14500 k3os-14500.localdomain ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters # これを追記(IPアドレス/ホスト名は適宜修正) 153.120.168.44 sv-113100883194
これでひとまず利用できる環境が整いました。 後は色々動かしてみましょう。
終わりに
ISOイメージを用意してくれてるのは楽ですね。 とりあえず雰囲気を確認したいというような場合に手軽に使えて良いと思います。
以上です。
RioでGitHubリポジトリからのRunを試す
新しくなったRio
KubeCon EUにあわせ新しくなったRioがアナウンスされました。
Rio自体は以前からOSSとして公開されていましたが、今回はRancher Labsからのリリースアナウンスもありある程度開発に区切りがついたということなのでしょう。
公式サイトもできてました。
今回は新しくなったRioを軽く触ってみました。
なおRioについては以前ブログ書いてますのでこちらもご一読ください。
事前準備
Kubernetesクラスタ
以前のRioはスタンドアロンという、embeddedなk8sクラスタ(後のk3s)を起動してくれるモードがありましたが、 新しいRioではk8sクラスタはあらかじめ準備しておく必要があります。
お好みのクラスタを用意しておきましょう。
k3sやDocker for Mac(のk8s)、minikubeもOKですし、GKE/AKS/EKSももちろんOKとのことです。 なおk8s v1.13以降が必要とのことですのでバージョンには注意しておいてください。
rio
コマンドのインストール
フロントエンドとなるコマンドrio
をインストールしておきます。
以下のコマンドでOKです。
$ curl -sfL https://get.rio.io | sh -
上記コマンドで実行されるシェルスクリプトの確認がめんどくさい場合はGitHubのReleaseページから直接バイナリをダウンロードしてもOKです。
Releases · rancher/rio · GitHub
Rioのセットアップ
各種コンポーネントのデプロイ
まずはRioの各種コンポーネントをk8sクラスタ上にデプロイします。
rio install
コマンドを実行することでrio-system
というnamespaceにデプロイされます。
$ rio install Creating namespace rio-system Defaulting cluster CIDR to 10.43.0.1/16 Deploying Rio control plane.... Waiting for rio controller to initialize Waiting for rio controller to initialize Waiting for rio controller to initialize Waiting for rio controller to initialize Waiting for rio controller to initialize Waiting for rio controller to initialize Waiting for rio controller to initialize Waiting for all the system components to be up. Not ready component: [autoscaler build-controller buildkit cert-manager grafana istio-citadel istio-pilot istio-telemetry kiali prometheus registry webhook] Waiting for all the system components to be up. Not ready component: [autoscaler build-controller buildkit cert-manager grafana istio-citadel istio-pilot istio-telemetry kiali prometheus registry webhook] Waiting for all the system components to be up. Not ready component: [autoscaler buildkit cert-manager grafana istio-citadel istio-pilot istio-telemetry kiali webhook] Waiting for all the system components to be up. Not ready component: [cert-manager grafana istio-pilot kiali] Waiting for service loadbalancer to be up Waiting for service loadbalancer to be up Waiting for service loadbalancer to be up Waiting for service loadbalancer to be up rio controller version v0.1.1-rc3 (2771703b) installed into namespace rio-system Please make sure all the system pods are actually running. Run `kubectl get po -n rio-system` to get more detail. Controller logs are available from `rio systemlogs` Welcome to Rio! Run `rio run https://github.com/rancher/rio-demo` as an example
なお、ここでtype=LoadBalancer
なserviceが使えない場合はこのまま待つかHostPortsを使うか聞かれます。
コードを見るとそのほかにも分岐するパターンが結構あるようですね。
環境に合わせ適宜回答しましょう。
デプロイされたか確認
rio install
が完了したらkubectl get pod -n rio-system
で確認してみます。
$ kubectl get pod -n rio-system NAME READY STATUS RESTARTS AGE autoscaler-696866b8f7-9fbcq 1/1 Running 0 9m11s build-controller-94b48b58f-m5kgw 2/2 Running 0 8m38s buildkit-7f46884f98-qkjv9 2/2 Running 0 9m6s cert-manager-57b4f876c5-hnxq6 1/1 Running 0 8m43s grafana-68c6d8494d-rt9gg 2/2 Running 0 9m6s istio-citadel-d76685f74-kczqs 1/1 Running 0 9m3s istio-gateway-4ssl5 2/2 Running 0 8m57s istio-gateway-872gl 2/2 Running 0 8m57s istio-gateway-979xb 2/2 Running 0 8m57s istio-pilot-85b894cd75-gg4n5 2/2 Running 0 8m54s istio-telemetry-6b686cbbf5-bzwq5 2/2 Running 0 9m7s kiali-7d4b6dc78c-mm5r2 2/2 Running 0 8m46s prometheus-59c5655d9c-rw8mp 1/1 Running 0 9m11s registry-6c4fddb8b6-2bvrm 2/2 Running 0 8m40s registry-proxy-46ftw 1/1 Running 0 9m8s registry-proxy-shjf9 1/1 Running 0 9m8s registry-proxy-smszz 1/1 Running 0 9m8s rio-controller-86c4bf9698-6blb5 1/1 Running 0 9m27s webhook-5f6fc8f6f9-q6h6w 2/2 Running 0 8m28s
AutoScalerやKnativeのbuild-controller、buildkit、cert-manager、grafana、istio、kiali、prometheus、、、、と色々なPodが並んでますね。
Rioの新機能を試す - GitリポジトリからのRun
前回Rioを試した時にはなかった機能としてGitHubのリポジトリのURLを指定してRunする機能が入っていました。
RioはデフォルトでKnative+buildkitでイメージをビルドするようになっているようです。
(オプションでbuildpackなども使えるようですがまだ試してないです)
ということで早速試してみました。
確認にはこちらのリポジトリを用意しました。
これはgolangでHTTPサーバを立ち上げHello Rio!
というメッセージを返すだけの簡単なもので、main.go
とDockerfile
の2ファイルだけで構成されているリポジトリとなっています。
main.goは以下の通りです。
package main import ( "fmt" "log" "net/http" "time" ) func handler(w http.ResponseWriter, r *http.Request) { time.Sleep(100 * time.Millisecond) fmt.Fprintln(w, "Hello Rio!!") } func main() { http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(":8080", nil)) }
Dockerfileは以下の通りです。
FROM golang:1.11.1 ENV GOPATH="/go" RUN ["mkdir", "-p", "/go/src/github.com/yamamoto-febc/rio-demo"] COPY * /go/src/github.com/yamamoto-febc/rio-demo/ WORKDIR /go/src/github.com/yamamoto-febc/rio-demo RUN ["go", "build", "-o", "demo"] CMD ["./demo"]
Runしてみる
ということで早速Runしてみました。
# -pオプション: 公開するポート -nオプション: 名前(今回はbuildという名前) $ rio run -p 8080/http -n build https://github.com/yamamoto-febc/rio-demo
rio ps
を実行してみるとイメージのビルドを待機中と出ました。
$ rio ps # イメージのビルド待ち NAME CREATED ENDPOINT REVISIONS SCALE WEIGHT DETAIL default/build 2 seconds ago https://build-default.7vlxuv.on-rio.io:9443 v0 0/1 100% v0 NotReady; v0 waiting on build
しばらく待つとイメージがビルドされ、コンテナの起動~公開まで行われました。
# イメージがビルドされ、コンテナ起動~公開までされた状態 $ rio ps NAME CREATED ENDPOINT REVISIONS SCALE WEIGHT DETAIL default/build 6 minutes ago https://build-default.7vlxuv.on-rio.io:9443 v0 1 100% # エンドポイント宛てにリクエストしてみる $ curl https://build-default.7vlxuv.on-rio.io:9443 Hello Rio!!
無事表示されましたね!!!
コードの修正〜pushを試す
次にコードを修正し、コミットとプッシュを試してみます。 Rioはデフォルトではmasterブランチへのタグ/コミットのpushをポーリングで検知してくれるとのことです。 (オプションでWebhookも利用できるとのこと)
ということで先ほどのコードを修正しpushして反映されるか確認してみます。
# メッセージを書き換えてみる: "Hello Rio!" から"Bonjour Rio!"へ $ vi main.go $ コミットしてpush $ git add main.go $ git commit -m"Update messages" $ git push origin master
pushしたらRioが検知しているかrio revision
コマンドで確認してみます。
$ rio revision default/build NAME IMAGE CREATED SCALE ENDPOINT WEIGHT DETAIL default/build:v0 localhost:5442/default/build:ff1d967decbfd34ecd1268d72b5a4e8e1067f9ee 19 minutes ago 1 https://build-v0-default.7vlxuv.on-rio.io:9443 100 default/build:v37d26 28 seconds ago 0/1 https://build-v37d26-default.7vlxuv.on-rio.io:9443 0
default/build
に:v37d26
というリビジョンができてますね。こちらをビルド中のようです。
しばらく待つと次のようになりました。
rio revision default/build NAME IMAGE CREATED SCALE ENDPOINT WEIGHT DETAIL default/build:v0 localhost:5442/default/build:ff1d967decbfd34ecd1268d72b5a4e8e1067f9ee 21 minutes ago 1 https://build-v0-default.7vlxuv.on-rio.io:9443 0 default/build:v37d26 localhost:5442/default/build-169daa9-b92af:37d2632cb0d649dda800f5375b48b19419836f93 2 minutes ago 1 https://build-v37d26-default.7vlxuv.on-rio.io:9443 100
新しい方のリビジョンのビルドが終わり、そちらに切り替わっているようですね。WEIGHTが新しいリビジョンの方に100%となりました。
では先ほどのエンドポイントあてに再度リクエストしてみます。
# 再度エンドポイント宛てにリクエストしてみる $ curl https://build-default.7vlxuv.on-rio.io:9443 Bonjour Rio!!
お!!!!更新されてますね!
この手軽さはなかなか良いですね!
ということで
時間と体力切れのため今回はここまでです。 とっつきにくいKubernetesのあれこれを上手く覆い隠すフロントエンド、という印象を持ちました。
モニタリング面なども面白そうなので時間を見つけてもう少し触ってみたいところです。
以上です。
k3os on さくらのクラウド
k3osを試してみましたのでメモ残しておきます。
Update: 2019/5/29
さくらのクラウド側でk3OSのISOイメージが提供されるようになりました。
この記事でのISOイメージのダウンロード/アップロードの部分は不要となりました。
===Updateここまで
k3osって?
kubernetesに特化した軽量OSで、軽量kubernetesディストリビュージョンである「k3s」を組み込んだOSとなっています。
Public Keyでも取り上げられましたね。 www.publickey1.jp
前見たときはリリースページにARM向けのISOファイルしかなかったのですが、今日改めて確認したらAMD64向けもちゃんと提供されるようになってたので試してみました。
試してみる
インストール
流れとしては以下の通りです。
ISOファイルのダウンロード〜さくらのクラウドへアップロード
curlコマンドでダウンロード、usacloudコマンド(さくらのクラウド向けCLI)でISOファイルをアップロードします。
# ISOファイルのダウンロード $ curl -LO https://github.com/rancher/k3os/releases/download/v0.2.0/k3os-amd64.iso # アップロード $ usacloud iso-image create --iso-file k3os-amd64.iso --name k3os
サーバ作成〜ISOイメージの挿入〜起動
以下のコマンドでサーバ作成〜ISOイメージを挿入〜起動まで行います。
$ usacloud server build --name k3os \ --core 2 \ --memory 4 \ --disk-size 40 \ --iso-image-id `usacloud iso-image read -q k3os`
VNCで接続
サーバが起動したらコンパネからコンソールを開くかVNC接続して操作できるようにします。
今回は以下のコマンドでVNC接続を行います。(windowsの方は拡張子.vnc
が適切に関連付けされていれば動くはずです)
$ usacloud server vnc --wait-for-boot k3os
うまくいけばこんな感じの画面が表示されるはずです。牛ですね!
ユーザー名rancher
でパスワードなしでログインできるはずです。
ディスクへのインストール
ディスクへのインストールは表示されている通りsudo os-config
コマンドを実行すればOKです。
いくつか聞かれますが適当に進めていきます。
途中でSSH用の公開鍵をGitHubから取ってくるか聞いてくれます。この機能便利ですよね。
あとはインストールが進みます。インストールが終わると再起動されるはずです。
SSHで接続してみる
ディスクへのインストール&再起動まで終わったらSSHで接続してみます。
$ ssh rancher@<サーバのIPアドレス>
動作確認
とりあえずkubectlしてみました。
OKっぽいですね。
次にpodを起動してみます。
kubectl run nginx --image=nginx
、、、あれ?いつまでたっても上がってこない? ということでログなどを確認すると、どうも自身のホスト名が名前解決できないってエラーが出てるようでした。
Waiting for hostname sv-NNNNNNNNNNNN to be resolvable: lookup sv-NNNNNNNNNNNN on 133.242.0.3:53: no such host
このIssueですかね。 cannot run k3s server · Issue #60 · rancher/k3s · GitHub
ひとまず/etc/hostsを編集したら動きました。
時間なくなっちゃったので細かな検証はまた今度。
終わりに
k3sの環境構築が楽に行えるのが確認できました。 細かいところはまだ確認できてませんが追々試していきます。
2019/5/20 追記
Packerでk3osのアーカイブ(AWSでのAMIみたいなやつ)作るサンプルを作成しておきました。
毎回ISOイメージからインストールするのが面倒という場合などにどうぞ。
===追記ここまで
以上です。