Kubernetesクラスター内のPodからkubectlコマンドを実行する方法について調べたのでメモ。
Minikube v0.32.0とIBM Cloud Private v3.1.0で確認。
参考リンク
以下に丁寧な回答がある。
イメージの作成
kubectlのバイナリを配置したイメージを作る。
(参考)jqだけ含むコンテナの作成
FROM ubuntu
ubuntuをベースにイメージを作る。
FROM ubuntu:18.04
RUN apt-get update \
  && apt-get install -y wget \
  && rm -rf /var/lib/apt/lists/* \
  && wget https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl \
  && mv kubectl /usr/local/bin/kubectl \
  && chmod +x /usr/local/bin/kubectl
ENTRYPOINT ["/usr/local/bin/kubectl"]
CMD [""]
docker build -t kubectl:v1.13.0 .
docker tag kubectl:v1.13.0 sotoiwa540/kubectl:v1.13.0
docker push sotoiwa540/kubectl:v1.13.0
FROM alpine
alpineをベースにする場合は以下のようにする。
FROM alpine:3.8
RUN apk add --no-cache --virtual=build-deps wget \
  && wget https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl \
  && mv kubectl /usr/local/bin/kubectl \
  && chmod +x /usr/local/bin/kubectl \
  && apk del build-deps
ENTRYPOINT ["/usr/local/bin/kubectl"]
CMD [""]
docker build -t kubectl:v1.13.0-alpine .
docker tag kubectl:v1.13.0-alpine sotoiwa540/kubectl:v1.13.0-alpine
docker push sotoiwa540/kubectl:v1.13.0-alpine
utuntuとaplineでイメージサイズはこれくらい違う。ubuntuのほうはwgetとその依存パッケージを削除していないので、削除するようにしたらもう少しだけ減る。
$ docker images | grep kubectl | grep -v sotoiwa540
kubectl                               v1.13.0                84029f6e1e30        2 minutes ago       133MB
kubectl                               v1.13.0-alpine         93f11846b1be        2 hours ago         43.6MB
$
ibmcom/kubectl
ICPだとibmcom/kubectl:v1.11.1.1というイメージが既にあり、同じようにaplineにkubectlのバイナリを配置したもののようだ。
$ docker images | grep ibmcom/kubectl
mycluster.icp:8500/ibmcom/kubectl           v1.11.1.1              710a64408d49        5 months ago        65.4MB
$
$ docker run --rm -it mycluster.icp:8500/ibmcom/kubectl:v1.11.1.1 sh
/ # which kubectl
/usr/local/bin/kubectl
/ # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.6.2
PRETTY_NAME="Alpine Linux v3.6"
HOME_URL="http://alpinelinux.org"
BUG_REPORT_URL="http://bugs.alpinelinux.org"
/ #
Podの実行
Podとして実行する場合、特に何もしなくてもkubectlが使える(apiserverに接続できる)。なぜなら、kubectlがこのようにapiserverへの接続情報を設定しているため。
- 接続するapiserverを環境変数KUBERNETES_SERVICE_HOSTとKUBERNETES_SERVICE_PORTから取得- KubernetesクラスターではapiserverはkubernetesというServiceリソースとして定義されていてクラスター内からService経由でアクセスできる
 
- Kubernetesクラスターではapiserverは
- アクセストークンをコンテナにマウントされている/var/run/secrets/kubernetes.io/serviceaccount/tokenから取得
- apiserverのサーバー証明書をコンテナにマウントされている/var/run/secrets/kubernetes.io/serviceaccount/ca.crtから取得
Podとして実行してみる。
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: kubectl
  name: kubectl-pod
spec:
  containers:
  - name: kubectl
    image: sotoiwa540/kubectl:v1.13.0
    command:
    - tail
    - -f
    - /dev/null
kubectl apply -f kubectl-pod.yaml
トークンと証明書はPodが実行されるときにKubernetesによって必ず自動的にマウントされている。
$ kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubectl-pod   1/1     Running   0          4s
$ kubectl get po kubectl-pod -o yaml
apiVersion: v1
kind: Pod
metadata:
...
  name: kubectl-pod
  namespace: default
...
spec:
  containers:
...
    image: sotoiwa540/kubectl:v1.13.0
    imagePullPolicy: IfNotPresent
    name: kubectl
...
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-cn7gt
      readOnly: true
...
  serviceAccount: default
  serviceAccountName: default
...
  volumes:
  - name: default-token-cn7gt
    secret:
      defaultMode: 420
      secretName: default-token-cn7gt
...
$
ただしこれだけではapiserverに接続できるものの、NamespaceのデフォルトのServiceAccountで実行しているため権限がなくPodをListすることもできない。
$ kubectl exec -it kubectl-pod -- kubectl get po
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:default" cannot list resource "pods" in API group "" in the namespace "default"
command terminated with exit code 1
$
新たにServiceAccountを作り、このServiceAccountに強力なClusterRoleを割り当てる。
$ kubectl create sa admin
serviceaccount/admin created
$
デフォルトで存在するcluster-adminのClusterRoleが強力なので、このClusterRoleを作成したServiceAccountにバインドする。
ClusterRoleはClusterRoleBindingでバインドすることもできるし、RoleBingingでバインドすることもできるが、RoleBidingでバインドした場合は権限がNamespaceに限定される
ClusterRoleBinding
はじめにClusterRoleBindingを作成する。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-clusterrolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin
  namespace: default
kubectl apply -f admin-clusterrolebinding.yaml
PodのマニフェストにserviceAccount: adminの指定を追加する。
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: kubectl
  name: kubectl-pod
spec:
  serviceAccount: admin
  containers:
  - name: kubectl
    image: sotoiwa540/kubectl:v1.13.0
    command:
    - tail
    - -f
    - /dev/null
Podを再作成する。
kubectl delete po kubectl-pod
kubectl apply -f kubectl-pod.yaml
kubectlでPodがリストできることを確認。
$ kubectl exec -it kubectl-pod -- kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubectl-pod   1/1     Running   0          30s
$ kubectl exec -it kubectl-pod -- kubectl get po -n kube-system
NAME                                        READY   STATUS    RESTARTS   AGE
coredns-576cbf47c7-blfxm                    1/1     Running   1          4d22h
coredns-576cbf47c7-pnnfc                    1/1     Running   1          4d22h
default-http-backend-5957bfbccb-lhr2p       1/1     Running   1          4d22h
etcd-minikube                               1/1     Running   1          4d22h
kube-addon-manager-minikube                 1/1     Running   1          4d22h
kube-apiserver-minikube                     1/1     Running   0          4h35m
kube-controller-manager-minikube            1/1     Running   0          4h35m
kube-proxy-qzh9m                            1/1     Running   0          4h34m
kube-scheduler-minikube                     1/1     Running   1          4d22h
kubernetes-dashboard-5bff5f8fb8-2fbwb       1/1     Running   3          4d22h
nginx-ingress-controller-6958898f8f-7z9dg   1/1     Running   3          4h21m
storage-provisioner                         1/1     Running   3          4d22h
$
一度ClusterRoleBindingを削除する。
kubectl delete clusterrolebinding admin-clusterrolebinding
RoleBinding
今度はRoleBindingを作成してみる。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: admin-clusterrolebinding
subjects:
- kind: ServiceAccount
  name: admin
  namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f admin-rolebinding.yaml
同じcluster-adminのClusterRoleをバインドしているにもかかわらず、自分以外のNamespaceへの権限がない。
$ kubectl exec -it kubectl-pod -- kubectl get po
NAME          READY   STATUS    RESTARTS   AGE
kubectl-pod   1/1     Running   0          7m37s
$ kubectl exec -it kubectl-pod -- kubectl get po -n kube-system
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:admin" cannot list resource "pods" in API group "" in the namespace "kube-system"
command terminated with exit code 1
$
