实现一个lister获取pod和deployment信息并部署到K8s集群

实现Kubernetes client

配置加载

加载本地的kubeconfig配置文件

go 复制代码
package main

import (
	"context"
	"log"
	"os/exec"
	"os/user"
	"strings"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	// "k8s.io/client-go/rest"
)

// read kube config path from homedir
func NewClient() (*kubernetes.Clientset, error) {
	user, err := user.Current()
	if err != nil {
		return nil, err
	}
	cmd := exec.Command("echo", user.HomeDir+"/.kube/config")
	output, err := cmd.Output()
	if err != nil {
		return nil, err
	}
	return nil, nil
}

找到当前用户的家目录,Kubernetes的集群配置文件路径就是$HOME/.kube/config

当程序运行在集群中后,就无法再使用上述方法读取到配置文件,此时需要使用InClusterConfig加载集群配置文件

go 复制代码
// read kube config path from homedir
func NewClient() (*kubernetes.Clientset, error) {

        ...
	configPath := strings.TrimSpace(string(output))
	log.Println("kube config file path: ", configPath)
	var config *rest.Config
	config, err = clientcmd.BuildConfigFromFlags("", configPath)
	if err != nil {
		// initialize from cluster config
		config, err = rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
	}
	return nil, nil
}

初始化client

加载kubeconfig配置文件并初始化client

go 复制代码
// read kube config path from homedir
func NewClient() (*kubernetes.Clientset, error) {
	user, err := user.Current()
	if err != nil {
		return nil, err
	}
	cmd := exec.Command("echo", user.HomeDir+"/.kube/config")
	output, err := cmd.Output()
	if err != nil {
		return nil, err
	}

	configPath := strings.TrimSpace(string(output))
	log.Println("kube config file path: ", configPath)
	var config *rest.Config
	config, err = clientcmd.BuildConfigFromFlags("", configPath)
	if err != nil {
		// initialize from cluster config
		config, err = rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
	}
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}
	return clientset, nil
}

获取Pod信息

通过client获取指定namespace下的pod列表信息

go 复制代码
package main

import (
	"context"
	"log"
	"os/exec"
	"os/user"
	"strings"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	// "k8s.io/client-go/rest"
)

// read kube config path from homedir
func NewClient() (*kubernetes.Clientset, error) {
    ...
}

func list(clientset *kubernetes.Clientset) {
	// get pod
	podList, err := clientset.CoreV1().Pods("kube-system").List(context.Background(), metav1.ListOptions{})
	if apierrors.IsNotFound(err) {
		log.Println("not found")
	}
	if err != nil {
		log.Fatal(err)
	}
	for _, pod := range podList.Items {
		log.Println(pod.Name)
	}
}

func main() {
	clientset, err := NewClient()
	if err != nil {
		log.Fatal(err)
	}
	list(clientset)
}

获取pod列表打印所有pod的名称

获取Deployment信息

获取名为"nginx-deployment"的deployment实例

go 复制代码
func list(clientset *kubernetes.Clientset) {
	// get pod
        ...
	// get a deployment by name
	name := "nginx-deployment"
	deploy, err := clientset.AppsV1().Deployments("default").Get(context.Background(), name, metav1.GetOptions{})
	if apierrors.IsNotFound(err) {
		log.Println("not found")
		return
	}
	if err != nil {
		log.Fatal(err)
	}
	log.Println("deployment name: ", deploy.Name)
}
...

在main中轮询list接口打印相关资源的信息

go 复制代码
func main() {
	clientset, err := NewClient()
	if err != nil {
		log.Fatal(err)
	}
	for {
		list(clientset)
		time.Sleep(30 * time.Second)
	}
}

部署应用到K8s集群

编译程序

sh 复制代码
➜  client-go-app GOPROXY=https://goproxy.io,direct go mod tidy
➜  client-go-app go build .
➜  client-go-app go build -o main .
2024/03/23 11:01:23 kube config file path:  /home/going/.kube/config
2024/03/23 11:01:23 coredns-76f75df574-2xpv8
2024/03/23 11:01:23 coredns-76f75df574-ncccv
2024/03/23 11:01:23 etcd-test-control-plane
2024/03/23 11:01:23 kindnet-cvbck
2024/03/23 11:01:23 kube-apiserver-test-control-plane
2024/03/23 11:01:23 kube-controller-manager-test-control-plane
2024/03/23 11:01:23 kube-proxy-9428x
2024/03/23 11:01:23 kube-scheduler-test-control-plane
2024/03/23 11:01:23 deployment name:  nginx-deployment

编写Dockerifle并构建镜像

编写Dockerfile

dockerfile 复制代码
FROM golang:1.22

WORKDIR /opt

COPY main.go main.go
COPY go.mod go.mod
COPY go.sum go.sum
RUN GOPROXY=https://goproxy.io,direct go mod tidy
RUN go build -a -o /opt/main .

CMD ["/opt/main"]

构建docker镜像

