概要
Pod内でk8sのAPIを使いたかったので、やり方を調べました。
Goのk8sクライアントであるclient-goのexampleを動かしてみます。
https://github.com/kubernetes/client-go
環境
- kops
- 1.9.1
- Kubernetes
- 1.9.6
詳細
in-cluster-client-configuration
以下のin-cluster-client-configurationというexampleを使います。
https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration
どうやら rest.InClusterConfig()
を呼ぶとPod内の認証情報を使ってAPIアクセスを行ってくれるようです。
ここではServiceAccountが利用されているのですが、ServiceAccountについては以下の記事がわかりやすかったです(ステマ)。
https://qiita.com/knqyf263/items/ecc799650fe247dce9c5
つまりServiceAccountに適切なRoleを付与しておけばプログラムからは意識せずに利用できます。
ビルド
正直ここが書きたかったです。
exampleには依存ライブラリが必要なのでdepで用意します。
$ dep init
Importing configuration from godep. These are only initial constraints, and are further refined during the solve process.
Importing configuration from godep. These are only initial constraints, and are further refined during the solve process.
Importing configuration from godep. These are only initial constraints, and are further refined during the solve process.
Locking in 1.0.0 (1df9eeb) for transitive dep github.com/modern-go/reflect2
Locking in (44d8105) for transitive dep github.com/google/gofuzz
Locking in master (8014b7b) for transitive dep golang.org/x/sys
Locking in v0.3.0 (f21a4df) for transitive dep golang.org/x/text
Locking in (c0656ed) for transitive dep github.com/gogo/protobuf
Locking in master (f2b4162) for transitive dep github.com/json-iterator/go
Locking in v2.2.1 (5420a8b) for transitive dep gopkg.in/yaml.v2
Locking in kubernetes-1.10.0 (73d9036) for transitive dep k8s.io/api
Using master as constraint for direct dep k8s.io/apimachinery
Locking in master (5a80132) for direct dep k8s.io/apimachinery
Locking in v0.9.0 (3887ee9) for transitive dep gopkg.in/inf.v0
Locking in (81e9090) for transitive dep golang.org/x/crypto
Locking in (1643683) for transitive dep github.com/golang/protobuf
Locking in (0c51083) for transitive dep github.com/googleapis/gnostic
Locking in (1c05540) for transitive dep golang.org/x/net
Locking in 1.0.3 (bacd9c7) for transitive dep github.com/modern-go/concurrent
Locking in (44145f0) for transitive dep github.com/golang/glog
Using ^7.0.0 as constraint for direct dep k8s.io/client-go
Locking in v7.0.0 (23781f4) for direct dep k8s.io/client-go
Locking in (73d445a) for transitive dep github.com/ghodss/yaml
Locking in (f51c127) for transitive dep golang.org/x/time
そしてビルドします。
$ GOOS=linux go build -o ./app .
# github.com/kubernetes/client-go/examples/in-cluster-client-configuration/vendor/k8s.io/client-go/discovery
vendor/k8s.io/client-go/discovery/restmapper.go:42:75: undefined: meta.VersionInterfacesFunc
vendor/k8s.io/client-go/discovery/restmapper.go:176:19: undefined: meta.VersionInterfacesFunc
エラーが出ました。Interfaceが存在しないと言われています。
エラーから察するに依存関係の解決がうまく行ってないです。
動作に必要なバージョンがうまく固定されておらず、動かないバージョンのmetaを持ってきているようです。
ここでしばらくハマったのですが、INSTALL.mdに答えは書いてありました。
https://github.com/kubernetes/client-go/blob/master/INSTALL.md#dep-not-supported-yet
Dep (Not supported yet!)
ということでサポートされてないらしいです。
glideかgodepsを使えと言われてます。
Kubernetesぐらい新しいプロジェクトなので、もっと最新の依存解決ツール使えと言われるのかと思いきや古いツールが使われてました。確かにGodepsディレクトリが置いてあります。
glideとか久々に使うのでコマンド忘れてましたが、何とか動きました。
$ glide create
$ glide install -v
-v
がないとvendorがネストされてエラーになるっぽいので気をつけて下さい。
ということであとはビルドすれば通ります
$ GOOS=linux go build -o ./app .
Dockerのビルド
これも普通にexampleのDockerfileを使うだけです。
$ docker build -t in-cluster .
あとはこれをk8sへデプロイ可能な場所へイメージをpushしておきます。
自分の場合はAWSでk8sを構築していたのでECRにpushしました。
Roleの付与
あとはDeploymentを使うだけ...かと思ったのですが、どうやらServiceAccountの default
は何もRoleが付与されていないようです。
そのためPodの一覧取得などに失敗します。
======
※ @superbrothers さんからコメントいただいたので追記
KubeCon 2017で以下の発表がされていました。
特定のツール・バージョンで構築した場合に default:default
のServiceAccountに対して強い権限が与えられていることがあったようです。
https://schd.ws/hosted_files/kccncna17/d8/Hacking%20and%20Hardening%20Kubernetes%20By%20Example%20v2.pdf
そのため何も気にしないでPodを利用していると、デプロイされたPodがk8sのAPIを利用可能になってしまってセキュリティリスクがある、という問題があったようです。悪意あるPodがデプロイされた場合ですね。
自分が利用したkops 1.9.1では default:default
は何も権限を持っておらず安全でした。
======
ということでPodの一覧取得権限などを default
に付与します。
今回は面倒なのでClusterRoleのviewを付与しました。実際に使う場合は適切なRoleを作ってRoleBindingを作るのが良いと思います。
$ kubectl create clusterrolebinding default-view --clusterrole=view --serviceaccount=default:default
デプロイ
これで準備は終わりなので、あとはデプロイするだけです。
成功していればPodの数が表示されます。
$ kubectl run --rm -i demo --image=in-cluster --image-pull-policy=Never
There are 23 pods in the cluster
Pod not found
There are 23 pods in the cluster
Pod not found
...
まとめ
kubernetes/client-go
のexampleを動かしてみました。
認証が一番面倒そうかなと思っていたので、そこが出来ればあとはGoをゴリゴリ書けば行けるんじゃないかと思ってます。