背景:
完成了前面一些简单list-watch的demo,这里开始进一步完成crud的基本操作,就从create开始了。这里从create namespace deployment pod service作一个简单的应用列举
create namespace
关于namespace
前面做过list的应用:client-go gin的简单整合八Service-list初步收尾,/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=zhangpeng
Create Deployment
参照:创建一个deployment(https://www.yuque.com/duiniwukenaihe/hg6ymd/mgg2r0#x0tFi).反正还是没有想好怎么搞,然后在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…
总结:
- github大法好,的善于查找资源
- 没有想好list watch是否可以创建deployment?
- /src/service/DepUtils.go还要消化,拿来的感觉很有用。ports的获取方式我开始一直没有想好怎么实现,感谢github…