本文发布于Cylon的收藏册,转载请著名原文链接~


在我们基于 Kubernetes 编写云原生 GoLang 代码时,通常在本地调试时,使用 kubeconfig 文件,以构建基于 clientSet 的客户端。而在将代码作为容器部署到集群时,则会使用集群 (in-cluster) 内的配置。

clientcmd 模块用于通过传递本地 kubeconfig 文件构建 clientSet。因此,在容器内使用相同模块构建 clientSet 将需要维护容器进程可访问的 kubeconfig 文件,并设置具有访问 Kubernetes 资源权限的 serviceaccount token。

下面是一个基于 kubeconfig 访问集群的代码模式

var (
    k8sconfig  *string //使用kubeconfig配置文件进行集群权限认证
    restConfig *rest.Config
    err        error
)
if home := homedir.HomeDir(); home != "" {
    k8sconfig = flag.String("kubeconfig", fmt.Sprintf("./admin.conf"), "kubernetes auth config")
}

flag.Parse()
if _, err := os.Stat(*k8sconfig); err != nil {
    panic(err)
}
clientset,err := kubernetes.NewConfig(k8sconfig)
if err != nil {
    panic(err)
}

这样做可能导致 serviceaccount token 本身被潜在地暴露出去。如果任何用户能够执行到使用 kubeconfig 与集群通信的容器,那么就可以获取该 token,并可以伪装成服务账号从集群外部与 kube-apiserver 进行通信。

为了避免这种情况,我们在 client-go 模块中使用了 rest 包。这将帮助我们从集群内部与集群通信,前提是使用适当的服务账号运行。但这需要对代码进行重写,以适应从集群外部构建 client-set 的方式。

下面代码时使用 in-cluster 方式进行通讯的模式

	var (
		k8sconfig  *string //使用kubeconfig配置文件进行集群权限认证
		restConfig *rest.Config
		err        error
	)
	if home := homedir.HomeDir(); home != "" {
		k8sconfig = flag.String("kubeconfig", fmt.Sprintf("./admin.conf"), "kubernetes auth config")
	}
	k8sconfig = k8sconfig
	flag.Parse()
	if _, err := os.Stat(*k8sconfig); err != nil {
		panic(err)
	}

	if restConfig, err = rest.InClusterConfig(); err != nil {
		// 这里是从masterUrl 或者 kubeconfig传入集群的信息,两者选一
        // 先从 in-cluster 方式获取,如果不能获取,再执行这里
		restConfig, err = clientcmd.BuildConfigFromFlags("", *k8sconfig)
		if err != nil {
			panic(err)
		}
	}
	restset, err := kubernetes.NewForConfig(restConfig)

除了这些之外,还需要创建对应的 serviceaccount 来让 Pod 在 in-cluster 有权限获取到自己要的资源,下面是一个完整的 deployment 创建这些资源的清单

apiVersion: v1
kind: Namespace
metadata:
  name: infra
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-proxier-secret-reader
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pod-proxier-rolebinding
subjects:
  - kind: ServiceAccount
    name: pod-proxier-secret-sa
    namespace: infra
roleRef:
  kind: ClusterRole
  name: pod-proxier-secret-reader
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: infra
  name: pod-proxier-secret-sa
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-proxier
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pod-proxier
  template:
    metadata:
      labels:
        app: pod-proxier
    spec:
      serviceAccount: pod-proxier-secret-sa # 使用上面定义的 sa 进行in-cluster 访问
      containers:
        - name: container-1
          image: haproxytech/haproxy-debian:2.6
          ports:
            - containerPort: 80
          hostPort: 8080  # 添加 hostPort 字段
        - name: container-2
          image: container-2-image:tag
          ports:
            - containerPort: 8080
          hostPort: 8081  # 添加 hostPort 字段

本文发布于Cylon的收藏册,转载请著名原文链接~

链接:https://www.oomkill.com/2023/11/ch07-in-cluster-pod/

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。