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