sh 复制代码
➜  client-go-app sudo docker build -t jxs1211/lister:v0.0.1 .
 => [internal] load build definition from Dockerfile                                                                                                                                                              0.0s
 => => transferring dockerfile: 211B                                                                                                                                                                              0.0s
 => [internal] load metadata for docker.io/library/golang:1.22                                                                                                                                                    1.8s
 => [auth] library/golang:pull token for registry-1.docker.io                                                                                                                                                     0.0s
 => [internal] load .dockerignore                                                                                                                                                                                 0.0s
 => => transferring context: 2B                                                                                                                                                                                   0.0s
 => [1/7] FROM docker.io/library/golang:1.22@sha256:0b55ab82ac2a54a6f8f85ec8b943b9e470c39e32c109b766bbc1b801f3fa8d3b                                                                                              0.0s
 => [internal] load build context                                                                                                                                                                                 0.0s
 => => transferring context: 1.53kB                                                                                                                                                                               0.0s
 => CACHED [2/7] WORKDIR /opt                                                                                                                                                                                     0.0s
 => [3/7] COPY main.go main.go                                                                                                                                                                                    0.0s
 => [4/7] COPY go.mod go.mod                                                                                                                                                                                      0.1s
 => [5/7] COPY go.sum go.sum                                                                                                                                                                                      0.0s
 => [6/7] RUN GOPROXY=https://goproxy.io,direct go mod tidy                                                                                                                                                      16.5s
 => [7/7] RUN go build .                                                                                                                                                                                        258.6s
 => exporting to image                                                                                                                                                                                            6.5s
 => => exporting layers                                                                                                                                                                                           6.5s
 => => writing image sha256:fa391e8509fcad8770467eaaad64a55839ae49e7608f5aea1abda26c09b02d47                                                                                                                      0.0s
 => => naming to docker.io/jxs1211/lister:v0.0.1                                                                                                                                                                  0.0s
➜  client-go-app 

上传镜像

sh 复制代码
➜  client-go-app sudo docker push jxs1211/lister:v0.0.1           
The push refers to repository [docker.io/jxs1211/lister]
9cea1fbbab41: Pushed 
5230f0e56593: Pushed 
49cbb87e7a8c: Pushed 
26cf4dbd97ef: Pushed 
eab45223e502: Pushed 
5f70bf18a086: Mounted from library/golang 
09efec90669c: Mounted from library/golang 
ae0862c6a26c: Mounted from library/golang 
e47d37fbe176: Mounted from library/golang 
68866beb2ed2: Mounted from library/golang 
e6e2ab10dba6: Mounted from library/golang 
0238a1790324: Mounted from library/golang 
v0.0.1: digest: sha256:98a4a45165779e218ae050cd485f87803d4566105f5988e6832d62f1e911f6fe size: 3043

部署应用到集群

编写Deployment配置文件

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: lister
  name: lister
spec:
  replicas: 1
  selector:
    matchLabels:
      app: lister
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: lister
    spec:
      containers:
        - image: jxs1211/lister:v0.0.1
          name: lister
          imagePullPolicy: Always
          resources: {}

部署Deployment到集群

sh 复制代码
➜  client-go-app ka -f lister.yaml          
deployment.apps/lister created
➜  client-go-app kg pod -w        
NAME                     READY   STATUS              RESTARTS   AGE
lister-9f8bf577b-hz42l   0/1     ContainerCreating   0          2s
lister-9f8bf577b-hz42l   1/1     Running             0          27s
lister-9f8bf577b-hz42l   0/1     Error               0          28s

发现问题,处理异常

发现异常,查看日志

sh 复制代码
➜  client-go-app k logs -f lister-9f8bf577b-hz42l                      
2024/03/23 03:49:40 kube config file path:  /root/.kube/config
2024/03/23 03:49:40 pods is forbidden: User "system:serviceaccount:default:default" cannot list resource "pods" in API group "" in the namespace "kube-system"
➜  client-go-app

报错信息显示:"pod使用的serviceaccount无法获取pod信息",原因是pod在集群中没有权限访问APIServer,所以无法获取Pod信息,于是我们需要配置RBAC为Pod提供相应的权限。

创建ClusterRole设置相关资源的访问权限

yaml 复制代码
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: lister
rules:
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - list
      - get
  - apiGroups:
      - apps
    resources:
      - deployments
    verbs:
      - list
      - get

编写ClusteRoleBinding并将ClusterRole绑定到Serviceaccount,这个serviceacount名为default,是pod使用的默认serviceaccount

yaml 复制代码
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  creationTimestamp: null
  name: lister
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: lister
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default

部署所有权限相关的配置到集群

sh 复制代码
➜  client-go-app ka -f role.yaml       
clusterrole.rbac.authorization.k8s.io/lister created
➜  client-go-app ka -f rolebinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/lister created

重新构建镜像并上传到镜像仓库

