Pod中からKubernetesのAPI Serverに認証
概要
やりたいことは簡単のアプリケーションを作って、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のRoleやClusterRoleが必要となってくる。ClusterRoleはクラスター範囲内でどんなことができるかを定義している。例えばどんなNamespaceの中でもPod作成、削除できるとか。
Kubernetesの中にデフォルトでいくつかのClusterRoleを定義している。例えばcluster-adminというClusterRoleは何でもできる。
逆にviewというClusterRoleは大体のもの(Pod、Deployment, Serviceとか)をみることができるけど、Pod、Deployment, Serviceとか作ることはできない。つまりread onlyになっている。
話が戻りますが、このアプリのService Account test-in-cluster:defaultにveiwのClusterRoleを付与すれば, 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