实现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