利用RBAC管理K8S集群资源

340 阅读2分钟

背景

之前基于k8s开发的AI相关平台,需要后台服务管理k8s创建的相关资源(namespace,job,service,deployment等)。

web服务使用python作为主要开发语言,选用k8s提供的python-client包来对k8s资源进行CRUD

python-clientb包在初始化client时,需要提供k8s的configure相关信息,代码如下:

from kubernetes import client, config
config.load_kube_config('path-of-config')
configuration = client.Configuration()

其中,path-of-config是可选的,如果没有指定config的文件路径,则默认从$HOME/.kube/config文件读取。

阅读python-client包的源码发现,通过从config文件中获取对应的tokenca证书数据来完成REST Api的认证。

实践

实践一

起初,是在编写服务的镜像打包文件Dockerfile时,将config直接COPY到镜像中,在实现过程中读取对应的config文件来完成k8s配置的加载。

这种方式,缺点很明显,就是切换一个集群环境就需要重新打包一次镜像,迁移性很差,不适合多地区部署。

实践二

既然,不能固定配置文件在镜像中,那就采用挂载的方式,将宿主机上的$Home/.kube/config挂载到容器中的$HOME/.kube/config中。

这种方式,虽然能够解决实践一中不需要切换一个集群更换一次镜像的问题,但是也有明显的缺点:

  • 需要确保每一个节点在$HOME/.kube下面有config文件。

其实,在k8s集群中应该只在master节点下含有config文件,slave节点根本不应该有config文件。并且,pod只会被调度到slave节点上运行

  • 多集群管理的情况下,$HOME/.kube/config文件含有多个集群的信息,一旦通过kubectl config user-context xxx切换到其他的集群下,服务连接的k8s集群就会发现错误,导致不可预料的问题。

在超多节点的集群下,这种方法一旦发现错误,纠错很难。多个pod可能连接不同的集群,不同的请求到达不同的pod,会出现时好时坏的情况。

实践三

其实,一直想通过RBAC机制来完善这套服务,由于时间节点不允许,一直拖着,最近时间节点已经完成,再进一步优化服务,下面,将介绍本文如何利用RBAC来管理K8s集群资源。

  • 创建clusterrole

服务除了需要管理namespace下的资源之外,还需要管理cluster级别的服务,因此需要创建clusterrole。为了便于演示,本次使用k8s自带的cluster-admin

  • 创建serviceaccoutclusterrolebinding
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-test
  namespace: default

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: test-crb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: test-sa
  namespace: default
  • python-client配置k8s相关配置信息
import os
from kubernetes import client, config
sa_path = '/var/run/secrets/kubernetes.io/serviceaccount/'

token_path = os.path.join(sa_path, 'token')

with open(token_path, 'r') as f:
    token = f.read()

configuration = client.Configuration()

configuration.api_key["authorization"] = token
configuration.api_key_prefix['authorization'] = 'Bearer'
configuration.host = 'https://{0}:{1}'.format(
        os.environ['KUBERNETES_SERVICE_HOST'],
        os.environ['KUBERNETES_SERVICE_PORT'])
configuration.ssl_ca_cert = os.path.join(sa_path, 'ca.crt')
  • 在Deployment中,指定spec.template.spec.serviceAccountName为test-sa