乐趣区

关于kubernetes:clientgo-gin的简单整合九Create

背景:

实现了后面一些简略 list-watch 的 demo, 这里开始进一步实现 crud 的基本操作,就从 create 开始了。这里从 create namespace deployment pod service 作一个简略的利用列举

create namespace

对于 namespace

后面做过 list 的利用:client-go list namespace,/src/service/Namespace.go 文件如下:

package service

import (
    "context"
    "github.com/gin-gonic/gin"
    . "k8s-demo1/src/lib"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "time"
)

type Time struct {time.Time `protobuf:"-"`}
type Namespace struct {
    Name       string
    CreateTime Time `json:"CreateTime"`
    Status     string
    Labels     map[string]string
}

func ListNamespace(g *gin.Context) {ns, err := K8sClient.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
    if err != nil {g.Error(err)
        return
    }
    ret := make([]*Namespace, 0)
    for _, item := range ns.Items {
        ret = append(ret, &Namespace{
            Name:       item.Name,
            CreateTime: Time(item.CreationTimestamp),
            Status:     string(item.Status.Phase),
            Labels:     item.Labels,
        })

    }
    g.JSON(200, ret)
    return
}

创立一个 namespace

当初要创立一个 create 创立命名空间的办法!


最终如下:

func create(ns Namespace) (*v1.Namespace, error) {ctx := context.Background()
    newNamespace, err := K8sClient.CoreV1().Namespaces().Create(ctx, &v1.Namespace{
        ObjectMeta: metav1.ObjectMeta{
            Name:   ns.Name,
            Labels: ns.Labels,
        },
    }, metav1.CreateOptions{})
    if err != nil {fmt.Println(err)
    }
    return newNamespace, err
}

而后创立 CreateNameSpace,最终如下:

package service

import (
    "context"
    "fmt"
    "github.com/gin-gonic/gin"
    . "k8s-demo1/src/lib"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "time"
)

type Time struct {time.Time `protobuf:"-"`}
type Namespace struct {
    Name        string            `json:"name"`
    CreateTime  time.Time         `json:"CreateTime"`
    Status      string            `json:"status"`
    Labels      map[string]string `json:"labels"`
    Annotations map[string]string `json:"annotations"`
}

func ListNamespace(g *gin.Context) {ns, err := K8sClient.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
    if err != nil {g.Error(err)
        return
    }
    ret := make([]*Namespace, 0)
    for _, item := range ns.Items {
        ret = append(ret, &Namespace{
            Name:       item.Name,
            CreateTime: item.CreationTimestamp.Time,
            Status:     string(item.Status.Phase),
            Labels:     item.Labels,
        })

    }
    g.JSON(200, ret)
    return
}
func create(ns Namespace) (*v1.Namespace, error) {ctx := context.Background()
    newNamespace, err := K8sClient.CoreV1().Namespaces().Create(ctx, &v1.Namespace{
        ObjectMeta: metav1.ObjectMeta{
            Name:   ns.Name,
            Labels: ns.Labels,
        },
    }, metav1.CreateOptions{})
    if err != nil {fmt.Println(err)
    }
    return newNamespace, err
}
func CreateNameSpace(g *gin.Context) {
    var nameSpace Namespace
    if err := g.ShouldBind(&nameSpace); err != nil {g.JSON(500, err)
    }
    namespace, err := create(nameSpace)
    if err != nil {g.JSON(500, err)
    }
    ns := Namespace{
        Name:        namespace.Name,
        CreateTime:  namespace.CreationTimestamp.Time,
        Status:      string(namespace.Status.Phase),
        Labels:      nil,
        Annotations: nil,
    }
    g.JSON(200, ns)
}

注:ShouldBind 强调一下参照:https://www.kancloud.cn/shuangdeyu/gin_book/949426。当然了 name 是不能够为空的能够尝试一下!

编辑并运行 main.go

package main

import (
    "github.com/gin-gonic/gin"
    "k8s-demo1/src/core"
    "k8s-demo1/src/service"
    //    "k8s.io/client-go/informers/core"
)

