准備工作
1. 檢查k8s的版本
[root@k8s-node1 ~]# kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5", GitCommit:"aea7bbadd2fc0cd689de94a54e5b7b758869d691", GitTreeState:"clean", BuildDate:"2021-09-15T21:10:45Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5", GitCommit:"aea7bbadd2fc0cd689de94a54e5b7b758869d691", GitTreeState:"clean", BuildDate:"2021-09-15T21:04:16Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"}
2. 選擇和kuberntes適配的client-go版本
client-go的源碼位置:https://github.com/kubernetes/client-go.git
ps:This repository is still a mirror of k8s.io/kubernetes/staging/src/client-go, the code development is still done in the staging area.
client-go是k8s.io/kubernetes/staging/src/client-go的一個鏡像,該倉庫下的代碼開發工作仍舊是在staging下完成的
由於我們的Kubernetes版本為v1.21.5,所以適配的client-go版本也為v0.1.25,關於如何適配,官方這樣描述:
- If you are using Kubernetes versions >= v1.17.0, use a corresponding v0.x.y tag. For example, k8s.io/client-go@v0.20.4 corresponds to Kubernetes v1.20.4:
go get k8s.io/client-go@v0.20.4- If you are using Kubernetes versions < v1.17.0, use a corresponding kubernetes-1.x.y tag. For example, k8s.io/client-go@kubernetes-1.16.3 corresponds to Kubernetes v1.16.3:
go get k8s.io/client-go@kubernetes-1.16.3
3. 到kubernets集群中拿到kubeconfig文件
關於client-go的運行方式,它可以運行在集群內的pod內,也可也運行在集群外
-
在集群內運行時,需要將應用打成鏡像,部署到集群內;client-go在調用“rest.InClusterConfig() ”將使用pod內“/var/run/secrets/kubernetes.io/serviceaccount”目錄下的token文件做集群內的訪問認證,如下面是某個container中該目錄下的內容:
-
在集群外部運行時,需要使用到kubeconfig文件,它包含了集群初始化一個client的信息,該文件也被kubectl命令用作訪問集群時的身份認證
這里我們選擇在集群之外運行
Authenticating outside the cluster
This example shows you how to configure a client with client-go to authenticate to the Kubernetes API from an application running outside the Kubernetes cluster.
You can use your kubeconfig file that contains the context information of your cluster to initialize a client. The kubeconfig file is also used by the
kubectl
command to authenticate to the clusters.
登錄到kuberntes集群,取得/root/.kube/config文件,將文件下載到本地的“C:\Users\Administrator\.kube\”路徑下。
點擊查看代碼
[root@k8s-node1 .kube]# cat config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1ERXlNREF5TVRFME1Gb1hEVE15TURFeE9EQXlNVEUwTUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTGhYCkEyY1B3T0Y0R0R0bGN3RFY3UGVOUThYOUd2MnlkRGJCNnhYd2ZJdGtTcGM1Vk50R3E1Q0FyeUtnSDcrdVJnUUkKK2VSeXNaT3Z1eGhoRGR5dmhCSnFhcm54TEJ0dmlTVTViYjlBT3NIUmsveWdHN2ZLbkl1bVp6K1hvSHFGcjAwTQo5ZzNPMXJBeVZuaFFTbmVqcEl6T09nOXlmNDZTN2ZLZi92USt0OWJmSzUySmN1VVlQZHA0b1p2ek5HWlc3MGdnCjFFbGRQMDJZYk81T1hBbjhzK2l3MG1JWm50QU1CU0pMT2x1eUkrK08remF0YTEvTStXNlc2YXRoT1Eyd0EyR3QKVm56bFpaVXZIRmJkVlFBNThBN2JmRWs3M24yVzdNZmlYMHdYKzRDdHZoNGJpaUNldkRoc3FXOHp6S0dZam5tNAp5dWZ5MTRXM3IwUFluNk5zR2k4Q0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZHSE9saWdkVUdCUlhodGxsL2xqRzY3S0FSQk5NQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFDdEt5R0pkVVMxUGs0bCs0YldMSUJOaTFWejlzeHFLMURZNmJWdjRXU2JxQmUyWnc0cgo4Mm5URzVKR0hmcEg1dmZ5RlRJR3VKYzNGRnc1dG82VDQ4alhyKzZTTUIxMXZnVUs0Yjl1cWVLU1JHM3RGRVRuCllyNXorZHk4QUFuNHdPUlZpY1RsQlM3OTN3bzVqdnhTMGQ5Vy9tVVJXVEkwSGluQ0grdzBWMXVhT2ljeUxpQTIKQjBIM2dtRmZaNlhmYlZHT2k0TnZXMHdtdnRGUmdpUnJsaC9ndHZ2amtBTVpsb2pyWWhKampuZUl3S1Bla1djYQpzKzEzRnVJdTE5QU11cUdJRW9OQVJFRlZtU3ArSFE2d1RnRmt2MSthbWFJRnowcHlvVFNzQWFaNEYvVXdCT016CmFpTDArTXhqWnZ4bkdHcFVXMUxVZGVtcS9YNlZVOEtMdXRWagotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://lb.kubesphere.local:6443
name: cluster.local
contexts:
- context:
cluster: cluster.local
user: kubernetes-admin
name: kubernetes-admin@cluster.local
current-context: kubernetes-admin@cluster.local
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJSURMWXUycmpjd0V3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TWpBeE1qQXdNakV4TkRCYUZ3MHlNekF4TWpBd01qRXhOREZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXh5cTd6MHphN2U3bmhKVnEKNy95ODlza2QyWmpXTUJtdlFWaVdxbFQyT0RtNGpIV3lRbllRYXROVXZHeTZmb1Y5TWpNWnB2Y1RhZWUvZlZWNQo1RE9zSEFhWjhnRzRieWlYaW5EaXU5aGljZTVCbldnR0R0aytOUnY0SXd1aHNXd25CZEgzQVc3eTNtNTd6RmxkCnNHeG1yMzhFdERUd0lVa3ZLazROMTJLRHFoZFNMRWhmVVlTRmRVVHJSV0VCTEtCNkFURGVsYWZiUW1WYnZDbzgKM3ZMeWxSbTB6VWdFVGc3NUZ0NGFkRWVJMjY2RDJZZmYvQnd3Z2w0cDJvSFlKb1h5VSthMnlnK1JWZDJIVzZXcQpVMTJVd2ZlUEpCQ3habnJrZmFCek16ajduK1l3RlF4THFMOFBsN01kc3RDMHdJb3BmLzNOaVp1YWR2TFIwUDVaCkZEWTNHUUlEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JSaHpwWW9IVkJnVVY0YlpaZjVZeHV1eWdFUQpUVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBSzU1QVJ2K1crT1lYaGEzdXVhd2NrbGYzVjEwTkc4NndpRnNJCkU2ejBiamV5dVVuUGxtdTZ0ZEN3Z0VYZFl0TDV4RHp3NG43RXVWRkZuSVZZRFpwM21LYmFtU0tsYm05WmZNKzcKWmtDVFlkdnkwbUcxS2dyR0dRejA4QVVOcUw5ZkR4M1ZSYUw5cWhvd1ozWG81Ykd6MGc5U2lCZGV0NGpuMnBuZQo1eUR1SWh2TE9PbVo1Rm5JTGZGY1pQYjc0RGZqaldnSEc3OGt3KzI2YXRFSWRZVWQxMWhxNk9nSEphaVRsZnRkCnlSNWdsV3JnQWIwT2JlSXk3cFR1bVhteGd1a25JaFhxMUlOZElaZWVwa3l0a3gxZm53ZmxkcGExYTA4RFlCNzMKcVlKVWY3V0o3dERnWFAzUFpnNVNYZVlFZFhLZVNnY1lSc3EwODF4aFBRaE5qQVI0REE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBeHlxN3owemE3ZTduaEpWcTcveTg5c2tkMlpqV01CbXZRVmlXcWxUMk9EbTRqSFd5ClFuWVFhdE5Vdkd5NmZvVjlNak1acHZjVGFlZS9mVlY1NURPc0hBYVo4Z0c0YnlpWGluRGl1OWhpY2U1Qm5XZ0cKRHRrK05SdjRJd3Voc1d3bkJkSDNBVzd5M201N3pGbGRzR3htcjM4RXREVHdJVWt2S2s0TjEyS0RxaGRTTEVoZgpVWVNGZFVUclJXRUJMS0I2QVREZWxhZmJRbVZidkNvODN2THlsUm0welVnRVRnNzVGdDRhZEVlSTI2NkQyWWZmCi9Cd3dnbDRwMm9IWUpvWHlVK2EyeWcrUlZkMkhXNldxVTEyVXdmZVBKQkN4Wm5ya2ZhQnpNemo3bitZd0ZReEwKcUw4UGw3TWRzdEMwd0lvcGYvM05pWnVhZHZMUjBQNVpGRFkzR1FJREFRQUJBb0lCQUM5R1VYWVBSQmdlRVE1RAplVEtseHlTODhEenFMazBVaTZqeklqQWtJcDJOOWVSQk82TFM2MnF2NXZraXhkR3FWZUZJaDlvOTQzbkw3SVFQCmVmTlU0SkYyYjZ3bUJHVStPVm8vR1ZLRk5qamMyTzVIOXNnbmdNQ1Nkdis2anhMU0hTRWdpWVRwbFBSL1BSdHcKU3ZESmlrWTEzQ1A2UE5WcHphdzVBc2dSTmpkMURnRFc2a0ZkMTRGQ3pxaTdlVmRhLzdaVjltVXNrb1lRaEVtYwp2ZVgyTTJRaXhOQUQvTkorblZzaGlFZExqTU9RTXc3VjNMK1VueHpHNm1qQjlJbXB6RGp0VkluYmZGWW4yekZ6Cmt0c0ljdWtRZWFkd2o3d1ZUL2c2U1NrcURiaWFuR3Bma0tkaTJEK1cvT1FoNTBadzZKSHE4MWtXY2VVMG8zVHoKUlk2YkI1RUNnWUVBOTZ3ZDk2QTV1Y2dwcjZ6L0tyejI5a3pjOVo5RFB3bnFoN0JsUFdWc1RiQkUvZmE0ckNSLwpsSHBhL2RJWFZ4dmpncTdRd0tRREdFcnN1SlRzTnNMczVLUUswdnFxVEZ4d29Rd0ZodlZLbWFMdndJWDlmNTZQCk1SWDVIV1BkYUV3L0JzcnZwdGUySTFtTDIxNVJpTC9BL0VSMVFvR2Y3b2xzNU5oZ21Kcko4K3NDZ1lFQXpkMFoKQ3F5L242Y2syRVUxUFNVa0NJVk15ZWdQVGNjVGdlelFaTjZBb2JJYjIzVXdhSlFDMndFK3l5QmhmMSthdGVDRApkSkRpU0ZBWVFyemJRUFdRSXNYQThWRm5KRzNOeGp0ZkI4OGNLaW1TcUJ3NmNOVVJuYmo2YzVLYzAvMmNyWlcvClFISzJwVDNXTi9HbEdRb1FlN2VmNUFjNndCT1lXS014c0dHM05Bc0NnWUVBbGRxQkkwUEJ5YVBQZlNpNkZ6elEKWEVRemFUWWN0UGFsL2NWLzYvOEM0WnFtazljRTg3cjlxblBCdkZPeXBaVU5PaFBWNE1rYnlrWURKc2VNaUxHMgpMYjBIZzVJQkdrVFFMTkVlUXdNRlNTSXAyQjM2UEk1T2EwKzFNOUFwdGFKMGZBS3JzQkpTZE44SVhRbWJZWmRNCkNCYlBzQmJJRXNiNXFSazJrUDhPOUZNQ2dZRUFwbUtoLzcrNXJTY2huMjdvWmNBa0RJTDRtbVBtSXAzWlJYU0sKeGt3VHVSekVhUzZoYnBUYWJmbm1yN1EvT1B5amhZYXRtTVFWTUE4VVhMUlpuWG9jQWc3Rk1BWDBFRHh6U1ZucApKOTJjVFBPRzVqclNmU21vOEVwMm1ueVFKc0xmSkdsWXg1VXZ6QVJicEtHNUo3Qzd1OUtnOTJOa2Q2UWV5TjAxCnB2S0RhUnNDZ1lFQWdNVk8xa1JkTDJpU2ZLTEl3dSs4SFQydHlXMGp0Y2VDTmlJdEJqdlMwRFA4d2JjMGk3SXkKdFlLNHl1MGdEdEdNZUZ3WXpRa3pMaE1DbzNBSldUbHZjdTdJbVZoUG04bEtWdTRUYThIdFI3L3B1NUNGWnhKMQpEODE5RnlkM3Q3dm51S3grMnY1Q3VYQmlvMTlHZVRoTjB3RkxRSzRnYzlXZmNrUktLanFBQmdnPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
[root@k8s-node1 .kube]#
**注意:如果應用是部署在ECS設備上,需要添加端口放行規則
創建開發項目
在Goland中創建go module項目“K8s-client-go”,添加依賴:go get k8s.io/client-go@v0.21.5
下面我們主要要查看的就是集群中的namespace
點擊查看代碼
package main
import (
"context"
"flag"
"fmt"
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"
"k8s.io/klog"
"path/filepath"
)
func main() {
var kubeConfig *string
ctx := context.Background()
//取得kubeconfig的路徑
if home := homedir.HomeDir();home!= ""{
kubeConfig=flag.String("kubeConfig",filepath.Join(home,".kube","config"),"absolute path to the kubeconfig file")
}else {
kubeConfig=flag.String("kubeConfig","","absolute path to the kubeconfig file")
}
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeConfig)
if err!=nil{
klog.Fatal(err)
return
}
clientset, err := kubernetes.NewForConfig(config)
if err!=nil{
klog.Fatal(err)
return
}
//獲取namespaces信息
namespaces := clientset.CoreV1().Namespaces()
namespaceList, err := namespaces.List(ctx, metav1.ListOptions{})
if err!=nil{
klog.Fatal(err)
return
}
for _, namespace := range namespaceList.Items {
fmt.Println(namespace.Name)
}
}
運行結果:
default
edu
his
his-devops98s4z
kube-node-lease
kube-public
kube-system
kubesphere-controls-system
kubesphere-devops-system
kubesphere-devops-worker
kubesphere-monitoring-federated
kubesphere-monitoring-system
kubesphere-system
mall
這里有一個需要說明的地方,我們在列舉namespace時,使用的是“clientset.CoreV1().Namespaces()”,為什么是corev1不是appsv1,這是因為namespaces在api-resouces中定義的位置所決定的:
點擊查看代碼
[root@k8s-node1 ~]# kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
podtemplates v1 true PodTemplate
replicationcontrollers rc v1 true ReplicationController
resourcequotas quota v1 true ResourceQuota
secrets v1 true Secret
serviceaccounts sa v1 true ServiceAccount
services svc v1 true Service
...
上面的這些APIVERSION為v1的都是corev1下的資源,但是有些版本中該字段顯示為空;它們在Kubernetes倉庫中的地址:kubernetes\staging\src\k8s.io\client-go\kubernetes\typed\core\v1
有些時候,若不確定資源在何路徑下,可以打印它的日志
namespace
[root@k8s-node1 ~]# kubectl get namespace -v=7
I0124 17:23:07.560906 590266 loader.go:372] Config loaded from file: /root/.kube/config
I0124 17:23:07.571697 590266 round_trippers.go:432] GET https://lb.kubesphere.local:6443/api/v1/namespaces?limit=500
daemonset
[root@k8s-node1 ~]#kubectl get daemonset -v=7
I0124 17:24:44.668978 592516 loader.go:372] Config loaded from file: /root/.kube/config
I0124 17:24:44.679221 592516 round_trippers.go:432] GET https://lb.kubesphere.local:6443/apis/apps/v1/namespaces/default/daemonsets?limit=500
如果想要直接通過API來訪問集群中的namespace,需要開啟代理
kubectl proxy --port=8080
訪問:
curl http://127.0.0.1:8080/api/v1/namespaces
GVR和GVK
GVR:Group Version Resource的簡寫。它唯一確定了一個HTTP路徑,如:在default的命名空間內,有一個
/apis/batch/v1/namespaces/default/jobs的GVR。下圖展示jobs資源的GVR形式
不過需要注意是,有些集群范圍內的資源,如節點或命名空間自身,它們的路徑中就不包含namespaces着一部分
。如nodes GVR的路徑可能是api/v1/nodes。另外,上面的$NAMESPACE本身也是一種資源,可以通過/api/v1/namespaces來訪問
GVK:Group Version Kind的簡寫,
(1)每種GVK對應一種Go語言的類型,但是一種GO語言類型可以用於多個不同的GVK。
比如 apps/v1/Deployment 就關聯着 K8s 源碼里面 http://k8s.io/api/apps/v1 package 中的 Deployment struct
(2)源定義 YAML 文件都需要寫:
- apiVersion:這個就是 GV 。
- kind:這個就是 K。
根據 GVK K8s 就能找到你到底要創建什么類型的資源,根據你定義的 Spec 創建好資源之后就成為了 Resource,也就是 GVR。GVK/GVR 就是 K8s 資源的坐標,是我們創建/刪除/修改/讀取資源的基礎。
通過YAML文件來創建Deployment
yamls/nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myngx
namespace: myweb
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
name: a2 #設置成自己的node名稱或刪除
containers:
- name: nginxtest
image: nginx:1.18-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
承接上面的代碼:
package main
import (
"context"
"flag"
"io/ioutil"
v1 "k8s.io/api/apps/v1"
coreV1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"k8s.io/klog/v2"
"path/filepath"
)
func main() {
var kubeConfig *string
ctx := context.Background()
//取得kubeconfig的路徑
if home := homedir.HomeDir();home!= ""{
kubeConfig=flag.String("kubeConfig",filepath.Join(home,".kube","config"),"absolute path to the kubeconfig file")
}else {
kubeConfig=flag.String("kubeConfig","","absolute path to the kubeconfig file")
}
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeConfig)
if err!=nil{
klog.Fatal(err)
return
}
clientset, err := kubernetes.NewForConfig(config)
if err!=nil{
klog.Fatal(err)
return
}
createDeploymentFromYaml(clientset,ctx)
}
func createDeploymentFromYaml(clientSet *kubernetes.Clientset,ctx context.Context) {
//創建namespace myweb
myweb:=&coreV1.Namespace{
ObjectMeta:metav1.ObjectMeta{Name: "myweb"},
}
clientSet.CoreV1().Namespaces().Create(ctx, myweb, metav1.CreateOptions{})
//創建deployment myngx
deploye:=&v1.Deployment{}
bytes, err := ioutil.ReadFile("yamls/nginx.yaml")
if err!= nil{
klog.Fatal(err)
}
toJSON, err := yaml.ToJSON(bytes)
if err!= nil{
klog.Fatal(err)
}
json.Unmarshal(toJSON,&deploye)
_, err = clientSet.AppsV1().Deployments("myweb").Create(ctx, deploye, metav1.CreateOptions{})
if err!= nil{
klog.Fatal(err)
}
}
查看:
[root@k8s-node1 ~]# kubectl get all -n myweb
NAME READY STATUS RESTARTS AGE
pod/myngx-d767d4644-4qn44 0/1 Running 0 2m28s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/myngx 0/1 1 0 2m28s
NAME DESIRED CURRENT READY AGE
replicaset.apps/myngx-d767d4644 1 1 0 2m28s
關於kubernetes的日志級別
--v=0 Generally useful for this to ALWAYS be visible to an operator.
--v=1 A reasonable default log level if you don’t want verbosity.
--v=2 Useful steady state information about the service and important log messages that may correlate to significant changes in the system. This is the recommended default log level for most systems.
--v=3 Extended information about changes.
--v=4 Debug level verbosity.
--v=6 Display requested resources.
--v=7 Display HTTP request headers.
--v=8 Display HTTP request contents
參考連接:
- k8s各組件啟動時, -v參數指定的日志級別
- kubernetes中kubeconfig的用法
- programming-kubernetes 作者: [Michael Hausenblas](https://book.douban.com/search/Michael Hausenblas) / [Stefan Schimanski](https://book.douban.com/search/Stefan Schimanski)