Go开发PaaS平台核心功能
代码仓库地址GitHub - yunixiangfeng/gopaas
第7章 云原生 Go PaaS 平台路由管理功能开发,对外域名映射,动态设置域名
域名能够让我们的服务提供外网访问的能力,让公网也能够访问到集群内部的资源,是我们开放业务的入口。将讲解 Ingress 的核心原理和流量转化流程,熟练掌握如何应用 K8s 中的服务通过域名的方式映射到公网,提供外网访问能力。
7-1 路由ingress 架构详解
Go PaaS 平台服务管理开发
主要内容
路由作用讲解
路由原理和架构说明
开发路由管理功能
为什么要用Ingress?
ClusterlP的方式只能在集群内部访问。
NodePort 当有几十上百的服务在集群中运行时,很难管理。
LoadBalance 方式受限于云平台。
路由 Ingress 简介
Ingress:一个普通资源对象,用来表明具体路由规则
Ingress-controller: 来执行转发规则
路由 Ingress 架构说明
路由Ingress-controller (nginx) 如何运作的?
7-2 路由model与repository开发调整
PS C:\Users\Administrator\Desktop\gopaas> .\yu-tool\yu-tool.exe newService github.com/yunixiangfeng/gopaas/route
cd route
go mod tidy
// versions:
// protoc-gen-go v1.27.1
// protoc v3.15.7
// source: proto/svc/svc.proto
protoc --proto_path=. --micro_out=. --go_out=:. ./proto/route/route.proto
C:\Users\Administrator\Desktop\gopaas\route\domain\model\route.go
package model
type Route struct {
ID int64 `gorm:"primary_key;not_null;auto_increment"`
RouteName string `json:"route_name"`
RouteNamespace string `json:"route_namespace"`
RouteHost string `json:"route_host"`
RoutePath []RoutePath `gorm:"ForeignKey:RouteID" json:"route_path"`
}
C:\Users\Administrator\Desktop\gopaas\route\domain\model\route_path.go
package model
type RoutePath struct {
ID int64 `gorm:"primary_key;not_null;auto_increment"`
RouteID int64 `json:"route_id"`
RoutePathName string `json:"route_path_name"`
RouteBackendService string `json:"route_backend_service"`
RouteBackendServicePort int32 `json:"route_backend_service_port"`
}
C:\Users\Administrator\Desktop\gopaas\route\domain\repository\route_repository.go
package repository
import (
"github.com/jinzhu/gorm"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/route/domain/model"
)
//创建需要实现的接口
type IRouteRepository interface {
//初始化表
InitTable() error
//根据ID查处找数据
FindRouteByID(int64) (*model.Route, error)
//创建一条 route 数据
CreateRoute(*model.Route) (int64, error)
//根据ID删除一条 route 数据
DeleteRouteByID(int64) error
//修改更新数据
UpdateRoute(*model.Route) error
//查找route所有数据
FindAll() ([]model.Route, error)
}
//创建routeRepository
func NewRouteRepository(db *gorm.DB) IRouteRepository {
return &RouteRepository{mysqlDb: db}
}
type RouteRepository struct {
mysqlDb *gorm.DB
}
//初始化表
func (u *RouteRepository) InitTable() error {
return u.mysqlDb.CreateTable(&model.Route{}, &model.RoutePath{}).Error
}
//根据ID查找Route信息
func (u *RouteRepository) FindRouteByID(routeID int64) (route *model.Route, err error) {
route = &model.Route{}
return route, u.mysqlDb.Preload("RoutePath").First(route, routeID).Error
}
//创建Route信息
func (u *RouteRepository) CreateRoute(route *model.Route) (int64, error) {
return route.ID, u.mysqlDb.Create(route).Error
}
//根据ID删除Route信息
func (u *RouteRepository) DeleteRouteByID(routeID int64) error {
tx := u.mysqlDb.Begin()
//遇到问题回滚
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if tx.Error != nil {
common.Error(tx.Error)
return tx.Error
}
//开始删除
if err := u.mysqlDb.Where("id = ?", routeID).Delete(&model.Route{}).Error; err != nil {
tx.Rollback()
common.Error(err)
return err
}
//删除关联表
if err := u.mysqlDb.Where("route_id = ?", routeID).Delete(&model.RoutePath{}).Error; err != nil {
tx.Rollback()
common.Error(err)
return err
}
return tx.Commit().Error
}
//更新Route信息
func (u *RouteRepository) UpdateRoute(route *model.Route) error {
return u.mysqlDb.Model(route).Update(route).Error
}
//获取结果集
func (u *RouteRepository) FindAll() (routeAll []model.Route, err error) {
return routeAll, u.mysqlDb.Preload("RoutePath").Find(&routeAll).Error
}
7-3 路由 service 开发
C:\Users\Administrator\Desktop\gopaas\route\domain\service\route_data_service.go
package service
import (
"context"
"errors"
"strconv"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/route/domain/model"
"github.com/yunixiangfeng/gopaas/route/domain/repository"
"github.com/yunixiangfeng/gopaas/route/proto/route"
v1 "k8s.io/api/apps/v1"
v12 "k8s.io/api/networking/v1"
v14 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//这里是接口类型
type IRouteDataService interface {
AddRoute(*model.Route) (int64, error)
DeleteRoute(int64) error
UpdateRoute(*model.Route) error
FindRouteByID(int64) (*model.Route, error)
FindAllRoute() ([]model.Route, error)
CreateRouteToK8s(*route.RouteInfo) error
DeleteRouteFromK8s(*model.Route) error
UpdateRouteToK8s(*route.RouteInfo) error
}
//创建
//注意:返回值 IRouteDataService 接口类型
func NewRouteDataService(routeRepository repository.IRouteRepository, clientSet *kubernetes.Clientset) IRouteDataService {
return &RouteDataService{RouteRepository: routeRepository, K8sClientSet: clientSet, deployment: &v1.Deployment{}}
}
type RouteDataService struct {
//注意:这里是 IRouteRepository 类型
RouteRepository repository.IRouteRepository
K8sClientSet *kubernetes.Clientset
deployment *v1.Deployment
}
//创建k8s(把proto 属性补全)
func (u *RouteDataService) CreateRouteToK8s(info *route.RouteInfo) (err error) {
ingress := u.setIngress(info)
//查找是否存在
if _, err = u.K8sClientSet.NetworkingV1().Ingresses(info.RouteNamespace).Get(context.TODO(), info.RouteName, v14.GetOptions{}); err != nil {
if _, err = u.K8sClientSet.NetworkingV1().Ingresses(info.RouteNamespace).Create(context.TODO(), ingress, v14.CreateOptions{}); err != nil {
//创建不成功记录错误
common.Error(err)
return err
}
return nil
} else {
common.Error("路由 " + info.RouteName + " 已经存在")
return errors.New("路由 " + info.RouteName + " 已经存在")
}
}
func (u *RouteDataService) setIngress(info *route.RouteInfo) *v12.Ingress {
route := &v12.Ingress{}
//设置路由
route.TypeMeta = v14.TypeMeta{
Kind: "Ingress",
APIVersion: "v1",
}
//设置路由基础信息
route.ObjectMeta = v14.ObjectMeta{
Name: info.RouteName,
Namespace: info.RouteNamespace,
Labels: map[string]string{
"app-name": info.RouteName,
"author": "wu123",
},
Annotations: map[string]string{
"k8s/generated-by-wu": "由代码创建",
},
}
//使用 ingress-nginx
className := "nginx"
//设置路由 spec 信息
route.Spec = v12.IngressSpec{
IngressClassName: &className,
//默认访问服务
DefaultBackend: nil,
//如果开启https这里要设置
TLS: nil,
Rules: u.getIngressPath(info),
}
return route
}
//根据info信息获取path路径
func (u *RouteDataService) getIngressPath(info *route.RouteInfo) (path []v12.IngressRule) {
//1.设置host
pathRule := v12.IngressRule{Host: info.RouteHost}
//2.设置Path
ingressPath := []v12.HTTPIngressPath{}
for _, v := range info.RoutePath {
pathType := v12.PathTypePrefix
ingressPath = append(ingressPath, v12.HTTPIngressPath{
Path: v.RoutePathName,
PathType: &pathType,
Backend: v12.IngressBackend{
Service: &v12.IngressServiceBackend{
Name: v.RouteBackendService,
Port: v12.ServiceBackendPort{
Number: v.RouteBackendServicePort,
},
},
},
})
}
//3.赋值 Path
pathRule.IngressRuleValue = v12.IngressRuleValue{HTTP: &v12.HTTPIngressRuleValue{Paths: ingressPath}}
path = append(path, pathRule)
return
}
//更新route
func (u *RouteDataService) UpdateRouteToK8s(info *route.RouteInfo) (err error) {
ingress := u.setIngress(info)
if _, err = u.K8sClientSet.NetworkingV1().Ingresses(info.RouteNamespace).Update(context.TODO(), ingress, v14.UpdateOptions{}); err != nil {
common.Error(err)
return err
}
return nil
}
//删除route
func (u *RouteDataService) DeleteRouteFromK8s(route2 *model.Route) (err error) {
//删除Ingress
if err = u.K8sClientSet.NetworkingV1().Ingresses(route2.RouteNamespace).Delete(context.TODO(), route2.RouteName, v14.DeleteOptions{}); err != nil {
//如果删除失败记录下
common.Error(err)
return err
} else {
if err := u.DeleteRoute(route2.ID); err != nil {
common.Error(err)
return err
}
common.Info("删除 ingress ID:" + strconv.FormatInt(route2.ID, 10) + " 成功!")
}
return
}
//插入
func (u *RouteDataService) AddRoute(route *model.Route) (int64, error) {
return u.RouteRepository.CreateRoute(route)
}
//删除
func (u *RouteDataService) DeleteRoute(routeID int64) error {
return u.RouteRepository.DeleteRouteByID(routeID)
}
//更新
func (u *RouteDataService) UpdateRoute(route *model.Route) error {
return u.RouteRepository.UpdateRoute(route)
}
//查找
func (u *RouteDataService) FindRouteByID(routeID int64) (*model.Route, error) {
return u.RouteRepository.FindRouteByID(routeID)
}
//查找
func (u *RouteDataService) FindAllRoute() ([]model.Route, error) {
return u.RouteRepository.FindAll()
}
C:\Users\Administrator\Desktop\gopaas\route\proto\route\route.proto
syntax = "proto3";
package route;
option go_package = "./proto/route;route";
service Route {
//对外提供添加服务
rpc AddRoute(RouteInfo) returns (Response) {}
rpc DeleteRoute(RouteId) returns (Response) {}
rpc UpdateRoute(RouteInfo) returns (Response) {}
rpc FindRouteByID(RouteId) returns (RouteInfo) {}
rpc FindAllRoute(FindAll) returns (AllRoute) {}
}
message RouteInfo {
int64 id = 1;
string route_name = 2;
string route_namespace =3;
string route_host =4;
repeated RoutePath route_path=5;
}
message RoutePath {
int64 id = 1;
int64 route_id =2;
string route_path_name=3;
string route_backend_service=4;
int32 route_backend_service_port=5;
}
message RouteId {
int64 id = 1;
}
message FindAll {
}
message Response {
string msg =1 ;
}
message AllRoute {
repeated RouteInfo route_info = 1;
}
7-4 路由 handler 逻辑开发和注意事项
创建handler对外暴露服务
C:\Users\Administrator\Desktop\gopaas\route\handler\routeHandler.go
package handler
import (
"context"
"strconv"
log "github.com/asim/go-micro/v3/logger"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/route/domain/model"
"github.com/yunixiangfeng/gopaas/route/domain/service"
route "github.com/yunixiangfeng/gopaas/route/proto/route"
)
type RouteHandler struct {
//注意这里的类型是 IRouteDataService 接口类型
RouteDataService service.IRouteDataService
}
// 添加路由
func (e *RouteHandler) AddRoute(ctx context.Context, info *route.RouteInfo, rsp *route.Response) error {
log.Info("Received *route.AddRoute request")
route := &model.Route{}
if err := common.SwapTo(info, route); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//创建route到k8s
if err := e.RouteDataService.CreateRouteToK8s(info); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
} else {
//写入数据库
routeID, err := e.RouteDataService.AddRoute(route)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
common.Info("Route 添加成功 ID 号为:" + strconv.FormatInt(routeID, 10))
rsp.Msg = "Route 添加成功 ID 号为:" + strconv.FormatInt(routeID, 10)
}
return nil
}
//删除route
func (e *RouteHandler) DeleteRoute(ctx context.Context, req *route.RouteId, rsp *route.Response) error {
log.Info("Received *route.DeleteRoute request")
routeModel, err := e.RouteDataService.FindRouteByID(req.Id)
if err != nil {
common.Error(err)
return err
}
//从k8s中删除,并且删除数据库中数据
if err := e.RouteDataService.DeleteRouteFromK8s(routeModel); err != nil {
common.Error(err)
return err
}
return nil
}
//更新route
func (e *RouteHandler) UpdateRoute(ctx context.Context, req *route.RouteInfo, rsp *route.Response) error {
log.Info("Received *route.UpdateRoute request")
if err := e.RouteDataService.UpdateRouteToK8s(req); err != nil {
common.Error(err)
return err
}
//查询数据库的信息
routeModel, err := e.RouteDataService.FindRouteByID(req.Id)
if err != nil {
common.Error(err)
return err
}
//数据更新
if err := common.SwapTo(req, routeModel); err != nil {
common.Error(err)
return err
}
return e.RouteDataService.UpdateRoute(routeModel)
}
//根据ID查询route信息
func (e *RouteHandler) FindRouteByID(ctx context.Context, req *route.RouteId, rsp *route.RouteInfo) error {
log.Info("Received *route.FindRouteByID request")
routeModel, err := e.RouteDataService.FindRouteByID(req.Id)
if err != nil {
common.Error(err)
return err
}
//数据转化
if err := common.SwapTo(routeModel, rsp); err != nil {
common.Error(err)
return err
}
return nil
}
func (e *RouteHandler) FindAllRoute(ctx context.Context, req *route.FindAll, rsp *route.AllRoute) error {
log.Info("Received *route.FindAllRoute request")
allRoute, err := e.RouteDataService.FindAllRoute()
if err != nil {
common.Error(err)
return err
}
//整理下格式
for _, v := range allRoute {
//创建实例
routeInfo := &route.RouteInfo{}
//把查询出来的数据进行转化
if err := common.SwapTo(v, routeInfo); err != nil {
common.Error(err)
return err
}
//数据合并
rsp.RouteInfo = append(rsp.RouteInfo, routeInfo)
}
return nil
}
C:\Users\Administrator\Desktop\gopaas\route\main.go
package main
import (
"flag"
"fmt"
"path/filepath"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/route/domain/repository"
//"github.com/afex/hystrix-go/hystrix"
"github.com/asim/go-micro/plugins/registry/consul/v3"
ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
"github.com/asim/go-micro/v3"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/server"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/opentracing/opentracing-go"
service2 "github.com/yunixiangfeng/gopaas/route/domain/service"
"github.com/yunixiangfeng/gopaas/route/handler"
//hystrix2 "github.com/yunixiangfeng/gopaas/route/plugin/hystrix"
"strconv"
route "github.com/yunixiangfeng/gopaas/route/proto/route"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
var (
//服务地址
hostIp = "192.168.204.130"
//服务地址
serviceHost = hostIp
//服务端口
servicePort = "8085"
//注册中心配置
consulHost = hostIp
consulPort int64 = 8500
//链路追踪
tracerHost = hostIp
tracerPort = 6831
//熔断端口,每个服务不能重复
//hystrixPort = 9095
//监控端口,每个服务不能重复
prometheusPort = 9195
)
func main() {
//需要本地启动,mysql,consul中间件服务
//1.注册中心
consul := consul.NewRegistry(func(options *registry.Options) {
options.Addrs = []string{
consulHost + ":" + strconv.FormatInt(consulPort, 10),
}
})
//2.配置中心,存放经常变动的变量
consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
if err != nil {
common.Error(err)
}
//3.使用配置中心连接 mysql
mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
//初始化数据库
db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
if err != nil {
//命令行输出下,方便查看错误
fmt.Println(err)
common.Fatal(err)
}
defer db.Close()
//禁止复表
db.SingularTable(true)
//4.添加链路追踪
t, io, err := common.NewTracer("go.micro.service.route", tracerHost+":"+strconv.Itoa(tracerPort))
if err != nil {
common.Error(err)
}
defer io.Close()
opentracing.SetGlobalTracer(t)
//添加熔断器,作为客户端需要启用
//hystrixStreamHandler := hystrix.NewStreamHandler()
//hystrixStreamHandler.Start()
//添加日志中心
//1)需要程序日志打入到日志文件中
//2)在程序中添加filebeat.yml 文件
//3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
//启动监听程序
//go func() {
// //http://192.168.204.130:9092/turbine/turbine.stream
// //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
// err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
// if err !=nil {
// common.Error(err)
// }
//}()
//5.添加监控
common.PrometheusBoot(prometheusPort)
//下载kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
//macos:
// 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
// 2.chmod +x ./kubectl
// 3.sudo mv ./kubectl /usr/local/bin/kubectl
// sudo chown root: /usr/local/bin/kubectl
// 5.kubectl version --client
// 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
// 注意:- config中的域名要能解析正确
// - 生产环境可以创建另一个证书
// 7.kubectl get ns 查看是否正常
//
//6.创建k8s连接
//在集群外面连接
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) 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 {
common.Fatal(err.Error())
}
//在集群中外的配置
//config, err := rest.InClusterConfig()
//if err != nil {
// panic(err.Error())
//}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
common.Fatal(err.Error())
}
//7.创建服务
service := micro.NewService(
//自定义服务地址,且必须写在其它参数前面
micro.Server(server.NewServer(func(options *server.Options) {
options.Advertise = serviceHost + ":" + servicePort
})),
micro.Name("go.micro.service.route"),
micro.Version("latest"),
//指定服务端口
micro.Address(":"+servicePort),
//添加注册中心
micro.Registry(consul),
//添加链路追踪
micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
//只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
//micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
//添加限流
micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
)
service.Init()
//只能执行一遍
err = repository.NewRouteRepository(db).InitTable()
if err != nil {
common.Fatal(err)
}
// 注册句柄,可以快速操作已开发的服务
routeDataService := service2.NewRouteDataService(repository.NewRouteRepository(db), clientset)
route.RegisterRouteHandler(service.Server(), &handler.RouteHandler{RouteDataService: routeDataService})
// 启动服务
if err := service.Run(); err != nil {
//输出启动失败信息
common.Fatal(err)
}
}
7-5 route 对外API的开发
PS C:\Users\Administrator\Desktop\gopaas> .\yu-tool\yu-tool.exe createApi github.com/yunixiangfeng/gopaas/routeApi
yu-v3 --proto_path=. --micro_out=. --go_out=:. ./proto/routeApi/routeApi.proto
go mod tidy
C:\Users\Administrator\Desktop\gopaas\routeapi\main.go
package main
import (
"fmt"
"github.com/afex/hystrix-go/hystrix"
"github.com/asim/go-micro/plugins/registry/consul/v3"
ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
"github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v3"
opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
"github.com/asim/go-micro/v3"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/server"
"github.com/yunixiangfeng/gopaas/common"
go_micro_service_route "github.com/yunixiangfeng/gopaas/route/proto/route"
"net"
"net/http"
"strconv"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/opentracing/opentracing-go"
"github.com/yunixiangfeng/gopaas/routeApi/handler"
hystrix2 "github.com/yunixiangfeng/gopaas/routeApi/plugin/hystrix"
routeApi "github.com/yunixiangfeng/gopaas/routeApi/proto/routeApi"
)
var (
//服务地址
hostIp = "192.168.204.130"
//服务地址
serviceHost = hostIp
//服务端口
servicePort = "8086"
//注册中心配置
consulHost = hostIp
consulPort int64 = 8500
//链路追踪
tracerHost = hostIp
tracerPort = 6831
//熔断端口,每个服务不能重复
hystrixPort = 9096
//监控端口,每个服务不能重复
prometheusPort = 9196
)
func main() {
//需要本地启动,mysql,consul中间件服务
//1.注册中心
consul := consul.NewRegistry(func(options *registry.Options) {
options.Addrs = []string{
consulHost + ":" + strconv.FormatInt(consulPort, 10),
}
})
//2.添加链路追踪
t, io, err := common.NewTracer("go.micro.api.routeApi", tracerHost+":"+strconv.Itoa(tracerPort))
if err != nil {
common.Error(err)
}
defer io.Close()
opentracing.SetGlobalTracer(t)
//3.添加熔断器
hystrixStreamHandler := hystrix.NewStreamHandler()
hystrixStreamHandler.Start()
//添加日志中心
//1)需要程序日志打入到日志文件中
//2)在程序中添加filebeat.yml 文件
//3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
//启动监听程序
go func() {
//http://192.168.204.130:9092/turbine/turbine.stream
//看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
if err != nil {
common.Error(err)
}
}()
//4.添加监控
common.PrometheusBoot(prometheusPort)
//5.创建服务
service := micro.NewService(
//自定义服务地址,且必须写在其它参数前面
micro.Server(server.NewServer(func(opts *server.Options) {
opts.Advertise = serviceHost + ":" + servicePort
})),
micro.Name("go.micro.api.routeApi"),
micro.Version("latest"),
//指定服务端口
micro.Address(":"+servicePort),
//添加注册中心
micro.Registry(consul),
//添加链路追踪
micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
//只作为客户端的时候起作用
micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
//添加限流
micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
//增加负载均衡
micro.WrapClient(roundrobin.NewClientWrapper()),
)
service.Init()
// 指定需要访问的服务,可以快速操作已开发的服务,
// 默认API服务名称带有"Api",程序会自动替换
// 如果不带有特定字符会使用默认"XXX" 请自行替换
routeService := go_micro_service_route.NewRouteService("go.micro.service.route", service.Client())
// 注册控制器
if err := routeApi.RegisterRouteApiHandler(service.Server(), &handler.RouteApi{RouteService: routeService}); err != nil {
common.Error(err)
}
// 启动服务
if err := service.Run(); err != nil {
//输出启动失败信息
common.Fatal(err)
}
}
C:\Users\Administrator\Desktop\gopaas\routeapi\handler\routeApiHandler.go
package handler
import (
"context"
"encoding/json"
"errors"
"strconv"
log "github.com/asim/go-micro/v3/logger"
"github.com/yunixiangfeng/gopaas/common"
route "github.com/yunixiangfeng/gopaas/route/proto/route"
routeApi "github.com/yunixiangfeng/gopaas/routeApi/proto/routeApi"
)
type RouteApi struct {
RouteService route.RouteService
}
// routeApi.FindRouteById 通过API向外暴露为/routeApi/findRouteById,接收http请求
// 即:/routeApi/FindRouteById 请求会调用go.micro.api.routeApi 服务的routeApi.FindRouteById 方法
func (e *RouteApi) FindRouteById(ctx context.Context, req *routeApi.Request, rsp *routeApi.Response) error {
log.Info("Received routeApi.FindRouteById request")
if _, ok := req.Get["route_id"]; !ok {
rsp.StatusCode = 500
return errors.New("参数异常")
}
//获取 route id
routeIdString := req.Get["route_id"].Values[0]
routeId, err := strconv.ParseInt(routeIdString, 10, 64)
if err != nil {
common.Error(err)
return err
}
//获取route信息
routeInfo, err := e.RouteService.FindRouteByID(ctx, &route.RouteId{
Id: routeId,
})
if err != nil {
common.Error(err)
return err
}
//返回route结果
rsp.StatusCode = 200
b, _ := json.Marshal(routeInfo)
rsp.Body = string(b)
return nil
}
// routeApi.AddRoute 通过API向外暴露为/routeApi/AddRoute,接收http请求
// 即:/routeApi/AddRoute 请求会调用go.micro.api.routeApi 服务的routeApi.AddRoute 方法
func (e *RouteApi) AddRoute(ctx context.Context, req *routeApi.Request, rsp *routeApi.Response) error {
log.Info("Received routeApi.AddRoute request")
addRouteInfo := &route.RouteInfo{}
routePathName, ok := req.Post["route_path_name"]
if ok && len(routePathName.Values) > 0 {
port, err := strconv.ParseInt(req.Post["route_backend_service_port"].Values[0], 10, 32)
if err != nil {
common.Error(err)
return err
}
//这里如果有多个Path需要处理多个
routePath := &route.RoutePath{
RoutePathName: req.Post["route_path_name"].Values[0],
RouteBackendService: req.Post["route_backend_service"].Values[0],
RouteBackendServicePort: int32(port),
}
//合并
addRouteInfo.RoutePath = append(addRouteInfo.RoutePath, routePath)
}
form.FormToSvcStruct(req.Post, addRouteInfo)
response, err := e.RouteService.AddRoute(ctx, addRouteInfo)
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(response)
rsp.Body = string(b)
return nil
}
// routeApi.DeleteRouteById 通过API向外暴露为/routeApi/DeleteRouteById,接收http请求
// 即:/routeApi/DeleteRouteById 请求会调用go.micro.api.routeApi 服务的 routeApi.DeleteRouteById 方法
func (e *RouteApi) DeleteRouteById(ctx context.Context, req *routeApi.Request, rsp *routeApi.Response) error {
log.Info("Received routeApi.DeleteRouteById request")
if _, ok := req.Get["route_id"]; !ok {
rsp.StatusCode = 500
return errors.New("参数异常")
}
//获取 route id
routeIdString := req.Get["route_id"].Values[0]
routeId, err := strconv.ParseInt(routeIdString, 10, 64)
if err != nil {
common.Error(err)
return err
}
//调用route 删除服务
response, err := e.RouteService.DeleteRoute(ctx, &route.RouteId{
Id: routeId,
})
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(response)
rsp.Body = string(b)
return nil
}
// routeApi.UpdateRoute 通过API向外暴露为/routeApi/UpdateRoute,接收http请求
// 即:/routeApi/UpdateRoute 请求会调用go.micro.api.routeApi 服务的routeApi.UpdateRoute 方法
func (e *RouteApi) UpdateRoute(ctx context.Context, req *routeApi.Request, rsp *routeApi.Response) error {
log.Info("Received routeApi.UpdateRoute request")
rsp.StatusCode = 200
b, _ := json.Marshal("{success:'成功访问/routeApi/UpdateRoute'}")
rsp.Body = string(b)
return nil
}
// 默认的方法routeApi.Call 通过API向外暴露为/routeApi/call,接收http请求
// 即:/routeApi/call或/routeApi/ 请求会调用go.micro.api.routeApi 服务的routeApi.FindRouteById 方法
func (e *RouteApi) Call(ctx context.Context, req *routeApi.Request, rsp *routeApi.Response) error {
log.Info("Received routeApi.Call request")
allRoute, err := e.RouteService.FindAllRoute(ctx, &route.FindAll{})
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(allRoute)
rsp.Body = string(b)
return nil
}
C:\Users\Administrator\Desktop\gopaas\routeapi\plugin\form\form.go
package form
import (
"errors"
"reflect"
"strconv"
"strings"
"time"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/routeApi/proto/routeApi"
)
//根据结构体中name标签映射数据到结构体中并且转换类型
func FormToSvcStruct(data map[string]*routeApi.Pair, obj interface{}) {
objValue := reflect.ValueOf(obj).Elem()
for i := 0; i < objValue.NumField(); i++ {
//获取sql对应的值
dataTag := strings.Replace(objValue.Type().Field(i).Tag.Get("json"), ",omitempty", "", -1)
dataSlice, ok := data[dataTag]
if !ok {
continue
}
valueSlice := dataSlice.Values
if len(valueSlice) <= 0 {
continue
}
//排除port和env
if dataTag == "route_path" {
continue
}
value := valueSlice[0]
//端口,环境变量的单独处理
//获取对应字段的名称
name := objValue.Type().Field(i).Name
//获取对应字段类型
structFieldType := objValue.Field(i).Type()
//获取变量类型,也可以直接写"string类型"
val := reflect.ValueOf(value)
var err error
if structFieldType != val.Type() {
//类型转换
val, err = TypeConversion(value, structFieldType.Name()) //类型转换
if err != nil {
common.Error(err)
}
}
//设置类型值
objValue.FieldByName(name).Set(val)
}
}
//类型转换
func TypeConversion(value string, ntype string) (reflect.Value, error) {
if ntype == "string" {
return reflect.ValueOf(value), nil
} else if ntype == "time.Time" {
t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
return reflect.ValueOf(t), err
} else if ntype == "Time" {
t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
return reflect.ValueOf(t), err
} else if ntype == "int" {
i, err := strconv.Atoi(value)
return reflect.ValueOf(i), err
} else if ntype == "int32" {
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return reflect.ValueOf(int32(i)), err
}
return reflect.ValueOf(int32(i)), err
} else if ntype == "int64" {
i, err := strconv.ParseInt(value, 10, 64)
return reflect.ValueOf(i), err
} else if ntype == "float32" {
i, err := strconv.ParseFloat(value, 64)
return reflect.ValueOf(float32(i)), err
} else if ntype == "float64" {
i, err := strconv.ParseFloat(value, 64)
return reflect.ValueOf(i), err
}
//else if .......增加其他一些类型的转换
return reflect.ValueOf(value), errors.New("未知的类型:" + ntype)
}
7-6 在k8s 中创建 nginx-controller 资源对象
C:\Users\Administrator\Desktop\gopaas\ingress\deploy.yml
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: default
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx
namespace: default
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx
namespace: default
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resourceNames:
- ingress-controller-leader
resources:
- configmaps
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission
namespace: default
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: default
---
apiVersion: v1
data:
allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-controller
namespace: default
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-controller
namespace: default
spec:
#externalTrafficPolicy: Local
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
# type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-controller-admission
namespace: default
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
#kind: Deployment
kind: DaemonSet
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-controller
namespace: default
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
spec:
containers:
- args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: k8s.gcr.io/ingress-nginx/controller:v1.2.0@sha256:d8196e3bc1e72547c5dec66d6556c0ff92a23f6d0919b206be170bc90d5f9185
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
# dnsPolicy: ClusterFirst
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission-create
namespace: default
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission-patch
namespace: default
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.2.0
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: default
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
#### 在master节点执行命令
kubectl apply -f deploy.yml
[root@k8s-master01 k8s]# kubectl apply -f ingress-deploy.yml
[root@k8s-master01 k8s]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
go-test ClusterIP 10.100.201.177 <none> 9099/TCP 13h
ingress-nginx-controller ClusterIP 10.106.55.124 <none> 80/TCP,443/TCP 21s
ingress-nginx-controller-admission ClusterIP 10.111.49.109 <none> 443/TCP 21s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 94d
[root@k8s-master01 k8s]# kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
ingress-nginx-controller 2 2 0 2 0 kubernetes.io/os=linux 2m51s
7-7 route 前端管理页面及效果演示
C:\Users\Administrator\Desktop\gopaas\go-paas-front\route-create.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="assets/img/logo-fav.png">
<title>CPaaS</title>
<link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
</head>
<body>
<div class="be-wrapper">
<nav class="navbar navbar-default navbar-fixed-top be-top-header">
<div class="container-fluid">
<div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
</div>
<div class="be-right-navbar">
<ul class="nav navbar-nav navbar-right be-user-nav">
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><img src="assets/img/avatar.png" alt="Avatar"><span class="user-name">Túpac Amaru</span></a>
<ul role="menu" class="dropdown-menu">
<li>
<div class="user-info">
<div class="user-name">Túpac Amaru</div>
<div class="user-position online">Available</div>
</div>
</li>
<li><a href="#"><span class="icon mdi mdi-face"></span> Account</a></li>
<li><a href="#"><span class="icon mdi mdi-settings"></span> Settings</a></li>
<li><a href="#"><span class="icon mdi mdi-power"></span> Logout</a></li>
</ul>
</li>
</ul>
<div class="page-title"><span>Form Validation</span></div>
<ul class="nav navbar-nav navbar-right be-icons-nav">
<li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-notifications"></span><span class="indicator"></span></a>
<ul class="dropdown-menu be-notifications">
<li>
<div class="title">Notifications<span class="badge">3</span></div>
<div class="list">
<div class="be-scroller">
<div class="content">
<ul>
<li class="notification notification-unread"><a href="#">
<div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">Jessica Caruso</span> accepted your invitation to join the team.</div><span class="date">2 min ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
<div class="notification-info"><span class="text"><span class="user-name">Emily Carter</span> is now following you</span><span class="date">5 days ago</span></div></a></li>
</ul>
</div>
</div>
</div>
<div class="footer"> <a href="#">View all notifications</a></div>
</li>
</ul>
</li>
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
<ul class="dropdown-menu be-connections">
<li>
<div class="list">
<div class="content">
<div class="row">
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
</div>
<div class="row">
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/mail_chimp.png" alt="Mail Chimp"><span>Mail Chimp</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
</div>
</div>
</div>
<div class="footer"> <a href="#">More</a></div>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!--
侧边栏-开始
-->
<div class="be-left-sidebar">
<div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
<div class="left-sidebar-spacer">
<div class="left-sidebar-scroll">
<div class="left-sidebar-content">
<ul class="sidebar-elements">
<li class="divider">菜单</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
<ul class="sub-menu">
<li ><a href="pod-index.html">添加应用</a>
</li>
</ul>
</li>
<li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
<ul class="sub-menu">
<li ><a href="svc-index.html">添加服务</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
<ul class="sub-menu">
<li class="active"><a href="route-index.html">添加路由</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
<ul class="sub-menu">
<li><a href="tables-general.html">General</a>
</li>
<li><a href="tables-datatables.html">Data Tables</a>
</li>
<li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
<ul class="sub-menu">
<li><a href="pages-blank.html">Blank Page</a>
</li>
<li><a href="pages-blank-header.html">Blank Page Header</a>
</li>
<li><a href="pages-login.html">Login</a>
</li>
<li><a href="pages-login2.html">Login v2</a>
</li>
<li><a href="pages-404.html">404 Page</a>
</li>
<li><a href="pages-sign-up.html">Sign Up</a>
</li>
<li><a href="pages-forgot-password.html">Forgot Password</a>
</li>
<li><a href="pages-profile.html">Profile</a>
</li>
<li><a href="pages-pricing-tables.html">Pricing Tables</a>
</li>
<li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
</li>
<li><a href="pages-timeline.html">Timeline</a>
</li>
<li><a href="pages-timeline2.html">Timeline v2</a>
</li>
<li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
</li>
<li><a href="pages-calendar.html">Calendar</a>
</li>
<li><a href="pages-gallery.html">Gallery</a>
</li>
<li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
</li>
<li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
</li>
<li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="progress-widget">
<div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
<div class="progress">
<div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
</div>
</div>
</div>
</div>
<!--
侧边栏-结束
-->
<div class="be-content">
<div class="main-content container-fluid">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default panel-border-color panel-border-color-primary">
<div class="panel-heading panel-heading-divider">添加路由<span class="panel-subtitle"></span></div>
<div class="panel-body">
<form action="http://localhost:8080/routeApi/addRoute" class="form-horizontal group-border-dashed" method="post" >
<div class="form-group">
<label class="col-sm-3 control-label">路由名称:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" id="route_name" name="route_name">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">命名空间:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" id="route_namespace" name="route_namespace" value="default">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">设置域名:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" id="route_host" name="route_host" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">设置路径:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" name="route_path_name" id="route_path_name">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">后端服务:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" id="" name="route_backend_service" id="route_backend_service">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">后端服务端口:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" name="route_backend_service_port" id="route_backend_service_port">
</div>
</div>
<div class="form-group">
<div class="col-sm-2 col-sm-10">
<button type="submit" class="btn btn-space btn-primary">添加路由</button>
<button class="btn btn-space btn-default">Cancel</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
<script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
<script src="assets/js/main.js" type="text/javascript"></script>
<script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
<script src="assets/lib/parsley/parsley.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
App.init();
});
//获取url中的参数
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]); return null; //返回参数值
}
</script>
</body>
</html>
C:\Users\Administrator\Desktop\gopaas\go-paas-front\route-detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="assets/img/logo-fav.png">
<title>CPaaS</title>
<link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
</head>
<body>
<div class="be-wrapper">
<nav class="navbar navbar-default navbar-fixed-top be-top-header">
<div class="container-fluid">
<div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
</div>
<div class="be-right-navbar">
<ul class="nav navbar-nav navbar-right be-user-nav">
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><img src="assets/img/avatar.png" alt="Avatar"><span class="user-name">Túpac Amaru</span></a>
<ul role="menu" class="dropdown-menu">
<li>
<div class="user-info">
<div class="user-name">Túpac Amaru</div>
<div class="user-position online">Available</div>
</div>
</li>
<li><a href="#"><span class="icon mdi mdi-face"></span> Account</a></li>
<li><a href="#"><span class="icon mdi mdi-settings"></span> Settings</a></li>
<li><a href="#"><span class="icon mdi mdi-power"></span> Logout</a></li>
</ul>
</li>
</ul>
<div class="page-title"><span>Form Validation</span></div>
<ul class="nav navbar-nav navbar-right be-icons-nav">
<li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-notifications"></span><span class="indicator"></span></a>
<ul class="dropdown-menu be-notifications">
<li>
<div class="title">Notifications<span class="badge">3</span></div>
<div class="list">
<div class="be-scroller">
<div class="content">
<ul>
<li class="notification notification-unread"><a href="#">
<div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">Jessica Caruso</span> accepted your invitation to join the team.</div><span class="date">2 min ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
<div class="notification-info"><span class="text"><span class="user-name">Emily Carter</span> is now following you</span><span class="date">5 days ago</span></div></a></li>
</ul>
</div>
</div>
</div>
<div class="footer"> <a href="#">View all notifications</a></div>
</li>
</ul>
</li>
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
<ul class="dropdown-menu be-connections">
<li>
<div class="list">
<div class="content">
<div class="row">
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
</div>
<div class="row">
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/mail_chimp.png" alt="Mail Chimp"><span>Mail Chimp</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
</div>
</div>
</div>
<div class="footer"> <a href="#">More</a></div>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!--
侧边栏-开始
-->
<div class="be-left-sidebar">
<div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
<div class="left-sidebar-spacer">
<div class="left-sidebar-scroll">
<div class="left-sidebar-content">
<ul class="sidebar-elements">
<li class="divider">菜单</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
<ul class="sub-menu">
<li ><a href="pod-index.html">添加应用</a>
</li>
</ul>
</li>
<li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
<ul class="sub-menu">
<li ><a href="svc-index.html">添加服务</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
<ul class="sub-menu">
<li class="active"><a href="route-index.html">添加路由</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
<ul class="sub-menu">
<li><a href="tables-general.html">General</a>
</li>
<li><a href="tables-datatables.html">Data Tables</a>
</li>
<li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
<ul class="sub-menu">
<li><a href="pages-blank.html">Blank Page</a>
</li>
<li><a href="pages-blank-header.html">Blank Page Header</a>
</li>
<li><a href="pages-login.html">Login</a>
</li>
<li><a href="pages-login2.html">Login v2</a>
</li>
<li><a href="pages-404.html">404 Page</a>
</li>
<li><a href="pages-sign-up.html">Sign Up</a>
</li>
<li><a href="pages-forgot-password.html">Forgot Password</a>
</li>
<li><a href="pages-profile.html">Profile</a>
</li>
<li><a href="pages-pricing-tables.html">Pricing Tables</a>
</li>
<li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
</li>
<li><a href="pages-timeline.html">Timeline</a>
</li>
<li><a href="pages-timeline2.html">Timeline v2</a>
</li>
<li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
</li>
<li><a href="pages-calendar.html">Calendar</a>
</li>
<li><a href="pages-gallery.html">Gallery</a>
</li>
<li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
</li>
<li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
</li>
<li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="progress-widget">
<div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
<div class="progress">
<div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
</div>
</div>
</div>
</div>
<!--
侧边栏-结束
-->
<div class="be-content">
<div class="main-content container-fluid">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default panel-border-color panel-border-color-primary">
<div class="panel-heading panel-heading-divider">路由详情<span class="panel-subtitle">查看路由详情信息</span></div>
<div class="panel-body">
<form action="#" class="form-horizontal group-border-dashed">
<div class="form-group">
<label class="col-sm-3 control-label">路由ID:</label>
<div class="col-sm-6">
<input type="text" required="" readonly class="form-control" id="route_id" name="route_id">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">路由名称:</label>
<div class="col-sm-6">
<input type="text" required="" readonly class="form-control" id="route_name" name="route_name">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">命名空间:</label>
<div class="col-sm-6">
<input type="text" required="" readonly class="form-control" id="route_namespace" name="route_namespace">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">设置域名:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" id="route_host" name="route_host" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">设置路径:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" name="route_path_name" id="route_path_name">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">后端服务:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" name="route_backend_service" id="route_backend_service">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">后端服务端口:</label>
<div class="col-sm-6">
<input type="text" required="" class="form-control" name="route_backend_service_port" id="route_backend_service_port">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
<script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
<script src="assets/js/main.js" type="text/javascript"></script>
<script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
<script src="assets/lib/parsley/parsley.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
App.init();
$('form').parsley();
$.ajax({
type:"get",
url:"http://127.0.0.1:8080/routeApi/findRouteById?route_id="+getUrlParam('route_id'),
success: function(data){
console.log(data);
if(data.id != "" || data.id != null || data.id != undefined){
$('#route_id').val(data.id);
$("#route_name").val(data.route_name);
$('#route_namespace').val(data.route_namespace);
$('#route_host').val(data.route_host);
//这里有多个要循环
$('#route_path_name').val(data.route_path[0]['route_path_name']);
$('#route_backend_service').val(data.route_path[0]['route_backend_service']);
$('#route_backend_service_port').val(data.route_path[0]['route_backend_service_port']);
}else{
console.log(data);
}
},
error: function(result){
console.log(result);
}
});
});
//获取url中的参数
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]); return null; //返回参数值
}
</script>
</body>
</html>
C:\Users\Administrator\Desktop\gopaas\go-paas-front\route-index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="assets/img/logo-fav.png">
<title>CPaaS</title>
<link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" type="text/css" href="assets/lib/datatables/css/dataTables.bootstrap.min.css"/>
<link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
</head>
<body>
<div class="be-wrapper">
<nav class="navbar navbar-default navbar-fixed-top be-top-header">
<div class="container-fluid">
<div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
</div>
<div class="be-right-navbar">
<ul class="nav navbar-nav navbar-right be-user-nav">
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><img src="assets/img/avatar.png" alt="Avatar"><span class="user-name">Túpac Amaru</span></a>
<ul role="menu" class="dropdown-menu">
<li>
<div class="user-info">
<div class="user-name">wu123</div>
<div class="user-position online">在线</div>
</div>
</li>
<li><a href="#"><span class="icon mdi mdi-face"></span> 账户</a></li>
<li><a href="#"><span class="icon mdi mdi-settings"></span> 设置</a></li>
<li><a href="#"><span class="icon mdi mdi-power"></span> 推出登录</a></li>
</ul>
</li>
</ul>
<div class="page-title"></div>
<ul class="nav navbar-nav navbar-right be-icons-nav">
<li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-notifications"></span><span class="indicator"></span></a>
<ul class="dropdown-menu be-notifications">
<li>
<div class="title">消息提醒<span class="badge">3</span></div>
<div class="list">
<div class="be-scroller">
<div class="content">
<ul>
<li class="notification notification-unread"><a href="#">
<div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">Jessica Caruso</span> accepted your invitation to join the team.</div><span class="date">2 min ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
<div class="notification-info">
<div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
</div></a></li>
<li class="notification"><a href="#">
<div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
<div class="notification-info"><span class="text"><span class="user-name">Emily Carter</span> is now following you</span><span class="date">5 days ago</span></div></a></li>
</ul>
</div>
</div>
</div>
<div class="footer"> <a href="#">View all notifications</a></div>
</li>
</ul>
</li>
<li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
<ul class="dropdown-menu be-connections">
<li>
<div class="list">
<div class="content">
<div class="row">
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
</div>
<div class="row">
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/mail_chimp.png" alt="Mail Chimp"><span>Mail Chimp</span></a></div>
<div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
</div>
</div>
</div>
<div class="footer"> <a href="#">More</a></div>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!--
侧边栏-开始
-->
<div class="be-left-sidebar">
<div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
<div class="left-sidebar-spacer">
<div class="left-sidebar-scroll">
<div class="left-sidebar-content">
<ul class="sidebar-elements">
<li class="divider">菜单</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
<ul class="sub-menu">
<li ><a href="pod-index.html">添加应用</a>
</li>
</ul>
</li>
<li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
<ul class="sub-menu">
<li ><a href="svc-index.html">添加服务</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
<ul class="sub-menu">
<li class="active"><a href="route-index.html">添加路由</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
<ul class="sub-menu">
<li><a href="tables-general.html">General</a>
</li>
<li><a href="tables-datatables.html">Data Tables</a>
</li>
<li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
</li>
</ul>
</li>
<li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
<ul class="sub-menu">
<li><a href="pages-blank.html">Blank Page</a>
</li>
<li><a href="pages-blank-header.html">Blank Page Header</a>
</li>
<li><a href="pages-login.html">Login</a>
</li>
<li><a href="pages-login2.html">Login v2</a>
</li>
<li><a href="pages-404.html">404 Page</a>
</li>
<li><a href="pages-sign-up.html">Sign Up</a>
</li>
<li><a href="pages-forgot-password.html">Forgot Password</a>
</li>
<li><a href="pages-profile.html">Profile</a>
</li>
<li><a href="pages-pricing-tables.html">Pricing Tables</a>
</li>
<li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
</li>
<li><a href="pages-timeline.html">Timeline</a>
</li>
<li><a href="pages-timeline2.html">Timeline v2</a>
</li>
<li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
</li>
<li><a href="pages-calendar.html">Calendar</a>
</li>
<li><a href="pages-gallery.html">Gallery</a>
</li>
<li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
</li>
<li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
</li>
<li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="progress-widget">
<div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
<div class="progress">
<div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
</div>
</div>
</div>
</div>
<!--
侧边栏-结束
-->
<div class="be-content">
<div class="page-head">
<h2 class="page-head-title">路由管理</h2>
<ol class="breadcrumb page-head-nav">
<li><a href="#">控制台</a></li>
<li><a href="#">路由管理</a></li>
<li class="active">路由列表</li>
</ol>
</div>
<div class="main-content container-fluid">
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default panel-table">
<div class="panel-heading">
<a href="route-create.html"><button class="btn btn-space btn-primary">添加路由</button></a>
<div class="tools dropdown"><span class="icon mdi mdi-download"></span><a href="#" type="button" data-toggle="dropdown" class="dropdown-toggle"><span class="icon mdi mdi-more-vert"></span></a>
<ul role="menu" class="dropdown-menu pull-right">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</div>
</div>
<div class="panel-body">
<table id="table1" class="table table-striped table-hover table-fw-widget">
<thead>
<tr>
<th>ID</th>
<th>域名</th>
<th>命名空间</th>
<th>路径</th>
<th>操作</th>
</tr>
</thead>
<tbody id="table-data">
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<nav class="be-right-sidebar">
<div class="sb-content">
<div class="tab-navigation">
<ul role="tablist" class="nav nav-tabs nav-justified">
<li role="presentation" class="active"><a href="#tab1" aria-controls="tab1" role="tab" data-toggle="tab">Chat</a></li>
<li role="presentation"><a href="#tab2" aria-controls="tab2" role="tab" data-toggle="tab">Todo</a></li>
<li role="presentation"><a href="#tab3" aria-controls="tab3" role="tab" data-toggle="tab">Settings</a></li>
</ul>
</div>
<div class="tab-panel">
<div class="tab-content">
<div id="tab1" role="tabpanel" class="tab-pane tab-chat active">
<div class="chat-contacts">
<div class="chat-sections">
<div class="be-scroller">
<div class="content">
<h2>Recent</h2>
<div class="contact-list contact-list-recent">
<div class="user"><a href="#"><img src="assets/img/avatar1.png" alt="Avatar">
<div class="user-data"><span class="status away"></span><span class="name">Claire Sassu</span><span class="message">Can you share the...</span></div></a></div>
<div class="user"><a href="#"><img src="assets/img/avatar2.png" alt="Avatar">
<div class="user-data"><span class="status"></span><span class="name">Maggie jackson</span><span class="message">I confirmed the info.</span></div></a></div>
<div class="user"><a href="#"><img src="assets/img/avatar3.png" alt="Avatar">
<div class="user-data"><span class="status offline"></span><span class="name">Joel King </span><span class="message">Ready for the meeti...</span></div></a></div>
</div>
<h2>Contacts</h2>
<div class="contact-list">
<div class="user"><a href="#"><img src="assets/img/avatar4.png" alt="Avatar">
<div class="user-data2"><span class="status"></span><span class="name">Mike Bolthort</span></div></a></div>
<div class="user"><a href="#"><img src="assets/img/avatar5.png" alt="Avatar">
<div class="user-data2"><span class="status"></span><span class="name">Maggie jackson</span></div></a></div>
<div class="user"><a href="#"><img src="assets/img/avatar6.png" alt="Avatar">
<div class="user-data2"><span class="status offline"></span><span class="name">Jhon Voltemar</span></div></a></div>
</div>
</div>
</div>
</div>
<div class="bottom-input">
<input type="text" placeholder="Search..." name="q"><span class="mdi mdi-search"></span>
</div>
</div>
<div class="chat-window">
<div class="title">
<div class="user"><img src="assets/img/avatar2.png" alt="Avatar">
<h2>Maggie jackson</h2><span>Active 1h ago</span>
</div><span class="icon return mdi mdi-chevron-left"></span>
</div>
<div class="chat-messages">
<div class="be-scroller">
<div class="content">
<ul>
<li class="friend">
<div class="msg">Hello</div>
</li>
<li class="self">
<div class="msg">Hi, how are you?</div>
</li>
<li class="friend">
<div class="msg">Good, I'll need support with my pc</div>
</li>
<li class="self">
<div class="msg">Sure, just tell me what is going on with your computer?</div>
</li>
<li class="friend">
<div class="msg">I don't know it just turns off suddenly</div>
</li>
</ul>
</div>
</div>
</div>
<div class="chat-input">
<div class="input-wrapper"><span class="photo mdi mdi-camera"></span>
<input type="text" placeholder="Message..." name="q" autocomplete="off"><span class="send-msg mdi mdi-mail-send"></span>
</div>
</div>
</div>
</div>
<div id="tab2" role="tabpanel" class="tab-pane tab-todo">
<div class="todo-container">
<div class="todo-wrapper">
<div class="be-scroller">
<div class="todo-content"><span class="category-title">Today</span>
<ul class="todo-list">
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo1" type="checkbox" checked="">
<label for="todo1">Initialize the project</label>
</div>
</li>
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo2" type="checkbox">
<label for="todo2">Create the main structure</label>
</div>
</li>
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo3" type="checkbox">
<label for="todo3">Updates changes to GitHub</label>
</div>
</li>
</ul><span class="category-title">Tomorrow</span>
<ul class="todo-list">
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo4" type="checkbox">
<label for="todo4">Initialize the project</label>
</div>
</li>
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo5" type="checkbox">
<label for="todo5">Create the main structure</label>
</div>
</li>
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo6" type="checkbox">
<label for="todo6">Updates changes to GitHub</label>
</div>
</li>
<li>
<div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
<input id="todo7" type="checkbox">
<label for="todo7" title="This task is too long to be displayed in a normal space!">This task is too long to be displayed in a normal space!</label>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="bottom-input">
<input type="text" placeholder="Create new task..." name="q"><span class="mdi mdi-plus"></span>
</div>
</div>
</div>
<div id="tab3" role="tabpanel" class="tab-pane tab-settings">
<div class="settings-wrapper">
<div class="be-scroller"><span class="category-title">General</span>
<ul class="settings-list">
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" checked="" name="st1" id="st1"><span>
<label for="st1"></label></span>
</div><span class="name">Available</span>
</li>
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" checked="" name="st2" id="st2"><span>
<label for="st2"></label></span>
</div><span class="name">Enable notifications</span>
</li>
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" checked="" name="st3" id="st3"><span>
<label for="st3"></label></span>
</div><span class="name">Login with Facebook</span>
</li>
</ul><span class="category-title">Notifications</span>
<ul class="settings-list">
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" name="st4" id="st4"><span>
<label for="st4"></label></span>
</div><span class="name">Email notifications</span>
</li>
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" checked="" name="st5" id="st5"><span>
<label for="st5"></label></span>
</div><span class="name">Project updates</span>
</li>
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" checked="" name="st6" id="st6"><span>
<label for="st6"></label></span>
</div><span class="name">New comments</span>
</li>
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" name="st7" id="st7"><span>
<label for="st7"></label></span>
</div><span class="name">Chat messages</span>
</li>
</ul><span class="category-title">Workflow</span>
<ul class="settings-list">
<li>
<div class="switch-button switch-button-sm">
<input type="checkbox" name="st8" id="st8"><span>
<label for="st8"></label></span>
</div><span class="name">Deploy on commit</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</nav>
</div>
<script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
<script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
<script src="assets/js/main.js" type="text/javascript"></script>
<script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
<script src="assets/lib/datatables/js/jquery.dataTables.min.js" type="text/javascript"></script>
<script src="assets/lib/datatables/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
<script src="assets/lib/datatables/plugins/buttons/js/dataTables.buttons.js" type="text/javascript"></script>
<script src="assets/lib/datatables/plugins/buttons/js/buttons.html5.js" type="text/javascript"></script>
<script src="assets/lib/datatables/plugins/buttons/js/buttons.flash.js" type="text/javascript"></script>
<script src="assets/lib/datatables/plugins/buttons/js/buttons.print.js" type="text/javascript"></script>
<script src="assets/lib/datatables/plugins/buttons/js/buttons.colVis.js" type="text/javascript"></script>
<script src="assets/lib/datatables/plugins/buttons/js/buttons.bootstrap.js" type="text/javascript"></script>
<script src="assets/js/app-tables-datatables.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
//initialize the javascript
App.init();
App.dataTables();
$.ajax({
type:"get",
url:"http://127.0.0.1:8080/routeApi/",
success: function(data){
console.log(data);
$("#table-data").html("");
$.each(data['route_info'],function (i,item) {
$("#table-data").append(' <tr class="gradeA">\
<td>'+item.id+'</td>\
<td>'+item.route_name+'</td>\
<td>'+item.route_namespace+'</td>\
<td class="center">'+item.route_host+'</td>\
<td class="center"><a href="route-detail.html?route_id='+item.id+'">详情</a> <a href="http://localhost:8080/routeApi/deleteRouteById?route_id='+item.id+'" style="color:red;" >删除</a></td>\
</tr>'
);
})
},
error: function(result){
console.log(result);
}
});
});
</script>
</body>
</html>
7-8 总结&思考
主要内容
介绍了ingress的以及ingress-controller的作用
说明ingress-controller的运行原理
ingress-controller (nginx)的代码功能开发
经验之谈
Ingress controller 的类型一般采用daemonset模式
路由管理要审核不然管理起来非常复杂。
Route-controller 其它模式的用法?
除去nginx以外 还有哪些是常用的类型?
7-9 【扩展阅读】Kubernetes 使用 ingress 配置 https 集群
第8章 云原生Go PaaS 平台后台监控能力建设,总览集群资源使用
集群的状态需要有强有力的全局视图,监控系统应运而生,通过强大的监控系统能够窥探整个 PaaS 的运行状态,实施反馈集群信息轻松掌握使用 Promethus 对整个 PaaS 平台应用和组件的监控能力,可以通过监控结合不同的业务逻辑适应企业多变的业务需求。
8-1 Go PaaS 平台监控系统 Prometheus 架构介绍
GO PaaS 平台监控系统建立
主要内容
主流监控 Promethus监控讲解
在 K8s 中安装监控
Promethus 监控维度效果展示
Promethus 架构介绍
监控可以监控哪些方面的信息
监控的核心组件
监控的核心架构
Go PaaS平台监控模块建立
监控的目标
发现已经存在的问题
预防即将出现的问题
监控哪些内容
系统基础指标(内存、CPU、IO、Disk、Network等)服务基础信息(存活,占用的系统资源等)
服务个性化(接口、固定返回值等) ;
日志内容(从日志中获取报错信息 );
K8s 中的监控内容
节点
服务
K8s自身的组件
如何监控?
数据采集:要先配置采集什么内容
数据存储:采集完数据之后,需要有数据库来进行存储定义报警规则:设置报警红线,满足条件进行报警
配置报警方式:设置短信,邮件,微信等报警:
(普罗米修斯)监控Prometheus
是一套开源的监控&报警&时间序列数据库的组合
由metric名称和 kv 标识的多维数据模型
支持 pull、push 两种方式添加数据
Prometheus(普罗米修斯)架构
(普罗米修斯)数据来源rometheus
服务器指标来源
容器指标来源
组件指标来源
8-2 Go PaaS 平台Prometheus 监控安装
C:\Users\Administrator\Desktop\gopaas\promethues\README.md
### Prometheus 安装说明
#### 1.解压 zip 包
```cassandraql
unzip v0.9.0.zip
```
#### 2.进入目录
```cassandraql
cd kube-prometheus-0.9.0
```
#### 3.执行安装命令
```cassandraql
//创建命名空间和CRD
kubectl create -f manifests/setup
//等待创建结束
until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done
//创建监控组件
kubectl create -f manifests/
//查看 monitoring 内的 pod
kubectl get pods -n monitoring
```
#### 4.添加路由外网访问
通过前一章开发的 route 功能添加 monitoring 命名空间下
grafana.wu123.com 域名
第一次登录默认账号:admin 密码:admin
[root@k8s-worker01 kube-prometheus-0.9.0]# kubectl get pods -n monitoring
NAME READY STATUS RESTARTS AGE
alertmanager-main-0 2/2 Running 0 4m52s
alertmanager-main-1 2/2 Running 0 4m41s
blackbox-exporter-589d9b456-zs74d 3/3 Running 0 4m52s
grafana-6767dc8755-sl48b 1/1 Running 0 4m55s
kube-state-metrics-8fc46689b-hgh9w 2/3 Running 0 4m52s
node-exporter-5h2vw 2/2 Running 0 4m52s
node-exporter-6gp27 2/2 Running 0 4m52s
node-exporter-j6phd 2/2 Running 0 4m52s
prometheus-adapter-58cd975bff-9rvj8 1/1 Running 0 4m52s
prometheus-adapter-58cd975bff-lwjhl 1/1 Running 0 4m52s
prometheus-k8s-0 2/2 Running 0 4m52s
prometheus-k8s-1 2/2 Running 0 4m52s
prometheus-operator-6cdd8db9f7-7mp6q 2/2 Running 0 9m6s
8-3 Go PaaS 平台 监控 Grafana 图标使用说明
8-4 总结&思考
主要内容
介绍了 Prometheus的基础组件与架构在 k8s 中安装Promethues 与监控看板
grafana功能展示
经验之谈
监控为GOPaaS平台不或缺的能力,数据需要近一步保存
PaaS 平台的监控扩展基于 Prometheus
监控更多要考虑业务属性和决策目标
还有哪些决策需要监控数据的支持
监控能够给 PaaS运营带来哪些场景
8-5 【扩展阅读】Prometheus Operator 安装配置详细文档
第9章 云原生 Go PaaS 平台分布式存储管理功能开发,提供数据落盘方案
数据是非常宝贵的财富,业务运行过程中产生的数据是无形的资产,分布式存储系统能够提供多种数据保存方案。深度解读 Ceph 分布式系统的原理、架构、核心组件等知识
9-1 Go PaaS 平台分布式存储 Ceph 架构介绍
GO PaaS 平台分布式存储开发
主要内容
Ceph 基础概念介绍
Ceph 架构说明及安装
服务后端功能开发
Ceph 集群基础介绍
Ceph 特性
Ceph 存储类型
Ceph 核心组件
Ceph 特性
高性能:支持上千个节点,支持TP到PB及的数据。
高可用:故障域分离,强一致性,自动修复。
高扩性:去中心化,扩展灵活。
Ceph 存储支持的类型
块存储:类比传统的存储硬盘,磁盘阵列
文件存储:类比FTP 服务
对象存储:类比大容量硬盘里面附带文件服务
Ceph 存储架构及核心组件
Ceph 基础存储系统 RADOS
全称: Reliable Autonomic Distributed Object Store
RADOS是ceph存储集群的基础
所有数据都以对象的形式存储
Ceph 基础库LIBRADOS
LIBRADOS层的功能是对 RADOS 进行抽象和封装
向上层提供 API以便直接基于 RADOS 进行应用开发
支持多种编程语言,比如GO、C、C++、Python 等
上层接口RADOSGW、RBD和CEPHFS
RADOSGW:基于RESTFUL协议,兼容S3和Swift
RBD提供分布式的块存储设备接口,像磁盘一样挂载使用
CephFS 是一个POSIX 兼容的分布式文件系统
9-2 Go PaaS 平台 Ceph 核心组件介绍
Ceph 核心组件简介 OSD(ceph-osd)
object storage daemon,用于集群中所有数据与对象的存储。
负责处理集群数据的复制、恢复、回填、再均衡。
Ceph 集群通过管理 OSD 来管理物理硬盘
Ceph 核心组件简介 Manager (ceph-mgr)
收集 Ceph 集群状态,运行指标(存储利用率、系统负载等)
外提供 ceph dashboard (ceph ui)和 resetful api。
Manager组件开启高可用时,至少2个实现高可用性。
Ceph 核心组件简介 MDSceph-mds):
Metadata server,元数据服务
为 Ceph 文件系统提供元数据计算、缓存与同步服务
MDS类似于元数据的代理缓存服务器
Ceph 核心组件简介 Monitor (ceph-mon)
维护集群Cluster Map的状态
维护集群的Cluster MAP二进制表,保证集群数据的一致性monitor组件信息,manger 组件信息,osd 组件信息,mds组件信息,crush 算法信息
9-3 Go PaaS 平台 Ceph 存储过程及核心概念介绍
RADOS的系统逻辑结构
RADOS存储过程
逻辑概念说明
File:用户需要存储或者访问的文件
Objects: RADOS的基本存储单元,即对象。
PG(Placement Group): 这里PG作用是对object的存储进行组织和位置映射
逻辑概念说明
OSD (object storage device
oid : 每个object都会有一个唯一的OID,由ino和ono生成
pgid: 使用静态hash函数对OID做hash去除特征码
存储过程中各层次之间的映射关系
file -> object
object -> PG
PG -> OSD
为什么引入 PG 概念?
因为 Obiect 对象的 size 很小,并不会直接存储进 OSD 中
多对象如果遍历寻址,速度很缓慢
直接映射到 OSD上当单个OSD 损坏后无法迁移数据
9-4 Go PaaS 平台Ceph 资源购买注意事项
Ceph 集群安装
3台 2C 4G 20G系统盘,20G数据盘
操作系统为 Centos 8.3
采用 Cephadm 方式安装 ceph 16 版本
9-5 Go PaaS 平台Ceph 安全机器初始化
### 基于 Centos8 系统通过 Cephadm 快速部署 Ceph16(pacific)版本
#### 前期准备
##### 1. 安装依赖
lvm因为系统自带的都有,所以就不用单独安装了,
```cassandraql
dnf install epel-release -y
dnf install python3 -y
dnf install podman -y
dnf install -y chrony
systemctl start chronyd && systemctl enable chronyd
```
chrony时间服务为必须安装,具体有2点原因:1为不安装在添加主机的时候会报错,2为即使安装成功ceph -s会也提示时间不同步!
##### 2.关闭防火墙和selinux (每台都执行)
```cassandraql
systemctl disable firewalld && systemctl stop firewalld
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
```
##### 3.分别在三个节点设置主机名
```cassandraql
hostnamectl set-hostname ceph01
hostnamectl set-hostname ceph02
hostnamectl set-hostname ceph03
```
重启机器 reboot
cephadm需要主机名为短主机名,不能为FQDN,否者在添加主机会报错!
##### 4.添加hosts文件中的主机名和IP关系,主机名需要和上面一致
172.31.96.70 ceph01 2Cpu 4G内存 20G系统盘,20G数据盘
172.31.96.71 ceph02 2Cpu 4G内存 20G系统盘,20G数据盘
172.31.96.72 ceph03 2Cpu 4G内存 20G系统盘,20G数据盘
```cassandraql
cat >> /etc/hosts <<EOF
172.31.96.70 ceph01
172.31.96.71 ceph02
172.31.96.72 ceph03
EOF
```
9-6 Go PaaS 平台cephadm 安装基础集群(上)
C:\Users\Administrator\Desktop\gopaas\ceph\1.ceph 安装.md
#### 安装 cephadm
cephadm 命令可以
1. 引导新集群
2. 使用有效的Ceph CLI启动容器化的Shell
3. 帮助调试容器化的Ceph守护进程。
以下操作只在一台节点执行就可以
##### 1.使用curl获取独立脚本的最新版本。网络不好的话可直接去GitHub复制
```cassandraql
curl --silent --remote-name --location https://github.com/ceph/ceph/raw/pacific/src/cephadm/cephadm
chmod +x cephadm
./cephadm add-repo --release pacific
./cephadm install
./cephadm install ceph-common
```
官方文档中还提到了另一种安装cephadm方式,就是通过dnf install -y cephadm安装,实践证明最好不要使用这种方式,这种方式安装的cephadm可能不是最新版本的,但cephadm去拉的容器版本又是最新的,会导致两个版本不一致!
#### 引导新群集
##### 1.先创建一个目录:/etc/ceph
```cassandraql
mkdir -p /etc/ceph
```
##### 2.运行该命令:ceph bootstrap
```cassandraql
cephadm bootstrap --mon-ip 172.31.96.70
```
此命令将会进行以下操作:
- 为本地主机上的新群集创建monitor和manager守护程序。
- 为 Ceph 群集生成新的 SSH 密钥,并将其添加到root用户的文件/root/.ssh/authorized_keys
- 将与新群集通信所需的最小配置文件保存到 /etc/ceph/ceph.conf
- 将client.admin管理(特权!)密钥的副本写入/etc/ceph/ceph.client.admin.keyring
- 将公钥的副本写入/etc/ceph/ceph.pub
安装日志如下为成功
```cassandraql
[root@ceph01 ~]# cephadm bootstrap --mon-ip 172.31.96.70
Verifying podman|docker is present...
Verifying lvm2 is present...
Verifying time synchronization is in place...
Unit chronyd.service is enabled and running
Repeating the final host check...
podman (/usr/bin/podman) version 3.3.1 is present
systemctl is present
lvcreate is present
Unit chronyd.service is enabled and running
Host looks OK
Cluster fsid: ba25aef4-19f6-11ed-867d-00163e005933
Verifying IP 172.31.96.71 port 3300 ...
ERROR: [Errno 99] Cannot assign requested address
[root@ceph01 ~]# cephadm bootstrap --mon-ip 172.31.96.70
Verifying podman|docker is present...
Verifying lvm2 is present...
Verifying time synchronization is in place...
Unit chronyd.service is enabled and running
Repeating the final host check...
podman (/usr/bin/podman) version 3.3.1 is present
systemctl is present
lvcreate is present
Unit chronyd.service is enabled and running
Host looks OK
Cluster fsid: c32ff766-19f6-11ed-aa17-00163e005933
Verifying IP 172.31.96.70 port 3300 ...
Verifying IP 172.31.96.70 port 6789 ...
Mon IP `172.31.96.70` is in CIDR network `172.31.96.0/20`
- internal network (--cluster-network) has not been provided, OSD replication will default to the public_network
Pulling container image quay.io/ceph/ceph:v16...
Ceph version: ceph version 16.2.10 (45fa1a083152e41a408d15505f594ec5f1b4fe17) pacific (stable)
Extracting ceph user uid/gid from container image...
Creating initial keys...
Creating initial monmap...
Creating mon...
Waiting for mon to start...
Waiting for mon...
mon is available
Assimilating anything we can from ceph.conf...
Generating new minimal ceph.conf...
Restarting the monitor...
Setting mon public_network to 172.31.96.0/20
Wrote config to /etc/ceph/ceph.conf
Wrote keyring to /etc/ceph/ceph.client.admin.keyring
Creating mgr...
Verifying port 9283 ...
Waiting for mgr to start...
Waiting for mgr...
mgr not available, waiting (1/15)...
mgr not available, waiting (2/15)...
mgr not available, waiting (3/15)...
mgr not available, waiting (4/15)...
mgr is available
Enabling cephadm module...
Waiting for the mgr to restart...
Waiting for mgr epoch 5...
mgr epoch 5 is available
Setting orchestrator backend to cephadm...
Generating ssh key...
Wrote public SSH key to /etc/ceph/ceph.pub
Adding key to root@localhost authorized_keys...
Adding host ceph01...
Deploying mon service with default placement...
Deploying mgr service with default placement...
Deploying crash service with default placement...
Deploying prometheus service with default placement...
Deploying grafana service with default placement...
Deploying node-exporter service with default placement...
Deploying alertmanager service with default placement...
Enabling the dashboard module...
Waiting for the mgr to restart...
Waiting for mgr epoch 9...
mgr epoch 9 is available
Generating a dashboard self-signed certificate...
Creating initial admin user...
Fetching dashboard port number...
Ceph Dashboard is now available at:
URL: https://ceph01:8443/
User: admin
Password: 9ro6qdzyel
Enabling client.admin keyring and conf on hosts with "admin" label
Enabling autotune for osd_memory_target
You can access the Ceph CLI as following in case of multi-cluster or non-default config:
sudo /usr/sbin/cephadm shell --fsid c32ff766-19f6-11ed-aa17-00163e005933 -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring
Or, if you are only running a single cluster on this host:
sudo /usr/sbin/cephcadm shell
Please consider enabling telemetry to help improve Ceph:
ceph telemetry on
For more information see:
https://docs.ceph.com/en/pacific/mgr/telemetry/
Bootstrap complete.
```
完成后记录以上了IP以及用户和密码,打开Ceph Dashboard并根据提示修改密码,打开后提示要激活统计模块。
如果错过使用命令
```cassandraql
如果Ceph Dashboard中错过了启用,也可以使用命令启用,命令是“ceph telemetry on --license sharing-1-0”。
```
如果忘记记录密码可以通过以下方法重置密码(将密码写入password文件中,通过命令导入密码)
```cassandraql
ceph dashboard ac-user-set-password admin -i password
{"username": "admin", "password": "$2b$12$6oFrEpssXCzLnKTWQy5fM.YZwlHjn8CuQRdeSSJR9hBGgVuwGCxoa", "roles": ["administrator"], "name": null, "email": null, "lastUpdate": 1620495653, "enabled": true, "pwdExpirationDate": null, "pwdUpdateRequired": false}
```
9-7 Go PaaS 平台cephadm 安装基础集群(下)
##### 3.添加主机
在引导成功单节点Ceph群集后会引导程序会将public key的副本写入/etc/ceph/ceph.pub,在添加主机节点前需要讲该key分发到要加入群集的主机上
拷贝到ceph02
```cassandraql
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph02
```
拷贝到ceph03
```cassandraql
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph03
```
添加ceph 02 节点
```cassandraql
ceph orch host add ceph02 172.31.96.71
```
添加ceph 03 节点
```cassandraql
ceph orch host add ceph03 172.31.96.72
```
查看节点
```cassandraql
[root@ceph01 ~]# ceph orch host ls
HOST ADDR LABELS STATUS
ceph01 172.31.96.70 _admin
ceph02 172.31.96.71
ceph03 172.31.96.72
3 hosts in cluster
```
##### 4.添加OSD
添加OSD需求满足以下所有条件:
- 设备必须没有分区。
- 设备不得具有任何LVM状态。
- 不得安装设备。
- 该设备不得包含文件系统。
- 该设备不得包含Ceph BlueStore OSD。
- 设备必须大于 5 GB。
添加OSD有2种方式,
1.为自动添加所有满足条件的OSD。
```
ceph orch apply osd --all-available-devices
```
2.为通过手工指定的方式添加OSD。
```cassandraql
ceph orch daemon add osd ceph1:/dev/sdb
```
本次使用第一种自动部署的方式,部署完成后查看设备列表,显示为NO就完成了。
```cassandraql
[root@ceph01 ~]# ceph orch device ls
HOST PATH TYPE DEVICE ID SIZE AVAILABLE REFRESHED REJECT REASONS
ceph01 /dev/vdb hdd j6c3xd1a6qug5beqk71y 21.4G 9s ago Insufficient space (<10 extents) on vgs, LVM detected, locked
ceph02 /dev/vdb hdd j6c3xd1a6qug5beqk720 21.4G 14s ago Insufficient space (<10 extents) on vgs, LVM detected, locked
ceph03 /dev/vdb hdd j6c3xd1a6qug5beqk71z 21.4G 14s ago Insufficient space (<10 extents) on vgs, LVM detected, locked
```
#### 5.查看Ceph部署服务
```cassandraql
[root@ceph01 ~]# ceph -s
cluster:
id: c32ff766-19f6-11ed-aa17-00163e005933
health: HEALTH_OK
services:
mon: 3 daemons, quorum ceph01,ceph02,ceph03 (age 4m)
mgr: ceph01.sdapbz(active, since 30m), standbys: ceph02.njhkgr
osd: 3 osds: 3 up (since 96s), 3 in (since 114s)
data:
pools: 1 pools, 1 pgs
objects: 0 objects, 0 B
usage: 15 MiB used, 60 GiB / 60 GiB avail
pgs: 1 active+clean
```
打开 dashboard 看监控数据
9-8 Go PaaS 平台ceph 核心组件安装
#### 6.部署RGW
使用指定数量匹配模式部署。
```
ceph orch apply rgw rgw --placement=3
```
通过Service查看命令ceph orch ls查看该服务状态。
```cassandraql
[root@ceph01 ~]# ceph orch ls
NAME PORTS RUNNING REFRESHED AGE PLACEMENT
alertmanager ?:9093,9094 1/1 10s ago 40m count:1
crash 3/3 15s ago 40m *
grafana ?:3000 1/1 10s ago 40m count:1
mgr 2/2 14s ago 40m count:2
mon 3/5 15s ago 40m count:5
node-exporter ?:9100 3/3 15s ago 40m *
osd.all-available-devices 3 15s ago 9m *
prometheus ?:9095 1/1 10s ago 40m count:1
rgw.rgw ?:80 3/3 15s ago 30s count:3
```
通过Deamon查看命令ceph orch ps查看该进程状态。
```cassandraql
[root@ceph01 ~]# ceph orch ps
NAME HOST PORTS STATUS REFRESHED AGE MEM USE MEM LIM VERSION IMAGE ID CONTAINER ID
alertmanager.ceph01 ceph01 *:9093,9094 running (12m) 41s ago 39m 27.9M - ba2b418f427c b6fbf7382136
crash.ceph01 ceph01 running (39m) 41s ago 39m 7717k - 16.2.10 0d668911f040 9660dd933bd2
crash.ceph02 ceph02 running (14m) 44s ago 14m 9713k - 16.2.10 0d668911f040 35cac443b75c
crash.ceph03 ceph03 running (13m) 45s ago 13m 8632k - 16.2.10 0d668911f040 3135f2560d98
grafana.ceph01 ceph01 *:3000 running (38m) 41s ago 39m 67.9M - 8.3.5 dad864ee21e9 7f47d88ad676
mgr.ceph01.sdapbz ceph01 *:9283 running (41m) 41s ago 41m 499M - 16.2.10 0d668911f040 9e001eab3a53
mgr.ceph02.njhkgr ceph02 *:8443,9283 running (14m) 44s ago 14m 409M - 16.2.10 0d668911f040 146058cf2aea
mon.ceph01 ceph01 running (41m) 41s ago 41m 147M 2048M 16.2.10 0d668911f040 5896f4b2a014
mon.ceph02 ceph02 running (14m) 44s ago 14m 85.3M 2048M 16.2.10 0d668911f040 7fd0c2c36613
mon.ceph03 ceph03 running (13m) 45s ago 13m 82.1M 2048M 16.2.10 0d668911f040 db5a5b5039d5
node-exporter.ceph01 ceph01 *:9100 running (38m) 41s ago 38m 16.5M - 1dbe0e931976 2d7d68e3a0da
node-exporter.ceph02 ceph02 *:9100 running (14m) 44s ago 14m 18.2M - 1dbe0e931976 083f26d39f07
node-exporter.ceph03 ceph03 *:9100 running (12m) 45s ago 12m 14.4M - 1dbe0e931976 c3b21c79b2f4
osd.0 ceph03 running (9m) 45s ago 9m 40.4M 4096M 16.2.10 0d668911f040 2210df27e314
osd.1 ceph02 running (9m) 44s ago 9m 44.7M 4096M 16.2.10 0d668911f040 9ab8967c65b9
osd.2 ceph01 running (9m) 41s ago 9m 47.6M 4096M 16.2.10 0d668911f040 78a2000670f7
prometheus.ceph01 ceph01 *:9095 running (12m) 41s ago 38m 69.2M - 514e6a882f6e 06de63766e30
rgw.rgw.ceph01.bvcnos ceph01 *:80 running (58s) 41s ago 57s 43.7M - 16.2.10 0d668911f040 96c4d8963d47
rgw.rgw.ceph02.awygjp ceph02 *:80 running (54s) 44s ago 53s 46.2M - 16.2.10 0d668911f040 9d0bd0b0b060
rgw.rgw.ceph03.iiixeq ceph03 *:80 running (50s) 45s ago 49s 21.2M - 16.2.10 0d668911f040 a5d6e8a8983a
```
集成到dashboard
```cassandraql
[root@ceph01 ~]# radosgw-admin user create --uid=rgw --display-name=rgw --system
以下是输出结果
"keys": [
{
"user": "rgw",
"access_key": "M0XRR80H4AGGE4PP0A5B",
"secret_key": "Tbln48sfIceDGNill5muCrX0oMCHrQcl2oC9OURe"
}
],{
"user_id": "rgw",
"display_name": "rgw",
"email": "",
"suspended": 0,
"max_buckets": 1000,
"subusers": [],
"keys": [
{
"user": "rgw",
"access_key": "43DTMZ3EY02B10QNTJSS",
"secret_key": "4d3qzY1A7uqVk3LWVMsGJY0negbcxg95d8QJYuzi"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"system": "true",
"default_placement": "",
"default_storage_class": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"temp_url_keys": [],
"type": "rgw",
"mfa_ids": []
}
```
查看 Dashboard 是否集成成功
#### 7.部署Cephfs
部署cephfs服务并创建cepfs,创建cephfs有两种方式,一种是使用的是ceph fs命令该命令会自动创建相应的池,另一种手工创建池并创建Service,下面方法任选一种。
方法一:
```cassandraql
ceph fs volume create cephfs --placement=3
```
方法二:
```cassandraql
#ceph osd pool create cephfs_data 32
#ceph osd pool create cephfs_metadata 32
#ceph fs new cephfs cephfs_metadata cephfs_data
#ceph orch apply mds cephfs --placement=3
```
我们采用方法一
查看Service状态。
```cassandraql
[root@ceph01 ~]# ceph fs volume create cephfs --placement=3
[root@ceph01 ~]# ceph orch ls
NAME PORTS RUNNING REFRESHED AGE PLACEMENT
alertmanager ?:9093,9094 1/1 9s ago 48m count:1
crash 3/3 13s ago 48m *
grafana ?:3000 1/1 9s ago 48m count:1
mds.cephfs 3/3 13s ago 29s count:3
mgr 2/2 13s ago 48m count:2
mon 3/5 13s ago 48m count:5
node-exporter ?:9100 3/3 13s ago 48m *
osd.all-available-devices 3 13s ago 17m *
prometheus ?:9095 1/1 9s ago 48m count:1
rgw.rgw ?:80 3/3 13s ago 8m count:3
```
查看Deamon状态。
```cassandraql
[root@ceph01 ~]# ceph orch ps
NAME HOST PORTS STATUS REFRESHED AGE MEM USE MEM LIM VERSION IMAGE ID CONTAINER ID
alertmanager.ceph01 ceph01 *:9093,9094 running (20m) 59s ago 48m 29.5M - ba2b418f427c b6fbf7382136
crash.ceph01 ceph01 running (48m) 59s ago 48m 7587k - 16.2.10 0d668911f040 9660dd933bd2
crash.ceph02 ceph02 running (22m) 63s ago 22m 9667k - 16.2.10 0d668911f040 35cac443b75c
crash.ceph03 ceph03 running (21m) 63s ago 21m 8606k - 16.2.10 0d668911f040 3135f2560d98
grafana.ceph01 ceph01 *:3000 running (46m) 59s ago 47m 77.2M - 8.3.5 dad864ee21e9 7f47d88ad676
mds.cephfs.ceph01.uwclzo ceph01 running (74s) 59s ago 74s 28.2M - 16.2.10 0d668911f040 e7ead0c130a6
mds.cephfs.ceph02.zqmpyt ceph02 running (71s) 63s ago 70s 23.7M - 16.2.10 0d668911f040 06ed8fd3bc1a
mds.cephfs.ceph03.glufpl ceph03 running (67s) 63s ago 67s 22.9M - 16.2.10 0d668911f040 a3e497cb8a85
mgr.ceph01.sdapbz ceph01 *:9283 running (49m) 59s ago 49m 508M - 16.2.10 0d668911f040 9e001eab3a53
mgr.ceph02.njhkgr ceph02 *:8443,9283 running (22m) 63s ago 22m 410M - 16.2.10 0d668911f040 146058cf2aea
mon.ceph01 ceph01 running (50m) 59s ago 50m 177M 2048M 16.2.10 0d668911f040 5896f4b2a014
mon.ceph02 ceph02 running (22m) 63s ago 22m 115M 2048M 16.2.10 0d668911f040 7fd0c2c36613
mon.ceph03 ceph03 running (21m) 63s ago 21m 111M 2048M 16.2.10 0d668911f040 db5a5b5039d5
node-exporter.ceph01 ceph01 *:9100 running (47m) 59s ago 47m 17.4M - 1dbe0e931976 2d7d68e3a0da
node-exporter.ceph02 ceph02 *:9100 running (22m) 63s ago 22m 18.0M - 1dbe0e931976 083f26d39f07
node-exporter.ceph03 ceph03 *:9100 running (21m) 63s ago 21m 14.7M - 1dbe0e931976 c3b21c79b2f4
osd.0 ceph03 running (17m) 63s ago 17m 69.7M 4096M 16.2.10 0d668911f040 2210df27e314
osd.1 ceph02 running (17m) 63s ago 17m 72.6M 4096M 16.2.10 0d668911f040 9ab8967c65b9
osd.2 ceph01 running (17m) 59s ago 17m 72.4M 4096M 16.2.10 0d668911f040 78a2000670f7
prometheus.ceph01 ceph01 *:9095 running (20m) 59s ago 46m 73.6M - 514e6a882f6e 06de63766e30
rgw.rgw.ceph01.bvcnos ceph01 *:80 running (9m) 59s ago 9m 73.3M - 16.2.10 0d668911f040 96c4d8963d47
rgw.rgw.ceph02.awygjp ceph02 *:80 running (9m) 63s ago 9m 80.8M - 16.2.10 0d668911f040 9d0bd0b0b060
rgw.rgw.ceph03.iiixeq ceph03 *:80 running (9m) 63s ago 8m 57.4M - 16.2.10 0d668911f040 a5d6e8a8983a
```
查看 Dashboard
#### 8.部署NFS
先创建nfs所需求的池。
```cassandraql
#ceph osd pool create ganesha_data 32
#ceph osd pool application enable ganesha_data nfs
```
部署nfs Service。
```cassandraql
#ceph orch apply nfs nfs ganesha_data --placement=3
```
查看Service状态。
```cassandraql
[root@ceph01 ~]# ceph orch ls
NAME PORTS RUNNING REFRESHED AGE PLACEMENT
alertmanager ?:9093,9094 1/1 8s ago 52m count:1
crash 3/3 13s ago 52m *
grafana ?:3000 1/1 8s ago 52m count:1
mds.cephfs 3/3 13s ago 4m count:3
mgr 2/2 13s ago 52m count:2
mon 3/5 13s ago 52m count:5
nfs.nfs 3/3 13s ago 36s count:3
node-exporter ?:9100 3/3 13s ago 52m *
osd.all-available-devices 3 13s ago 21m *
prometheus ?:9095 1/1 8s ago 52m count:1
rgw.rgw ?:80 3/3 13s ago 12m count:3
```
查看Deamon状态。
```cassandraql
[root@ceph01 ~]# ceph orch ls
NAME PORTS RUNNING REFRESHED AGE PLACEMENT
alertmanager ?:9093,9094 1/1 8s ago 52m count:1
crash 3/3 13s ago 52m *
grafana ?:3000 1/1 8s ago 52m count:1
mds.cephfs 3/3 13s ago 4m count:3
mgr 2/2 13s ago 52m count:2
mon 3/5 13s ago 52m count:5
nfs.nfs 3/3 13s ago 36s count:3
node-exporter ?:9100 3/3 13s ago 52m *
osd.all-available-devices 3 13s ago 21m *
prometheus ?:9095 1/1 8s ago 52m count:1
rgw.rgw ?:80 3/3 13s ago 12m count:3
```
#### 9.部署iSCSi
创建iscsi所需求的池。
```cassandraql
#ceph osd pool create iscsi_pool 16 16
#ceph osd pool application enable iscsi_pool iscsi
```
部署iscsi我们换YAM方式
```cassandraql
#vi iscsi.yaml
service_type: iscsi
service_id: gw
placement:
hosts:
- ceph01
- ceph02
- ceph03
spec:
pool: iscsi_pool
trusted_ip_list: "172.31.96.70,172.31.96.71,172.31.96.72"
api_user: admin
api_password: admin
api_secure: false
```
通过apply命令部署,cephadm也是声明式的,所以如果想修改配置参数只需要直接修改YAML文件。
```cassandraql
[root@ceph01 ~]# ceph orch apply -i iscsi.yaml
Scheduled iscsi.gw update...
```
查看Service状态。
```cassandraql
[root@ceph01 ~]# ceph orch ls
NAME PORTS RUNNING REFRESHED AGE PLACEMENT
alertmanager ?:9093,9094 1/1 9s ago 67m count:1
crash 3/3 21s ago 67m *
grafana ?:3000 1/1 9s ago 67m count:1
iscsi.gw 3/3 21s ago 40s ceph01;ceph02;ceph03
mds.cephfs 3/3 21s ago 19m count:3
mgr 2/2 20s ago 67m count:2
mon 3/5 21s ago 67m count:5
nfs.nfs 3/3 21s ago 16m count:3
node-exporter ?:9100 3/3 21s ago 67m *
osd.all-available-devices 3 21s ago 36m *
prometheus ?:9095 1/1 9s ago 67m count:1
rgw.rgw ?:80 3/3 21s ago 27m count:3
```
查看Deamon状态。
```cassandraql
[root@ceph01 ~]# ceph orch ps
NAME HOST PORTS STATUS REFRESHED AGE MEM USE MEM LIM VERSION IMAGE ID CONTAINER ID
alertmanager.ceph01 ceph01 *:9093,9094 running (39m) 33s ago 67m 35.2M - ba2b418f427c b6fbf7382136
crash.ceph01 ceph01 running (67m) 33s ago 67m 7386k - 16.2.10 0d668911f040 9660dd933bd2
crash.ceph02 ceph02 running (41m) 44s ago 41m 10.5M - 16.2.10 0d668911f040 35cac443b75c
crash.ceph03 ceph03 running (40m) 45s ago 40m 10.8M - 16.2.10 0d668911f040 3135f2560d98
grafana.ceph01 ceph01 *:3000 running (65m) 33s ago 66m 80.2M - 8.3.5 dad864ee21e9 7f47d88ad676
iscsi.gw.ceph01.mqjxqu ceph01 running (60s) 33s ago 59s 76.1M - 3.5 0d668911f040 e712bdbb2d80
iscsi.gw.ceph02.xeggjo ceph02 running (56s) 44s ago 56s 52.9M - 3.5 0d668911f040 04c7f5263155
iscsi.gw.ceph03.xykglu ceph03 running (52s) 45s ago 52s 76.9M - 3.5 0d668911f040 59cb4c7bbfd5
mds.cephfs.ceph01.uwclzo ceph01 running (20m) 33s ago 20m 27.6M - 16.2.10 0d668911f040 e7ead0c130a6
mds.cephfs.ceph02.zqmpyt ceph02 running (20m) 44s ago 20m 26.8M - 16.2.10 0d668911f040 06ed8fd3bc1a
mds.cephfs.ceph03.glufpl ceph03 running (20m) 45s ago 20m 26.5M - 16.2.10 0d668911f040 a3e497cb8a85
mgr.ceph01.sdapbz ceph01 *:9283 running (68m) 33s ago 68m 495M - 16.2.10 0d668911f040 9e001eab3a53
mgr.ceph02.njhkgr ceph02 *:8443,9283 running (41m) 44s ago 41m 411M - 16.2.10 0d668911f040 146058cf2aea
mon.ceph01 ceph01 running (68m) 33s ago 69m 237M 2048M 16.2.10 0d668911f040 5896f4b2a014
mon.ceph02 ceph02 running (41m) 44s ago 41m 164M 2048M 16.2.10 0d668911f040 7fd0c2c36613
mon.ceph03 ceph03 running (40m) 45s ago 40m 146M 2048M 16.2.10 0d668911f040 db5a5b5039d5
nfs.nfs.0.0.ceph01.ijxnwe ceph01 *:2049 running (16m) 33s ago 16m 72.4M - 3.5 0d668911f040 f9b0609cbe7b
nfs.nfs.1.0.ceph02.pedadk ceph02 *:2049 running (16m) 44s ago 16m 75.8M - 3.5 0d668911f040 54d58b785ed6
nfs.nfs.2.0.ceph03.daqdkw ceph03 *:2049 running (16m) 45s ago 16m 73.0M - 3.5 0d668911f040 c1bebe7782d4
node-exporter.ceph01 ceph01 *:9100 running (66m) 33s ago 66m 17.7M - 1dbe0e931976 2d7d68e3a0da
node-exporter.ceph02 ceph02 *:9100 running (41m) 44s ago 41m 18.3M - 1dbe0e931976 083f26d39f07
node-exporter.ceph03 ceph03 *:9100 running (40m) 45s ago 40m 15.5M - 1dbe0e931976 c3b21c79b2f4
osd.0 ceph03 running (36m) 45s ago 36m 77.8M 4096M 16.2.10 0d668911f040 2210df27e314
osd.1 ceph02 running (36m) 44s ago 36m 80.1M 4096M 16.2.10 0d668911f040 9ab8967c65b9
osd.2 ceph01 running (36m) 33s ago 36m 79.3M 4096M 16.2.10 0d668911f040 78a2000670f7
prometheus.ceph01 ceph01 *:9095 running (39m) 33s ago 65m 97.3M - 514e6a882f6e 06de63766e30
rgw.rgw.ceph01.bvcnos ceph01 *:80 running (28m) 33s ago 28m 61.8M - 16.2.10 0d668911f040 96c4d8963d47
rgw.rgw.ceph02.awygjp ceph02 *:80 running (28m) 44s ago 28m 81.6M - 16.2.10 0d668911f040 9d0bd0b0b060
rgw.rgw.ceph03.iiixeq ceph03 *:80 running (27m) 45s ago 27m 60.0M - 16.2.10 0d668911f040 a5d6e8a8983a
```
9-9 Go PaaS 平台 k8s 通过CSI方式添加外部Ceph 系统(上)
C:\Users\Administrator\Desktop\gopaas\ceph\2.k8s 使用 CSI 添加 ceph 为存储.md
### k8s 1.21.5 CSI 模式添加 ceph 16 为为外部存储(动态存储卷)
#### 1.动态持久卷
不需要存储管理员干预,使k8s使用的存储image创建自动化,即根据使用需要可以动态申请存储空间并自动创建。需要先定义一个或者多个StorageClass,每个StorageClass都必须配置一个provisioner,用来决定使用哪个卷插件分配PV。然后,StorageClass资源指定持久卷声明请求StorageClass时使用哪个provisioner来在对应存储创建持久卷。
#### 2.创建一个普通用户来给k8s做rdb的映射
在ceph集群中创建一个k8s专用的pool和用户:
```cassandraql
ceph osd pool create kubernetes 16 16
ceph auth get-or-create client.kubernetes mon 'profile rbd' osd 'profile rbd pool=kubernetes' mgr 'profile rbd pool=kubernetes'
初始化
rbd pool init kubernetes
查看 pool
ceph osd pool ls
rados lspools
```
得到
```cassandraql
[client.kubernetes]
key = AQC2Q/ZiecM/MBAA2nwfDPKgfReHxz/o4kQV3A==
```
后面的配置需要用到这里的 key,如果忘了可以通过以下命令来获取:
```cassandraql
ceph auth get client.kubernetes
```
得到
```cassandraql
[client.kubernetes]
key = AQC2Q/ZiecM/MBAA2nwfDPKgfReHxz/o4kQV3A==
caps mgr = "profile rbd pool=kubernetes"
caps mon = "profile rbd"
caps osd = "profile rbd pool=kubernetes"
exported keyring for client.kubernetes
```
#### 3. 部署 ceph-csi 在k8s master 集群上
拉取 ceph-csi 的 最新 release 分支(v3.6.2)
```cassandraql
git clone --depth 1 --branch v3.6.2 https://github.com/ceph/ceph-csi
```
##### 修改 Configmap
获取 Ceph 集群的信息:
```cassandraql
[root@ceph01 ~]# ceph mon dump
epoch 3
fsid c32ff766-19f6-11ed-aa17-00163e005933
last_changed 2022-08-12T04:55:22.875422+0000
created 2022-08-12T04:26:27.658334+0000
min_mon_release 16 (pacific)
election_strategy: 1
0: [v2:172.31.96.70:3300/0,v1:172.31.96.70:6789/0] mon.ceph01
1: [v2:172.31.96.71:3300/0,v1:172.31.96.71:6789/0] mon.ceph02
2: [v2:172.31.96.72:3300/0,v1:172.31.96.72:6789/0] mon.ceph03
dumped monmap epoch 3
```
这里需要用到两个信息:
- fsid : 这个是 Ceph 的集群 ID。
- 监控节点信息。目前 ceph-csi 只支持 v1 版本的协议,所以监控节点那里我们只能用 v1 的那个 IP 和端口号(例如,172.31.96.70:6789)。
进入 ceph-csi 的 deploy/rbd/kubernetes 目录:
```cassandraql
[root@master ~]# cd ceph-csi/deploy/rbd/kubernetes
[root@master kubernetes]# ls -l ./
total 40
-rw-r--r-- 1 root root 309 Aug 12 20:18 csi-config-map.yaml
-rw-r--r-- 1 root root 435 Aug 12 20:18 csidriver.yaml
-rw-r--r-- 1 root root 1776 Aug 12 20:18 csi-nodeplugin-psp.yaml
-rw-r--r-- 1 root root 1110 Aug 12 20:18 csi-nodeplugin-rbac.yaml
-rw-r--r-- 1 root root 1199 Aug 12 20:18 csi-provisioner-psp.yaml
-rw-r--r-- 1 root root 3264 Aug 12 20:18 csi-provisioner-rbac.yaml
-rw-r--r-- 1 root root 8021 Aug 12 20:18 csi-rbdplugin-provisioner.yaml
-rw-r--r-- 1 root root 7242 Aug 12 20:18 csi-rbdplugin.yaml
```
将以上获取的信息写入 csi-config-map.yaml:
vi csi-config-map.yaml
```cassandraql
apiVersion: v1
kind: ConfigMap
data:
config.json: |-
[
{
"clusterID": "c32ff766-19f6-11ed-aa17-00163e005933",
"monitors": [
"172.31.96.70:6789",
"172.31.96.71:6789",
"172.31.96.72:6789"
]
}
]
metadata:
name: ceph-csi-config
```
将此 Configmap 存储到 Kubernetes 集群中:
```cassandraql
kubectl apply -f csi-config-map.yaml
```
创建ceph-config
```cassandraql
cat <<EOF > ceph-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
ceph.conf: |
[global]
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
# keyring is a required key and its value should be empty
keyring: |
metadata:
name: ceph-config
EOF
```
创建
```cassandraql
kubectl apply -f ceph-config-map.yaml
```
创建 ceph-csi-encryption-kms-config
```cassandraql
cat <<EOF > csi-kms-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
config.json: |-
{}
metadata:
name: ceph-csi-encryption-kms-config
EOF
```
启用
```cassandraql
kubectl apply -f csi-kms-config-map.yaml
```
9-10 Go PaaS 平台 k8s 通过CSI方式添加外部Ceph 系统(下)
##### 新建 Secret
使用创建的 kubernetes 用户 ID 和 cephx 密钥生成 Secret:
```cassandraql
cat <<EOF > csi-rbd-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: csi-rbd-secret
namespace: default
stringData:
userID: kubernetes
userKey: AQC2Q/ZiecM/MBAA2nwfDPKgfReHxz/o4kQV3A==
EOF
```
部署 Secret:
```cassandraql
kubectl apply -f csi-rbd-secret.yaml
```
##### RBAC 授权
创建必须的 ServiceAccount 和 RBAC ClusterRole/ClusterRoleBinding 资源对象:
```cassandraql
kubectl create -f csi-provisioner-rbac.yaml
kubectl create -f csi-nodeplugin-rbac.yaml
```
创建 PodSecurityPolicy:
```cassandraql
kubectl create -f csi-provisioner-psp.yaml
kubectl create -f csi-nodeplugin-psp.yaml
```
##### 部署 CSI sidecar
将 csi-rbdplugin-provisioner.yaml 和 csi-rbdplugin.yaml 中的 kms 部分配置注释掉:
```cassandraql
# - name: ceph-csi-encryption-kms-config
# mountPath: /etc/ceph-csi-encryption-kms-config/
....
#- name: ceph-csi-encryption-kms-config
# configMap:
# name: ceph-csi-encryption-kms-config
```
注释掉pod亲和性
```cassandraql
# affinity:
# podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# - labelSelector:
# matchExpressions:
# - key: app
# operator: In
# values:
# - csi-rbdplugin-provisioner
# topologyKey: "kubernetes.io/hostname"
```
改为一个副本
```cassandraql
spec:
replicas: 1
```
部署 csi-rbdplugin-provisioner:
```
kubectl create -f csi-rbdplugin-provisioner.yaml
```
这里面包含了 6 个 Sidecar 容器,包括 external-provisioner、external-attacher、csi-resizer 和 csi-rbdplugin。
##### 部署 RBD CSI driver
最后部署 RBD CSI Driver:
```
kubectl create -f csi-rbdplugin.yaml
```
Pod 中包含两个容器:CSI node-driver-registrar 和 CSI RBD driver。
##### 创建 Storageclass
```cassandraql
cat <<EOF > storageclass.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
clusterID: c32ff766-19f6-11ed-aa17-00163e005933
pool: kubernetes
imageFeatures: layering
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
csi.storage.k8s.io/controller-expand-secret-namespace: default
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- discard
EOF
```
创建 storageclass
```cassandraql
kubectl apply -f storageclass.yaml
```
- 这里的 clusterID 对应之前步骤中的 fsid。
- imageFeatures 用来确定创建的 image 特征,如果不指定,就会使用 RBD 内核中的特征列表,但 Linux 不一定支持所有特征,所以这里需要限制一下。
#### 4.试用 ceph-csi
Kubernetes 通过 PersistentVolume 子系统为用户和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来,其中 PV(PersistentVolume) 是实际的存储,PVC(PersistentVolumeClaim) 是用户对存储的请求。
下面通过官方仓库的示例来演示如何使用 ceph-csi。
先进入 ceph-csi 项目的 example/rbd 目录,然后直接创建 PVC:
```cassandraql
kubectl apply -f pvc.yaml
```
查看 PVC 和申请成功的 PV:
```cassandraql
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
rbd-pvc Bound pvc-44b89f0e-4efd-4396-9316-10a04d289d7f 1Gi RWO csi-rbd-sc 8m21s
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-44b89f0e-4efd-4396-9316-10a04d289d7f 1Gi RWO Delete Bound default/rbd-pvc csi-rbd-sc 8m18s
```
再创建示例 Pod:
```
kubectl apply -f pod.yaml
```
进入 Pod 里面测试读写数据:
```cassandraql
kubectl apply -f pod.yaml
```
进入 Pod 里面测试读写数据:
```cassandraql
kubectl exec -it csi-rbd-demo-pod bash
root@csi-rbd-demo-pod:/# cd /var/lib/www/
root@csi-rbd-demo-pod:/var/lib/www# ls -l
total 4
drwxrwxrwx 3 root root 4096 Sep 14 09:09 html
root@csi-rbd-demo-pod:/var/lib/www# echo "你好!" > wu123.txt
wu123
```
列出 kubernetes pool 中的 rbd images:
```cassandraql
rbd ls -p kubernetes
csi-vol-fe40eb16-1a4e-11ed-bb7c-0eb2f382cefd
```
查看该 image 的特征:
```cassandraql
[root@ceph01 ceph]# rbd info csi-vol-fe40eb16-1a4e-11ed-bb7c-0eb2f382cefd -p kubernetes
rbd image 'csi-vol-fe40eb16-1a4e-11ed-bb7c-0eb2f382cefd':
size 1 GiB in 256 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: d50f18182e6b
block_name_prefix: rbd_data.d50f18182e6b
format: 2
features: layering
op_features:
flags:
create_timestamp: Fri Aug 12 22:56:49 2022
access_timestamp: Fri Aug 12 22:56:49 2022
modify_timestamp: Fri Aug 12 22:56:49 2022
```
到此,k8s 使用外部 ceph 存储配置结束
9-11 Go PaaS 平台PVC 模型开发
yu-tool.exe newService github.com/yunixiangfeng/gopaas/volume
yu-v3 --proto_path=. --micro_out=. --go_out=:. ./proto/volume/volume.proto
go mod tidy
C:\Users\Administrator\Desktop\gopaas\volume\domain\model\volume.go
package model
type Volume struct{
ID int64 `gorm:"primary_key;not_null;auto_increment"`
//存储的名称
VolumeName string `json:"volume_name"`
//存储的所属的命名空间
VolumeNamespace string `json:"volume_namespace"`
//存储的访问模式,RWO,ROX,RWX
VolumeAccessMode string `json:"volume_access_mode"`
//sc 的 class name
VolumeStorageClassName string `json:"volume_storage_class_name"`
//请求资源的大小
VolumeRequest float32 `json:"volume_request"`
//存储类型 Block,filesystem
VolumePersistentVolumeMode string `json:"volume_persistent_volume_mode"`
}
C:\Users\Administrator\Desktop\gopaas\volume\proto\volume\volume.proto
syntax = "proto3";
package volume;
option go_package = "./proto/volume;volume";
service Volume {
//对外提供添加服务
rpc AddVolume(VolumeInfo) returns (Response) {}
rpc DeleteVolume(VolumeId) returns (Response) {}
rpc UpdateVolume(VolumeInfo) returns (Response) {}
rpc FindVolumeByID(VolumeId) returns (VolumeInfo) {}
rpc FindAllVolume(FindAll) returns (AllVolume) {}
}
message VolumeInfo {
int64 id = 1;
string volume_name=2;
string volume_namespace=3;
string volume_access_mode=4;
string volume_storage_class_name=5;
float volume_request=6;
string volume_persistent_volume_mode=7;
}
message VolumeId {
int64 id = 1;
}
message FindAll {
}
message Response {
string msg =1 ;
}
message AllVolume {
repeated VolumeInfo volume_info = 1;
}
9-12 Go PaaS 平台 Service 开发(上)
C:\Users\Administrator\Desktop\gopaas\volume\domain\service\volume_data_service.go
package service
import (
"context"
"errors"
"strconv"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/volume/domain/model"
"github.com/yunixiangfeng/gopaas/volume/domain/repository"
"github.com/yunixiangfeng/gopaas/volume/proto/volume"
"k8s.io/api/apps/v1"
v12 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v13 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//这里是接口类型
type IVolumeDataService interface {
AddVolume(*model.Volume) (int64 , error)
DeleteVolume(int64) error
UpdateVolume(*model.Volume) error
FindVolumeByID(int64) (*model.Volume, error)
FindAllVolume() ([]model.Volume, error)
CreateVolumeToK8s(*volume.VolumeInfo) error
DeleteVolumeFromK8s(*model.Volume) error
}
//创建
//注意:返回值 IVolumeDataService 接口类型
func NewVolumeDataService(volumeRepository repository.IVolumeRepository,clientSet *kubernetes.Clientset) IVolumeDataService{
return &VolumeDataService{ VolumeRepository:volumeRepository, K8sClientSet: clientSet,deployment:&v1.Deployment{}}
}
type VolumeDataService struct {
//注意:这里是 IVolumeRepository 类型
VolumeRepository repository.IVolumeRepository
K8sClientSet *kubernetes.Clientset
deployment *v1.Deployment
}
//从 k8s 删除一个 pvc
func (u *VolumeDataService) DeleteVolumeFromK8s(volume *model.Volume) (err error) {
//先从K8s 中删除
if err = u.K8sClientSet.CoreV1().PersistentVolumeClaims(volume.VolumeNamespace).Delete(context.TODO(),volume.VolumeName, v13.DeleteOptions{});err!=nil {
common.Error(err)
return err
} else {
//从数据表中删除
if err := u.DeleteVolume(volume.ID);err !=nil {
common.Error(err)
return err
}
common.Info("删除存储ID"+ strconv.FormatInt(volume.ID,10)+" 成功!")
}
return
}
//创建存储到 k8s 中
func (u *VolumeDataService) CreateVolumeToK8s(info *volume.VolumeInfo)(err error) {
volume := u.setVolume(info)
if _,err = u.K8sClientSet.CoreV1().PersistentVolumeClaims(info.VolumeNamespace).Get(context.TODO(),info.VolumeName,v13.GetOptions{});err !=nil {
//如果存储不存在
if _,err = u.K8sClientSet.CoreV1().PersistentVolumeClaims(info.VolumeNamespace).Create(context.TODO(),volume,v13.CreateOptions{});err !=nil{
common.Error(err)
return err
}
common.Info("存储创建成功")
return nil
}else {
common.Error("存储空间"+ info.VolumeName +" 已经存在")
return errors.New("存储空间"+ info.VolumeName +" 已经存在")
}
}
//设置 pvc 的详情信息
func (u *VolumeDataService) setVolume(info *volume.VolumeInfo) *v12.PersistentVolumeClaim {
pvc := &v12.PersistentVolumeClaim{}
//设置接口类型
pvc.TypeMeta = v13.TypeMeta{
Kind: "PersistentVolumeClaim",
APIVersion: "v1",
}
//设置存储基础信息
pvc.ObjectMeta = v13.ObjectMeta{
Name: info.VolumeName,
Namespace: info.VolumeNamespace,
Annotations: map[string]string{
"pv.kubernetes.io/bound-by-controller":"yes",
"volume.beta.kubernetes.io/storage-provisioner":"rbd.csi.ceph.com",
"wu":"wu123",
},
}
//设置存储动态信息
pvc.Spec = v12.PersistentVolumeClaimSpec{
AccessModes: u.getAccessModes(info),
Resources: u.getResource(info),
StorageClassName: &info.VolumeStorageClassName,
VolumeMode: u.getVolumeMode(info),
}
return pvc
}
//获取存储类型
func (u *VolumeDataService) getVolumeMode(info *volume.VolumeInfo) *v12.PersistentVolumeMode {
var pvm v12.PersistentVolumeMode
switch info.VolumePersistentVolumeMode {
case "Block":
pvm = v12.PersistentVolumeBlock
case "Filesystem":
pvm = v12.PersistentVolumeFilesystem
default:
pvm = v12.PersistentVolumeFilesystem
}
return &pvm
}
//插入
func (u *VolumeDataService) AddVolume(volume *model.Volume) (int64 ,error) {
return u.VolumeRepository.CreateVolume(volume)
}
//删除
func (u *VolumeDataService) DeleteVolume(volumeID int64) error {
return u.VolumeRepository.DeleteVolumeByID(volumeID)
}
//更新
func (u *VolumeDataService) UpdateVolume(volume *model.Volume) error {
return u.VolumeRepository.UpdateVolume(volume)
}
//查找
func (u *VolumeDataService) FindVolumeByID(volumeID int64) (*model.Volume, error) {
return u.VolumeRepository.FindVolumeByID(volumeID)
}
//查找
func (u *VolumeDataService) FindAllVolume() ([]model.Volume, error) {
return u.VolumeRepository.FindAll()
}
9-13 Go PaaS 平台 Service 开发(下)
C:\Users\Administrator\Desktop\gopaas\volume\domain\service\volume_data_service.go
//获取资源配置
func (u *VolumeDataService) getResource (info *volume.VolumeInfo)(source v12.ResourceRequirements) {
source.Requests = v12.ResourceList{
"storage": resource.MustParse(strconv.FormatFloat(float64(info.VolumeRequest),'f',6,64)+"Gi"),
}
return
}
//获取访问模式
func (u *VolumeDataService) getAccessModes(info *volume.VolumeInfo)(pvam []v12.PersistentVolumeAccessMode) {
var pm v12.PersistentVolumeAccessMode
switch info.VolumeAccessMode {
case "ReadWriteOnce":
pm = v12.ReadWriteOnce
case "ReadOnlyMany":
pm = v12.ReadOnlyMany
case "ReadWriteMany":
pm = v12.ReadWriteMany
case "ReadWriteOncePod":
pm = v12.ReadWriteOncePod
default:
pm = v12.ReadWriteOnce
}
pvam = append(pvam,pm)
return pvam
}
9-14 Go PaaS 平台 PV与PVC 的关系和原理说明
PV和PVC的关系
PV (Persistent Volume): 持久化卷的意思,是对底层的共享存储的一种抽象
PVC (Persistent Volume Claim): 用户存储的请求
PV的访问模式(accessModes
ReadWriteOnce(RWO): 可读可写,单挂载
ReadOnlyMany(ROX): 只读,多挂载
ReadWriteMany(RWX): 可读可写,多挂载
PV 的回收策略(persistentVolumeReclaimPolicy)
Retain:不清理,保留Volume(需要手动清理
Recycle:会删除数据,类似 rm -rf /xxx/*
Delete:删除存储资源
PV的状态
Available :可用
Bound :已经分配给PVC
Released:PVC 解绑但是还未执行回收策略
Failed:存储异常
PVC的关键参数
访问模式(accessModes):标明访问权限选择器(selector):label选择筛选绑定PV
存储类别 (storageClassName): 设置用来自动创建PV
请求资源 (Resources) :标明需要的存储大小
PV与PVC的生命周期:Provisioning 配置阶段
静态:管理员创建多个PV,属性确定,绑定了真实的存储设。
动态:通过StorageClass,k8s 会创建动态的为PVC 创建PV好处时候资源能够除非利用。创建模式自动。
PV与PVC的生命周期:Binding
在动态配置的情况下,用户创建了PVC后,标明PVC与PV绑
定过程
如果没有满足PVC请求的PV,PVC将无法被创建。
如果绑定了PVC 绑定了Pod,pod将无法创建
PV与PVC的生命周期
Using:PVC与PV绑定后,Pod对存储空间正常使用
Releasing:当Pod被删除或者PV的资源使用结束后
Reclaiming:PV的回收策略对被释放的PV的处理
Recycling: PV被执行擦除后再被分配
9-15 Go PaaS 平台 Service Handler 开发
C:\Users\Administrator\Desktop\gopaas\volume\handler\volumeHandler.go
package handler
import (
"context"
"strconv"
log "github.com/asim/go-micro/v3/logger"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/volume/domain/model"
"github.com/yunixiangfeng/gopaas/volume/domain/service"
volume "github.com/yunixiangfeng/gopaas/volume/proto/volume"
)
type VolumeHandler struct {
//注意这里的类型是 IVolumeDataService 接口类型
VolumeDataService service.IVolumeDataService
}
// Call is a single request handler called via client.Call or the generated client code
func (e *VolumeHandler) AddVolume(ctx context.Context, info *volume.VolumeInfo, rsp *volume.Response) error {
log.Info("Received *volume.AddVolume request")
volume := &model.Volume{}
if err := common.SwapTo(info, volume); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//创建volume
if err := e.VolumeDataService.CreateVolumeToK8s(info); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
} else {
//写入数据库
volumeID, err := e.VolumeDataService.AddVolume(volume)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
rsp.Msg = "volume 添加成功 ID 号为:" + strconv.FormatInt(volumeID, 10)
}
return nil
}
//删除
func (e *VolumeHandler) DeleteVolume(ctx context.Context, req *volume.VolumeId, rsp *volume.Response) error {
log.Info("Received *volume.DeleteVolume request")
volumModel, err := e.VolumeDataService.FindVolumeByID(req.Id)
if err != nil {
common.Error(err)
return err
}
//从k8s中删除,并且删除数据库
if err := e.VolumeDataService.DeleteVolumeFromK8s(volumModel); err != nil {
common.Error(err)
return err
}
return nil
}
func (e *VolumeHandler) UpdateVolume(ctx context.Context, req *volume.VolumeInfo, rsp *volume.Response) error {
log.Info("Received *volume.UpdateVolume request")
return nil
}
//根据 ID 查找 volume
func (e *VolumeHandler) FindVolumeByID(ctx context.Context, req *volume.VolumeId, rsp *volume.VolumeInfo) error {
log.Info("Received *volume.FindVolumeByID request")
volumeModel, err := e.VolumeDataService.FindVolumeByID(req.Id)
if err != nil {
common.Error(err)
return err
}
//数据转化
if err := common.SwapTo(volumeModel, rsp); err != nil {
common.Error(err)
return err
}
return nil
}
func (e *VolumeHandler) FindAllVolume(ctx context.Context, req *volume.FindAll, rsp *volume.AllVolume) error {
log.Info("Received *volume.FindAllVolume request")
allVolume, err := e.VolumeDataService.FindAllVolume()
if err != nil {
common.Error(err)
return err
}
//整理格式
for _, v := range allVolume {
//创建实例
volumeInfo := &volume.VolumeInfo{}
//数据转化
if err := common.SwapTo(v, volumeInfo); err != nil {
common.Error(err)
return err
}
//数据合并
rsp.VolumeInfo = append(rsp.VolumeInfo, volumeInfo)
}
return nil
}
C:\Users\Administrator\Desktop\gopaas\volume\main.go
package main
import (
"flag"
"fmt"
"path/filepath"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/volume/domain/repository"
//"github.com/afex/hystrix-go/hystrix"
"github.com/asim/go-micro/plugins/registry/consul/v3"
ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
"github.com/asim/go-micro/v3"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/server"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/opentracing/opentracing-go"
service2 "github.com/yunixiangfeng/gopaas/volume/domain/service"
"github.com/yunixiangfeng/gopaas/volume/handler"
//hystrix2 "github.com/yunixiangfeng/gopaas/volume/plugin/hystrix"
"strconv"
volume "github.com/yunixiangfeng/gopaas/volume/proto/volume"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
var (
//服务地址
hostIp = "192.168.204.130"
//服务地址
serviceHost = hostIp
//服务端口
servicePort = "8087"
//注册中心配置
consulHost = hostIp
consulPort int64 = 8500
//链路追踪
tracerHost = hostIp
tracerPort = 6831
//熔断端口,每个服务不能重复
//hystrixPort = 9097
//监控端口,每个服务不能重复
prometheusPort = 9197
)
func main() {
//需要本地启动,mysql,consul中间件服务
//1.注册中心
consul := consul.NewRegistry(func(options *registry.Options) {
options.Addrs = []string{
consulHost + ":" + strconv.FormatInt(consulPort, 10),
}
})
//2.配置中心,存放经常变动的变量
consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
if err != nil {
common.Error(err)
}
//3.使用配置中心连接 mysql
mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
//初始化数据库
db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
if err != nil {
//命令行输出下,方便查看错误
fmt.Println(err)
common.Fatal(err)
}
defer db.Close()
//禁止复表
db.SingularTable(true)
//4.添加链路追踪
t, io, err := common.NewTracer("go.micro.service.volume", tracerHost+":"+strconv.Itoa(tracerPort))
if err != nil {
common.Error(err)
}
defer io.Close()
opentracing.SetGlobalTracer(t)
//添加熔断器,作为客户端需要启用
//hystrixStreamHandler := hystrix.NewStreamHandler()
//hystrixStreamHandler.Start()
//添加日志中心
//1)需要程序日志打入到日志文件中
//2)在程序中添加filebeat.yml 文件
//3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
//启动监听程序
//go func() {
// //http://192.168.204.130:9092/turbine/turbine.stream
// //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
// err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
// if err !=nil {
// common.Error(err)
// }
//}()
//5.添加监控
common.PrometheusBoot(prometheusPort)
//下载kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
//macos:
// 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
// 2.chmod +x ./kubectl
// 3.sudo mv ./kubectl /usr/local/bin/kubectl
// sudo chown root: /usr/local/bin/kubectl
// 5.kubectl version --client
// 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
// 注意:- config中的域名要能解析正确
// - 生产环境可以创建另一个证书
// 7.kubectl get ns 查看是否正常
//
//6.创建k8s连接
//在集群外面连接
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) 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 {
common.Fatal(err.Error())
}
//在集群中外的配置
//config, err := rest.InClusterConfig()
//if err != nil {
// panic(err.Error())
//}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
common.Fatal(err.Error())
}
//7.创建服务
service := micro.NewService(
//自定义服务地址,且必须写在其它参数前面
micro.Server(server.NewServer(func(options *server.Options) {
options.Advertise = serviceHost + ":" + servicePort
})),
micro.Name("go.micro.service.volume"),
micro.Version("latest"),
//指定服务端口
micro.Address(":"+servicePort),
//添加注册中心
micro.Registry(consul),
//添加链路追踪
micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
//只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
//micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
//添加限流
micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
)
service.Init()
//只能执行一遍
//err = repository.NewVolumeRepository(db).InitTable()
//if err != nil {
// common.Fatal(err)
//}
// 注册句柄,可以快速操作已开发的服务
volumeDataService := service2.NewVolumeDataService(repository.NewVolumeRepository(db), clientset)
volume.RegisterVolumeHandler(service.Server(), &handler.VolumeHandler{VolumeDataService: volumeDataService})
// 启动服务
if err := service.Run(); err != nil {
//输出启动失败信息
common.Fatal(err)
}
}
9-16 Go PaaS 平台 volume api 开发
PS C:\Users\Administrator\Desktop\gopaas> .\yu-tool\yu-tool.exe createApi github.com/yunixiangfeng/gopaas/volumeApi
yu-v3 --proto_path=. --micro_out=. --go_out=:. ./proto/volumeApi/volumeApi.proto
go mod tidy
C:\Users\Administrator\Desktop\gopaas\volumeapi\handler\volumeApiHandler.go
package handler
import (
"context"
"encoding/json"
"errors"
"strconv"
log "github.com/asim/go-micro/v3/logger"
"github.com/yunixiangfeng/gopaas/common"
volume "github.com/yunixiangfeng/gopaas/volume/proto/volume"
"github.com/yunixiangfeng/gopaas/volumeApi/plugin/form"
volumeApi "github.com/yunixiangfeng/gopaas/volumeApi/proto/volumeApi"
)
type VolumeApi struct {
VolumeService volume.VolumeService
}
// volumeApi.FindVolumeById 通过API向外暴露为/volumeApi/findVolumeById,接收http请求
// 即:/volumeApi/FindVolumeById 请求会调用go.micro.api.volumeApi 服务的volumeApi.FindVolumeById 方法
func (e *VolumeApi) FindVolumeById(ctx context.Context, req *volumeApi.Request, rsp *volumeApi.Response) error {
log.Info("Received volumeApi.FindVolumeById request")
if _, ok := req.Get["volume_id"]; !ok {
rsp.StatusCode = 500
return errors.New("参数有异常")
}
//获取 volume_id
volumeIdString := req.Get["volume_id"].Values[0]
volumeId, err := strconv.ParseInt(volumeIdString, 10, 64)
if err != nil {
common.Error(err)
return err
}
//获取 volume 信息
volumeInfo, err := e.VolumeService.FindVolumeByID(ctx, &volume.VolumeId{
Id: volumeId,
})
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(volumeInfo)
rsp.Body = string(b)
return nil
}
// volumeApi.AddVolume 通过API向外暴露为/volumeApi/AddVolume,接收http请求
// 即:/volumeApi/AddVolume 请求会调用go.micro.api.volumeApi 服务的volumeApi.AddVolume 方法
func (e *VolumeApi) AddVolume(ctx context.Context, req *volumeApi.Request, rsp *volumeApi.Response) error {
log.Info("Received volumeApi.AddVolume request")
addVolumeInfo := &volume.VolumeInfo{}
form.FormToSvcStruct(req.Post, addVolumeInfo)
response, err := e.VolumeService.AddVolume(ctx, addVolumeInfo)
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(response)
rsp.Body = string(b)
return nil
}
// volumeApi.DeleteVolumeById 通过API向外暴露为/volumeApi/DeleteVolumeById,接收http请求
// 即:/volumeApi/DeleteVolumeById 请求会调用go.micro.api.volumeApi 服务的 volumeApi.DeleteVolumeById 方法
func (e *VolumeApi) DeleteVolumeById(ctx context.Context, req *volumeApi.Request, rsp *volumeApi.Response) error {
log.Info("Received volumeApi.DeleteVolumeById request")
if _, ok := req.Get["volume_id"]; !ok {
rsp.StatusCode = 500
return errors.New("参数异常")
}
//获取 volume_id
volumeIdString := req.Get["volume_id"].Values[0]
volumeId, err := strconv.ParseInt(volumeIdString, 10, 64)
if err != nil {
common.Error(err)
return err
}
//调用 volume 删除服务
response, err := e.VolumeService.DeleteVolume(ctx, &volume.VolumeId{
Id: volumeId,
})
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(response)
rsp.Body = string(b)
return nil
}
// volumeApi.UpdateVolume 通过API向外暴露为/volumeApi/UpdateVolume,接收http请求
// 即:/volumeApi/UpdateVolume 请求会调用go.micro.api.volumeApi 服务的volumeApi.UpdateVolume 方法
func (e *VolumeApi) UpdateVolume(ctx context.Context, req *volumeApi.Request, rsp *volumeApi.Response) error {
log.Info("Received volumeApi.UpdateVolume request")
rsp.StatusCode = 200
b, _ := json.Marshal("{success:'成功访问/volumeApi/UpdateVolume'}")
rsp.Body = string(b)
return nil
}
// 默认的方法volumeApi.Call 通过API向外暴露为/volumeApi/call,接收http请求
// 即:/volumeApi/call或/volumeApi/ 请求会调用go.micro.api.volumeApi 服务的volumeApi.FindVolumeById 方法
func (e *VolumeApi) Call(ctx context.Context, req *volumeApi.Request, rsp *volumeApi.Response) error {
log.Info("Received volumeApi.Call request")
allVolume, err := e.VolumeService.FindAllVolume(ctx, &volume.FindAll{})
if err != nil {
common.Error(err)
return err
}
rsp.StatusCode = 200
b, _ := json.Marshal(allVolume)
rsp.Body = string(b)
return nil
}
C:\Users\Administrator\Desktop\gopaas\volumeapi\plugin\form\form.go
package form
import (
"errors"
"reflect"
"strconv"
"strings"
"time"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/volumeApi/proto/volumeApi"
)
//根据结构体中name标签映射数据到结构体中并且转换类型
func FormToSvcStruct(data map[string]*volumeApi.Pair, obj interface{}) {
objValue := reflect.ValueOf(obj).Elem()
for i := 0; i < objValue.NumField(); i++ {
//获取sql对应的值
dataTag := strings.Replace(objValue.Type().Field(i).Tag.Get("json"), ",omitempty", "", -1)
dataSlice, ok := data[dataTag]
if !ok {
continue
}
valueSlice := dataSlice.Values
if len(valueSlice) <= 0 {
continue
}
//排除port和env
if dataTag == "route_path" {
continue
}
value := valueSlice[0]
//端口,环境变量的单独处理
//获取对应字段的名称
name := objValue.Type().Field(i).Name
//获取对应字段类型
structFieldType := objValue.Field(i).Type()
//获取变量类型,也可以直接写"string类型"
val := reflect.ValueOf(value)
var err error
if structFieldType != val.Type() {
//类型转换
val, err = TypeConversion(value, structFieldType.Name()) //类型转换
if err != nil {
common.Error(err)
}
}
//设置类型值
objValue.FieldByName(name).Set(val)
}
}
//类型转换
func TypeConversion(value string, ntype string) (reflect.Value, error) {
if ntype == "string" {
return reflect.ValueOf(value), nil
} else if ntype == "time.Time" {
t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
return reflect.ValueOf(t), err
} else if ntype == "Time" {
t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
return reflect.ValueOf(t), err
} else if ntype == "int" {
i, err := strconv.Atoi(value)
return reflect.ValueOf(i), err
} else if ntype == "int32" {
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return reflect.ValueOf(int32(i)), err
}
return reflect.ValueOf(int32(i)), err
} else if ntype == "int64" {
i, err := strconv.ParseInt(value, 10, 64)
return reflect.ValueOf(i), err
} else if ntype == "float32" {
i, err := strconv.ParseFloat(value, 64)
return reflect.ValueOf(float32(i)), err
} else if ntype == "float64" {
i, err := strconv.ParseFloat(value, 64)
return reflect.ValueOf(i), err
}
//else if .......增加其他一些类型的转换
return reflect.ValueOf(value), errors.New("未知的类型:" + ntype)
}
C:\Users\Administrator\Desktop\gopaas\volumeapi\main.go
package main
import (
"fmt"
"github.com/afex/hystrix-go/hystrix"
"github.com/asim/go-micro/plugins/registry/consul/v3"
ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
"github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v3"
opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
"github.com/asim/go-micro/v3"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/server"
"github.com/yunixiangfeng/gopaas/common"
go_micro_service_volume "github.com/yunixiangfeng/gopaas/volume/proto/volume"
"net"
"net/http"
"strconv"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/opentracing/opentracing-go"
"github.com/yunixiangfeng/gopaas/volumeApi/handler"
hystrix2 "github.com/yunixiangfeng/gopaas/volumeApi/plugin/hystrix"
volumeApi "github.com/yunixiangfeng/gopaas/volumeApi/proto/volumeApi"
)
var (
//服务地址
hostIp = "192.168.204.130"
//服务地址
serviceHost = hostIp
//服务端口
servicePort = "8087"
//注册中心配置
consulHost = hostIp
consulPort int64 = 8500
//链路追踪
tracerHost = hostIp
tracerPort = 6831
//熔断端口,每个服务不能重复
hystrixPort = 9097
//监控端口,每个服务不能重复
prometheusPort = 9197
)
func main() {
//需要本地启动,mysql,consul中间件服务
//1.注册中心
consul := consul.NewRegistry(func(options *registry.Options) {
options.Addrs = []string{
consulHost + ":" + strconv.FormatInt(consulPort, 10),
}
})
//2.添加链路追踪
t, io, err := common.NewTracer("go.micro.api.volumeApi", tracerHost+":"+strconv.Itoa(tracerPort))
if err != nil {
common.Error(err)
}
defer io.Close()
opentracing.SetGlobalTracer(t)
//3.添加熔断器
hystrixStreamHandler := hystrix.NewStreamHandler()
hystrixStreamHandler.Start()
//添加日志中心
//1)需要程序日志打入到日志文件中
//2)在程序中添加filebeat.yml 文件
//3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
//启动监听程序
go func() {
//http://192.168.204.130:9092/turbine/turbine.stream
//看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
if err != nil {
common.Error(err)
}
}()
//4.添加监控
common.PrometheusBoot(prometheusPort)
//5.创建服务
service := micro.NewService(
//自定义服务地址,且必须写在其它参数前面
micro.Server(server.NewServer(func(opts *server.Options) {
opts.Advertise = serviceHost + ":" + servicePort
})),
micro.Name("go.micro.api.volumeApi"),
micro.Version("latest"),
//指定服务端口
micro.Address(":"+servicePort),
//添加注册中心
micro.Registry(consul),
//添加链路追踪
micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
//只作为客户端的时候起作用
micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
//添加限流
micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
//增加负载均衡
micro.WrapClient(roundrobin.NewClientWrapper()),
)
service.Init()
// 指定需要访问的服务,可以快速操作已开发的服务,
// 默认API服务名称带有"Api",程序会自动替换
// 如果不带有特定字符会使用默认"XXX" 请自行替换
volumeService := go_micro_service_volume.NewVolumeService("go.micro.service.volume", service.Client())
// 注册控制器
if err := volumeApi.RegisterVolumeApiHandler(service.Server(), &handler.VolumeApi{VolumeService: volumeService}); err != nil {
common.Error(err)
}
// 启动服务
if err := service.Run(); err != nil {
//输出启动失败信息
common.Fatal(err)
}
}
file:///home/gopath/src/gopaas/go-paas-front/volume-create.html
9-17 总结&思考
主要内容
Ceph 基础概念介绍
Ceph 架构说明及安装
服务后端功能开发
经验之谈
Ceph 在创建支出需要规划好 PG 数量
分布式存储为了数据不丢失和高可用建议最小保留2个副本
运行过程中重要的数据操作前打快照
Ceph 单个节点宕机数据恢复过程是什么?
Ceph 的监控有哪些维度是要关心的?
9-18 【扩展阅读】基于kubernetes-1.21.5使用Rook方式部署Ceph
第10章 云原生 Go PaaS 平台中间件后端管理服务,动态创建中间件
研发过程中通常有创建不同中间件的需求,能够提供开箱即用的提供中间件资源,是一件非常高效的方式,学习mysql 的中间件的创建和管理,并且通过中间件挂载分布式存储来满足数据落盘的需求。
10-1 Go 云原生PaaS平台中间件model–middleware创建
GO PaaS 平台中间件创建与管理
PS C:\Users\Administrator\Desktop\gopaas> .\yu-tool\yu-tool.exe newService github.com/yunixiangfeng/gopaas/middleware
yu-v3 --proto_path=. --micro_out=. --go_out=:. ./proto/middleware/middleware.proto
go mod tidy
middleware\domain\model\middleware.go
package model
type Middleware struct {
ID int64 `gorm:"primary_key;not_null;auto_increment"`
//中间件的名称
MiddleName string `json:"middle_name"`
//中间件创建的命名空间
MiddleNamespace string `json:"middle_namespace"`
//中间件的类型
MiddleTypeID int64 `json:"middle_type_id"`
//中间件的版本
MiddleVersionID int64 `json:"middle_version_id"`
//中间件的端口
MiddlePort []MiddlePort `gorm:"ForeignKey:MiddleID" json:"middle_port"`
//默认生成的账号密码
MiddleConfig MiddleConfig `gorm:"ForeignKey:MiddleID" json:"middle_config"`
//环境变量
MiddleEnv []MiddleEnv `gorm:"ForeignKey:MiddleID" json:"middle_env"`
//中间件的CPU
MiddleCpu float32 `json:"middle_cpu"`
//中间件内存
MiddleMemory float32 `json:"middle_memory"`
//中间件存储
MiddleStorage []MiddleStorage `gorm:"ForeignKey:MiddleID" json:"middle_storage"`
//中间件副本
MiddleReplicas int32 `json:"middle_replicas"`
}
10-2 Go PAAS平台中间件model-middle_port创建
C:\Users\Administrator\Desktop\gopaas\middleware\domain\model\middle_port.go
package model
type MiddlePort struct {
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
//主要用来关联中间件的ID
MiddleID int64 `json:"middle_id"`
//中间件开放的端口
MiddlePort int32 `json:"middle_port"`
//中间件开放的端口协议
MiddleProtocol string `json:"middle_protocol"`
}
10-3 中间件model-middle_env创建
C:\Users\Administrator\Desktop\gopaas\middleware\domain\model\middle_env.go
package model
//中间件的变量
type MiddleEnv struct {
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
//关联的环境变量ID
MiddleID int64 `json:"middle_id"`
//环境变量key
EnvKey string `json:"env_key"`
//环境变量Value
EnvValue string `json:"env_value"`
}
10-4 中间件model-MiddleConfig创建
C:\Users\Administrator\Desktop\gopaas\middleware\domain\model\middle_config.go
package model
//中间件配置的结构体
type MiddleConfig struct {
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
//关联的中间件ID
MiddleID int64 `json:"middle_id"`
//可能存在的root 用户
MiddleConfigRootUser string `json:"middle_config_root_user"`
//可能存在的root 密码
MiddleConfigRootPwd string `json:"middle_config_root_pwd"`
//可能存在的普通用户
MiddleConfigUser string `json:"middle_config_user"`
//普通用户的密码
MiddleConfigPwd string `json:"middle_config_pwd"`
//预置数据库名称
MiddleConfigDataBase string `json:"middle_config_data_base"`
//其它设置
}
10-5 中间件model-MiddleStorage创建
C:\Users\Administrator\Desktop\gopaas\middleware\domain\model\middle_storage.go
package model
//中间件的存储盘
type MiddleStorage struct {
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
//关联的中间件ID
MiddleID int64 `json:"middle_id"`
//存储名称
MiddleStorageName string `json:"middle_storage_name"`
//存储的大小
MiddleStorageSize float32 `json:"middle_storage_size"`
//存储需要挂载的目录
MiddleStoragePath string `json:"middle_storage_path"`
//存储创建的类型
MiddleStorageClass string `json:"middle_storage_class"`
//存储的权限
MiddleStorageAccessMode string `json:"middle_storage_access_mode"`
}
10-6 中间件类型type 和 version创建
C:\Users\Administrator\Desktop\gopaas\middleware\domain\model\middle_type.go
package model
//中间件类型
type MiddleType struct {
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
//中间件类型名称
MiddleTypeName string `json:"middle_type_name"`
//中间件图片地址
MiddleTypeImageSrc string `json:"middle_type_image_src"`
//中间件的版本
MiddleVersion[] MiddleVersion `gorm:"ForeignKey:MiddleTypeID" json:"middle_version"`
}
C:\Users\Administrator\Desktop\gopaas\middleware\domain\model\middle_version.go
package model
type MiddleVersion struct {
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
MiddleTypeID int64 `json:"middle_type_id"`
//镜像地址
MiddleDockerImage string `json:"middle_docker_image"`
//镜像版本
MiddleVS string `json:"middle_vs"`
//MiddleDockerImage:MiddleVS
//其它
}
10-7 中间件 middleware repository开发
C:\Users\Administrator\Desktop\gopaas\middleware\domain\repository\middleware_repository.go
package repository
import (
"github.com/jinzhu/gorm"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
)
//创建需要实现的接口
type IMiddlewareRepository interface {
//初始化表
InitTable() error
//根据ID查处找数据
FindMiddlewareByID(int64) (*model.Middleware, error)
//创建一条 middleware 数据
CreateMiddleware(*model.Middleware) (int64, error)
//根据ID删除一条 middleware 数据
DeleteMiddlewareByID(int64) error
//修改更新数据
UpdateMiddleware(*model.Middleware) error
//查找middleware所有数据
FindAll() ([]model.Middleware, error)
//根据类型查找所有中间件
FindAllByTypeID(int64) ([]model.Middleware, error)
}
//创建middlewareRepository
func NewMiddlewareRepository(db *gorm.DB) IMiddlewareRepository {
return &MiddlewareRepository{mysqlDb: db}
}
type MiddlewareRepository struct {
mysqlDb *gorm.DB
}
//初始化表
func (u *MiddlewareRepository) InitTable() error {
return u.mysqlDb.CreateTable(&model.Middleware{}, &model.MiddleConfig{}, &model.MiddlePort{}, &model.MiddleEnv{}, &model.MiddleStorage{}).Error
}
//根据ID查找Middleware信息
func (u *MiddlewareRepository) FindMiddlewareByID(middlewareID int64) (middleware *model.Middleware, err error) {
middleware = &model.Middleware{}
//要多个则添加 Preload
return middleware, u.mysqlDb.First(middleware, middlewareID).Error
}
//创建Middleware信息
func (u *MiddlewareRepository) CreateMiddleware(middleware *model.Middleware) (int64, error) {
return middleware.ID, u.mysqlDb.Create(middleware).Error
}
//根据ID删除Middleware信息
func (u *MiddlewareRepository) DeleteMiddlewareByID(middlewareID int64) error {
//开启事物
tx := u.mysqlDb.Begin()
//遇到问题回滚
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
//遇到错误返回
if tx.Error != nil {
return tx.Error
}
//删除中间件
if err := u.mysqlDb.Where("id = ?", middlewareID).Delete(&model.Middleware{}).Error; err != nil {
tx.Rollback()
return err
}
//删除中间件的配置
if err := u.mysqlDb.Where("middle_id = ?", middlewareID).Delete(&model.MiddleConfig{}).Error; err != nil {
tx.Rollback()
return err
}
//删除端口
if err := u.mysqlDb.Where("middle_id = ?", middlewareID).Delete(&model.MiddlePort{}).Error; err != nil {
tx.Rollback()
return err
}
//删除中间件环境变量
if err := u.mysqlDb.Where("middle_id = ?", middlewareID).Delete(&model.MiddleEnv{}).Error; err != nil {
tx.Rollback()
return err
}
//删除中间件存储
if err := u.mysqlDb.Where("middle_id = ?", middlewareID).Delete(&model.MiddleStorage{}).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
//更新Middleware信息
func (u *MiddlewareRepository) UpdateMiddleware(middleware *model.Middleware) error {
return u.mysqlDb.Model(middleware).Update(middleware).Error
}
//获取结果集
func (u *MiddlewareRepository) FindAll() (middlewareAll []model.Middleware, err error) {
//要多个则添加 Preload
return middlewareAll, u.mysqlDb.Find(&middlewareAll).Error
}
func (u *MiddlewareRepository) FindAllByTypeID(typeID int64) (middlewareAll []model.Middleware, err error) {
//要多个则添加 Preload
return middlewareAll, u.mysqlDb.Where("middle_type_id = ?", typeID).Find(&middlewareAll).Error
}
10-8 中间件类型type和verison repository开发
C:\Users\Administrator\Desktop\gopaas\middleware\domain\repository\middle_type_repository.go
package repository
import (
"github.com/jinzhu/gorm"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
)
//创建需要实现的接口
type IMiddleTypeRepository interface {
//初始化表
InitTable() error
//根据ID查处找数据
FindTypeByID(int64) (*model.MiddleType, error)
//创建一条 middleware 数据
CreateMiddleType(*model.MiddleType) (int64, error)
//根据ID删除一条 middleware 数据
DeleteMiddleTypeByID(int64) error
//修改更新数据
UpdateMiddleType(*model.MiddleType) error
//查找middleware所有数据
FindAll() ([]model.MiddleType, error)
FindVersionByID(int64) (*model.MiddleVersion, error)
FindAllVersionByTypeID(int64) ([]model.MiddleVersion, error)
}
//创建MiddleTypeRepository
func NewMiddleTypeRepository(db *gorm.DB) IMiddleTypeRepository {
return &MiddleTypeRepository{mysqlDb: db}
}
type MiddleTypeRepository struct {
mysqlDb *gorm.DB
}
//初始化表
func (u *MiddleTypeRepository) InitTable() error {
return u.mysqlDb.CreateTable(&model.MiddleType{}, &model.MiddleVersion{}).Error
}
//按照 ID 查找中间件类型
func (u *MiddleTypeRepository) FindTypeByID(middleTypeID int64) (middleType *model.MiddleType, err error) {
middleType = &model.MiddleType{}
return middleType, u.mysqlDb.Preload("MiddleVersion").First(middleType, middleTypeID).Error
}
//创建中间件
func (u *MiddleTypeRepository) CreateMiddleType(middleType *model.MiddleType) (int64, error) {
return middleType.ID, u.mysqlDb.Create(middleType).Error
}
//删除中间件
func (u *MiddleTypeRepository) DeleteMiddleTypeByID(middleTypeID int64) error {
tx := u.mysqlDb.Begin()
//遇到问题回滚
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
//遇到错误返回
if tx.Error != nil {
return tx.Error
}
//删除中间件类型
if err := u.mysqlDb.Where("id = ?", middleTypeID).Delete(&model.MiddleType{}).Error; err != nil {
tx.Rollback()
return err
}
//开始删除版本
if err := u.mysqlDb.Where("middle_type_id = ?", middleTypeID).Delete(&model.MiddleVersion{}).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
//更新middleware 信息
func (u *MiddleTypeRepository) UpdateMiddleType(middleType *model.MiddleType) error {
return u.mysqlDb.Model(middleType).Update(middleType).Error
}
//获取类型的结果集
func (u *MiddleTypeRepository) FindAll() (middleTypeAll []model.MiddleType, err error) {
return middleTypeAll, u.mysqlDb.Find(&middleTypeAll).Error
}
//根据ID查找单个版本
func (u *MiddleTypeRepository) FindVersionByID(middleVersionID int64) (middleVersion *model.MiddleVersion, err error) {
middleVersion = &model.MiddleVersion{}
return middleVersion, u.mysqlDb.First(middleVersion, middleVersionID).Error
}
//根据中间件类型查找所有版本
func (u *MiddleTypeRepository) FindAllVersionByTypeID(middleTypeID int64) (middleVersionAll []model.MiddleVersion, err error) {
return middleVersionAll, u.mysqlDb.Where("middle_type_id = ?", middleTypeID).Find(&middleVersionAll).Error
}
10-9 中间件 proto 文件开发
C:\Users\Administrator\Desktop\gopaas\middleware\proto\middleware\middleware.proto
syntax = "proto3";
package middleware;
option go_package = "./proto/middleware;middleware";
service Middleware {
//对外提供添加服务
rpc AddMiddleware(MiddlewareInfo) returns (Response) {}
rpc DeleteMiddleware(MiddlewareId) returns (Response) {}
rpc UpdateMiddleware(MiddlewareInfo) returns (Response) {}
rpc FindMiddlewareByID(MiddlewareId) returns (MiddlewareInfo) {}
rpc FindAllMiddleware(FindAll) returns (AllMiddleware) {}
//根据中间件的类型查找所有中间件
rpc FindAllMiddlewareByTypeID(FindAllByTypeId) returns (AllMiddleware){}
//获取中间件类型
rpc FindMiddleTypeByID(MiddleTypeId) returns (MiddleTypeInfo){}
rpc AddMiddleType(MiddleTypeInfo) returns (Response){}
rpc DeleteMiddleTypeByID(MiddleTypeId) returns (Response){}
rpc UpdateMiddleType(MiddleTypeInfo) returns(Response){}
rpc FindAllMiddleType(FindAll) returns (AllMiddleType){}
}
message MiddlewareInfo {
int64 id = 1;
string middle_name = 2;
string middle_namespace =3;
int64 middle_type_id = 4;
int64 middle_version_id =5;
repeated MiddlePort middle_port=6;
MiddleConfig middle_config=7;
repeated MiddleEnv middle_env=8;
float middle_cpu=9;
float middle_memory=10;
repeated MiddleStorage middle_storage =11;
int32 middle_replicas = 12;
//添加需要的镜像版本
string middle_docker_image_version=13;
}
//中间件的端口
message MiddlePort {
int64 middle_id=1;
int32 middle_port=2;
string middle_protocol=3;
}
//中间的配置
message MiddleConfig{
int64 middle_id =1;
string middle_config_root_user =2;
string middle_config_root_pwd =3;
string middle_config_user =4;
string middle_config_pwd =5;
string middle_config_data_base =6;
}
//中间件环境变量
message MiddleEnv {
int64 middle_id=1;
string env_key=2;
string env_value=3;
}
//中间件存储
message MiddleStorage{
int64 middle_id =1;
string middle_storage_name=2;
float middle_storage_size=3;
string middle_storage_path=4;
string middle_storage_class=5;
string middle_storage_access_mode=6;
}
message FindAllByTypeId {
int64 type_id =1;
}
message MiddleTypeId {
int64 id=1;
}
message MiddlewareId {
int64 id = 1;
}
message FindAll {
}
message Response {
string msg =1 ;
}
message AllMiddleware {
repeated MiddlewareInfo middleware_info = 1;
}
message MiddleTypeInfo {
int64 id =1;
string middle_type_name=2;
string middle_type_image_src=3;
repeated MiddleVersion middle_version=4;
}
message MiddleVersion{
int64 middle_type_id =1;
string middle_docker_image=2;
string middle_vs=3;
}
message AllMiddleType{
repeated MiddleTypeInfo middle_type_info =1;
}
yu-v3 --proto_path=. --micro_out=. --go_out=:. ./proto/middleware/middleware.proto
10-10 中间件 service 开发(1)
C:\Users\Administrator\Desktop\gopaas\middleware\domain\service\middleware_data_service.go
package service
import (
"context"
"errors"
"strconv"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/repository"
"github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
v1 "k8s.io/api/apps/v1"
v13 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//这里是接口类型
type IMiddlewareDataService interface {
AddMiddleware(*model.Middleware) (int64, error)
DeleteMiddleware(int64) error
UpdateMiddleware(*model.Middleware) error
FindMiddlewareByID(int64) (*model.Middleware, error)
FindAllMiddleware() ([]model.Middleware, error)
//根据类型查找中间件
FindAllMiddlewareByTypeID(int64) ([]model.Middleware, error)
//操作中间件s
CreateToK8s(*middleware.MiddlewareInfo) error
DeleteFromK8s(*model.Middleware) error
UpdateToK8s(*middleware.MiddlewareInfo) error
}
//创建
//注意:返回值 IMiddlewareDataService 接口类型
func NewMiddlewareDataService(middlewareRepository repository.IMiddlewareRepository, clientSet *kubernetes.Clientset) IMiddlewareDataService {
return &MiddlewareDataService{MiddlewareRepository: middlewareRepository, K8sClientSet: clientSet}
}
type MiddlewareDataService struct {
//注意:这里是 IMiddlewareRepository 类型
MiddlewareRepository repository.IMiddlewareRepository
K8sClientSet *kubernetes.Clientset
}
//更新中间件到k8s
func (u *MiddlewareDataService) UpdateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
common.Error(err)
return errors.New("中间件 " + info.MiddleName + " 不存在请先创建")
} else {
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Update(context.TODO(), statefulSet, v12.UpdateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件 " + info.MiddleName + " 更新成功!")
return nil
}
}
//删除中间件
func (u *MiddlewareDataService) DeleteFromK8s(middleware *model.Middleware) (err error) {
if err := u.K8sClientSet.AppsV1().StatefulSets(middleware.MiddleNamespace).Delete(context.TODO(), middleware.MiddleName, v12.DeleteOptions{}); err != nil {
common.Error(err)
return err
} else {
if err := u.DeleteMiddleware(middleware.ID); err != nil {
common.Error(err)
return err
}
common.Info("删除中间件:" + middleware.MiddleName + "成功!")
return nil
}
}
//在k8s中创建中间件
func (u *MiddlewareDataService) CreateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
//如果没有获取到
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Create(context.TODO(), statefulSet, v12.CreateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件:" + info.MiddleName + "创建成功")
return nil
} else {
common.Error("中间件:" + info.MiddleName + "创建失败")
return errors.New("中间件:" + info.MiddleName + "创建失败")
}
}
//根据info信息设置值
func (u *MiddlewareDataService) setStatefulSet(info *middleware.MiddlewareInfo) *v1.StatefulSet {
statefulSet := &v1.StatefulSet{}
statefulSet.TypeMeta = v12.TypeMeta{
Kind: "StatefulSet",
APIVersion: "v1",
}
//设置详情
statefulSet.ObjectMeta = v12.ObjectMeta{
Name: info.MiddleName,
Namespace: info.MiddleNamespace,
//设置label标签
Labels: map[string]string{
"app-name": info.MiddleName,
"author": "wu123",
},
}
statefulSet.Name = info.MiddleName
statefulSet.Spec = v1.StatefulSetSpec{
//副本数
Replicas: &info.MiddleReplicas,
Selector: &v12.LabelSelector{
MatchLabels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器模版
Template: v13.PodTemplateSpec{
ObjectMeta: v12.ObjectMeta{
Labels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器详情
Spec: v13.PodSpec{
Containers: []v13.Container{
{
Name: info.MiddleName,
Image: info.MiddleDockerImageVersion,
//获取容器的端口
Ports: u.getContainerPort(info),
//获取环境变量
Env: u.getEnv(info),
//获取容器CPU,内存
Resources: u.getResources(info),
//设置挂载目录
VolumeMounts: u.setMounts(info),
},
},
//不能设置为0,这样不安全
//https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod/
TerminationGracePeriodSeconds: u.getTime("10"),
//私有仓库设置密钥
ImagePullSecrets: nil,
},
},
VolumeClaimTemplates: u.getPVC(info),
ServiceName: info.MiddleName,
}
return statefulSet
}
func (u *MiddlewareDataService) getTime(stringTime string) *int64 {
b, err := strconv.ParseInt(stringTime, 10, 64)
if err != nil {
common.Error(err)
return nil
}
return &b
}
//设置存储路径
func (u *MiddlewareDataService) setMounts(info *middleware.MiddlewareInfo) (mount []v13.VolumeMount) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
mt := &v13.VolumeMount{
Name: v.MiddleStorageName,
MountPath: v.MiddleStoragePath,
}
mount = append(mount, *mt)
}
return
}
//获取pvc
func (u *MiddlewareDataService) getPVC(info *middleware.MiddlewareInfo) (pvcAll []v13.PersistentVolumeClaim) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
pvc := &v13.PersistentVolumeClaim{
TypeMeta: v12.TypeMeta{
Kind: "PersistentVolumeClaim",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: v.MiddleStorageName,
Namespace: info.MiddleNamespace,
Annotations: map[string]string{
"pv.kubernetes.io/bound-by-controller": "yes",
"volume.beta.kubernetes.io/storage-provisioner": "rbd.csi.ceph.com",
},
},
Spec: v13.PersistentVolumeClaimSpec{
AccessModes: u.getAccessModes(v.MiddleStorageAccessMode),
Resources: u.getPvcResource(v.MiddleStorageSize),
VolumeName: v.MiddleStorageName,
StorageClassName: &v.MiddleStorageClass,
},
}
pvcAll = append(pvcAll, *pvc)
}
return
}
//获取大小
func (u *MiddlewareDataService) getPvcResource(size float32) (source v13.ResourceRequirements) {
source.Requests = v13.ResourceList{
"storage": resource.MustParse(strconv.FormatFloat(float64(size), 'f', 6, 64) + "Gi"),
}
return
}
//获取权限的
func (u *MiddlewareDataService) getAccessModes(accessMode string) (pvam []v13.PersistentVolumeAccessMode) {
var pm v13.PersistentVolumeAccessMode
switch accessMode {
case "ReadWriteOnce":
pm = v13.ReadWriteOnce
case "ReadOnlyMany":
pm = v13.ReadOnlyMany
case "ReadWriteMany":
pm = v13.ReadWriteMany
case "ReadWriteOncePod":
pm = v13.ReadWriteOncePod
default:
pm = v13.ReadWriteOnce
}
pvam = append(pvam, pm)
return pvam
}
//获取容器的端口
func (u *MiddlewareDataService) getContainerPort(info *middleware.MiddlewareInfo) (containerPort []v13.ContainerPort) {
for _, v := range info.MiddlePort {
containerPort = append(containerPort, v13.ContainerPort{
Name: "middle-port-" + strconv.FormatInt(int64(v.MiddlePort), 10),
ContainerPort: v.MiddlePort,
Protocol: u.getProtocol(v.MiddleProtocol),
})
}
return
}
//获取protocol 协议
func (u *MiddlewareDataService) getProtocol(protocol string) v13.Protocol {
switch protocol {
case "TCP":
return "TCP"
case "UDP":
return "UDP"
case "SCTP":
return "SCTP"
default:
return "TCP"
}
}
10-11 中间件 service 开发(2)
C:\Users\Administrator\Desktop\gopaas\middleware\domain\service\middleware_data_service.go
package service
import (
"context"
"errors"
"strconv"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/repository"
"github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
v1 "k8s.io/api/apps/v1"
v13 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//这里是接口类型
type IMiddlewareDataService interface {
AddMiddleware(*model.Middleware) (int64, error)
DeleteMiddleware(int64) error
UpdateMiddleware(*model.Middleware) error
FindMiddlewareByID(int64) (*model.Middleware, error)
FindAllMiddleware() ([]model.Middleware, error)
//根据类型查找中间件
FindAllMiddlewareByTypeID(int64) ([]model.Middleware, error)
//操作中间件s
CreateToK8s(*middleware.MiddlewareInfo) error
DeleteFromK8s(*model.Middleware) error
UpdateToK8s(*middleware.MiddlewareInfo) error
}
//创建
//注意:返回值 IMiddlewareDataService 接口类型
func NewMiddlewareDataService(middlewareRepository repository.IMiddlewareRepository, clientSet *kubernetes.Clientset) IMiddlewareDataService {
return &MiddlewareDataService{MiddlewareRepository: middlewareRepository, K8sClientSet: clientSet}
}
type MiddlewareDataService struct {
//注意:这里是 IMiddlewareRepository 类型
MiddlewareRepository repository.IMiddlewareRepository
K8sClientSet *kubernetes.Clientset
}
//更新中间件到k8s
func (u *MiddlewareDataService) UpdateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
common.Error(err)
return errors.New("中间件 " + info.MiddleName + " 不存在请先创建")
} else {
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Update(context.TODO(), statefulSet, v12.UpdateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件 " + info.MiddleName + " 更新成功!")
return nil
}
}
//删除中间件
func (u *MiddlewareDataService) DeleteFromK8s(middleware *model.Middleware) (err error) {
if err := u.K8sClientSet.AppsV1().StatefulSets(middleware.MiddleNamespace).Delete(context.TODO(), middleware.MiddleName, v12.DeleteOptions{}); err != nil {
common.Error(err)
return err
} else {
if err := u.DeleteMiddleware(middleware.ID); err != nil {
common.Error(err)
return err
}
common.Info("删除中间件:" + middleware.MiddleName + "成功!")
return nil
}
}
//在k8s中创建中间件
func (u *MiddlewareDataService) CreateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
//如果没有获取到
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Create(context.TODO(), statefulSet, v12.CreateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件:" + info.MiddleName + "创建成功")
return nil
} else {
common.Error("中间件:" + info.MiddleName + "创建失败")
return errors.New("中间件:" + info.MiddleName + "创建失败")
}
}
//根据info信息设置值
func (u *MiddlewareDataService) setStatefulSet(info *middleware.MiddlewareInfo) *v1.StatefulSet {
statefulSet := &v1.StatefulSet{}
statefulSet.TypeMeta = v12.TypeMeta{
Kind: "StatefulSet",
APIVersion: "v1",
}
//设置详情
statefulSet.ObjectMeta = v12.ObjectMeta{
Name: info.MiddleName,
Namespace: info.MiddleNamespace,
//设置label标签
Labels: map[string]string{
"app-name": info.MiddleName,
"author": "wu123",
},
}
statefulSet.Name = info.MiddleName
statefulSet.Spec = v1.StatefulSetSpec{
//副本数
Replicas: &info.MiddleReplicas,
Selector: &v12.LabelSelector{
MatchLabels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器模版
Template: v13.PodTemplateSpec{
ObjectMeta: v12.ObjectMeta{
Labels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器详情
Spec: v13.PodSpec{
Containers: []v13.Container{
{
Name: info.MiddleName,
Image: info.MiddleDockerImageVersion,
//获取容器的端口
Ports: u.getContainerPort(info),
//获取环境变量
Env: u.getEnv(info),
//获取容器CPU,内存
Resources: u.getResources(info),
//设置挂载目录
VolumeMounts: u.setMounts(info),
},
},
//不能设置为0,这样不安全
//https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod/
TerminationGracePeriodSeconds: u.getTime("10"),
//私有仓库设置密钥
ImagePullSecrets: nil,
},
},
VolumeClaimTemplates: u.getPVC(info),
ServiceName: info.MiddleName,
}
return statefulSet
}
func (u *MiddlewareDataService) getTime(stringTime string) *int64 {
b, err := strconv.ParseInt(stringTime, 10, 64)
if err != nil {
common.Error(err)
return nil
}
return &b
}
//设置存储路径
func (u *MiddlewareDataService) setMounts(info *middleware.MiddlewareInfo) (mount []v13.VolumeMount) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
mt := &v13.VolumeMount{
Name: v.MiddleStorageName,
MountPath: v.MiddleStoragePath,
}
mount = append(mount, *mt)
}
return
}
//获取pvc
func (u *MiddlewareDataService) getPVC(info *middleware.MiddlewareInfo) (pvcAll []v13.PersistentVolumeClaim) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
pvc := &v13.PersistentVolumeClaim{
TypeMeta: v12.TypeMeta{
Kind: "PersistentVolumeClaim",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: v.MiddleStorageName,
Namespace: info.MiddleNamespace,
Annotations: map[string]string{
"pv.kubernetes.io/bound-by-controller": "yes",
"volume.beta.kubernetes.io/storage-provisioner": "rbd.csi.ceph.com",
},
},
Spec: v13.PersistentVolumeClaimSpec{
AccessModes: u.getAccessModes(v.MiddleStorageAccessMode),
Resources: u.getPvcResource(v.MiddleStorageSize),
VolumeName: v.MiddleStorageName,
StorageClassName: &v.MiddleStorageClass,
},
}
pvcAll = append(pvcAll, *pvc)
}
return
}
//获取大小
func (u *MiddlewareDataService) getPvcResource(size float32) (source v13.ResourceRequirements) {
source.Requests = v13.ResourceList{
"storage": resource.MustParse(strconv.FormatFloat(float64(size), 'f', 6, 64) + "Gi"),
}
return
}
//获取权限的
func (u *MiddlewareDataService) getAccessModes(accessMode string) (pvam []v13.PersistentVolumeAccessMode) {
var pm v13.PersistentVolumeAccessMode
switch accessMode {
case "ReadWriteOnce":
pm = v13.ReadWriteOnce
case "ReadOnlyMany":
pm = v13.ReadOnlyMany
case "ReadWriteMany":
pm = v13.ReadWriteMany
case "ReadWriteOncePod":
pm = v13.ReadWriteOncePod
default:
pm = v13.ReadWriteOnce
}
pvam = append(pvam, pm)
return pvam
}
//获取容器的端口
func (u *MiddlewareDataService) getContainerPort(info *middleware.MiddlewareInfo) (containerPort []v13.ContainerPort) {
for _, v := range info.MiddlePort {
containerPort = append(containerPort, v13.ContainerPort{
Name: "middle-port-" + strconv.FormatInt(int64(v.MiddlePort), 10),
ContainerPort: v.MiddlePort,
Protocol: u.getProtocol(v.MiddleProtocol),
})
}
return
}
//获取protocol 协议
func (u *MiddlewareDataService) getProtocol(protocol string) v13.Protocol {
switch protocol {
case "TCP":
return "TCP"
case "UDP":
return "UDP"
case "SCTP":
return "SCTP"
default:
return "TCP"
}
}
//获取中间件的环境变量
func (u *MiddlewareDataService) getEnv(info *middleware.MiddlewareInfo) (envVar []v13.EnvVar) {
for _, v := range info.MiddleEnv {
envVar = append(envVar, v13.EnvVar{
Name: v.EnvKey,
Value: v.EnvValue,
ValueFrom: nil,
})
}
return
}
//获取中间件需要的资源
func (u *MiddlewareDataService) getResources(info *middleware.MiddlewareInfo) (source v13.ResourceRequirements) {
//最大能够使用的资源
source.Limits = v13.ResourceList{
"cpu": resource.MustParse(strconv.FormatFloat(float64(info.MiddleCpu), 'f', 6, 64)),
"memory": resource.MustParse(strconv.FormatFloat(float64(info.MiddleMemory), 'f', 6, 64)),
}
//最小请求资源
source.Requests = v13.ResourceList{
"cpu": resource.MustParse(strconv.FormatFloat(float64(info.MiddleCpu), 'f', 6, 64)),
"memory": resource.MustParse(strconv.FormatFloat(float64(info.MiddleMemory), 'f', 6, 64)),
}
return
}
//插入
func (u *MiddlewareDataService) AddMiddleware(middleware *model.Middleware) (int64, error) {
return u.MiddlewareRepository.CreateMiddleware(middleware)
}
//删除
func (u *MiddlewareDataService) DeleteMiddleware(middlewareID int64) error {
return u.MiddlewareRepository.DeleteMiddlewareByID(middlewareID)
}
//更新
func (u *MiddlewareDataService) UpdateMiddleware(middleware *model.Middleware) error {
return u.MiddlewareRepository.UpdateMiddleware(middleware)
}
//查找
func (u *MiddlewareDataService) FindMiddlewareByID(middlewareID int64) (*model.Middleware, error) {
return u.MiddlewareRepository.FindMiddlewareByID(middlewareID)
}
//查找
func (u *MiddlewareDataService) FindAllMiddleware() ([]model.Middleware, error) {
return u.MiddlewareRepository.FindAll()
}
//根据类型查找所有的中间件
func (u *MiddlewareDataService) FindAllMiddlewareByTypeID(typeID int64) ([]model.Middleware, error) {
return u.MiddlewareRepository.FindAllByTypeID(typeID)
}
10-12 中间件middleware service开发(3)
C:\Users\Administrator\Desktop\gopaas\middleware\domain\service\middleware_data_service.go
package service
import (
"context"
"errors"
"strconv"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/repository"
"github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
v1 "k8s.io/api/apps/v1"
v13 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//这里是接口类型
type IMiddlewareDataService interface {
AddMiddleware(*model.Middleware) (int64, error)
DeleteMiddleware(int64) error
UpdateMiddleware(*model.Middleware) error
FindMiddlewareByID(int64) (*model.Middleware, error)
FindAllMiddleware() ([]model.Middleware, error)
//根据类型查找中间件
FindAllMiddlewareByTypeID(int64) ([]model.Middleware, error)
//操作中间件s
CreateToK8s(*middleware.MiddlewareInfo) error
DeleteFromK8s(*model.Middleware) error
UpdateToK8s(*middleware.MiddlewareInfo) error
}
//创建
//注意:返回值 IMiddlewareDataService 接口类型
func NewMiddlewareDataService(middlewareRepository repository.IMiddlewareRepository, clientSet *kubernetes.Clientset) IMiddlewareDataService {
return &MiddlewareDataService{MiddlewareRepository: middlewareRepository, K8sClientSet: clientSet}
}
type MiddlewareDataService struct {
//注意:这里是 IMiddlewareRepository 类型
MiddlewareRepository repository.IMiddlewareRepository
K8sClientSet *kubernetes.Clientset
}
//更新中间件到k8s
func (u *MiddlewareDataService) UpdateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
common.Error(err)
return errors.New("中间件 " + info.MiddleName + " 不存在请先创建")
} else {
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Update(context.TODO(), statefulSet, v12.UpdateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件 " + info.MiddleName + " 更新成功!")
return nil
}
}
//删除中间件
func (u *MiddlewareDataService) DeleteFromK8s(middleware *model.Middleware) (err error) {
if err := u.K8sClientSet.AppsV1().StatefulSets(middleware.MiddleNamespace).Delete(context.TODO(), middleware.MiddleName, v12.DeleteOptions{}); err != nil {
common.Error(err)
return err
} else {
if err := u.DeleteMiddleware(middleware.ID); err != nil {
common.Error(err)
return err
}
common.Info("删除中间件:" + middleware.MiddleName + "成功!")
return nil
}
}
//在k8s中创建中间件
func (u *MiddlewareDataService) CreateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
//如果没有获取到
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Create(context.TODO(), statefulSet, v12.CreateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件:" + info.MiddleName + "创建成功")
return nil
} else {
common.Error("中间件:" + info.MiddleName + "创建失败")
return errors.New("中间件:" + info.MiddleName + "创建失败")
}
}
//根据info信息设置值
func (u *MiddlewareDataService) setStatefulSet(info *middleware.MiddlewareInfo) *v1.StatefulSet {
statefulSet := &v1.StatefulSet{}
statefulSet.TypeMeta = v12.TypeMeta{
Kind: "StatefulSet",
APIVersion: "v1",
}
//设置详情
statefulSet.ObjectMeta = v12.ObjectMeta{
Name: info.MiddleName,
Namespace: info.MiddleNamespace,
//设置label标签
Labels: map[string]string{
"app-name": info.MiddleName,
"author": "wu123",
},
}
statefulSet.Name = info.MiddleName
statefulSet.Spec = v1.StatefulSetSpec{
//副本数
Replicas: &info.MiddleReplicas,
Selector: &v12.LabelSelector{
MatchLabels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器模版
Template: v13.PodTemplateSpec{
ObjectMeta: v12.ObjectMeta{
Labels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器详情
Spec: v13.PodSpec{
Containers: []v13.Container{
{
Name: info.MiddleName,
Image: info.MiddleDockerImageVersion,
//获取容器的端口
Ports: u.getContainerPort(info),
//获取环境变量
Env: u.getEnv(info),
//获取容器CPU,内存
Resources: u.getResources(info),
//设置挂载目录
VolumeMounts: u.setMounts(info),
},
},
//不能设置为0,这样不安全
//https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod/
TerminationGracePeriodSeconds: u.getTime("10"),
//私有仓库设置密钥
ImagePullSecrets: nil,
},
},
VolumeClaimTemplates: u.getPVC(info),
ServiceName: info.MiddleName,
}
return statefulSet
}
func (u *MiddlewareDataService) getTime(stringTime string) *int64 {
b, err := strconv.ParseInt(stringTime, 10, 64)
if err != nil {
common.Error(err)
return nil
}
return &b
}
//设置存储路径
func (u *MiddlewareDataService) setMounts(info *middleware.MiddlewareInfo) (mount []v13.VolumeMount) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
mt := &v13.VolumeMount{
Name: v.MiddleStorageName,
MountPath: v.MiddleStoragePath,
}
mount = append(mount, *mt)
}
return
}
//获取pvc
func (u *MiddlewareDataService) getPVC(info *middleware.MiddlewareInfo) (pvcAll []v13.PersistentVolumeClaim) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
pvc := &v13.PersistentVolumeClaim{
TypeMeta: v12.TypeMeta{
Kind: "PersistentVolumeClaim",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: v.MiddleStorageName,
Namespace: info.MiddleNamespace,
Annotations: map[string]string{
"pv.kubernetes.io/bound-by-controller": "yes",
"volume.beta.kubernetes.io/storage-provisioner": "rbd.csi.ceph.com",
},
},
Spec: v13.PersistentVolumeClaimSpec{
AccessModes: u.getAccessModes(v.MiddleStorageAccessMode),
Resources: u.getPvcResource(v.MiddleStorageSize),
VolumeName: v.MiddleStorageName,
StorageClassName: &v.MiddleStorageClass,
},
}
pvcAll = append(pvcAll, *pvc)
}
return
}
//获取大小
func (u *MiddlewareDataService) getPvcResource(size float32) (source v13.ResourceRequirements) {
source.Requests = v13.ResourceList{
"storage": resource.MustParse(strconv.FormatFloat(float64(size), 'f', 6, 64) + "Gi"),
}
return
}
//获取权限的
func (u *MiddlewareDataService) getAccessModes(accessMode string) (pvam []v13.PersistentVolumeAccessMode) {
var pm v13.PersistentVolumeAccessMode
switch accessMode {
case "ReadWriteOnce":
pm = v13.ReadWriteOnce
case "ReadOnlyMany":
pm = v13.ReadOnlyMany
case "ReadWriteMany":
pm = v13.ReadWriteMany
case "ReadWriteOncePod":
pm = v13.ReadWriteOncePod
default:
pm = v13.ReadWriteOnce
}
pvam = append(pvam, pm)
return pvam
}
//获取容器的端口
func (u *MiddlewareDataService) getContainerPort(info *middleware.MiddlewareInfo) (containerPort []v13.ContainerPort) {
for _, v := range info.MiddlePort {
containerPort = append(containerPort, v13.ContainerPort{
Name: "middle-port-" + strconv.FormatInt(int64(v.MiddlePort), 10),
ContainerPort: v.MiddlePort,
Protocol: u.getProtocol(v.MiddleProtocol),
})
}
return
}
//获取protocol 协议
func (u *MiddlewareDataService) getProtocol(protocol string) v13.Protocol {
switch protocol {
case "TCP":
return "TCP"
case "UDP":
return "UDP"
case "SCTP":
return "SCTP"
default:
return "TCP"
}
}
//获取中间件的环境变量
func (u *MiddlewareDataService) getEnv(info *middleware.MiddlewareInfo) (envVar []v13.EnvVar) {
for _, v := range info.MiddleEnv {
envVar = append(envVar, v13.EnvVar{
Name: v.EnvKey,
Value: v.EnvValue,
ValueFrom: nil,
})
}
return
}
//获取中间件需要的资源
func (u *MiddlewareDataService) getResources(info *middleware.MiddlewareInfo) (source v13.ResourceRequirements) {
//最大能够使用的资源
source.Limits = v13.ResourceList{
"cpu": resource.MustParse(strconv.FormatFloat(float64(info.MiddleCpu), 'f', 6, 64)),
"memory": resource.MustParse(strconv.FormatFloat(float64(info.MiddleMemory), 'f', 6, 64)),
}
//最小请求资源
source.Requests = v13.ResourceList{
"cpu": resource.MustParse(strconv.FormatFloat(float64(info.MiddleCpu), 'f', 6, 64)),
"memory": resource.MustParse(strconv.FormatFloat(float64(info.MiddleMemory), 'f', 6, 64)),
}
return
}
//插入
func (u *MiddlewareDataService) AddMiddleware(middleware *model.Middleware) (int64, error) {
return u.MiddlewareRepository.CreateMiddleware(middleware)
}
//删除
func (u *MiddlewareDataService) DeleteMiddleware(middlewareID int64) error {
return u.MiddlewareRepository.DeleteMiddlewareByID(middlewareID)
}
//更新
func (u *MiddlewareDataService) UpdateMiddleware(middleware *model.Middleware) error {
return u.MiddlewareRepository.UpdateMiddleware(middleware)
}
//查找
func (u *MiddlewareDataService) FindMiddlewareByID(middlewareID int64) (*model.Middleware, error) {
return u.MiddlewareRepository.FindMiddlewareByID(middlewareID)
}
//查找
func (u *MiddlewareDataService) FindAllMiddleware() ([]model.Middleware, error) {
return u.MiddlewareRepository.FindAll()
}
//根据类型查找所有的中间件
func (u *MiddlewareDataService) FindAllMiddlewareByTypeID(typeID int64) ([]model.Middleware, error) {
return u.MiddlewareRepository.FindAllByTypeID(typeID)
}
10-13 中间件middleware service开发(4)
C:\Users\Administrator\Desktop\gopaas\middleware\domain\service\middleware_data_service.go
package service
import (
"context"
"errors"
"strconv"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/repository"
"github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
v1 "k8s.io/api/apps/v1"
v13 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
//这里是接口类型
type IMiddlewareDataService interface {
AddMiddleware(*model.Middleware) (int64, error)
DeleteMiddleware(int64) error
UpdateMiddleware(*model.Middleware) error
FindMiddlewareByID(int64) (*model.Middleware, error)
FindAllMiddleware() ([]model.Middleware, error)
//根据类型查找中间件
FindAllMiddlewareByTypeID(int64) ([]model.Middleware, error)
//操作中间件s
CreateToK8s(*middleware.MiddlewareInfo) error
DeleteFromK8s(*model.Middleware) error
UpdateToK8s(*middleware.MiddlewareInfo) error
}
//创建
//注意:返回值 IMiddlewareDataService 接口类型
func NewMiddlewareDataService(middlewareRepository repository.IMiddlewareRepository, clientSet *kubernetes.Clientset) IMiddlewareDataService {
return &MiddlewareDataService{MiddlewareRepository: middlewareRepository, K8sClientSet: clientSet}
}
type MiddlewareDataService struct {
//注意:这里是 IMiddlewareRepository 类型
MiddlewareRepository repository.IMiddlewareRepository
K8sClientSet *kubernetes.Clientset
}
//更新中间件到k8s
func (u *MiddlewareDataService) UpdateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
common.Error(err)
return errors.New("中间件 " + info.MiddleName + " 不存在请先创建")
} else {
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Update(context.TODO(), statefulSet, v12.UpdateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件 " + info.MiddleName + " 更新成功!")
return nil
}
}
//删除中间件
func (u *MiddlewareDataService) DeleteFromK8s(middleware *model.Middleware) (err error) {
if err := u.K8sClientSet.AppsV1().StatefulSets(middleware.MiddleNamespace).Delete(context.TODO(), middleware.MiddleName, v12.DeleteOptions{}); err != nil {
common.Error(err)
return err
} else {
if err := u.DeleteMiddleware(middleware.ID); err != nil {
common.Error(err)
return err
}
common.Info("删除中间件:" + middleware.MiddleName + "成功!")
return nil
}
}
//在k8s中创建中间件
func (u *MiddlewareDataService) CreateToK8s(info *middleware.MiddlewareInfo) error {
statefulSet := u.setStatefulSet(info)
if _, err := u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Get(context.TODO(), info.MiddleName, v12.GetOptions{}); err != nil {
//如果没有获取到
if _, err = u.K8sClientSet.AppsV1().StatefulSets(info.MiddleNamespace).Create(context.TODO(), statefulSet, v12.CreateOptions{}); err != nil {
common.Error(err)
return err
}
common.Info("中间件:" + info.MiddleName + "创建成功")
return nil
} else {
common.Error("中间件:" + info.MiddleName + "创建失败")
return errors.New("中间件:" + info.MiddleName + "创建失败")
}
}
//根据info信息设置值
func (u *MiddlewareDataService) setStatefulSet(info *middleware.MiddlewareInfo) *v1.StatefulSet {
statefulSet := &v1.StatefulSet{}
statefulSet.TypeMeta = v12.TypeMeta{
Kind: "StatefulSet",
APIVersion: "v1",
}
//设置详情
statefulSet.ObjectMeta = v12.ObjectMeta{
Name: info.MiddleName,
Namespace: info.MiddleNamespace,
//设置label标签
Labels: map[string]string{
"app-name": info.MiddleName,
"author": "wu123",
},
}
statefulSet.Name = info.MiddleName
statefulSet.Spec = v1.StatefulSetSpec{
//副本数
Replicas: &info.MiddleReplicas,
Selector: &v12.LabelSelector{
MatchLabels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器模版
Template: v13.PodTemplateSpec{
ObjectMeta: v12.ObjectMeta{
Labels: map[string]string{
"app-name": info.MiddleName,
},
},
//设置容器详情
Spec: v13.PodSpec{
Containers: []v13.Container{
{
Name: info.MiddleName,
Image: info.MiddleDockerImageVersion,
//获取容器的端口
Ports: u.getContainerPort(info),
//获取环境变量
Env: u.getEnv(info),
//获取容器CPU,内存
Resources: u.getResources(info),
//设置挂载目录
VolumeMounts: u.setMounts(info),
},
},
//不能设置为0,这样不安全
//https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod/
TerminationGracePeriodSeconds: u.getTime("10"),
//私有仓库设置密钥
ImagePullSecrets: nil,
},
},
VolumeClaimTemplates: u.getPVC(info),
ServiceName: info.MiddleName,
}
return statefulSet
}
func (u *MiddlewareDataService) getTime(stringTime string) *int64 {
b, err := strconv.ParseInt(stringTime, 10, 64)
if err != nil {
common.Error(err)
return nil
}
return &b
}
//设置存储路径
func (u *MiddlewareDataService) setMounts(info *middleware.MiddlewareInfo) (mount []v13.VolumeMount) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
mt := &v13.VolumeMount{
Name: v.MiddleStorageName,
MountPath: v.MiddleStoragePath,
}
mount = append(mount, *mt)
}
return
}
//获取pvc
func (u *MiddlewareDataService) getPVC(info *middleware.MiddlewareInfo) (pvcAll []v13.PersistentVolumeClaim) {
if len(info.MiddleStorage) == 0 {
return
}
for _, v := range info.MiddleStorage {
pvc := &v13.PersistentVolumeClaim{
TypeMeta: v12.TypeMeta{
Kind: "PersistentVolumeClaim",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
Name: v.MiddleStorageName,
Namespace: info.MiddleNamespace,
Annotations: map[string]string{
"pv.kubernetes.io/bound-by-controller": "yes",
"volume.beta.kubernetes.io/storage-provisioner": "rbd.csi.ceph.com",
},
},
Spec: v13.PersistentVolumeClaimSpec{
AccessModes: u.getAccessModes(v.MiddleStorageAccessMode),
Resources: u.getPvcResource(v.MiddleStorageSize),
VolumeName: v.MiddleStorageName,
StorageClassName: &v.MiddleStorageClass,
},
}
pvcAll = append(pvcAll, *pvc)
}
return
}
//获取大小
func (u *MiddlewareDataService) getPvcResource(size float32) (source v13.ResourceRequirements) {
source.Requests = v13.ResourceList{
"storage": resource.MustParse(strconv.FormatFloat(float64(size), 'f', 6, 64) + "Gi"),
}
return
}
//获取权限的
func (u *MiddlewareDataService) getAccessModes(accessMode string) (pvam []v13.PersistentVolumeAccessMode) {
var pm v13.PersistentVolumeAccessMode
switch accessMode {
case "ReadWriteOnce":
pm = v13.ReadWriteOnce
case "ReadOnlyMany":
pm = v13.ReadOnlyMany
case "ReadWriteMany":
pm = v13.ReadWriteMany
case "ReadWriteOncePod":
pm = v13.ReadWriteOncePod
default:
pm = v13.ReadWriteOnce
}
pvam = append(pvam, pm)
return pvam
}
//获取容器的端口
func (u *MiddlewareDataService) getContainerPort(info *middleware.MiddlewareInfo) (containerPort []v13.ContainerPort) {
for _, v := range info.MiddlePort {
containerPort = append(containerPort, v13.ContainerPort{
Name: "middle-port-" + strconv.FormatInt(int64(v.MiddlePort), 10),
ContainerPort: v.MiddlePort,
Protocol: u.getProtocol(v.MiddleProtocol),
})
}
return
}
//获取protocol 协议
func (u *MiddlewareDataService) getProtocol(protocol string) v13.Protocol {
switch protocol {
case "TCP":
return "TCP"
case "UDP":
return "UDP"
case "SCTP":
return "SCTP"
default:
return "TCP"
}
}
//获取中间件的环境变量
func (u *MiddlewareDataService) getEnv(info *middleware.MiddlewareInfo) (envVar []v13.EnvVar) {
for _, v := range info.MiddleEnv {
envVar = append(envVar, v13.EnvVar{
Name: v.EnvKey,
Value: v.EnvValue,
ValueFrom: nil,
})
}
return
}
//获取中间件需要的资源
func (u *MiddlewareDataService) getResources(info *middleware.MiddlewareInfo) (source v13.ResourceRequirements) {
//最大能够使用的资源
source.Limits = v13.ResourceList{
"cpu": resource.MustParse(strconv.FormatFloat(float64(info.MiddleCpu), 'f', 6, 64)),
"memory": resource.MustParse(strconv.FormatFloat(float64(info.MiddleMemory), 'f', 6, 64)),
}
//最小请求资源
source.Requests = v13.ResourceList{
"cpu": resource.MustParse(strconv.FormatFloat(float64(info.MiddleCpu), 'f', 6, 64)),
"memory": resource.MustParse(strconv.FormatFloat(float64(info.MiddleMemory), 'f', 6, 64)),
}
return
}
//插入
func (u *MiddlewareDataService) AddMiddleware(middleware *model.Middleware) (int64, error) {
return u.MiddlewareRepository.CreateMiddleware(middleware)
}
//删除
func (u *MiddlewareDataService) DeleteMiddleware(middlewareID int64) error {
return u.MiddlewareRepository.DeleteMiddlewareByID(middlewareID)
}
//更新
func (u *MiddlewareDataService) UpdateMiddleware(middleware *model.Middleware) error {
return u.MiddlewareRepository.UpdateMiddleware(middleware)
}
//查找
func (u *MiddlewareDataService) FindMiddlewareByID(middlewareID int64) (*model.Middleware, error) {
return u.MiddlewareRepository.FindMiddlewareByID(middlewareID)
}
//查找
func (u *MiddlewareDataService) FindAllMiddleware() ([]model.Middleware, error) {
return u.MiddlewareRepository.FindAll()
}
//根据类型查找所有的中间件
func (u *MiddlewareDataService) FindAllMiddlewareByTypeID(typeID int64) ([]model.Middleware, error) {
return u.MiddlewareRepository.FindAllByTypeID(typeID)
}
10-14 中间件service 对应版本服务代码开发
C:\Users\Administrator\Desktop\gopaas\middleware\domain\service\middle_type_data_service.go
package service
import (
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/repository"
)
//定义接口类型
type IMiddleTypeDataService interface {
AddMiddleType(*model.MiddleType) (int64, error)
DeleteMiddleType(int64) error
UpdateMiddleType(*model.MiddleType) error
FindMiddleTypeByID(int64) (*model.MiddleType, error)
FindAllMiddleType() ([]model.MiddleType, error)
//根据ID返回地址
FindImageVersionByID(int64) (string, error)
FindVersionByID(int64) (*model.MiddleVersion, error)
FindAllVersionByTypeID(int64) ([]model.MiddleVersion, error)
}
//注意:返回值的类型
func NewMiddleTypeDataService(repository repository.IMiddleTypeRepository) IMiddleTypeDataService {
return &MiddleTypeDataService{MiddleTypeRepository: repository}
}
type MiddleTypeDataService struct {
MiddleTypeRepository repository.IMiddleTypeRepository
}
//插入
func (u *MiddleTypeDataService) AddMiddleType(middleType *model.MiddleType) (int64, error) {
return u.MiddleTypeRepository.CreateMiddleType(middleType)
}
//删除
func (u *MiddleTypeDataService) DeleteMiddleType(middleTypeID int64) error {
return u.MiddleTypeRepository.DeleteMiddleTypeByID(middleTypeID)
}
//更新
func (u *MiddleTypeDataService) UpdateMiddleType(middleType *model.MiddleType) error {
return u.MiddleTypeRepository.UpdateMiddleType(middleType)
}
//查找
func (u *MiddleTypeDataService) FindMiddleTypeByID(middleTypeID int64) (*model.MiddleType, error) {
return u.MiddleTypeRepository.FindTypeByID(middleTypeID)
}
//查找所有
func (u *MiddleTypeDataService) FindAllMiddleType() ([]model.MiddleType, error) {
return u.MiddleTypeRepository.FindAll()
}
//根据version ID查找镜像地址
func (u *MiddleTypeDataService) FindImageVersionByID(middleVersionID int64) (string, error) {
version, err := u.MiddleTypeRepository.FindVersionByID(middleVersionID)
if err != nil {
return "", err
}
//返回需要的镜像地址
return version.MiddleDockerImage + ":" + version.MiddleVS, nil
}
//根据versionID 查找单个镜像
func (u *MiddleTypeDataService) FindVersionByID(middleVersionID int64) (*model.MiddleVersion, error) {
return u.MiddleTypeRepository.FindVersionByID(middleVersionID)
}
//根据中间件类型查找对应的所有版本
func (u *MiddleTypeDataService) FindAllVersionByTypeID(middleTypeID int64) ([]model.MiddleVersion, error) {
return u.MiddleTypeRepository.FindAllVersionByTypeID(middleTypeID)
}
10-15 中间件main调整 及 handler 开发(上)
C:\Users\Administrator\Desktop\gopaas\middleware\main.go
//只能执行一遍
//err = repository.NewMiddlewareRepository(db).InitTable()
//if err != nil {
// common.Fatal(err)
//}
//if err:= repository.NewMiddleTypeRepository(db).InitTable();err!=nil{
// common.Fatal(err)
//}
// 注册句柄,可以快速操作已开发的服务
middlewareDataService := service2.NewMiddlewareDataService(repository.NewMiddlewareRepository(db), clientset)
middleTypeDataService := service2.NewMiddleTypeDataService(repository.NewMiddleTypeRepository(db))
middleware.RegisterMiddlewareHandler(service.Server(), &handler.MiddlewareHandler{MiddlewareDataService: middlewareDataService, MiddleTypeDataService: middleTypeDataService})
C:\Users\Administrator\Desktop\gopaas\middleware\handler\middlewareHandler.go
package handler
import (
"context"
"strconv"
log "github.com/asim/go-micro/v3/logger"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/service"
middleware "github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
)
type MiddlewareHandler struct {
//注意这里的类型是 IMiddlewareDataService 接口类型
MiddlewareDataService service.IMiddlewareDataService
// 添加中间件类型服务
MiddleTypeDataService service.IMiddleTypeDataService
}
// Call is a single request handler called via client.Call or the generated client code
func (e *MiddlewareHandler) AddMiddleware(ctx context.Context, info *middleware.MiddlewareInfo, rsp *middleware.Response) error {
log.Info("Received *middleware.AddMiddleware request")
middleModel := &model.Middleware{}
if err := common.SwapTo(info, middleModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//调用其它的服务处理数据
//根据ID产销需要的镜像地址
imageAddress, err := e.MiddleTypeDataService.FindImageVersionByID(info.MiddleVersionId)
if err != nil {
common.Error(err)
return err
}
//赋值
info.MiddleDockerImageVersion = imageAddress
//在k8s 中创建资源
if err := e.MiddlewareDataService.CreateToK8s(info); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
} else {
//插入数据库
middleID, err := e.MiddlewareDataService.AddMiddleware(middleModel)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
rsp.Msg = "中间件添加成功 ID 号为:" + strconv.FormatInt(middleID, 10)
common.Info(rsp.Msg)
}
return nil
}
func (e *MiddlewareHandler) DeleteMiddleware(ctx context.Context, req *middleware.MiddlewareId, rsp *middleware.Response) error {
log.Info("Received *middleware.DeleteMiddleware request")
middleModel, err := e.MiddlewareDataService.FindMiddlewareByID(req.Id)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//删除k8s中资源
if err := e.MiddlewareDataService.DeleteFromK8s(middleModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
return nil
}
func (e *MiddlewareHandler) UpdateMiddleware(ctx context.Context, req *middleware.MiddlewareInfo, rsp *middleware.Response) error {
log.Info("Received *middleware.UpdateMiddleware request")
if err := e.MiddlewareDataService.UpdateToK8s(req); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//查询中间件相关的信息
middleModle, err := e.MiddlewareDataService.FindMiddlewareByID(req.Id)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//更新model数据
if err := common.SwapTo(req, middleModle); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//更新model
if err := e.MiddlewareDataService.UpdateMiddleware(middleModle); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
return nil
}
func (e *MiddlewareHandler) FindMiddlewareByID(ctx context.Context, req *middleware.MiddlewareId, rsp *middleware.MiddlewareInfo) error {
log.Info("Received *middleware.FindMiddlewareByID request")
//查询中间件
middlewareModel, err := e.MiddlewareDataService.FindMiddlewareByID(req.Id)
if err != nil {
common.Error(err)
return err
}
if err := common.SwapTo(middlewareModel, rsp); err != nil {
common.Error(err)
return err
}
return nil
}
func (e *MiddlewareHandler) FindAllMiddleware(ctx context.Context, req *middleware.FindAll, rsp *middleware.AllMiddleware) error {
log.Info("Received *middleware.FindAllMiddleware request")
allMiddleware, err := e.MiddlewareDataService.FindAllMiddleware()
if err != nil {
common.Error(err)
return err
}
//整理格式
for _, v := range allMiddleware {
middleInfo := &middleware.MiddlewareInfo{}
if err := common.SwapTo(v, middleInfo); err != nil {
common.Error(err)
return err
}
rsp.MiddlewareInfo = append(rsp.MiddlewareInfo, middleInfo)
}
return nil
}
make proto
10-16 中间件main调整 及 handler 开发(下)
C:\Users\Administrator\Desktop\gopaas\middleware\main.go
package main
import (
"flag"
"fmt"
"path/filepath"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/repository"
//"github.com/afex/hystrix-go/hystrix"
"github.com/asim/go-micro/plugins/registry/consul/v3"
ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
"github.com/asim/go-micro/v3"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/server"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/opentracing/opentracing-go"
service2 "github.com/yunixiangfeng/gopaas/middleware/domain/service"
"github.com/yunixiangfeng/gopaas/middleware/handler"
//hystrix2 "github.com/yunixiangfeng/gopaas/middleware/plugin/hystrix"
"strconv"
middleware "github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)
var (
//服务地址
hostIp = "192.168.204.130"
//服务地址
serviceHost = hostIp
//服务端口
servicePort = "8089"
//注册中心配置
consulHost = hostIp
consulPort int64 = 8500
//链路追踪
tracerHost = hostIp
tracerPort = 6831
//熔断端口,每个服务不能重复
//hystrixPort = 9099
//监控端口,每个服务不能重复
prometheusPort = 9199
)
func main() {
//需要本地启动,mysql,consul中间件服务
//1.注册中心
consul := consul.NewRegistry(func(options *registry.Options) {
options.Addrs = []string{
consulHost + ":" + strconv.FormatInt(consulPort, 10),
}
})
//2.配置中心,存放经常变动的变量
consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
if err != nil {
common.Error(err)
}
//3.使用配置中心连接 mysql
mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
//初始化数据库
db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
if err != nil {
//命令行输出下,方便查看错误
fmt.Println(err)
common.Fatal(err)
}
defer db.Close()
//禁止复表
db.SingularTable(true)
//4.添加链路追踪
t, io, err := common.NewTracer("go.micro.service.middleware", tracerHost+":"+strconv.Itoa(tracerPort))
if err != nil {
common.Error(err)
}
defer io.Close()
opentracing.SetGlobalTracer(t)
//添加熔断器,作为客户端需要启用
//hystrixStreamHandler := hystrix.NewStreamHandler()
//hystrixStreamHandler.Start()
//添加日志中心
//1)需要程序日志打入到日志文件中
//2)在程序中添加filebeat.yml 文件
//3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
//启动监听程序
//go func() {
// //http://192.168.204.130:9092/turbine/turbine.stream
// //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
// err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
// if err !=nil {
// common.Error(err)
// }
//}()
//5.添加监控
common.PrometheusBoot(prometheusPort)
//下载kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
//macos:
// 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
// 2.chmod +x ./kubectl
// 3.sudo mv ./kubectl /usr/local/bin/kubectl
// sudo chown root: /usr/local/bin/kubectl
// 5.kubectl version --client
// 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
// 注意:- config中的域名要能解析正确
// - 生产环境可以创建另一个证书
// 7.kubectl get ns 查看是否正常
//
//6.创建k8s连接
//在集群外面连接
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) 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 {
common.Fatal(err.Error())
}
//在集群中外的配置
//config, err := rest.InClusterConfig()
//if err != nil {
// panic(err.Error())
//}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
common.Fatal(err.Error())
}
//7.创建服务
service := micro.NewService(
//自定义服务地址,且必须写在其它参数前面
micro.Server(server.NewServer(func(options *server.Options) {
options.Advertise = serviceHost + ":" + servicePort
})),
micro.Name("go.micro.service.middleware"),
micro.Version("latest"),
//指定服务端口
micro.Address(":"+servicePort),
//添加注册中心
micro.Registry(consul),
//添加链路追踪
micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
//只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
//micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
//添加限流
micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
)
service.Init()
//只能执行一遍
//err = repository.NewMiddlewareRepository(db).InitTable()
//if err != nil {
// common.Fatal(err)
//}
//if err:= repository.NewMiddleTypeRepository(db).InitTable();err!=nil{
// common.Fatal(err)
//}
// 注册句柄,可以快速操作已开发的服务
middlewareDataService := service2.NewMiddlewareDataService(repository.NewMiddlewareRepository(db), clientset)
middleTypeDataService := service2.NewMiddleTypeDataService(repository.NewMiddleTypeRepository(db))
middleware.RegisterMiddlewareHandler(service.Server(), &handler.MiddlewareHandler{MiddlewareDataService: middlewareDataService, MiddleTypeDataService: middleTypeDataService})
// 启动服务
if err := service.Run(); err != nil {
//输出启动失败信息
common.Fatal(err)
}
}
C:\Users\Administrator\Desktop\gopaas\middleware\handler\middlewareHandler.go
package handler
import (
"context"
"strconv"
log "github.com/asim/go-micro/v3/logger"
"github.com/yunixiangfeng/gopaas/common"
"github.com/yunixiangfeng/gopaas/middleware/domain/model"
"github.com/yunixiangfeng/gopaas/middleware/domain/service"
middleware "github.com/yunixiangfeng/gopaas/middleware/proto/middleware"
)
type MiddlewareHandler struct {
//注意这里的类型是 IMiddlewareDataService 接口类型
MiddlewareDataService service.IMiddlewareDataService
// 添加中间件类型服务
MiddleTypeDataService service.IMiddleTypeDataService
}
func (e *MiddlewareHandler) DeleteMiddleTypeById(context.Context, *middleware.MiddleTypeId, *middleware.Response) error {
panic("implement me")
}
// Call is a single request handler called via client.Call or the generated client code
func (e *MiddlewareHandler) AddMiddleware(ctx context.Context, info *middleware.MiddlewareInfo, rsp *middleware.Response) error {
log.Info("Received *middleware.AddMiddleware request")
middleModel := &model.Middleware{}
if err := common.SwapTo(info, middleModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//调用其它的服务处理数据
//根据ID产销需要的镜像地址
imageAddress, err := e.MiddleTypeDataService.FindImageVersionByID(info.MiddleVersionId)
if err != nil {
common.Error(err)
return err
}
//赋值
info.MiddleDockerImageVersion = imageAddress
//在k8s 中创建资源
if err := e.MiddlewareDataService.CreateToK8s(info); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
} else {
//插入数据库
middleID, err := e.MiddlewareDataService.AddMiddleware(middleModel)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
rsp.Msg = "中间件添加成功 ID 号为:" + strconv.FormatInt(middleID, 10)
common.Info(rsp.Msg)
}
return nil
}
func (e *MiddlewareHandler) DeleteMiddleware(ctx context.Context, req *middleware.MiddlewareId, rsp *middleware.Response) error {
log.Info("Received *middleware.DeleteMiddleware request")
middleModel, err := e.MiddlewareDataService.FindMiddlewareByID(req.Id)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//删除k8s中资源
if err := e.MiddlewareDataService.DeleteFromK8s(middleModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
return nil
}
func (e *MiddlewareHandler) UpdateMiddleware(ctx context.Context, req *middleware.MiddlewareInfo, rsp *middleware.Response) error {
log.Info("Received *middleware.UpdateMiddleware request")
if err := e.MiddlewareDataService.UpdateToK8s(req); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//查询中间件相关的信息
middleModle, err := e.MiddlewareDataService.FindMiddlewareByID(req.Id)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//更新model数据
if err := common.SwapTo(req, middleModle); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
//更新model
if err := e.MiddlewareDataService.UpdateMiddleware(middleModle); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
return nil
}
//查询中间件
func (e *MiddlewareHandler) FindMiddlewareByID(ctx context.Context, req *middleware.MiddlewareId, rsp *middleware.MiddlewareInfo) error {
log.Info("Received *middleware.FindMiddlewareByID request")
//查询中间件
middlewareModel, err := e.MiddlewareDataService.FindMiddlewareByID(req.Id)
if err != nil {
common.Error(err)
return err
}
if err := common.SwapTo(middlewareModel, rsp); err != nil {
common.Error(err)
return err
}
return nil
}
//查找所有的中间件
func (e *MiddlewareHandler) FindAllMiddleware(ctx context.Context, req *middleware.FindAll, rsp *middleware.AllMiddleware) error {
log.Info("Received *middleware.FindAllMiddleware request")
allMiddleware, err := e.MiddlewareDataService.FindAllMiddleware()
if err != nil {
common.Error(err)
return err
}
//整理格式
for _, v := range allMiddleware {
middleInfo := &middleware.MiddlewareInfo{}
if err := common.SwapTo(v, middleInfo); err != nil {
common.Error(err)
return err
}
rsp.MiddlewareInfo = append(rsp.MiddlewareInfo, middleInfo)
}
return nil
}
//查找所有的中间件
func (e *MiddlewareHandler) FindAllMiddlewareByTypeID(ctx context.Context, req *middleware.FindAllByTypeId, rsp *middleware.AllMiddleware) error {
log.Info("Received *middleware.FindAllMiddleware request")
allMiddleware, err := e.MiddlewareDataService.FindAllMiddlewareByTypeID(req.TypeId)
if err != nil {
common.Error(err)
return err
}
//整理格式
for _, v := range allMiddleware {
middleInfo := &middleware.MiddlewareInfo{}
if err := common.SwapTo(v, middleInfo); err != nil {
common.Error(err)
return err
}
rsp.MiddlewareInfo = append(rsp.MiddlewareInfo, middleInfo)
}
return nil
}
//根据ID查找中间件类型信息
func (e *MiddlewareHandler) FindMiddleTypeByID(ctx context.Context, req *middleware.MiddleTypeId, rsp *middleware.MiddleTypeInfo) error {
typeModel, err := e.MiddleTypeDataService.FindMiddleTypeByID(req.Id)
if err != nil {
common.Error(err)
return err
}
if err := common.SwapTo(typeModel, rsp); err != nil {
common.Error(err)
return err
}
return nil
}
//添加中间件
func (e *MiddlewareHandler) AddMiddleType(ctx context.Context, info *middleware.MiddleTypeInfo, rsp *middleware.Response) error {
typeModel := &model.MiddleType{}
if err := common.SwapTo(info, typeModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
id, err := e.MiddleTypeDataService.AddMiddleType(typeModel)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
rsp.Msg = "中间件类型 ID 号为: " + strconv.FormatInt(id, 10)
common.Info(rsp.Msg)
return nil
}
//删除中间件类型
func (e *MiddlewareHandler) DeleteMiddleTypeByID(ctx context.Context, req *middleware.MiddleTypeId, rsp *middleware.Response) error {
if err := e.MiddleTypeDataService.DeleteMiddleType(req.Id); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
return nil
}
//更新中间件类型
func (e *MiddlewareHandler) UpdateMiddleType(ctx context.Context, req *middleware.MiddleTypeInfo, rsp *middleware.Response) error {
typeModel, err := e.MiddleTypeDataService.FindMiddleTypeByID(req.Id)
if err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
if err := common.SwapTo(req, typeModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
if err := e.MiddleTypeDataService.UpdateMiddleType(typeModel); err != nil {
common.Error(err)
rsp.Msg = err.Error()
return err
}
return nil
}
//查找所有的类型
func (e *MiddlewareHandler) FindAllMiddleType(ctx context.Context, req *middleware.FindAll, rsp *middleware.AllMiddleType) error {
//查询所有中间件
allMiddleType, err := e.MiddleTypeDataService.FindAllMiddleType()
if err != nil {
common.Error(err)
return err
}
//整理格式
for _, v := range allMiddleType {
middleInfo := &middleware.MiddleTypeInfo{}
if err := common.SwapTo(v, middleInfo); err != nil {
common.Error(err)
return err
}
rsp.MiddleTypeInfo = append(rsp.MiddleTypeInfo, middleInfo)
}
return nil
}
make proto
10-17 中间件前端页面以及核心API开发(上)
PS C:\Users\Administrator\Desktop\gopaas> .\yu-tool\yu-tool.exe newService github.com/yunixiangfeng/gopaas/middlewareApi
make proto
go mod tidy
C:\Users\Administrator\Desktop\gopaas\middlewareapi\proto\middlewareApi\middlewareApi.proto
syntax = "proto3";
package middlewareApi;
option go_package = "./proto/middlewareApi;middlewareApi";
service MiddlewareApi {
rpc FindMiddlewareById(Request) returns (Response){}
rpc AddMiddleware(Request) returns (Response){}
rpc DeleteMiddlewareById(Request) returns (Response){}
rpc UpdateMiddleware(Request) returns (Response){}
//默认接口
rpc Call(Request) returns (Response){}
//根据类型获取所有中间件
rpc FindAllMiddlewareByTypeId(Request) returns (Response){}
//中间件类型对外开发的API
rpc FindMiddleTypeById(Request) returns (Response){}
rpc AddMiddleType(Request) returns (Response){}
rpc DeleteMiddleTypeById(Request) returns (Response){}
rpc UpdateMiddleType(Request) returns (Response){}
rpc FindAllMiddleType(Request) returns (Response){}
}
message Pair {
string key = 1;
repeated string values = 2;
}
message Request {
string method = 1;
string path = 2;
map<string, Pair> header = 3;
map<string, Pair> get = 4;
map<string, Pair> post = 5;
string body = 6;
string url = 7;
}
message Response {
int32 statusCode = 1;
map<string, Pair> header = 2;
string body = 3;
}
make proto
C:\Users\Administrator\Desktop\gopaas\middlewareapi\proto\middlewareApi\middlewareApi.pb.micro.go
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/middlewareApi/middlewareApi.proto
package middlewareApi
import (
fmt "fmt"
proto "google.golang.org/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/asim/go-micro/v3/api"
client "github.com/asim/go-micro/v3/client"
server "github.com/asim/go-micro/v3/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for MiddlewareApi service
func NewMiddlewareApiEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for MiddlewareApi service
type MiddlewareApiService interface {
FindMiddlewareById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
AddMiddleware(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
DeleteMiddlewareById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
UpdateMiddleware(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
//默认接口
Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
//根据类型获取所有中间件
FindAllMiddlewareByTypeId(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
//中间件类型对外开发的API
FindMiddleTypeById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
AddMiddleType(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
DeleteMiddleTypeById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
UpdateMiddleType(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
FindAllMiddleType(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
}
type middlewareApiService struct {
c client.Client
name string
}
func NewMiddlewareApiService(name string, c client.Client) MiddlewareApiService {
return &middlewareApiService{
c: c,
name: name,
}
}
func (c *middlewareApiService) FindMiddlewareById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.FindMiddlewareById", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) AddMiddleware(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.AddMiddleware", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) DeleteMiddlewareById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.DeleteMiddlewareById", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) UpdateMiddleware(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.UpdateMiddleware", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.Call", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) FindAllMiddlewareByTypeId(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.FindAllMiddlewareByTypeId", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) FindMiddleTypeById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.FindMiddleTypeById", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) AddMiddleType(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.AddMiddleType", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) DeleteMiddleTypeById(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.DeleteMiddleTypeById", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) UpdateMiddleType(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.UpdateMiddleType", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *middlewareApiService) FindAllMiddleType(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "MiddlewareApi.FindAllMiddleType", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for MiddlewareApi service
type MiddlewareApiHandler interface {
FindMiddlewareById(context.Context, *Request, *Response) error
AddMiddleware(context.Context, *Request, *Response) error
DeleteMiddlewareById(context.Context, *Request, *Response) error
UpdateMiddleware(context.Context, *Request, *Response) error
//默认接口
Call(context.Context, *Request, *Response) error
//根据类型获取所有中间件
FindAllMiddlewareByTypeId(context.Context, *Request, *Response) error
//中间件类型对外开发的API
FindMiddleTypeById(context.Context, *Request, *Response) error
AddMiddleType(context.Context, *Request, *Response) error
DeleteMiddleTypeById(context.Context, *Request, *Response) error
UpdateMiddleType(context.Context, *Request, *Response) error
FindAllMiddleType(context.Context, *Request, *Response) error
}
func RegisterMiddlewareApiHandler(s server.Server, hdlr MiddlewareApiHandler, opts ...server.HandlerOption) error {
type middlewareApi interface {
FindMiddlewareById(ctx context.Context, in *Request, out *Response) error
AddMiddleware(ctx context.Context, in *Request, out *Response) error
DeleteMiddlewareById(ctx context.Context, in *Request, out *Response) error
UpdateMiddleware(ctx context.Context, in *Request, out *Response) error
Call(ctx context.Context, in *Request, out *Response) error
FindAllMiddlewareByTypeId(ctx context.Context, in *Request, out *Response) error
FindMiddleTypeById(ctx context.Context, in *Request, out *Response) error
AddMiddleType(ctx context.Context, in *Request, out *Response) error
DeleteMiddleTypeById(ctx context.Context, in *Request, out *Response) error
UpdateMiddleType(ctx context.Context, in *Request, out *Response) error
FindAllMiddleType(ctx context.Context, in *Request, out *Response) error
}
type MiddlewareApi struct {
middlewareApi
}
h := &middlewareApiHandler{hdlr}
return s.Handle(s.NewHandler(&MiddlewareApi{h}, opts...))
}
type middlewareApiHandler struct {
MiddlewareApiHandler
}
func (h *middlewareApiHandler) FindMiddlewareById(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.FindMiddlewareById(ctx, in, out)
}
func (h *middlewareApiHandler) AddMiddleware(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.AddMiddleware(ctx, in, out)
}
func (h *middlewareApiHandler) DeleteMiddlewareById(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.DeleteMiddlewareById(ctx, in, out)
}
func (h *middlewareApiHandler) UpdateMiddleware(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.UpdateMiddleware(ctx, in, out)
}
func (h *middlewareApiHandler) Call(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.Call(ctx, in, out)
}
func (h *middlewareApiHandler) FindAllMiddlewareByTypeId(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.FindAllMiddlewareByTypeId(ctx, in, out)
}
func (h *middlewareApiHandler) FindMiddleTypeById(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.FindMiddleTypeById(ctx, in, out)
}
func (h *middlewareApiHandler) AddMiddleType(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.AddMiddleType(ctx, in, out)
}
func (h *middlewareApiHandler) DeleteMiddleTypeById(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.DeleteMiddleTypeById(ctx, in, out)
}
func (h *middlewareApiHandler) UpdateMiddleType(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.UpdateMiddleType(ctx, in, out)
}
func (h *middlewareApiHandler) FindAllMiddleType(ctx context.Context, in *Request, out *Response) error {
return h.MiddlewareApiHandler.FindAllMiddleType(ctx, in, out)
}
C:\Users\Administrator\Desktop\gopaas\middlewareapi\proto\middlewareApi\middlewareApi.pb.go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.15.7
// source: proto/middlewareApi/middlewareApi.proto
package middlewareApi
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Pair struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
}
func (x *Pair) Reset() {
*x = Pair{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_middlewareApi_middlewareApi_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Pair) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Pair) ProtoMessage() {}
func (x *Pair) ProtoReflect() protoreflect.Message {
mi := &file_proto_middlewareApi_middlewareApi_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Pair.ProtoReflect.Descriptor instead.
func (*Pair) Descriptor() ([]byte, []int) {
return file_proto_middlewareApi_middlewareApi_proto_rawDescGZIP(), []int{0}
}
func (x *Pair) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *Pair) GetValues() []string {
if x != nil {
return x.Values
}
return nil
}
type Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Header map[string]*Pair `protobuf:"bytes,3,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Get map[string]*Pair `protobuf:"bytes,4,rep,name=get,proto3" json:"get,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Post map[string]*Pair `protobuf:"bytes,5,rep,name=post,proto3" json:"post,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Body string `protobuf:"bytes,6,opt,name=body,proto3" json:"body,omitempty"`
Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"`
}
func (x *Request) Reset() {
*x = Request{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_middlewareApi_middlewareApi_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Request) ProtoMessage() {}
func (x *Request) ProtoReflect() protoreflect.Message {
mi := &file_proto_middlewareApi_middlewareApi_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Request.ProtoReflect.Descriptor instead.
func (*Request) Descriptor() ([]byte, []int) {
return file_proto_middlewareApi_middlewareApi_proto_rawDescGZIP(), []int{1}
}
func (x *Request) GetMethod() string {
if x != nil {
return x.Method
}
return ""
}
func (x *Request) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
func (x *Request) GetHeader() map[string]*Pair {
if x != nil {
return x.Header
}
return nil
}
func (x *Request) GetGet() map[string]*Pair {
if x != nil {
return x.Get
}
return nil
}
func (x *Request) GetPost() map[string]*Pair {
if x != nil {
return x.Post
}
return nil
}
func (x *Request) GetBody() string {
if x != nil {
return x.Body
}
return ""
}
func (x *Request) GetUrl() string {
if x != nil {
return x.Url
}
return ""
}
type Response struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
StatusCode int32 `protobuf:"varint,1,opt,name=statusCode,proto3" json:"statusCode,omitempty"`
Header map[string]*Pair `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
}
func (x *Response) Reset() {
*x = Response{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_middlewareApi_middlewareApi_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Response) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_proto_middlewareApi_middlewareApi_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Response.ProtoReflect.Descriptor instead.
func (*Response) Descriptor() ([]byte, []int) {
return file_proto_middlewareApi_middlewareApi_proto_rawDescGZIP(), []int{2}
}
func (x *Response) GetStatusCode() int32 {
if x != nil {
return x.StatusCode
}
return 0
}
func (x *Response) GetHeader() map[string]*Pair {
if x != nil {
return x.Header
}
return nil
}
func (x *Response) GetBody() string {
if x != nil {
return x.Body
}
return ""
}
var File_proto_middlewareApi_middlewareApi_proto protoreflect.FileDescriptor
var file_proto_middlewareApi_middlewareApi_proto_rawDesc = []byte{
0x0a, 0x27, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
0x72, 0x65, 0x41, 0x70, 0x69, 0x2f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65,
0x41, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x6d, 0x69, 0x64, 0x64, 0x6c,
0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x22, 0x30, 0x0a, 0x04, 0x50, 0x61, 0x69, 0x72,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xeb, 0x03, 0x0a, 0x07, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12,
0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,
0x74, 0x68, 0x12, 0x3a, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41,
0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65,
0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x31,
0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x69,
0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x67, 0x65,
0x74, 0x12, 0x34, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x20, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18,
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75,
0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x1a, 0x4e, 0x0a,
0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x50, 0x61,
0x69, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a,
0x08, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x69, 0x64,
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4c, 0x0a, 0x09, 0x50, 0x6f,
0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c,
0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcb, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43,
0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18,
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48,
0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64,
0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x1a, 0x4e, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xa0, 0x06, 0x0a, 0x0d, 0x4d, 0x69, 0x64, 0x64, 0x6c,
0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x12, 0x47, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64,
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x16,
0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x12, 0x42, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
0x72, 0x65, 0x12, 0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41,
0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64,
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d,
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x16, 0x2e,
0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x45, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
0x77, 0x61, 0x72, 0x65, 0x12, 0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d,
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12,
0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65,
0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x4e, 0x0a, 0x19, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x4d, 0x69, 0x64,
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x42, 0x79, 0x54, 0x79, 0x70, 0x65, 0x49, 0x64, 0x12,
0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65,
0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x47, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
0x54, 0x79, 0x70, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c,
0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69,
0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x0d, 0x41,
0x64, 0x64, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x2e, 0x6d,
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x49, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x54,
0x79, 0x70, 0x65, 0x42, 0x79, 0x49, 0x64, 0x12, 0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65,
0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x10, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16,
0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x12, 0x46, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x6c, 0x6c, 0x4d, 0x69, 0x64, 0x64,
0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17,
0x2e, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69, 0x2e, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x25, 0x5a, 0x23, 0x2e, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41,
0x70, 0x69, 0x3b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x41, 0x70, 0x69,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proto_middlewareApi_middlewareApi_proto_rawDescOnce sync.Once
file_proto_middlewareApi_middlewareApi_proto_rawDescData = file_proto_middlewareApi_middlewareApi_proto_rawDesc
)
func file_proto_middlewareApi_middlewareApi_proto_rawDescGZIP() []byte {
file_proto_middlewareApi_middlewareApi_proto_rawDescOnce.Do(func() {
file_proto_middlewareApi_middlewareApi_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_middlewareApi_middlewareApi_proto_rawDescData)
})
return file_proto_middlewareApi_middlewareApi_proto_rawDescData
}
var file_proto_middlewareApi_middlewareApi_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_proto_middlewareApi_middlewareApi_proto_goTypes = []interface{}{
(*Pair)(nil), // 0: middlewareApi.Pair
(*Request)(nil), // 1: middlewareApi.Request
(*Response)(nil), // 2: middlewareApi.Response
nil, // 3: middlewareApi.Request.HeaderEntry
nil, // 4: middlewareApi.Request.GetEntry
nil, // 5: middlewareApi.Request.PostEntry
nil, // 6: middlewareApi.Response.HeaderEntry
}
var file_proto_middlewareApi_middlewareApi_proto_depIdxs = []int32{
3, // 0: middlewareApi.Request.header:type_name -> middlewareApi.Request.HeaderEntry
4, // 1: middlewareApi.Request.get:type_name -> middlewareApi.Request.GetEntry
5, // 2: middlewareApi.Request.post:type_name -> middlewareApi.Request.PostEntry
6, // 3: middlewareApi.Response.header:type_name -> middlewareApi.Response.HeaderEntry
0, // 4: middlewareApi.Request.HeaderEntry.value:type_name -> middlewareApi.Pair
0, // 5: middlewareApi.Request.GetEntry.value:type_name -> middlewareApi.Pair
0, // 6: middlewareApi.Request.PostEntry.value:type_name -> middlewareApi.Pair
0, // 7: middlewareApi.Response.HeaderEntry.value:type_name -> middlewareApi.Pair
1, // 8: middlewareApi.MiddlewareApi.FindMiddlewareById:input_type -> middlewareApi.Request
1, // 9: middlewareApi.MiddlewareApi.AddMiddleware:input_type -> middlewareApi.Request
1, // 10: middlewareApi.MiddlewareApi.DeleteMiddlewareById:input_type -> middlewareApi.Request
1, // 11: middlewareApi.MiddlewareApi.UpdateMiddleware:input_type -> middlewareApi.Request
1, // 12: middlewareApi.MiddlewareApi.Call:input_type -> middlewareApi.Request
1, // 13: middlewareApi.MiddlewareApi.FindAllMiddlewareByTypeId:input_type -> middlewareApi.Request
1, // 14: middlewareApi.MiddlewareApi.FindMiddleTypeById:input_type -> middlewareApi.Request
1, // 15: middlewareApi.MiddlewareApi.AddMiddleType:input_type -> middlewareApi.Request
1, // 16: middlewareApi.MiddlewareApi.DeleteMiddleTypeById:input_type -> middlewareApi.Request
1, // 17: middlewareApi.MiddlewareApi.UpdateMiddleType:input_type -> middlewareApi.Request
1, // 18: middlewareApi.MiddlewareApi.FindAllMiddleType:input_type -> middlewareApi.Request
2, // 19: middlewareApi.MiddlewareApi.FindMiddlewareById:output_type -> middlewareApi.Response
2, // 20: middlewareApi.MiddlewareApi.AddMiddleware:output_type -> middlewareApi.Response
2, // 21: middlewareApi.MiddlewareApi.DeleteMiddlewareById:output_type -> middlewareApi.Response
2, // 22: middlewareApi.MiddlewareApi.UpdateMiddleware:output_type -> middlewareApi.Response
2, // 23: middlewareApi.MiddlewareApi.Call:output_type -> middlewareApi.Response
2, // 24: middlewareApi.MiddlewareApi.FindAllMiddlewareByTypeId:output_type -> middlewareApi.Response
2, // 25: middlewareApi.MiddlewareApi.FindMiddleTypeById:output_type -> middlewareApi.Response
2, // 26: middlewareApi.MiddlewareApi.AddMiddleType:output_type -> middlewareApi.Response
2, // 27: middlewareApi.MiddlewareApi.DeleteMiddleTypeById:output_type -> middlewareApi.Response
2, // 28: middlewareApi.MiddlewareApi.UpdateMiddleType:output_type -> middlewareApi.Response
2, // 29: middlewareApi.MiddlewareApi.FindAllMiddleType:output_type -> middlewareApi.Response
19, // [19:30] is the sub-list for method output_type
8, // [8:19] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_proto_middlewareApi_middlewareApi_proto_init() }
func file_proto_middlewareApi_middlewareApi_proto_init() {
if File_proto_middlewareApi_middlewareApi_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proto_middlewareApi_middlewareApi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Pair); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_middlewareApi_middlewareApi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_middlewareApi_middlewareApi_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Response); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_middlewareApi_middlewareApi_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_middlewareApi_middlewareApi_proto_goTypes,
DependencyIndexes: file_proto_middlewareApi_middlewareApi_proto_depIdxs,
MessageInfos: file_proto_middlewareApi_middlewareApi_proto_msgTypes,
}.Build()
File_proto_middlewareApi_middlewareApi_proto = out.File
file_proto_middlewareApi_middlewareApi_proto_rawDesc = nil
file_proto_middlewareApi_middlewareApi_proto_goTypes = nil
file_proto_middlewareApi_middlewareApi_proto_depIdxs = nil
}