func main() {r := gin.Default()
    r.GET("/", func(context *gin.Context) {context.JSON(200, "hello")
    })
    r.GET("/namespaces", service.ListNamespace)
  r.POST("/namespace", service.CreateNameSpace)
    r.GET("/deployments", service.ListDeployment)
    r.GET("/service", service.ListService)
    r.GET("pods", service.ListallPod)
    core.InitDeployment()
    r.Run()}
[zhangpeng@zhangpeng ~]$ kubectl get ns
NAME              STATUS   AGE
default           Active   50d
kube-node-lease   Active   50d
kube-public       Active   50d
kube-system       Active   50d

运行 main.go……

Postman 测试


Create Pod

参照:https://blog.csdn.net/weixin_42562106/article/details/122024744, 比照下面的后面创立 namespace 步骤创立 Pod 文件:

Pod.go

/src/service/Pod.go

package service

import (
    "context"
    "fmt"
    "github.com/gin-gonic/gin"
    "k8s-demo1/src/core"
    . "k8s-demo1/src/lib"
    v1 "k8s.io/api/apps/v1"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type Pod struct {
    Namespace   string                 `json:"namespace"`
    Name        string                 `json:"name"`
    Status      string                 `json:"status"`
    Images      string                 `json:"images"`
    NodeName    string                 `json:"nodename"`
    CreateTime  string                 `json:"createtime"`
    Annotations map[string]string      `json:"annotations"`
    Port        []corev1.ContainerPort `json:"port"`
    //IsReady    bool
    //Message      string
    //HostIp       string
    //PodIp        string
    //RestartCount int32
    Labels map[string]string `json:"labels"`
}

func ListallPod(g *gin.Context) {ns := g.Query("ns")

    //pods, err := K8sClient.CoreV1().Pods(ns).List(context.Background(), metav1.ListOptions{})
    pods, err := core.PodMap.ListByNS(ns)
    if err != nil {g.Error(err)
    }
    ret := make([]*Pod, 0)
    for _, item := range pods {

        ret = append(ret, &Pod{
            Namespace: item.Namespace,
            Name:      item.Name,
            Status:    string(item.Status.Phase),
            Labels:    item.Labels,
            NodeName:  item.Spec.NodeName,
            Images:    item.Spec.Containers[0].Image,
            //IsReady:   GetPodIsReady(*item),
            //Message: GetPodMessage(*item),
            //Message:      core.EventMap.GetMessage(item.Namespace, "Pod", item.Name),
            //HostIp:       item.Status.HostIP,
            //PodIp:        item.Status.PodIP,
            //RestartCount: item.Status.ContainerStatuses[0].RestartCount,
            CreateTime: item.CreationTimestamp.Format("2006-01-02 15:04:05"),
        })

    }
    g.JSON(200, ret)
    return
}
func Createpod(pod Pod) (*corev1.Pod, error) {newpod, err := K8sClient.CoreV1().Pods(pod.Namespace).Create(context.TODO(), &corev1.Pod{
        ObjectMeta: metav1.ObjectMeta{
            Name:        pod.Name,
            Namespace:   pod.Namespace,
            Labels:      pod.Labels,
            Annotations: pod.Annotations,
        },
        Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: pod.Name, Image: pod.Images},
            },
        },
    }, metav1.CreateOptions{})
    if err != nil {fmt.Println(err)
    }
    return newpod, err
}
func CreatePod(g *gin.Context) {
    var NewPod Pod
    if err := g.ShouldBind(&NewPod); err != nil {g.JSON(500, err)
    }
    pod, err := Createpod(NewPod)
    if err != nil {g.JSON(500, err)
    }
    newpod := Pod{
        Namespace:   pod.Namespace,
        Name:        pod.Name,
        Images:      pod.Spec.Containers[0].Image,
        CreateTime:  pod.CreationTimestamp.Format("2006-01-02 15:04:05"),
        Annotations: nil,
    }
    g.JSON(200, newpod)
}

注:json:"",shouldbind 的应用仍然是是 ……