ini 复制代码
➜  client-go-app sudo docker build -t jxs1211/lister:v0.0.1 . && sudo docker push jxs1211/lister:v0.0.1
[sudo] password for going: 
[+] Building 273.7s (13/13) FINISHED                                                     docker:default
 => [internal] load build definition from Dockerfile                                               0.0s
 => => transferring dockerfile: 229B                                                               0.0s
 => [internal] load metadata for docker.io/library/golang:1.22                                     1.9s
 => [auth] library/golang:pull token for registry-1.docker.io                                      0.0s
 => [internal] load .dockerignore                                                                  0.0s
 => => transferring context: 2B                                                                    0.0s
 => [1/7] FROM docker.io/library/golang:1.22@sha256:0b55ab82ac2a54a6f8f85ec8b943b9e470c39e32c109b  0.0s
 => [internal] load build context                                                                  0.0s
 => => transferring context: 1.84kB                                                                0.0s
 => CACHED [2/7] WORKDIR /opt                                                                      0.0s
 => [3/7] COPY main.go main.go                                                                     0.0s
 => [4/7] COPY go.mod go.mod                                                                       0.0s
 => [5/7] COPY go.sum go.sum                                                                       0.0s
 => [6/7] RUN GOPROXY=https://goproxy.io,direct go mod tidy                                       10.1s
 => [7/7] RUN go build -a -o /opt/main .                                                         256.6s 
 => exporting to image                                                                             4.9s 
 => => exporting layers                                                                            4.9s 
 => => writing image sha256:418a3f81de6dea5eb16ee16daecef5f32a6359f1efdcb9b5754f7239de8c22c3       0.0s 
 => => naming to docker.io/jxs1211/lister:v0.0.1                                                   0.0s 
The push refers to repository [docker.io/jxs1211/lister]                                                
2f7236794eeb: Pushed 
c37d55347bb1: Pushed 
58e88ebcbf16: Pushed 
8be899e11629: Pushed 
2ebcc941d35e: Pushed 
5f70bf18a086: Layer already exists 
09efec90669c: Layer already exists 
ae0862c6a26c: Layer already exists 
e47d37fbe176: Layer already exists 
68866beb2ed2: Layer already exists 
e6e2ab10dba6: Layer already exists 
0238a1790324: Layer already exists 
v0.0.1: digest: sha256:dfc547c278cd230783efbf0913ac5a5ba97cc9885a49c9dcef19534ffaad43d0 size: 3043
➜  client-go-app 

重新部署应用并查看日志显示成功获取到资源信息

sh 复制代码
➜  client-go-app kd -f lister.yaml 
deployment.apps "lister" deleted
➜  client-go-app ka -f lister.yaml
deployment.apps/lister created
➜  client-go-app kg pod           
NAME                     READY   STATUS              RESTARTS   AGE
lister-9f8bf577b-dgljv   0/1     ContainerCreating   0          7s
➜  client-go-app kg pod    
NAME                     READY   STATUS    RESTARTS   AGE
lister-9f8bf577b-dgljv   1/1     Running   0          47s
➜  client-go-app k logs -f lister-9f8bf577b-dgljv                      
2024/03/23 05:16:22 kube config file path:  /root/.kube/config
2024/03/23 05:16:22 coredns-76f75df574-2xpv8
2024/03/23 05:16:22 coredns-76f75df574-ncccv
2024/03/23 05:16:22 etcd-test-control-plane
2024/03/23 05:16:22 kindnet-cvbck
2024/03/23 05:16:22 kube-apiserver-test-control-plane
2024/03/23 05:16:22 kube-controller-manager-test-control-plane
2024/03/23 05:16:22 kube-proxy-9428x
2024/03/23 05:16:22 kube-scheduler-test-control-plane
2024/03/23 05:16:22 not found
2024/03/23 05:16:52 coredns-76f75df574-2xpv8
2024/03/23 05:16:52 coredns-76f75df574-ncccv
2024/03/23 05:16:52 etcd-test-control-plane
2024/03/23 05:16:52 kindnet-cvbck
2024/03/23 05:16:52 kube-apiserver-test-control-plane
2024/03/23 05:16:52 kube-controller-manager-test-control-plane
2024/03/23 05:16:52 kube-proxy-9428x
2024/03/23 05:16:52 kube-scheduler-test-control-plane
2024/03/23 05:16:52 not found
相关推荐
苏三的开发日记18 分钟前
windows系统搭建kafka环境
后端
爬山算法28 分钟前
Netty(19)Netty的性能优化手段有哪些?
java·后端
Tony Bai29 分钟前
Cloudflare 2025 年度报告发布——Go 语言再次“屠榜”API 领域,AI 流量激增!
开发语言·人工智能·后端·golang
想用offer打牌42 分钟前
虚拟内存与寻址方式解析(面试版)
java·后端·面试·系统架构
無量1 小时前
AQS抽象队列同步器原理与应用
后端
9号达人1 小时前
支付成功订单却没了?MyBatis连接池的坑我踩了
java·后端·面试
用户497357337982 小时前
【轻松掌握通信协议】C#的通信过程与协议实操 | 2024全新
后端
草莓熊Lotso2 小时前
C++11 核心精髓:类新功能、lambda与包装器实战
开发语言·c++·人工智能·经验分享·后端·nginx·asp.net
追逐时光者2 小时前
精选 8 个 .NET 开发实用的类库,效率提升利器!
后端·.net
a程序小傲3 小时前
京东Java面试被问:Fork/Join框架的使用场景
java·开发语言·后端·postgresql·面试·职场和发展