0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

client-goを使ってkube configを取得してみる

Posted at

最近k8sのコードリーディングを始めたのでまずは簡単そうなものから始めます。
in-cluster-client-configurationを参考にします。

main.go

READMEのAuthenticating inside the clusterの部分を読むとmain.goの一番最初にあるrest.InClusterConfig()の説明がある。
リンクは真面目に読まなくてもいい気がする。Service Account Tokens.

rest.InClusterConfig()の実装

KUBERNETES_SERVICE_HOST, KUBERNETES_SERVICE_PORTの環境変数をみて現在クラスタ内ではない場合エラーを出している。
その後対象のパスからトークンを取って返している。これを使ってclient-setを作る。

func InClusterConfig() (*Config, error) {
	const (
		tokenFile  = "/var/run/secrets/kubernetes.io/serviceaccount/token"
		rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
	)
	host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
	if len(host) == 0 || len(port) == 0 {
		return nil, ErrNotInCluster
	}

	token, err := os.ReadFile(tokenFile)
	if err != nil {
		return nil, err
	}
// ~~~~省略
	return &Config{
		// TODO: switch to using cluster DNS.
		Host:            "https://" + net.JoinHostPort(host, port),
		TLSClientConfig: tlsClientConfig,
		BearerToken:     string(token),
		BearerTokenFile: tokenFile,
	}, nil
}

client-setの作成

client-goのkubernetes.NewForConfig()と先ほどのトークンを使い作成される。

NewForConfig()の実装

NewForConfigAndClient関数でClientset構造体を作っている(省略)。
Clientset構造体にはcorev1などのよくみるものが定義されていて、k8s.io/client-go/kubernetes/typedあたりで定義されている。

このディレクトリのcorev1の下にはpod.go, service.goなどがあり、このClientset構造体から各種APIを叩くことになりそう。

func NewForConfig(c *rest.Config) (*Clientset, error) {
	configShallowCopy := *c

	// share the transport between all clients
	httpClient, err := rest.HTTPClientFor(&configShallowCopy)
	if err != nil {
		return nil, err
	}

	return NewForConfigAndClient(&configShallowCopy, httpClient)
}

forループ

主に全てのnamespaceのPodをリストする例とエラーハンドリングの例がある。

Podのリスト

clientset.CoreV1()が呼ばれると、core_client.goのCoreV1Client構造体が返される。
Pods("")でrest clientやnamespaceの情報が保持される。
List()は以下のような実装。
PodListに定義されたItemsに実際のPodが入っている。

func (c *pods) List(ctx context.Context, opts metav1.ListOptions) (result *v1.PodList, err error) {
	var timeout time.Duration
	if opts.TimeoutSeconds != nil {
		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
	}
	result = &v1.PodList{}
	err = c.client.Get().
		Namespace(c.ns).
		Resource("pods").
		VersionedParams(&opts, scheme.ParameterCodec).
		Timeout(timeout).
		Do(ctx).
		Into(result)
	return
}

エラーハンドリング

Getで存在しないPodを取得しようとした場合に、apimachineryのerrors.goからifを書ける。

_, err = clientset.CoreV1().Pods("default").Get(context.TODO(), "example-xxxxx", metav1.GetOptions{})
if errors.IsNotFound(err) {
  fmt.Printf("Pod example-xxxxx not found in default namespace\n")
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
  fmt.Printf("Error getting pod %v\n", statusError.ErrStatus.Message)
} else if err != nil {
  panic(err.Error())
} else {
  fmt.Printf("Found example-xxxxx pod in default namespace\n")
}

所感

serviceaccountのtoken辺りをふんわり知れた。
clientsetを作らないことには始まらない印象を持った。
apimachinery, api, client-goを行ったり来たりして迷った。
両者の違いはKubernetes APIをGoから使う最初の一歩。書かれてるような実体と補助という関係らしいがイメージはついていない。

実装を追うと大変だが、最後にmain.goを見てみるとすごくシンプルでスッキリしていると感じる。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?