main.go 增加路由

main.go

package main

import (
    "github.com/gin-gonic/gin"
    "k8s-demo1/src/core"
    "k8s-demo1/src/service"
    //    "k8s.io/client-go/informers/core"
)

func main() {r := gin.Default()
    r.GET("/", func(context *gin.Context) {context.JSON(200, "hello")
    })
    r.GET("/namespaces", service.ListNamespace)
    r.GET("/deployments", service.ListDeployment)
    r.GET("/service", service.ListService)
    r.GET("pods", service.ListallPod)
    r.POST("/namespace", service.CreateNameSpace)
    r.POST("/pod", service.CreatePod)
    core.InitDeployment()
    r.Run()}

运行 main.go

go run main.go(间接 goland 运行了)

Postman 测试创立 pod

在 zhangpeng 命名空间下创立镜像为 nginx,名为 zhangpeng 的 pod

get 拜访验证 pod 是否创立胜利:
http://127.0.0.1:8080/pods?ns…

Create Deployment

参照:创立一个 deployment. 反正还是没有想好怎么搞,而后在 github 找到了一个我能看懂的拿来主义了:
https://github.com/c18871384325/Go-teacher/blob/784f81c7309e2567cbdd45580c3a8f277a1f3528/course/day20-20200829/codes/cmdb/forms/k8s.go
and https://github.com/c18871384325/Go-teacher/blob/784f81c7309e2567cbdd45580c3a8f277a1f3528/course/day20-20200829/codes/cmdb/services/k8s.go

github 拿来主义

/src/service/DepUtils.go

package service

import (
    coreV1 "k8s.io/api/core/v1"
    "strconv"
    "strings"
)

func (d *Deployment) GetLabels() map[string]string {labelsMap := make(map[string]string)
    labels := strings.Split(d.Labels, "\n")
    for _, label := range labels {values := strings.SplitN(label, ":", 2)
        if len(values) != 2 {continue}
        labelsMap[strings.TrimSpace(values[0])] = strings.TrimSpace(values[1])
    }
    return labelsMap
}

func (d *Deployment) GetSelectors() map[string]string {selectors := d.GetLabels()
    selectors["app"] = d.Name
    return selectors
}
func (d *Deployment) GetPorts() []coreV1.ContainerPort {portList := make([]coreV1.ContainerPort, 0, 5)
    ports := strings.Split(d.Ports, "\n")
    for _, port := range ports {values := strings.SplitN(port, ",", 3)
        if len(values) != 3 {continue}
        intPort, err := strconv.Atoi(values[1])
        if err != nil {continue}
        protocol := coreV1.ProtocolTCP
        if strings.Compare(strings.ToLower(values[0]), "tcp") != 0 {protocol = coreV1.ProtocolUDP}
        portList = append(portList, coreV1.ContainerPort{Name:          strings.TrimSpace(values[2]),
            ContainerPort: int32(intPort),
            Protocol:      protocol,
        })
    }

    return portList
}
func (d *Deployment) GetImageName() string {
    // 全副为应为字母数字和:
    pods := strings.Index(d.Images, ":")
    if pods > 0 {return d.Images[:pods]
    }
    return d.Images
}

/src/service/deployment.go

package service

import (
    "context"
    "fmt"
    "github.com/gin-gonic/gin"
    "k8s-demo1/src/core"
    . "k8s-demo1/src/lib"
    v1 "k8s.io/api/apps/v1"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "log"
)

type Deployment struct {
    Namespace           string `json:"namespace"`
    Name                string `json:"name"`
    Replicas            int32  `json:"replicas"`
    AvailableReplicas   int32  `json:"available-replicas"`
    UnavailableReplicas int32  `json:"unavailable-replicas"`
    Images              string `json:"images"`
    Ports               string `json:"ports"`
    CreateTime          string `json:"CreateTime"`
    Labels              string `json:"labels"`
    Pods                []*Pod `json:"pods"`}

