Client-go 入门和实战(一) 简介与简单运用 电脑版发表于:2025/10/17 15:42  >#Client-go 入门和实战(一) 简介与简单运用 [TOC] Client-go 简介 ------------ ### 什么是 Client-go? tn2>Client-go 是 Kubernetes 官方提供的 Go 语言的客户端库, 使用该库可以访问 Kubernetes API Server,实现对 Kubernetes 资源(包括 CRD)的增删改查操作。 ### Kubernetes API Group tn2>K8s API 分为核心 API 和命名 API 组,对资源的增删改查可以理解为是对 K8s API 的请求 Client-go 封装了请求 API 所需的鉴权、请求参数以及将返回 JSON 转化为 Go 结构体(Unmarshaling)  ### Kubernetes Core API tn2>包括 namespace、 service、pods、nodes、configmap、secrets、pv 等对象  ### Kubernetes Named API tn2>包括 apps/v1/deployments、 apps/v1/replicasets 等对象  ### 验证 K8s API 请求 tn2>获取 namespaces(core API) :`https://172.30.1.2:6443/api/v1/namespaces?limit=500` 当然你们可能是`127.0.0.1` ```bash kubectl get ns -v6 ```  tn2>获取 deployment(named API):`https://172.30.1.2:6443/apis/apps/v1/namespaces/default/deployments?limit=500` ```bash kubectl get deploy -v6 ```  ### 理解 GVK 和 GVR   ### 快速尝试 tn2>以获取 Pod 和 Deployment 为例介绍 Client-go 的用法 首先初始化go mod ```bash go mod init github.com/lyzhang1999/demo1 ``` tn>go.mod 就是用来记录这些依赖的清单的。 而 go.sum 是用来记录每个依赖的哈希值(确保安全和一致性)的。 tn2>下面展示了使用`client-go`查看`kube-system`名称空间下的pod。 ```go package main import ( "context" "flag" "fmt" "path/filepath" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" ) func main() { // 加载 kubeconfig 配置 var kubeconfig *string if home := homedir.HomeDir(); home != "" { kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "kubeconfig 文件路径") } else { kubeconfig = flag.String("kubeconfig", "", "kubeconfig 文件路径") } flag.Parse() // 构建配置 config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) if err != nil { panic(err.Error()) } // 创建 Kubernetes 客户端 clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err.Error()) } // 获取所有 Pod pods, err := clientset.CoreV1().Pods("kube-system").List(context.TODO(), metav1.ListOptions{}) if err != nil { panic(err.Error()) } fmt.Printf("找到 %d 个 Pod:\n", len(pods.Items)) for _, pod := range pods.Items { fmt.Println(pod.Name) } } ``` tn2>go mod tidy 会自动清理和修复 go.mod 与 go.sum 文件,让它们保持与项目实际依赖一致。 ```bash go mod tidy ``` tn2>运行我们的代码。 ```bash go run main.go ```  tn2>接着我们使用命令进行查看是否正确。 ```bash kubectl get pod -n kube-system ```  tn2>输出的Pod我们发现是一样的。 tn>注意:如果go的版本比较落后请进行升级,我这里Linux的升级脚本如下: ```bash wget https://go.dev/dl/go1.23.2.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.23.2.linux-amd64.tar.gz ``` ### 获取Deployment tn2>在上面的基础上添加如下代码,来获取`kube-system`名词空间下的deployment。 ```go deplouments, err := clientset.AppsV1().Deployments("kube-system").List(context.TODO(), metav1.ListOptions{}) for _, deploument := range deplouments.Items { fmt.Println(deploument.Name) } ```  tn2>可以看到它输出了`calico-kube-controllers`和`coredns`,与我们执行的获取deploy是一样的。 Client-go 在集群内的配置 ------------ tn2>借助`InClusterConfig`的方法来获取K8s API的Token。 需要注意给Service Account授权,否则无对应权限。 ### In Cluster Configuration原理 tn2>1.K8s 会给每个Pod注入Service Account配置文件,包括token和ca证书,路径如下: `/var/run/secrets/kubernetes.io/serviceaccount/token` `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` 2.K8s默认会给所有Pod注入`KUBERNETES_SERVICE_HOST`和`KUBERNETES_SERVICE_PORT`变量。 首先,我们尝试创建一个简单的nginx pod,然后查看一下。 ```bash kubectl run nginx --image=nginx ``` tn2>创建完成之后我们看一下它的环境变量。 ```bash kubectl exec pod/nginx -- env ```  ```bash KUBERNETES_SERVICE_HOST=10.96.0.1 KUBERNETES_SERVICE_PORT=443 ``` tn2>查看注入的token文件地址。  ### 代码示例 tn2>首先创建一个`demo`的集群角色,并给它`pod`和`deployment`的`list`权限,除此之外我们将`demo`绑定到我们的默认角色中。 ```bash kubectl create clusterrole demo --resource pods,deployment --verb list kubectl create clusterrolebinding demo --clusterrole demo --serviceaccount default:default ``` tn2>代码示例如下,这里的`InClusterConfig`将会直接使用我们之前看到的路径下的Token进行访问集群。 ```go package main import ( "context" "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) func main() { config, err := rest.InClusterConfig() if err != nil { fmt.Printf("error %s", err.Error()) } clientset, err := kubernetes.NewForConfig(config) if err != nil { fmt.Printf("error %s", err.Error()) } pods, err := clientset.CoreV1().Pods("kube-system").List(context.Background(), metav1.ListOptions{}) if err != nil { fmt.Printf("error %s", err.Error()) } for _, pod := range pods.Items { fmt.Printf("Pod name %s\n", pod.Name) } deployment, err := clientset.AppsV1().Deployments("kube-system").List(context.Background(), metav1.ListOptions{}) for _, d := range deployment.Items { fmt.Printf("deployment name %s", d.Name) } } ``` tn2>定义`Containerfile`文件。 ```bash FROM golang AS build-stage WORKDIR /app COPY . . RUN go mod download && go build main.go FROM ubuntu WORKDIR / COPY --from=build-stage app/main /main ENTRYPOINT ["/main"] ``` tn2>通过`nerdctl build -t lyzhang1999/model-6-demo-1:in-cluster-1 . --namespace=k8s.io`打包成容器后,定义`deployment.yaml`文件进行执行。 ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: demo-1 name: demo-1 spec: replicas: 1 selector: matchLabels: app: demo-1 strategy: {} template: metadata: labels: app: demo-1 spec: nodeName: controlplane containers: - image: lyzhang1999/model-6-demo-1:in-cluster-1 name: model-6-demo-1 imagePullPolicy: Never status: {} ``` tn>可以通过这样的方式安装`nerdctl`: ```bash wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-amd64.tar.gz sudo tar -C /usr/local -xzf nerdctl-full-1.7.6-linux-amd64.tar.gz sudo systemctl enable --now buildkit ``` tn2>查看生成的容器镜像。 ```bash nerdctl images ```  tn2>接着我们开始部署`deployment.yaml`文件。 ```bash kubectl apply -f deployment.yaml ``` tn2>发现报错 ```bash arning ErrImageNeverPull 6s (x4 over 19s) kubelet Container image "lyzhang1999/model-6-demo-1:in-cluster-1" is not present with pull policy of Never Warning Failed 6s (x4 over 19s) kubelet Error: ErrImageNeverPull ``` tn2>把镜像从 nerdctl 默认空间导出 ```bash nerdctl save --namespace default lyzhang1999/model-6-demo-1:in-cluster-1 -o model.tar ``` tn2>用 ctr 导入到 k8s.io 命名空间 ```bash sudo ctr -n=k8s.io image import model.tar ``` tn2>验证 kubelet 现在能看到 ```bash sudo crictl images | grep model-6-demo-1 ```  tn2>我们再次来进行查看就可以了。 