Go言語からkubernetes APIを呼び出すクライアント「client-go」の紹介

これはKubernetes2 Advent Calendar 2017 25日目の記事です。この記事ではclient-goというライブラリを使ってgo言語からkubernetesのAPIを呼び出す方法を紹介します。

とりあえず使ってみるところから、任意のkubernetesクラスタにつなぐ方法、service accountを利用した認証方法、テストの書き方まで紹介します。

Client-goとは

Kubernetes APIを叩くためのGo製ライブラリです。おなじみのkubectlコマンドでも使われています。僕の関わっているサービスでは、kubernetes外のサーバーやkubernetes内部のコンテナからkubernetesを操作したいときに使っています。

インストールは、以下のコマンドでできます。

$ go get k8s.io/client-go/...

インストールに関する詳細はドキュメントを参照して下さい。ちゃんと使うならバージョン管理してね、といったことが書かれています。

まずは叩いてみる

以下の例ではPod一覧を取得しています。なお、実行にはkubectlが必要です(後述しますが、client-go利用の際にkubectlが常に必要になるわけではありません)。

まずはnewClient()でクライアントを生成しています。その際の認証情報は、~/.kube/configファイルから取得しています。これはkubectlが作成するファイルで、接続先サーバーや認証情報が格納されています。

その後、client.CoreV1().Pods("").List()でPod一覧を取得しています。Pods("")の引数ではnamespaceを指定することができ、空文字列にすると、全namespace指定と同等になります。

実行すると、Pod一覧が出力されます。

$ go run get_started.go
kube-addon-manager-minikube
kube-dns-6fc954457d-f58rp
kubernetes-dashboard-jcjjn

接続先kubernetesクラスタを指定する

先程の例では、kubectlの作成したクラスタ/認証情報を使用しました。kubectlは複数のクラスタが存在する場合でもcontextを切り替えて対応できますが、先程はkubectl config current-contextで得られるcontextを自動的に使うようになっていました。

そこで今度は、contextを指定して任意のクラスタに接続できるようにしてみます。こちらも、実行にはkubectlが必要です。

主に変更したのはnewClient()です。clientcmd.ConfigOverrides{}を使用してcontextを指定しています。試したことはないですが接続先サーバーや認証情報の上書きもできるようです。clientcmd.NewDefaultClientConfigLoadingRules()では、クラスタ/認証情報のロード方法を指定しています。デフォルトでは、~/.kube/configの情報がロードされます。これらの情報を元にconfigとclientを作成しています。

実行の際は、引数でcontextを指定します。kubectl config get-contextsで得られるcontext名が指定できます。

$ go run choose_k8s_cluster.go minikube
kube-addon-manager-minikube
kube-dns-6fc954457d-f58rp
kubernetes-dashboard-jcjjn

Kubernetes内部のPodからAPIを叩く

ここまでの例では、kubectlの作成したクラスタ/認証情報を使用してクライアントを作成していました。kubectlが利用できる環境ではここまでの方法でも良いですが、kubernetes内部のPodからAPIを叩くような場合には、kubectlがインストールされていないことがあります。

そのような場合、kubernetesがPodに対して付与するservice accountを使うと便利です。Service accountについてはこのドキュメントが詳しいです。

主に変更したのはnewClient()です。rest.InClusterConfig()でservice accountを利用するための設定をしています。/var/run/secrets/kubernetes.io/serviceaccount/以下のトークンや証明書が使われます。

Pod内のコンテナにログインして実行すると、~/.kube/configのない環境でもPod一覧を取得できることがわかります。 (もしパッケージがない旨のエラーが出たら、client-goをインストールして下さい)

root@golang:/go# ls ~/.kube
ls: cannot access '/root/.kube': No such file or directory
root@golang:/go# go run in_cluster_client.go
golang
kube-addon-manager-minikube
kube-dns-6fc954457d-f58rp
kubernetes-dashboard-jcjjn

テストを書く

最後にテストを書いてみます。client-goに含まれるfakeパッケージを使用すると、テスト用のデータを予め仕込んだ上で各種APIを叩くことができます。

newClient()でのクライアント作成はfake.NewSimpleClientset()を呼ぶだけになりました。addTestData()でテスト用のPodを作成していますが、方法は非テストコードでPodを作成する場合と同じです。今回は省略しましたが、ここでPodの状態や各種ポリシーを設定することもできます。

実行すると、作成したテスト用Podが出力されることがわかります。

$ go run normal_case_test.go
test

今度は、kubernetes APIがエラーを返す場合のテストを書いてみます。

setServerError()API呼び出し時にエラーを返すようにしています。テスト用クライアントは内部にReactionChainと呼ばれるハンドラリストをもっていて、先頭のハンドラから順番にリクエストを処理していきます。上記のコードでは常にエラーを返すハンドラを先頭に挿入しているので、API呼び出しがエラーを返すようになります。ちなみに、PrependReactor()の第一引数でverb、第二引数でresourceを指定できるので、第一引数をlist、第二引数をpodsとすれば、Pod一覧取得のときだけエラーを返すようになります。

実行すると、Pod一覧を取得するAPIがエラーを返して終了します。

$ go run error_case_test.go
2017/12/22 13:03:08 server error
exit status 1

まとめ

この記事ではclient-goの使い方について簡単に紹介しました。ドキュメントはそれほど充実していないですが、kubectlで使われているだけあって、やりたいことは大体できる印象です。Kubernetes APIを使うときはぜひ利用を検討してみて下さい。