Pod中からKubernetesのAPI Serverに認証

Page content

概要

やりたいことは簡単のアプリケーションを作って、Kubernetesの中にPodとしてデプロイして、このアプリは現在Kubernetesクラスター中に何個のPodがあるかをKubernetesのApi Serverに問い合わせる。

つまりPodの中のアプリケーションはどうやってKubernetesのAPI Serverに認証して、情報を取得することである。

このアプリを作るためにKubernetesのclient-goライブラリを使います。サンプルとしてここに載っています。Pod内からKubernetesのApi Serverと通信するための認証部分の設定は rest.InClusterConfig()を呼び出すことになる。

プログラム作成

ファイル名はin-cluster-client-configuration.go

package main

import (
        "fmt"
        "time"

        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/rest"
)

func main() {
        // creates the in-cluster config
        config, err := rest.InClusterConfig()
        if err != nil {
                panic(err.Error())
        }
        // creates the clientset
        clientset, err := kubernetes.NewForConfig(config)
        if err != nil {
                panic(err.Error())
        }
        for {
                pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
                if err != nil {
                        panic(err.Error())
                }
                fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
                time.Sleep(10 * time.Second)
        }
}

Podの中からKubernetesのAPI Serverとやり取りするので、まずソースをビルドして、Podの形でKubernetesにデプロイする必要があります。

GOOS=linux go build -o ./app  in-cluster-client-configuration.go
docker build -t in-cluster .
docker tag in-cluster wzj8698/in-cluster
docker push wzj8698/in-cluster

デプロイ

これでアプリのImageを準備できました。Podとしてtest-in-clusterという名前のnamespaceにデプロイしたいので、test-in-cluster namespaceを作ります。namespaceが作成されるタイミングでdefaultという名前のService Accountが作成される。

# kubectl create namespace test-in-cluster 

# kubectl get serviceaccounts -n test-in-cluster ### defaultという名前のservice account
NAME      SECRETS   AGE
default   1         58m


## 現在のnamespaceをtest-in-clusterに切り替え
# kubectl config set-context $(kubectl config current-context) --namespace=test-in-cluster 

kubectl runコマンドでデプロイしてみる。

# kubectl run --rm -i demo  --image=wzj8698/in-cluster

しかしチェックしてみるとデプロイは失敗しています。 CrashLoopBackOffというエラー出ています。

# kubectl get pod -n test-in-cluster
NAME                    READY     STATUS             RESTARTS   AGE
demo-7575dcf9c9-5b595   0/1       CrashLoopBackOff   4          2m


# kubectl describe pod demo-7575dcf9c9-5b595 -n test-in-cluster
......
  Warning  BackOff                1m (x7 over 2m)  kubelet, kube-04   Back-off restarting failed container
......

そしてこのPodの内部のログを見てみます。User "system:serviceaccount:test-in-cluster:default" cannot list pods at the cluster scopeのようなエラーが出ています。

# kubectl logs -f demo-7575dcf9c9-5b595 -n test-in-cluster
panic: pods is forbidden: User "system:serviceaccount:test-in-cluster:default" cannot list pods at the cluster scope
goroutine 1 [running]:
main.main()
        /root/work/golang/in-cluster-client-configuration.go:26 +0x1ec

上のエラーの意味はPodがtest-in-cluster:defaultというService Accountの身分でKubernetesのApi ServerからPodをリストしようとすると、権限がなくて、失敗している。

Service Accountの意味

Kubernetesの中で二種類のアカウントがあります。一つはUser Account、もう一つはここに出てきたService Account

User Accountは人がKubernetes のApi Serverと通信するために用意されているアカウントで、Service AccountはPodの中に動いているプロセスがKubernetes のApi Serverと通信するためのアカウント。

つまりService AccountはPodのアイデンティティーでもあります。上の例ではdemo-7575dcf9c9-5b595 Podはあるtest-in-cluster ネームスペース中のdefaultというService Accountの身分でApi Serverと通信しようとしている

Service Accountは色々な違う権限があります。上のアプリの例だと、そのPodがKubernetesのApi Serverからクラスター内の全部のPodの数を取得しようとしています。しかし、User "system:serviceaccount:test-in-cluster:default" cannot list pods at the cluster scopeというエラーが出ているってことはtest-in-cluster:defaultという名前のService AccountがPodをListする権限がない。

ここでtest-in-cluster:default Service AccountにPodをリストする権限を付与しないといけない。

Service Accountに権限を付与する際にKubernetesのRoleClusterRoleが必要となってくる。ClusterRoleはクラスター範囲内でどんなことができるかを定義している。例えばどんなNamespaceの中でもPod作成、削除できるとか。

Kubernetesの中にデフォルトでいくつかのClusterRoleを定義している。例えばcluster-adminというClusterRoleは何でもできる。

逆にviewというClusterRoleは大体のもの(Pod、Deployment, Serviceとか)をみることができるけど、Pod、Deployment, Serviceとか作ることはできない。つまりread onlyになっている。

話が戻りますが、このアプリのService Account test-in-cluster:defaultveiwClusterRoleを付与すれば, KubernetesのApi Serverと通信して、Podの数を取得できはず。

やってみる . Service Account と ClusterRoleをBindする必要があるので、Kubernetesの中でclusterrolebindingを作るということになる

kubectl create clusterrolebinding default-view --clusterrole=view --serviceaccount=test-in-cluster:default

上のコマンドの意味はtest-in-cluster:defaultという名前のService Accountにviewという名前のCluserRoleの権限を付与して、作成される のClusterRoleBindingの名前は default-viewである。

これでこのアプリはtest-in-cluster:default Service Accountの身分で動かしているので、今はKubernetesのクラスター内部のPodを全部リストできるはず

もう一回アプリをデプロイしてみると。ちゃんとPodが数が取れた。

kubectl delete demo -n test-in-cluster
kubectl run --rm -i demo  --image=wzj8698/in-cluster
There are 32 pods in the cluster
There are 32 pods in the cluster
There are 32 pods in the cluster
About Wang Zhijun
機械学習好きなプログラマー