在kubernetes相关云原生程序的开发过程中,离不开的工具就是 client-go 这个库。目前,集群权限认证基本有两种方式,一是使用 kubeconfig 文件进行认证,另一个就是把服务运行到集群内,使用 InClusterConfig 进行认证(即 serviceaccount 拥有的集群权限),但是在实际的开发过程中,这两种方式都不够灵活。比如,需要对多个集群进行控制时,如果使用kubeconfig文件的方式,就必须指定配置文件,而InCluster只能对当前集群起作用,多个集群,势必需要在每个集群都运行一个程序
分析 InClusterConfig 函数,可以看到,实际上只需要构造一个 *rest.Config 结构体,然后返回,就可以了
func InClusterConfig() (*Config, error) {
const (
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
)
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
if len(host) == 0 || len(port) == 0 {
return nil, ErrNotInCluster
}
token, err := ioutil.ReadFile(tokenFile)
if err != nil {
return nil, err
}
tlsClientConfig := TLSClientConfig{}
if _, err := certutil.NewPool(rootCAFile); err != nil {
klog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
} else {
tlsClientConfig.CAFile = rootCAFile
}
return &Config{
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(host, port),
TLSClientConfig: tlsClientConfig,
BearerToken: string(token),
BearerTokenFile: tokenFile,
}, nil
}
那么, 这个Config中那些字段是必须的呢?
-
Host 用于提供需要访问的集群地址
-
Token 用于提供授权
-
TLSClientConfig 提供tls安全访问层的数据
如果不考虑数据传输的安全性,可直接设置 Insecure 为 true ,此时不需要对证书进行验证,当然不建议这么做,如果要使用证书,在CAData 中放ca证书就可以了
利用serviceaccount进行多集群访问示例:
package main
import (
"context"
"log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
type K8sConfig struct {
Name string // 集群名称
Host string // 集群地址 https://xxxx:8443
Token string // Token
CA string // CA证书
}
var (
testconfig K8sConfig = K8sConfig{
Name: "test",
Host: "https://172.16.10.10:6443",
Token: "xxxxxxxx", // 存放 serviceaccount对应secret的token
CA: testCa,
}
prodconfig K8sConfig = K8sConfig{
Name: "prod",
Host: "https://172.16.20.10:6443",
Token: "xxxxxxxx",
CA: prodCa,
}
// 可继续添加其他集群配置
)
const (
testCa = `xxxxxx` // 存放 serviceaccount对应secret的ca
prodCa = `xxxxxx`
)
func SelectClusterConfig(env string) (*rest.Config, error) {
var c K8sConfig
switch env { // 多集群支持
case "test":
c = testconfig
case "prod":
c = prodconfig
default:
log.Printf("环境: %s 不支持", env)
return nil, fmt.Errorf("环境: %s 不支持", env)
}
return &rest.Config{
Host: c.Host,
BearerToken: c.Token,
BearerTokenFile: "",
TLSClientConfig: rest.TLSClientConfig{
// Insecure: true, // 设置为true时 不需要CA
CAData: []byte(c.CA),
},
}, nil
}
// GetPodByName 获取pod信息
func GetPodByName(env, namespace, podname string) {
config, err := SelectClusterConfig(env)
//config, err := clientcmd.BuildConfigFromFlags("", "C:\\Users\\Admin\\.kube\\config")
if err != nil {
log.Println("BuildConfigFromFlags Err:", err)
return
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Println("NewForConfig Err:", err)
return
}
pod, err := clientset.CoreV1().Pods(namespace).Get(context.Background(), podname, metav1.GetOptions{})
if err != nil {
log.Println("GetPod Err:", err)
return
}
log.Println("获取到pod:", pod)
}
func main() {
GetPodByName("test", "default", "nginx-xxxx-xxxxxxxx")
}
上面的示例中,集群的配置信息直接硬编码,在实际的应用中,这部分的数据可以从配置中心、配置文件中获取
以上配置和下面直接使用curl访问的方式类似
# 获取服务器地址及端口
APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
# tr -d '\t' 可能会失败 可能是空格
# TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t')
TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
curl $APISERVER/api/v1/namespaces/default/pods/nginx-xxxx-xxxxxxxx --header "Authorization: Bearer $TOKEN" --insecure
因为集群通常为rbac认证,如果没有相应的权限,则不能访问对应的资源,所以还需要serviceaccount赋予对应的权限
serviceaccount授权示例:
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: example
name: sa-example
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app: example
name: sa-example
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: sa-example
subjects:
- kind: ServiceAccount
name: sa-example
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app: example
name: sa-example
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- delete
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list