func ListDeployment(g *gin.Context) {ns := g.Query("ns")
    deplist, _ := core.DepMap.ListByNS(ns)

    ret := make([]*Deployment, 0)
    for _, item := range deplist {
        ret = append(ret, &Deployment{
            Namespace:           item.Namespace,
            Name:                item.Name,
            Replicas:            item.Status.Replicas,
            AvailableReplicas:   item.Status.AvailableReplicas,
            UnavailableReplicas: item.Status.UnavailableReplicas,
            Images:              item.Spec.Template.Spec.Containers[0].Image,
            //Labels:              item.GetLabels(),
            Pods:       GetPodsByDep(*item),
            CreateTime: item.CreationTimestamp.Format("2006-01-02 15:03:04"),
        })

    }
    g.JSON(200, ret)
    return
}
func Createdep(dep Deployment) (*v1.Deployment, error) {newdep, err := K8sClient.AppsV1().Deployments(dep.Namespace).Create(context.TODO(), &v1.Deployment{
        ObjectMeta: metav1.ObjectMeta{
            Name:      dep.Name,
            Namespace: dep.Namespace,
            Labels:    dep.GetLabels(),},
        Spec: v1.DeploymentSpec{
            Replicas: &dep.Replicas,
            Selector: &metav1.LabelSelector{MatchLabels: dep.GetSelectors(),
            },
            Template: corev1.PodTemplateSpec{
                ObjectMeta: metav1.ObjectMeta{
                    Name:   dep.Name,
                    Labels: dep.GetSelectors(),},
                Spec: corev1.PodSpec{Containers: []corev1.Container{
                        {Name:  dep.GetImageName(),
                            Image: dep.Images,
                            Ports: dep.GetPorts(),},
                    },
                },
            },
        },
    }, metav1.CreateOptions{})
    if err != nil {fmt.Println(err)
    }
    return newdep, err
}

func CreateDep(g *gin.Context) {
    var newDep Deployment
    if err := g.ShouldBind(&newDep); err != nil {g.JSON(500, err)
    }
    newdep, err := Createdep(newDep)
    if err != nil {g.JSON(500, err)
    }
    newDep1 := Deployment{
        Namespace:  newdep.Namespace,
        Name:       newdep.Name,
        Pods:       GetPodsByDep(*newdep),
        CreateTime: newdep.CreationTimestamp.Format("2006-01-02 15:03:04"),
    }
    g.JSON(200, newDep1)
}

func GetLabels(m map[string]string) string {
    labels := ""
    // aa=xxx,xxx=xx

    for k, v := range m {
        if labels != "" {labels += ","}
        labels += fmt.Sprintf("%s=%s", k, v)
    }
    return labels
}
func GetPodsByDep(dep v1.Deployment) []*Pod {rsLabelsMap, err := core.RSMap.GetRsLabelsByDeployment(&dep)
    //fmt.Println(rsLabelsMap)
    if err != nil {log.Fatal(err)
    }
    pods, err := core.PodMap.ListByRsLabels(dep.Namespace, rsLabelsMap)
    if err != nil {log.Fatal(err)
    }
    ret := make([]*Pod, 0)
    for _, pod := range pods {
        //
        if core.RSMap.GetRsLabelsByDeploymentname(&dep) == pod.OwnerReferences[0].Name {
            ret = append(ret, &Pod{
                Name:      pod.Name,
                Namespace: pod.Namespace,
                Images:    pod.Spec.Containers[0].Image,
                NodeName:  pod.Spec.NodeName,
                Labels:    pod.Labels,
                Status:    string(pod.Status.Phase),
                //IsReady:   GetPodIsReady(*pod),
                //    Message:    GetPodMessage(*pod),
                //Message:      core.EventMap.GetMessage(pod.Namespace, "Pod", pod.Name),
                //HostIp:       pod.Status.HostIP,
                //PodIp:        pod.Status.PodIP,
                //RestartCount: pod.Status.ContainerStatuses[0].RestartCount,
                CreateTime: pod.CreationTimestamp.Format("2006-01-02 15:04:05"),
            })
        }
    }
    return ret
}

