client-go gin的简单整合九-Create

2022-06-21 17:39:12 浏览数 (4)

背景:

完成了前面一些简单list-watch的demo,这里开始进一步完成crud的基本操作,就从create开始了。这里从create namespace deployment pod service作一个简单的应用列举

create namespace

关于namespace

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

代码语言:txt复制
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 创建命名空间的方法!

image.pngimage.png
image.pngimage.png

最终如下:

代码语言:txt复制
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,最终如下:

代码语言:txt复制
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

代码语言:txt复制
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()
}
代码语言:txt复制
[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 测试

7g3olHY80B.png7g3olHY80B.png
8rtFS5e0c0.png8rtFS5e0c0.png

Create Pod

参照:https://blog.csdn.net/weixin_42562106/article/details/122024744,对比上面的前面创建namespace步骤创建Pod 文件:

Pod.go

/src/service/Pod.go

代码语言:txt复制
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

代码语言:txt复制
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运行了)

image.pngimage.png

Postman 测试创建pod

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

image.pngimage.png

get访问验证pod是否创建成功:

http://127.0.0.1:8080/pods?ns=zhangpeng

GF3YlJTT63.pngGF3YlJTT63.png

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

代码语言:txt复制
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

代码语言:txt复制
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!

代码语言:txt复制
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

代码语言:txt复制
{"name":"zhangpeng",
"namespace":"zhangpeng",
"replicas":1,
"ports":"tcp,80,web",
"images":"nginx"}
image.pngimage.png

kubernetes集群操作:

代码语言:txt复制
[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

代码语言:txt复制
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的相关配置!

瑕疵

image.pngimage.png

再搞一次程序就挂......打印关于rs的错误,估计list watch还算那里有问题,先忽略:

image.pngimage.png

后面再去研究吧.......现在我就是想能创建deployment......

总结:

  1. github大法好,的善于查找资源
  2. 没有想好list watch是否可以创建deployment?
  3. /src/service/DepUtils.go还要消化,拿来的感觉很有用。ports的获取方式我开始一直没有想好怎么实现,感谢github......

1 人点赞