0,前言
之前说的,使用k8s client 在pod内部操作外部k8s集群,curd configmap,但是在这里遇到一个问题,就是k8s client需要提供/root/.kube/config文件作为参数,如何提供这个配置文件呢?
1,想到的解决方案
1,代码写死。
缺点:(1)当node为master节点时,master:127.0.0.1:6443,需要把这个本地地址改为ip v4地址.
(2)如果node挂掉,pod需要调度到别的node上时,提供的master地址需要随之变化。
2,docker打包镜像时,执行一个脚本,将/root/.kube/config文件复制到容器内。
分析:如果在node上打包,是没有问题,(测试版本就是这样干的)但是如果需要把这个打包好的镜像丢到别的机器上运行,master节点就无法修改了。
缺点:必须要在node节点上打包。并且master地址不能变化。
3,使用存储etcd。
分析:每个node可以把自己的信息丢高etcd去,然后当pod被调度或者启动的时候,从etcd中拿取node节点地址,但是这个功能原生的k8s好像没有提供。
缺点:要自己去实现,可能需要通过crontab做,很麻烦。
2,最终解决方案
后边经过同事的指导,才发现,其实pod和k8s集群交互的方式有两种,一种是处于集群内部(也就是容器内pod操作容器外集群),还有一种就是集群外部操作集群(比如使用一个集群内的pod,操作另一个集群),链接分别如下:集群内,集群外上边是k8s client for go,java版本在这里:集群内,集群外。
而一开始的使用/root/.kube/config这种方式属于集群外部操作,比较麻烦。而如果时在集群内部操作,则直接可以通过
// loading the in-cluster config, including:
// 1. service-account CA
// 2. service-account bearer-token
// 3. service-account namespace
// 4. master endpoints(ip, port) from pre-set environment variables
ApiClient client = ClientBuilder.cluster().build();
Configuration.setDefaultApiClient(client);
CoreV1Api api = new CoreV1Api();
V1PodList list =
api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
这也太直接,太暴力了,希特。
从代码注释可以看出,是通过pod内部的token来访问的,并且环境变量已经设置了ip和port信息,自己可以去pod内部echo一下
3,说干就干,动手实践。
(1),遇到的问题
使用上边的代码,删除configmap的时候,报错:
exception :forbidden
(2)分析
通过万能的Google,了解到是pod的权限太低。也就是这个pod不允许删除和创建configmap,(应该可以查看)
(3)solution
既然权限不够,那就使用rbac给它一点儿权限咯,稍微改一下,使用给ServiceAccount加权限,大概步骤:
1,创建一个ServiceAccount。伪代码:
apiVersion: v1
kind: ServiceAccount
metadata:
name: curd-serviceaccount
automountServiceAccountToken: true #一定要注意这里,如果这个值是false,是不会将serivceAccount的token挂在到pod里去的,其实不用手动声明为true,因为默认值是true。手动改为false导致k8s config初始化失败,因为token没挂进去,并且go代码报错一点儿也不友好,排查起来很费力,花了好长时间才定位是这里的问题。可恶:(
2,创建一个ClusterRole,以及ClusterRoleBinding。(和Role以及RoleBinding的区别是,集群级别和namespace级别,并且可以混合搭配使用,不过一般建议配套使用)。伪代码:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: curd-clusterRole
labels:
rbac.example.com/aggregate-to-monitoring: "true"
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
# 这些规则将被添加到 "monitoring" 角色中。
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "pods", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: ServiceAccount
name: curd-serviceaccount# 名称区分大小写
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: curd-clusterRole
具体说明参见,上面的操作做完了后,就可以使用这里ServiceAccount创建pod资源了,
3,修改pod容器定义,引用ServiceAccount。伪代码:
spec:
serviceAccount: curd-serviceaccount
containers:
- image: prom/prometheus
这样创建出来的pod就有了对外部k8s集群各种资源的操作权限了。
4,经过验证,此方法可行。
心得:
遇到问题,可以多看看官方文档,一般来说,你遇到的问题,官方早就已经想到了。所以一定要多看官方文档,或者多看书。