![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwIjNx8CX39CXy8CXycXZpZVZnFWbp9zZlBnauQWO1ADO5Y2MlNmN0gTZiVTZ3YWMhN2NmRWY1EmNhRmYvwVM5UjNzYzMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.jpeg)
使用開源項目 client-go 調用 Kubernetes API,是現在go項目的開發中調用Kubernetes的主流方案。下面給幾個簡單的例子:
- 建立 KubernetesClient
- 建立 KubernetesDynamicClient - 動态用戶端資料結構更靈活,但是好像支援的kind有限
- KubernetesClient 擷取deployment清單,擷取storageclass清單,擷取pvc清單,擷取pod清單,建立pod。
- 通用資料結構 使用NewKubernetesDynamicClient建立pod
- yaml檔案 使用NewKubernetesDynamicClient建立pod
- 使用KubernetesClient建立、更新、删除secret。為了更新Openstack的keystone資訊,比如Openstack的租戶變了,使用者變了,密碼變了,可以通過client-go更新Kubernetes中的secret,借助Kubernetes的Openstack CSI插件:cinder-csi-plugin,可以讓Kubernetes繼續使用keystone變更後的Cinder存儲。
建立 KubernetesClient 和 KubernetesDynamicClient
type Config struct {
Hosts []string
Token string
}
func NewKubernetesClient(c *Config) (*kubernetes.Clientset, error) {
var aliveHost string
aliveHost, err := SelectAliveHost(c.Hosts)
if err != nil {
return nil, err
}
if !strings.Contains(aliveHost, ":") {
aliveHost = fmt.Sprintf("%s:%d", aliveHost, constant.ClusterApiServerPort)
}
kubeConf := &rest.Config{
Host: string(aliveHost),
BearerToken: c.Token,
TLSClientConfig: rest.TLSClientConfig{
Insecure: true,
},
}
client, err := kubernetes.NewForConfig(kubeConf)
if err != nil {
return client, errors.Wrap(err, fmt.Sprintf("new kubernetes client with config failed: %v", err))
}
return client, nil
}
func NewKubernetesDynamicClient(c *Config) (dynamic.Interface, error) {
var aliveHost string
aliveHost, err := SelectAliveHost(c.Hosts)
if err != nil {
return nil, err
}
if !strings.Contains(aliveHost, ":") {
aliveHost = fmt.Sprintf("%s:%d", aliveHost, constant.ClusterApiServerPort)
}
kubeConf := &rest.Config{
Host: string(aliveHost),
BearerToken: c.Token,
TLSClientConfig: rest.TLSClientConfig{
Insecure: true,
},
}
client, err := dynamic.NewForConfig(kubeConf)
if err != nil {
return client, errors.Wrap(err, fmt.Sprintf("new kubernetes client with config failed: %v", err))
}
return client, nil
}
複制代碼
複制
KubernetesClient 擷取deployment清單,擷取storageclass清單,擷取pvc清單,擷取pod清單,建立pod。
config := kubeutil.Config{
Hosts: service.hosts,
Token: service.token,
}
clientset, err := kubeutil.NewKubernetesClient(&config)
if err != nil {
logger.Log.Errorf("get clientset error:%+v, host:%s", err, strings.Join(service.hosts, ","))
return err
}
deploymentsClient := clientset.AppsV1().Deployments(apiv1.NamespaceDefault)
list, _ := deploymentsClient.List(context.TODO(), metav1.ListOptions{})
for _, d := range list.Items {
fmt.Printf(" * deployment %s (%d replicas)\n", d.Name, *d.Spec.Replicas)
}
scClient := clientset.StorageV1().StorageClasses()
scList, _ := scClient.List(context.TODO(), metav1.ListOptions{})
for _, d := range scList.Items {
fmt.Printf(" * sc %v %v\n", d.Name, d.Provisioner)
}
pvcClient := clientset.CoreV1().PersistentVolumeClaims(apiv1.NamespaceDefault)
pvcList, _ := pvcClient.List(context.TODO(), metav1.ListOptions{})
for _, d := range pvcList.Items {
fmt.Printf(" * pvc %v %v\n", d.Name, d.Status.Capacity)
}
podClient := clientset.CoreV1().Pods(apiv1.NamespaceDefault)
podList, _ := podClient.List(context.TODO(), metav1.ListOptions{})
for _, d := range podList.Items {
fmt.Printf(" * pod %v %v\n", d.Name, d.Status.PodIP)
}
var pod apiv1.Pod
pod.APIVersion = "v1"
pod.Kind = "Pod"
pod.ObjectMeta = metav1.ObjectMeta{
Name: "nginx-by-go",
}
containerList := make([]apiv1.Container, 0)
containerList = append(containerList, apiv1.Container{
Name: "nginx-by-go",
Image: "registry.paas:8087/library/nginx",
ImagePullPolicy: "IfNotPresent",
})
pod.Spec = apiv1.PodSpec{
Containers: containerList,
}
podClient.Create(context.TODO(), &pod, metav1.CreateOptions{})
複制代碼
複制
使用NewKubernetesDynamicClient建立pod,和上面的例子對比明顯感受到動态用戶端的資料的靈活性。接下來的例子更靈活,直接用了yaml檔案。
client, err := kubeutil.NewKubernetesDynamicClient(&config)
podRes := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
dynamicPod := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Pod",
"metadata": map[string]interface{}{
"name": "nginx",
},
"spec": map[string]interface{}{
"containers": []map[string]interface{}{
{
"image": "registry.paas:8087/library/nginx",
"imagePullPolicy": "IfNotPresent",
"name": "nginx",
},
},
},
},
}
fmt.Println(dynamicPod)
dynamicPodList, err := client.Resource(podRes).Namespace(apiv1.NamespaceDefault).List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err)
}
for _, d := range dynamicPodList.Items {
fmt.Printf(" * dynamicPod %s \n", d.GetName())
}
createrResult, err := client.Resource(podRes).Namespace(apiv1.NamespaceDefault).Create(context.TODO(), dynamicPod, metav1.CreateOptions{})
if err != nil {
return err
}
fmt.Printf("Created deployment %q.\n", createrResult.GetName())
複制代碼
複制
使用NewKubernetesDynamicClient建立pod,該例子和上面的例子明顯感受到動态用戶端的資料的靈活性
client, err := kubeutil.NewKubernetesDynamicClient(&config)
gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
decoder := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
obj := &unstructured.Unstructured{}
var gvk schema.GroupVersionKind
yamlData, err := ioutil.ReadFile("resources/simple.yaml")
if _, _, err := decoder.Decode(yamlData, &gvk, obj); err != nil {
return err
}
utd, err := client.Resource(gvr).Namespace(apiv1.NamespaceDefault).Create(context.TODO(), obj, metav1.CreateOptions{})
if err != nil {
return err
}
fmt.Println("utd")
fmt.Println(utd)
複制代碼
複制
secret好像動态用戶端建立不了,是以使用KubernetesClient建立、更新、删除secret。為了更新Openstack的keystone資訊,比如Openstack的租戶變了,使用者變了,密碼變了,可以通過client-go更新Kubernetes中的secret,借助Kubernetes的Openstack CSI插件:cinder-csi-plugin,可以讓Kubernetes繼續使用keystone變更後的Cinder存儲。
func (service *ClusterSCService) TT() error {
config := kubeutil.Config{
Hosts: service.hosts,
Token: service.token,
}
clientset, err := kubeutil.NewKubernetesClient(&config)
if err != nil {
logger.Log.Errorf("get clientset error:%+v, host:%s", err, strings.Join(service.hosts, ","))
return err
}
secretClient := clientset.CoreV1().Secrets("kube-system")
secretList, _ := secretClient.List(context.TODO(), metav1.ListOptions{})
for _, d := range secretList.Items {
fmt.Printf(" * secret: %v %v\n", d.Name, d.Type)
}
var secret apiv1.Secret
secret.Kind = "Secret"
secret.APIVersion = "v1"
secret.ObjectMeta = metav1.ObjectMeta{
Name: "cloud-config",
Namespace: "kube-system",
}
dataMap := make(map[string][]byte)
dataMap["cloud.conf"] = []byte("W0dsb2JhbF0KdXNlcm5hbWUgPSBhZG1pbgpwYXNzd29yZCA9IEFkbWluX1BXRF84NjQ4NjczNTFxc2Myd2R2M2VmYjRyZ24KdGVuYW50LWlkID0gOWEyY2I0MDlmMGRhNDhlMzg1ODY4ZjI3ZmM5YzhjOWIKZG9tYWluLW5hbWUgPSBEZWZhdWx0CmF1dGgtdXJsID0gaHR0cDovL29wZW5zdGFjay1rZXlzdG9uZS12aXA6MzUzNTcvdjMKcmVnaW9uID0gcmVnaW9ub25lCg==")
secret.Data = dataMap
fmt.Println(secret)
result, err := secretClient.Create(context.TODO(), &secret, metav1.CreateOptions{})
if err != nil {
fmt.Printf("err ... %v", err)
return err
}
fmt.Printf(" * secret create: %v\n", result)
result.Data["cloud.conf"] = []byte("hhh")
fmt.Printf(" * new secret: %v\n", result)
result, err = secretClient.Update(context.TODO(), result, metav1.UpdateOptions{})
if err != nil {
fmt.Printf("err ... %v", err)
return err
}
fmt.Printf(" * secret update: %v\n", result)
err = secretClient.Delete(context.TODO(), "cloud-config", metav1.DeleteOptions{})
if err != nil {
fmt.Printf("err ... %v", err)
return err
}
return nil
}
複制代碼
複制