注:Deployment struct 有几个数据类型改了,办法有的也没有提交进来 …… 前面整合 ……

增加 post 路由并运行 main.go

main.go 路由增加 POST(“/deployment”, service.CreateDep),运行 main.go!

package main

import (
    "github.com/gin-gonic/gin"
    "k8s-demo1/src/core"
    "k8s-demo1/src/service"
    //    "k8s.io/client-go/informers/core"
)

func main() {r := gin.Default()
    r.GET("/", func(context *gin.Context) {context.JSON(200, "hello")
    })
    r.GET("/namespaces", service.ListNamespace)
    r.GET("/deployments", service.ListDeployment)
    r.GET("/service", service.ListService)
    r.GET("pods", service.ListallPod)
    r.POST("/namespace", service.CreateNameSpace)
    r.POST("/pod", service.CreatePod)
    r.POST("/deployment", service.CreateDep)
    core.InitDeployment()
    r.Run()}

Postman 测试创立 deployment

http://127.0.0.1:8080/deployment

{"name":"zhangpeng",
"namespace":"zhangpeng",
"replicas":1,
"ports":"tcp,80,web",
"images":"nginx"}


kubernetes 集群操作:

[zhangpeng@zhangpeng ~]$ kubectl get all -n zhangpeng
NAME                             READY   STATUS    RESTARTS   AGE
pod/zhangpeng-5dffd5664f-z567c   1/1     Running   0          62s

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/zhangpeng   1/1     1            1           62s

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/zhangpeng-5dffd5664f   1         1         1       62s

[zhangpeng@zhangpeng ~]$ kubectl get deployment -n zhangpeng -o yaml

apiVersion: v1
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    annotations:
      deployment.kubernetes.io/revision: "1"
    creationTimestamp: "2022-06-21T08:36:12Z"
    generation: 1
    name: zhangpeng
    namespace: zhangpeng
    resourceVersion: "5991952"
    uid: e8a48bdf-4c86-4413-8fb0-99ef1ddd1d6d
  spec:
    progressDeadlineSeconds: 600
    replicas: 1
    revisionHistoryLimit: 10
    selector:
      matchLabels:
        app: zhangpeng
    strategy:
      rollingUpdate:
        maxSurge: 25%
        maxUnavailable: 25%
      type: RollingUpdate
    template:
      metadata:
        creationTimestamp: null
        labels:
          app: zhangpeng
        name: zhangpeng
      spec:
        containers:
        - image: nginx
          imagePullPolicy: Always
          name: nginx
          ports:
          - containerPort: 80
            name: web
            protocol: TCP
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
        dnsPolicy: ClusterFirst
        restartPolicy: Always
        schedulerName: default-scheduler
        securityContext: {}
        terminationGracePeriodSeconds: 30
  status:
    availableReplicas: 1
    conditions:
    - lastTransitionTime: "2022-06-21T08:36:29Z"
      lastUpdateTime: "2022-06-21T08:36:29Z"
      message: Deployment has minimum availability.
      reason: MinimumReplicasAvailable
      status: "True"
      type: Available
    - lastTransitionTime: "2022-06-21T08:36:12Z"
      lastUpdateTime: "2022-06-21T08:36:29Z"
      message: ReplicaSet "zhangpeng-5dffd5664f" has successfully progressed.
      reason: NewReplicaSetAvailable
      status: "True"
      type: Progressing
    observedGeneration: 1
    readyReplicas: 1
    replicas: 1
    updatedReplicas: 1
kind: List
metadata:
  resourceVersion: ""

次要是想验证一下 ports 的相干配置!

瑕疵


再搞一次程序就挂 …… 打印对于 rs 的谬误, 预计 list watch 还算那里有问题,先疏忽:

前面再去钻研吧 ……. 当初我就是想能创立 deployment……

总结:

  1. github 大法好,的长于查找资源
  2. 没有想好 list watch 是否能够创立 deployment?
  3. /src/service/DepUtils.go 还要消化,拿来的感觉很有用。ports 的获取形式我开始始终没有想好怎么实现,感激 github……
退出移动版