一、背景
1、从开发角度
(1)服务通过容器化部署的方式运行在云环境的Pod中,然而在 Kubernetes 中,Pod 中的服务不能直接通过 client-go
访问 Kubernetes 资源,而是需要通过 Kubernetes API Server 来进行访问。client-go
库实际上是通过与 Kubernetes API Server 的交互来完成对 Kubernetes 资源的操作。
(2)在使用 client-go
时,通常需要提供 Kubernetes API Server 的地址、认证信息(如服务账号的凭证),以及所需的 API 访问权限(通过 RBAC 角色授权)。这些信息将帮助 client-go
库正确地建立与 Kubernetes API Server 的连接,并确保操作的安全性和正确性。
2、从调库角度
(1)在使用 Kubernetes API 客户端——client-go 的过程中,我们通常需要获取 *rest.Config 配置对象来与 Kubernetes API 服务器进行交互。
(2)通常有四种获取 *rest.Config 的方法
使用 kubeconfig 文件
kubeconfig 文件是一个 YAML 文件,用于指定 Kubernetes 集群的访问凭证、上下文和集群信息等。
使用 Kubernetes 集群内的 Service Account
在 Kubernetes 中,每个 Namespace 都有一个默认的 Service Account。ServiceAccount仅局限它所在的namespace,每个namespace创建时都会自动创建一个default service account。
ServiceAccount是给运行在Pod的程序使用的身份认证,Pod容器的进程需要访问API Server时用的就是ServiceAccount账户。
创建Pod时,如果没有指定Service Account,Pod则会使用default Service Account。
直接指定 API Server 的地址和认证信息
我们可以直接指定 API Server 的地址和认证信息来获取 *rest.Config 对象。直接将api地址和认证token配置到代码中,但实际开发中一般不用。
从环境变量、默认配置文件等多个来源获取配置信息
`genericclioptions.NewConfigFlags()` 方法可以从环境变量、命令行参数、默认配置文件等多个来源中获取 Kubernetes 集群的配置信息,并生成对应的 *rest.Config 对象。
二、在pod中调用自定义资源
1、pod绑定服务账号
(1)创建serviceAccount
apiVersion: v1 kind: ServiceAccount metadata: name: test-sa namespace: test |
(2)创建相关的角色/rbac
Role 只能用来给某个特定 namespace 中的资源作鉴权,对多 namespace 和集群级的资源或者是非资源类的 API(如 /healthz)使用 ClusterRole
ClusterRole用于所有namespace下的资源,例如需要具备操作 CRD(CustomResourceDefinition) 相关权限,CRD 存在于所有 namespace 下
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: my-cluster rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get","list"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: my-bind subjects: - kind: ServiceAccount name: test-sa namespace: test roleRef: kind: ClusterRole name: my-cluster apiGroup: rbac.authorization.k8s.io |
(3)在pod中绑定对应的serviceAccount
serviceAccount所需要的证书会被mount到 : /var/run/secrets/kubernetes.io/serviceaccount
apiVersion: v1 kind: Pod metadata: name: testpod namespace: test labels: app: test spec: containers: - name: app image: xxxx serviceAccountName: test-sa |
(4)client-go 中调用
config,err := rest.InClusterConfig() if err!=nil { panic(err) } client,err := kubernetes.NewForConfig(config) if err!=nil { panic(err) } |
2、client-go中操作自定义资源
(1)DynamicClient客户端(推荐)
DynamicClient客户端是一种动态客户端,可以对任意的Kubernetes资源进行RESTful操作,包括CRD资源。
代码示例
func TestDynamicClient(t *testing.T) {
config,err := rest.InClusterConfig()
if err!=nil {
panic(err)
}
if err != nil {
panic(err)
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
panic(err)
}
gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"}
//用于设置请求的资源组,资源版本,资源名称即命名空间;List函数用于获取Pod列表
unstructObj, err := dynamicClient.Resource(gvr).Namespace(corev1.NamespaceDefault).
List(context.Background(), metav1.ListOptions{Limit: 500})
if err != nil {
panic(err)
}
podList := &corev1.PodList{}
//通过runtime的函数将unstructured.UnstructuredList转换为PodList
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.UnstructuredContent(), podList)
if err != nil {
panic(err)
}
for _, d := range podList.Items {
fmt.Printf("NAMESPACE:%v \t NAME:%v \t STATU:%v\n", d.Namespace, d.Name, d.Status.Phase)
}
}
DynamicClient如何操作CRD资源
代码示例:
func TestDynamicClient(t *testing.T) { config,err := rest.InClusterConfig() if err!=nil { panic(err) } if err != nil { panic(err) } dynamicClient, err := dynamic.NewForConfig(config) if err != nil { panic(err) } // 定义要操作的 CRD 资源的 Group 和 Version group := "example.com" version := "v1" plural := "foos" // 创建一个自定义资源对象 foo := &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": fmt.Sprintf("%s/%s", group, version), "kind": "Foo", "metadata": map[string]interface{}{ "name": "example-foo", }, "spec": map[string]interface{}{ "message": "Hello, CRD!", }, }, } // 指定要操作的资源的 Group、Version 和 Resource resource := schema.GroupVersionResource{Group: group, Version: version, Resource: plural} // 创建 Foo 资源 created, err := dynamicClient.Resource(resource).Namespace("default").Create(context.TODO(), foo, metav1.CreateOptions{}) if err != nil { fmt.Printf("Error creating foo: %s\n", err.Error()) panic(err) } fmt.Printf("Created foo: %v\n", created) }
(2)Typed Clients客户端
它们是针对 Kubernetes API 中定义的具体资源类型的客户端,如 Pods、Services 等。这些客户端通常是类型安全的,可以享受静态类型语言的一些好处。
代码示例
func TestTypedClient(t *testing.T) {
config,err := rest.InClusterConfig()
if err!=nil {
panic(err)
}
if err != nil {
panic(err)
}
client, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
namespace := "myns"
deploy,err := client.AppsV1().Deployments(namespace).Get("test",metav1.GetOptions{})
if err != nil {
panic(err)
}
}
CRD 如何使用 Typed Client
对于 CRD,如果想通过 Client-Go Typed Client 的方式来操作的话,那么第一步,是得我们先定义 CRD 的 Go 数据结构
通过 Kubernetes 的官方工具:Code Generator 来生成可以直接使用的 ClientSet(可以以 Typed Client 和 API Server 交互的 Client)
参考