当前位置:   article > 正文

基于Go开发PaaS平台1_mysql集群管理平台

mysql集群管理平台

Go开发PaaS平台核心功能

代码仓库地址GitHub - yunixiangfeng/gopaas

云原生PaaS平台介绍

随着云计算的发展,越来越多的企业逐步的把IT资源迁移到云上。PaaS平台作为基础设施基座,可以帮助企业快速构建功能丰富的容器云平台,提升交付效率,降低成本。 

[1.1] 云原生平台使用的主流技术

建设路径,先建设pass平台,再开发go微服务,然后扩大云原生支持.

容器监控系统 Promethus + Grafana

容器模式下中间件主流的接入方案

标准的路由管理技术 nginx ingress

云原生平台展示

[1.2] 什么是云原生GOPaaS平台以及有哪些优势 

PaaS 平台是什么?
PaaS 平台与 DevOps
PaaS平台与服务网格
PaaS 平台与低代码

PaaS 平台是什么?
PaaS(平台即服务):提供了一个用于开发、运行和管理应用程序的完整、灵活且经济高效的云平台。
是一种云计算模型,它为客户提供一个完整的云平台以用于开发、运行和管理应用程序,而无需考虑在本地构建和维护该平台通常会带来的成本、复杂性和不灵活性。 

PaaS 平台的优势
缩短产品上市时间
开发团队提供更大的灵活性
降低总体成本

[1.3] 云原生GoPaaS平台与DevOps的关系

PaaS 与 DevOps
DevOps 开发规范流程每个公司都有多种
新体系的下 DevOps 会融入到 PaaS 平台中
规模化的交付将借助于现有的 PaaS 体系进行 

[1.4] 云原生PaaS平台与服务网格 

PaaS 与 服务网格
Service Mesh 是下一代微服务架构
Service Mesh 有成熟的观测台
Service Mesh 需要通过 PaaS 平台进行系统性的管理

[1.5] 云原生GoPaaS平台与低代码

Paas 与 低代码
低代码是当今的风口,通过图形化编程方式来快速落地业务
低代码生成源码后会跑在 PaaS 平台中
低代码的交付模式将直接在 PaaS平台的基础上发展 

第2章 Go 搭建基础开发环境

准备开发环境,介绍go mod 的代理设置、工程目录结构的规划、Docker-compose 的使用。准备了自动化的生成框架 yu-tool ,可以无缝衔接日常业务。

2-1 环境安装级版本说明 

Go 代理设置& git 设置
micro 生产第一个项目目录及目录说明
Docker-compose 安装及使用

环境版本说明
Go版本使用 1.18.3
docker-compose 1.27.4
docker version 20.10.21

环境版本说明
Go 安装:https://golang.org/
docker-compose安装:
https://github.com/docker/compose/releases
docker 安装: https://docs.docker.com/get-docker/

2-2 go 代理和 git 设置 

Go 开发环境搭建
Go代理设置&git设置
设置go mod 代理: go env -wGOPROXY=https://goproxy.io,direct
私有仓库不设置代理:go env -w
GOPRIVATE=*.xxx.com

Go代理设置&git设置
go get 内部使用 https 的 clone 命令,默认只支持公有仓库

若用的是ssh 方式(注意用了80端口),需要替换。

2-3 项目目录结构

Go 开发环境搭建
生成第一个项目目录
如何创建我们的代码目录,目录结构是什么意思?
专用工具生成目录
D:\Workspace\gopaas\yu-tool\

go run main.go new github.com/xxxx/仓库名称

项目目录

D:\Workspace\Go\src\gopaas\base\

2-4 yu-tool 代码目录生成 & proto 文件生成

D:\Workspace\Go\src\gopaas\yu-tool

 go run main.go new user

  1. PS D:\Workspace\gopaas\yu-tool> go run main.go new user
  2. 创建初始化项目 user
  3. .
  4. ├── main.go
  5. ├── handler
  6. │ └── userHandler.go
  7. ├── plugin
  8. │ └── hystrix
  9. │ └── hystrix.go
  10. ├── domain
  11. │ ├── model
  12. │ │ └── user.go
  13. │ ├── repository
  14. │ │ └── user_repository.go
  15. │ └── service
  16. │ └── user_data_service.go
  17. ├── proto
  18. │ └── user
  19. │ └── user.proto
  20. ├── Dockerfile
  21. ├── filebeat.yml
  22. ├── Makefile
  23. ├── README.md
  24. ├── .gitignore
  25. └── go.mod
  26. ======================说明===========================
  27. 该工具为定制工具,旨在提高开发效率
  28. 工具主要功能如下:
  29. 1、快速创建项目目录结构。
  30. ======================操作============================
  31. 接下来直接使用代码中的 make proto 来自动生成基于 proto 的相关文件
  32. 具体操作如下:
  33. 1、make proto ( window 下要修改 docker 命令)
  34. 2、执行 go mod tidy
  35. 3、go run main.go 检查是否能够启动成功
  36. 4、查看注册中心服务是否存在(地址默认:127.0.0.1:8500)
  37. 注意:你也可以在本机安装 proto ,protoc-gen-go,protoc-gen-micro 运行 protoc 进行生成。
  38. ************恭喜!项目初始化成功!************

D:\Workspace\Go\src\gopaas\user

protoc --proto_path=. --micro_out=. --go_out=:. ./proto/user/user.proto

2-5 docker-compose yml编写和常见用法

Docker-compose 安装和使用
docker-compose yaml文件的编写
docker-compose 编译
docker-compose 启动

  1. PS D:\Workspace\Go\src\gopaas\yu-tool> go run main.go new base
  2. 创建初始化项目 base
  3. .
  4. ├── main.go
  5. ├── handler
  6. │ └── baseHandler.go
  7. ├── plugin
  8. │ └── hystrix
  9. │ └── hystrix.go
  10. ├── domain
  11. │ ├── model
  12. │ │ └── base.go
  13. │ ├── repository
  14. │ │ └── base_repository.go
  15. │ └── service
  16. │ └── base_data_service.go
  17. ├── proto
  18. │ └── base
  19. │ └── base.proto
  20. ├── Dockerfile
  21. ├── filebeat.yml
  22. ├── Makefile
  23. ├── README.md
  24. ├── .gitignore
  25. └── go.mod
  26. ======================说明===========================
  27. 该工具为定制工具,旨在提高开发效率
  28. 工具主要功能如下:
  29. 1、快速创建项目目录结构。
  30. ======================操作============================
  31. 接下来直接使用代码中的 make proto 来自动生成基于 proto 的相关文件
  32. 具体操作如下:
  33. 1、make proto ( window 下要修改 docker 命令)
  34. 2、执行 go mod tidy
  35. 3、go run main.go 检查是否能够启动成功
  36. 4、查看注册中心服务是否存在(地址默认:127.0.0.1:8500)
  37. 注意:你也可以在本机安装 proto ,protoc-gen-go,protoc-gen-micro 运行 protoc 进行生成。
  38. ************恭喜!项目初始化成功!************
  1. D:\Workspace\Go\src\gopaas\base
  2. #protoc --proto_path=. --micro_out=. --go_out=:. ./proto/base/base.proto
  3. protoc --proto_path=D:\Workspace\Go\src\gopaas\base --micro_out=D:\Workspace\Go\src\gopaas\base --go_out=:D:\Workspace\Go\src\gopaas\base proto/base/base.proto
  1. go mod tidy
  2. # go build
  3. go env -w CGO_ENABLED=0 GOOS=windows GOARCH=amd64
  4. go build -o base *.go

D:\Workspace\gopaas\docker-compose\chapter2\docker-compose.yml

  1. # yaml 配置实例
  2. version: '3'
  3. services:
  4. #服务名称
  5. base-service:
  6. # 构建
  7. build:
  8. context: ../../base
  9. dockerfile: Dockerfile
  10. image: base-service:1.0.0
  11. container_name: base-yu-service
  12. restart: always
  13. ports:
  14. - "5000:5000"
  15. - "8080:8080"
  1. cd  docker-compose\chapter2
  2. docker-compose build base-service
  3. docker images |grep base
  4. docker-compose up -d
  5. docker ps |grep base
  6. docker-compose down

2-6 总结&思考

你如何看待自动生成工具?
它能带来哪些方便?

完成Go基础环境安装和git 设置
使用yu-tool 创建第一个项目目录
完成 docker-compose 的安装

2-7 【扩展阅读】docker 安装和详细操作命令

2-8 【扩展阅读】Dockerfile 详细说明

第3章 Go 微服务 go-micro v3 框架快速入门

要完成PaaS 平台的开发,需要对微服务有充分的认知。认识 v3 与 micro 的区别;了解 go-micro框架,认识它的注册中心、配置中心、链路追踪、熔断&限流、监控等模块组件的使用,掌握Go主流微服务框架的核心应用。

3-1 本章概览

go-micro v3 和mirco v3 是什么关系?
go-micro v3整体架构
go-micro v3 框架技术栈讲解 

3-2 go-micro v3 框架与 micro v3 的关系

Go 微服务框架go-micro
go-micro 是什么?
go-micro 是一个go微服务开放框架
Framework(程序开发框架): 用来方便编写微服务
Clients(多语言客户端):支持多语言访问服务端 

go-micro v3与 micro v3 的关系
microv3版本类似isito 把基础设施抽象成能力
micro的技术体系和官方平台绑定较多
go-microv3为微服务开发框架,自由度相对较高

3-3 go-micro v3 框架整体介绍

go-micro v3组件
注册(Registry):提供了服务发现机制
选择器(Selector) :能够实现负载均衡
传输(Transport): 服务与服务之间通信接口

代理(Broker):提供异步通信的消息发布/订阅接口
编码(Codec):消息传输到两端时进行编码与解码
Server(服务端),Client (客户端)

Framework(go-micro) 通信图

3-4 go-micro v3 添加集群版本consul(上)

go-micro v3 技术栈使用
注册中心&配置中心
链路追踪
熔断 

限流
日志中心
监控

go-microv3技术栈-注册中心&配置中心consul 集群版
docker-compose 镜像引入 consul 集群版本
base 基础工程中添加 consul
consul 控制面板添加配置

3-5 go-micro v3 添加集群版本consul(下

D:\Workspace\gopaas\docker-compose\chapter3\docker-compose.yml

  1. version: '3.3'
  2. services:
  3. #注册中心集群版本设置
  4. consul1:
  5. image: consul
  6. container_name: node1
  7. command: agent -server -bootstrap-expect=3 -node=node1 -bind=0.0.0.0 -client=0.0.0.0 -datacenter=dc1
  8. consul2:
  9. image: consul
  10. container_name: node2
  11. command: agent -server -retry-join=node1 -bootstrap-expect=3 -node=node2 -bind=0.0.0.0 -client=0.0.0.0 -datacenter=dc1
  12. depends_on:
  13. - consul1
  14. consul3:
  15. image: consul
  16. container_name: node3
  17. command: agent -server -retry-join=node1 -bootstrap-expect=3 -node=node3 -bind=0.0.0.0 -client=0.0.0.0 -datacenter=dc1
  18. depends_on:
  19. - consul1
  20. #添加对外暴露的节点,启动控制面板
  21. consul4:
  22. image: consul
  23. container_name: node4
  24. command: agent -retry-join=node1 -node=node4 -bind=0.0.0.0 -client=0.0.0.0 -datacenter=dc1 -ui
  25. ports:
  26. - 8500:8500
  27. depends_on:
  28. - consul2
  29. - consul3
  30. #添加数据库
  31. paas-mysql:
  32. image: mysql
  33. environment:
  34. MYSQL_ROOT_PASSWORD: 1234
  35. container_name: paas-mysql
  36. ports:
  37. - "3306:3306"
  38. #重要的数据挂盘
  39. volumes:
  40. - ./mysql:/var/lib/mysql
  41. #添加jaeger
  42. jaeger:
  43. image: jaeger
  44. ports:
  45. - "6831:6831/udp"
  46. - "16686:16686"
  47. #添加熔断看板
  48. # hystrix-dashboard:
  49. # #镜像名称
  50. # image: hystrix-dashboard
  51. # ports:
  52. # - "9002:9002"
  53. #添加监控镜像
  54. prometheus:
  55. image: prometheus
  56. volumes:
  57. - ./prometheus.yml:/etc/prometheus/prometheus.yml
  58. ports:
  59. - "9090:9090"
  60. #监控看板,默认密码为admin/admin
  61. grafana:
  62. image: grafana
  63. ports:
  64. - "3000:3000"
  1. cd docker-compose\chapter3
  2. docker-compose up

浏览器访问consul 127.0.0.1:8500

将consul服务添加到base工程

  1. //1.注册中心
  2. consul := consul.NewRegistry(func(options *registry.Options) {
  3. options.Addrs = []string{
  4. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  5. }
  6. })
  7. //7.创建服务
  8. service := micro.NewService(
  9. //自定义服务地址,且必须写在其它参数前面
  10. micro.Server(server.NewServer(func(options *server.Options) {
  11. options.Advertise = serviceHost + ":" + servicePort
  12. })),
  13. micro.Name("go.micro.service.base"),
  14. micro.Version("latest"),
  15. //指定服务端口
  16. micro.Address(":"+servicePort),
  17. //添加注册中心
  18. micro.Registry(consul),
  19. //添加链路追踪
  20. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  21. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  22. //只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
  23. //micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  24. //添加限流
  25. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  26. )

D:\Workspace\Go\src\gopaas\base\main.go

go get github.com/asim/go-micro/plugins/registry/consul/v3

  1. package main
  2. import (
  3. "base/domain/repository"
  4. "flag"
  5. "fmt"
  6. "path/filepath"
  7. "github.com/yunixiangfeng/common"
  8. //"github.com/afex/hystrix-go/hystrix"
  9. service2 "base/domain/service"
  10. "base/handler"
  11. "github.com/asim/go-micro/plugins/registry/consul/v3"
  12. ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
  13. opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
  14. "github.com/asim/go-micro/v3"
  15. "github.com/asim/go-micro/v3/registry"
  16. "github.com/asim/go-micro/v3/server"
  17. "github.com/jinzhu/gorm"
  18. _ "github.com/jinzhu/gorm/dialects/mysql"
  19. // "github.com/micro/go-micro/server"
  20. "github.com/opentracing/opentracing-go"
  21. //hystrix2 "base/plugin/hystrix"
  22. base "base/proto/base"
  23. "strconv"
  24. "k8s.io/client-go/kubernetes"
  25. "k8s.io/client-go/tools/clientcmd"
  26. "k8s.io/client-go/util/homedir"
  27. )
  28. var (
  29. //服务地址
  30. hostIp = "192.168.204.130"
  31. //服务地址
  32. serviceHost = hostIp
  33. //服务端口
  34. servicePort = "8081"
  35. //注册中心配置
  36. consulHost = hostIp
  37. consulPort int64 = 8500
  38. //链路追踪
  39. tracerHost = hostIp
  40. tracerPort = 6831
  41. //熔断端口,每个服务不能重复
  42. //hystrixPort = 9092
  43. //监控端口,每个服务不能重复
  44. prometheusPort = 9192
  45. )
  46. func main() {
  47. //需要本地启动,mysql,consul中间件服务
  48. //1.注册中心
  49. consul := consul.NewRegistry(func(options *registry.Options) {
  50. options.Addrs = []string{
  51. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  52. }
  53. })
  54. //2.配置中心,存放经常变动的变量
  55. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  56. if err != nil {
  57. common.Error(err)
  58. }
  59. //3.使用配置中心连接 mysql
  60. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  61. //初始化数据库
  62. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  63. if err != nil {
  64. //命令行输出下,方便查看错误
  65. fmt.Println(err)
  66. common.Fatal(err)
  67. }
  68. defer db.Close()
  69. //禁止复表
  70. db.SingularTable(true)
  71. //4.添加链路追踪
  72. t, io, err := common.NewTracer("go.micro.service.base", tracerHost+":"+strconv.Itoa(tracerPort))
  73. if err != nil {
  74. common.Error(err)
  75. }
  76. defer io.Close()
  77. opentracing.SetGlobalTracer(t)
  78. //添加熔断器,作为客户端需要启用
  79. //hystrixStreamHandler := hystrix.NewStreamHandler()
  80. //hystrixStreamHandler.Start()
  81. //添加日志中心
  82. //1)需要程序日志打入到日志文件中
  83. //2)在程序中添加filebeat.yml 文件
  84. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  85. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  86. //启动监听程序
  87. //go func() {
  88. // //http://192.168.204.130:9092/turbine/turbine.stream
  89. // //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  90. // err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
  91. // if err !=nil {
  92. // common.Error(err)
  93. // }
  94. //}()
  95. //5.添加监控
  96. common.PrometheusBoot(prometheusPort)
  97. //下载kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
  98. //macos:
  99. // 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
  100. // 2.chmod +x ./kubectl
  101. // 3.sudo mv ./kubectl /usr/local/bin/kubectl
  102. // sudo chown root: /usr/local/bin/kubectl
  103. // 5.kubectl version --client
  104. // 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
  105. // 注意:- config中的域名要能解析正确
  106. // - 生产环境可以创建另一个证书
  107. // 7.kubectl get ns 查看是否正常
  108. //
  109. //6.创建k8s连接
  110. //在集群外面连接
  111. var kubeconfig *string
  112. if home := homedir.HomeDir(); home != "" {
  113. kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
  114. } else {
  115. kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
  116. }
  117. flag.Parse()
  118. config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
  119. if err != nil {
  120. common.Fatal(err.Error())
  121. }
  122. //在集群中外的配置
  123. //config, err := rest.InClusterConfig()
  124. //if err != nil {
  125. // panic(err.Error())
  126. //}
  127. // create the clientset
  128. clientset, err := kubernetes.NewForConfig(config)
  129. if err != nil {
  130. common.Fatal(err.Error())
  131. }
  132. //7.创建服务
  133. service := micro.NewService(
  134. //自定义服务地址,且必须写在其它参数前面
  135. micro.Server(server.NewServer(func(options *server.Options) {
  136. options.Advertise = serviceHost + ":" + servicePort
  137. })),
  138. micro.Name("go.micro.service.base"),
  139. micro.Version("latest"),
  140. //指定服务端口
  141. micro.Address(":"+servicePort),
  142. //添加注册中心
  143. micro.Registry(consul),
  144. //添加链路追踪
  145. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  146. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  147. //只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
  148. //micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  149. //添加限流
  150. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  151. )
  152. service.Init()
  153. //只能执行一遍
  154. //err = repository.NewBaseRepository(db).InitTable()
  155. //if err != nil {
  156. // common.Fatal(err)
  157. //}
  158. // 注册句柄,可以快速操作已开发的服务
  159. baseDataService := service2.NewBaseDataService(repository.NewBaseRepository(db), clientset)
  160. base.RegisterBaseHandler(service.Server(), &handler.BaseHandler{BaseDataService: baseDataService})
  161. // 启动服务
  162. if err := service.Run(); err != nil {
  163. //输出启动失败信息
  164. common.Fatal(err)
  165. }
  166. }

3-6 go-micro v3 添加配置中心 

创建common仓库 

  1. ​git clone https://github.com/yunixiangfeng/common
  2. D:\Workspace\Go\src\gopaas\common

common\config.go 

  1. package common
  2. import (
  3. "github.com/asim/go-micro/plugins/config/source/consul/v3"
  4. "github.com/asim/go-micro/v3/config"
  5. "strconv"
  6. )
  7. func GetConsulConfig(host string,port int64,prefix string)(config.Config,error) {
  8. consulSource := consul.NewSource(
  9. //设置配置中心的地址
  10. consul.WithAddress(host+":"+strconv.FormatInt(port,10)),
  11. //设置前缀,不设置 /micro/config
  12. consul.WithPrefix(prefix),
  13. consul.StripPrefix(true),
  14. )
  15. conf,err:= config.NewConfig()
  16. if err!=nil {
  17. return conf,err
  18. }
  19. err = conf.Load(consulSource)
  20. return conf,err
  21. }
  1. module github.com/yunixiangfeng/common
  2. go 1.16
  3. require (
  4. github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
  5. github.com/asim/go-micro/plugins/config/source/consul/v3 v3.0.0-20210904061721-270d910b7328
  6. github.com/asim/go-micro/v3 v3.6.0
  7. github.com/opentracing/opentracing-go v1.2.0
  8. github.com/prometheus/client_golang v1.1.0
  9. github.com/prometheus/common v0.6.0
  10. github.com/uber/jaeger-client-go v2.29.1+incompatible
  11. github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
  12. go.uber.org/zap v1.10.0
  13. gopkg.in/natefinch/lumberjack.v2 v2.0.0
  14. )

提交到git仓库

然后在base工程main.go添加配置中心

  1. //2.配置中心,存放经常变动的变量
  2. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  3. if err != nil {
  4. common.Error(err)
  5. }

http://127.0.0.1:8500/ui/dc1/kv创建key

micro/config/mysql 

  1. {
  2. "host" : "127.0.0.1",
  3. "user" : "root",
  4. "pwd" : "1234",
  5. "database" : "paas",
  6. "port" : 3306
  7. }

 

3-7 go-micro v3 如何使用配置中心连接 mysql 

common\mysql.go

  1. package common
  2. import "github.com/asim/go-micro/v3/config"
  3. //创建结构体
  4. type MysqlConfig struct {
  5. Host string `json:"host"`
  6. User string `json:"user"`
  7. Pwd string `json:"pwd"`
  8. Database string `json:"database"`
  9. Port string `json:"port"`
  10. }
  11. func GetMysqlFromConsul(config config.Config,path ...string) *MysqlConfig {
  12. mysqlConfig := &MysqlConfig{}
  13. config.Get(path...).Scan(mysqlConfig)
  14. return mysqlConfig
  15. }
  1. //3.使用配置中心连接 mysql
  2. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  3. //初始化数据库
  4. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  5. if err != nil {
  6. //命令行输出下,方便查看错误
  7. fmt.Println(err)
  8. common.Fatal(err)
  9. }
  10. defer db.Close()
  11. //禁止复表
  12. db.SingularTable(true)

go run base/main.go

  1. [root@k8s-worker01 base]# go run main.go
  2. 日志统一记录在根目录 micro.log 文件中,请点击查看日志!
  3. 2023-05-22 10:37:06 file=v3@v3.7.0/service.go:206 level=info Starting [service] go.micro.service.base
  4. 2023-05-22 10:37:06 file=server/rpc_server.go:820 level=info Transport [http] Listening on [::]:8081
  5. 2023-05-22 10:37:06 file=server/rpc_server.go:840 level=info Broker [http] Connected to 127.0.0.1:43121
  6. 2023-05-22 10:37:06 file=server/rpc_server.go:654 level=info Registry [consul] Registering node: go.micro.service.base-1431e43d-f735-4fba-b5e4-aaa8c0ab57f6

3-8 go-micro v3 添加链路追踪 

go-micro v3 技术栈-链路追踪jaeger
jaeger 原理讲解& docker-compose 安装 jaeger
common 统一模块添加jaeger
base 基础代码添加 jaeger 代码

微服务链路追踪(jaeger)的原理

common\jaeger.go

  1. package common
  2. import (
  3. "github.com/opentracing/opentracing-go"
  4. "github.com/uber/jaeger-client-go"
  5. jaegercfg "github.com/uber/jaeger-client-go/config"
  6. "io"
  7. "time"
  8. )
  9. //创建jaeger链路追踪实例
  10. func NewTracer(serviceName string, addr string) (opentracing.Tracer, io.Closer, error) {
  11. cfg := &jaegercfg.Configuration{
  12. ServiceName: serviceName,
  13. Sampler: &jaegercfg.SamplerConfig{
  14. Type: jaeger.SamplerTypeConst,
  15. Param: 1,
  16. },
  17. Reporter: &jaegercfg.ReporterConfig{
  18. LogSpans: true,
  19. BufferFlushInterval: 1 * time.Second,
  20. LocalAgentHostPort: addr,
  21. },
  22. }
  23. tracer, closer, err := cfg.NewTracer()
  24. return tracer, closer, err
  25. }

提交到common仓库

启动jaeger 

访问熔断器地址http://127.0.0.1:16686/ 

在base工程main.go中使用jaeger

  1. //4.添加链路追踪
  2. t, io, err := common.NewTracer("go.micro.service.base", tracerHost+":"+strconv.Itoa(tracerPort))
  3. if err != nil {
  4. common.Error(err)
  5. }
  6. defer io.Close()
  7. opentracing.SetGlobalTracer(t)
  8. //添加熔断器,作为客户端需要启用
  9. //hystrixStreamHandler := hystrix.NewStreamHandler()
  10. //hystrixStreamHandler.Start()
  11. //添加日志中心
  12. //1)需要程序日志打入到日志文件中
  13. //2)在程序中添加filebeat.yml 文件
  14. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  15. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  16. //启动监听程序
  17. //go func() {
  18. // //http://192.168.204.130:9092/turbine/turbine.stream
  19. // //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  20. // err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
  21. // if err !=nil {
  22. // common.Error(err)
  23. // }
  24. //}()
  1. //7.创建服务
  2. service := micro.NewService(
  3. //自定义服务地址,且必须写在其它参数前面
  4. micro.Server(server.NewServer(func(options *server.Options) {
  5. options.Advertise = serviceHost + ":" + servicePort
  6. })),
  7. micro.Name("go.micro.service.base"),
  8. micro.Version("latest"),
  9. //指定服务端口
  10. micro.Address(":"+servicePort),
  11. //添加注册中心
  12. micro.Registry(consul),
  13. //添加链路追踪
  14. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  15. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  16. //只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
  17. //micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  18. //添加限流
  19. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  20. )
  21. service.Init()

    opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"

go run base/main.go 

3-9 go-micro v3 添加熔断和限流 

go-micro v3 技术栈- 链路熔断 hystrix
hystrix流程讲解
docker-compose 使用 hystrix 面板
base 基础代码添加熔断&限流代码

添加熔断看板 

Pulling hystrix-dashboard (hystrix-dashboard:) 

base/main.go

  1. //添加熔断器,作为客户端需要启用
  2. hystrixStreamHandler := hystrix.NewStreamHandler()
  3. hystrixStreamHandler.Start()
  4. //启动监听程序
  5. go func() {
  6. //http://192.168.204.130:9092/turbine/turbine.stream
  7. // //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  8. err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
  9. if err !=nil {
  10. common.Error(err)
  11. }
  12. }()

http://127.0.0.1:9002/hystrix

D:\Workspace\Go\src\gopaas\base\plugin\hystrix\hystrix.go

  1. package hystrix
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/afex/hystrix-go/hystrix"
  6. "github.com/asim/go-micro/v3/client"
  7. )
  8. type clientWrapper struct {
  9. client.Client
  10. }
  11. //熔断逻辑
  12. func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
  13. return hystrix.Do(req.Service()+"."+req.Endpoint(), func() error {
  14. //正常执行
  15. fmt.Println(req.Service() + "." + req.Endpoint())
  16. return c.Client.Call(ctx, req, rsp, opts...)
  17. }, func(e error) error {
  18. //走熔断逻辑,每个服务都不一样
  19. fmt.Println(req.Service() + "." + req.Endpoint()+"的熔断逻辑")
  20. return e
  21. })
  22. }
  23. func NewClientHystrixWrapper() client.Wrapper {
  24. return func(i client.Client) client.Client {
  25. return &clientWrapper{i}
  26. }
  27. }

base/main.go 

      //只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用

        //micro.WrapClient(hystrix2.NewClientHystrixWrapper()),

        //服务端添加限流,qps 1000

        micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),

  1. //7.创建服务
  2. service := micro.NewService(
  3. //自定义服务地址,且必须写在其它参数前面
  4. micro.Server(server.NewServer(func(options *server.Options) {
  5. options.Advertise = serviceHost + ":" + servicePort
  6. })),
  7. micro.Name("go.micro.service.base"),
  8. micro.Version("latest"),
  9. //指定服务端口
  10. micro.Address(":"+servicePort),
  11. //添加注册中心
  12. micro.Registry(consul),
  13. //添加链路追踪
  14. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  15. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  16. //只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
  17. //micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  18. //添加限流
  19. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  20. )

3-10 go-micro v3 启用日志中心 

go-micro v3 技术栈-日志系统 elk
elk 流程讲解
docker-compose 使用引入 elk 体系
comon zap 日志,base 基础代码使用和filebeat 使用

docker-compose\chapter3\docker-stack.yml 

  1. version: '3.3'
  2. services:
  3. elasticsearch:
  4. image: elasticsearch:7.9.3
  5. ports:
  6. - "9200:9200"
  7. - "9300:9300"
  8. volumes:
  9. - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
  10. environment:
  11. ES_JAVA_OPTS: "-Xmx256m -Xms256m"
  12. ELASTIC_PASSWORD: password
  13. discovery.type: single-node
  14. network.publish_host: _eth0_
  15. logstash:
  16. image: logstash:7.9.3
  17. ports:
  18. - "5044:5044"
  19. - "5000:5000"
  20. - "9600:9600"
  21. volumes:
  22. - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
  23. - ./logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
  24. environment:
  25. LS_JAVA_OPTS: "-Xmx256m -Xms256m"
  26. kibana:
  27. image: kibana:7.9.3
  28. ports:
  29. - "5601:5601"
  30. volumes:
  31. - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
  32. depends_on:
  33. - elasticsearch

docker-compose\chapter3\elasticsearch\config\elasticsearch.yml

  1. ---
  2. cluster.name: "cluster"
  3. network.host: 0.0.0.0
  4. xpack.license.self_generated.type: trial
  5. xpack.security.enabled: true
  6. xpack.monitoring.collection.enabled: true

docker-compose\chapter3\kibana\config\kibana.yml

  1. ---
  2. server.name: kibana
  3. server.host: 0.0.0.0
  4. elasticsearch.hosts: ["http://elasticsearch:9200"]
  5. monitoring.ui.container.elasticsearch.enabled: true
  6. elasticsearch.username: elastic
  7. elasticsearch.password: pwd

docker-compose\chapter3\logstash\config\logstash.yml

  1. ---
  2. http.host: "0.0.0.0"
  3. xpack.monitoring.elasticsearch.hosts: ["http://elasticsearch:9200"]
  4. xpack.monitoring.enabled: true
  5. xpack.monitoring.elasticsearch.username: elastic
  6. xpack.monitoring.elasticsearch.password: pwd

docker-compose\chapter3\logstash\pipeline\logstash.conf

  1. input {
  2. beats {
  3. port => 5044
  4. }
  5. tcp {
  6. port => 5000
  7. }
  8. }
  9. output {
  10. elasticsearch {
  11. hosts => "elasticsearch:9200"
  12. user => "elastic"
  13. password => "password"
  14. index => "%{[@metadata]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
  15. }
  16. }

cd chapter3

docker-compose -f docker-stack.yml up

common\zap.go

  1. package common
  2. import (
  3. "go.uber.org/zap"
  4. "go.uber.org/zap/zapcore"
  5. "gopkg.in/natefinch/lumberjack.v2"
  6. )
  7. var(
  8. logger *zap.SugaredLogger
  9. )
  10. func init() {
  11. //日志文件名称
  12. fileName := "micro.log"
  13. syncWriter:= zapcore.AddSync(
  14. &lumberjack.Logger{
  15. Filename: fileName, //文件名称
  16. MaxSize: 512,//MB
  17. //MaxAge: 0,
  18. MaxBackups: 0, //最大备份
  19. LocalTime: true,
  20. Compress: true, //是否启用压缩
  21. })
  22. //编码
  23. encoder:=zap.NewProductionEncoderConfig()
  24. //时间格式
  25. encoder.EncodeTime = zapcore.ISO8601TimeEncoder
  26. core:= zapcore.NewCore(
  27. // 编码器
  28. zapcore.NewJSONEncoder(encoder),
  29. syncWriter,
  30. //
  31. zap.NewAtomicLevelAt(zap.DebugLevel))
  32. log := zap.New(
  33. core,
  34. zap.AddCaller(),
  35. zap.AddCallerSkip(1))
  36. logger = log.Sugar()
  37. }
  38. func Debug(args ...interface{}) {
  39. logger.Debug(args)
  40. }
  41. func Debugf(template string, args ...interface{}) {
  42. logger.Debugf(template, args...)
  43. }
  44. func Info(args ...interface{}) {
  45. logger.Info(args...)
  46. }
  47. func Infof(template string, args ...interface{}) {
  48. logger.Infof(template, args...)
  49. }
  50. func Warn(args ...interface{}) {
  51. logger.Warn(args...)
  52. }
  53. func Warnf(template string, args ...interface{}) {
  54. logger.Warnf(template, args...)
  55. }
  56. func Error(args ...interface{}) {
  57. logger.Error(args...)
  58. }
  59. func Errorf(template string, args ...interface{}) {
  60. logger.Errorf(template, args...)
  61. }
  62. func DPanic(args ...interface{}) {
  63. logger.DPanic(args...)
  64. }
  65. func DPanicf(template string, args ...interface{}) {
  66. logger.DPanicf(template, args...)
  67. }
  68. func Panic(args ...interface{}) {
  69. logger.Panic(args...)
  70. }
  71. func Panicf(template string, args ...interface{}) {
  72. logger.Panicf(template, args...)
  73. }
  74. func Fatal(args ...interface{}) {
  75. logger.Fatal(args...)
  76. }
  77. func Fatalf(template string, args ...interface{}) {
  78. logger.Fatalf(template, args...)
  79. }

go get gopkg.in/natefinch/lumberjack.v2

提交到common仓库

浏览器访问127.0.0.1:5601 kibana 

D:\Workspace\Go\src\gopaas\base\main.go

  1. //添加日志中心
  2. 1)需要程序日志打入到日志文件中
  3. 2)在程序中添加filebeat.yml 文件
  4. 3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  5. common.Info("添加日志系统!")
  6. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")

base\filebeat.yml 

# filebeat 下载地址

# https://www.elastic.co/cn/downloads/past-releases/filebeat-7-9-3/

3-11 go-micro v3 添加监控中心 

go-micro v3 技术栈- 监控系统 prometheus + grafana
docker-compose 使用引入监控体系
prometheus 公共代码编写
base 基础代码启动 promethues,grafana监控看板

docker-compose\chapter3\docker-compose.yml

  1. #添加监控镜像
  2. prometheus:
  3. image: prometheus
  4. volumes:
  5. - ./prometheus.yml:/etc/prometheus/prometheus.yml
  6. ports:
  7. - "9090:9090"
  8. #监控看板,默认密码为admin/admin
  9. grafana:
  10. image: grafana
  11. ports:
  12. - "3000:3000"

docker-compose\chapter3\prometheus.yml

  1. global:
  2. scrape_interval: 15s #默认15秒采集一次
  3. external_labels:
  4. monitor: 'go-paas-monitor'
  5. scrape_configs:
  6. #监控的服务
  7. - job_name: 'base'
  8. scrape_interval: 5s #覆盖默认值
  9. static_configs:
  10. # 这个可以改,但是需要每个服务能暴露访问到
  11. - targets: ['192.168.204.130:9192']

docker-compose up

common\prometheus.go

  1. package common
  2. import (
  3. "github.com/prometheus/client_golang/prometheus/promhttp"
  4. "github.com/prometheus/common/log"
  5. "net/http"
  6. "strconv"
  7. )
  8. func PrometheusBoot(port int) {
  9. http.Handle("/metrics",promhttp.Handler())
  10. //启动web 服务
  11. go func() {
  12. err := http.ListenAndServe("0.0.0.0:"+strconv.Itoa(port),nil)
  13. if err !=nil {
  14. log.Fatal("启动失败")
  15. }
  16. log.Info("监控启动,端口为:"+strconv.Itoa(port))
  17. }()
  18. }

git add .

git commit -m "添加监控"

git push

D:\Workspace\Go\src\gopaas\base\main.go

  1. //5.添加监控
  2. common.PrometheusBoot(prometheusPort)

启动查看grafana 127.0.0.1:3000 

添加数据源192.168.204.130:9090

创建看板go gc 时间

Metrics go_gc_duration_seconds

3-12 总结&思考

主要内容
go-micro v3 框架介绍和说明
docker-compose 的编写和使用
微服务技术栈介绍

作业
完成go-micro v3技术栈添加
理解回顾原理较深入的中间件
根据课程内容完成 docker-compose yml 文件编写 

3-13 【扩展阅读】升入源码理解 Go-micro v3

第4章 云原生 Go PaaS 平台 K8s 快速入门

开发 PaaS 平台必须要对底层 K8s 的核心有深入的了解,探究 k8s 核心组件以及核心组件的原理。

4-1 Go PaaS 平台k8s 架构原理

K8S的原理架构
K8S核心组件说明
K8S系统安装

K8S相关术语
主机(Master):用于控制 Kubernetes 节点的计算机。所有任务分配都来自于此
节点(Node):负责执行请求和所分配任务的计算机。由 Kubernetes 主机负责对节点进行控制。
容器集(Pod):被部署在单个节点上的,且包含一个或多个容器的容器组。同一容器集中的所有容器共享同一个IP 地址、IPC、主机名称及其它资源

服务 (Service):将工作内容与容器集分离
Kubelet:运行在节点上的服务,可读取容器清单 (container manifest),确保指定的容器启动并运行。
kubectl: Kubernetes 的命令行配置工具

K8S架构原理

4-2 Go PaaS 平台 k8s 核心组件-apiserver 架构原理讲解

核心组件K8S
集群管理入口: kube-apiserver
管理控制中心: kube-controller-manager
调度器: kube-scheduler

K8S核心组件
配置中心:etcd
集群管理工具: kubectl
节点 POD 管家: kubelet

K8S 核心组件-apiserver 架构解析

4-3 Go PaaS 平台 controller 与 scheduler 调度器原理(上)

K8S 核心组件- Controller Manager
副本控制器: Replication Controller
节点控制器: Node Controller
资源控制器: ResourceQuota Controller

命名空间控制器:Namespace Controller
Endpoints 控制器: Endpoints Controller

服务控制器: Service Controller

K8S 核心组件- Replication Manager 职责
确保在当前集群中有且仅有N个Pod实例,N是在RC中定义的Pod副本数量
通过调整RC的spec.replicas属性值来实现系统扩容或者缩容

通过改变RC中的Pod模板(主要是镜像版本)来实现系统的 滚动升级

K8S 核心组件- ResourceQuota Manager 三个层次资源配额管理
容器级别-可以对CPU和Memory进行限制。
Pod级别-可以对一个Pod内所有容器的可用资源进行限制
Namespace级别,为Namespace(多租户)级别的资源限制,包括:POD 、RC、Service、ResourceQuota、Secret、PV数量.

4-4 Go PaaS 平台 controller 与 scheduler 调度器原理(下)

K8S 核心组件- Endpoints Controller 说明

K8S 核心组件- 调度器 scheduler

作用:承接controller 创建的pod,为其安排可以运行的目标node。
默认调度流程一:预选调度
默认调度流程二:最优节点调度

 K8S 核心组件- 调度器 scheduler 预选策略
NoDisConflict:检查备选pod的所有volume与备选节点上的均无冲突
PodFitsResource:判断备选节点资源是否满足
PodsSelectorMatches:判断备选节点是否包含制定的标签选择器

PodFitsHost:判断备选pod的nodename是否与备选节点一致
checkNodeLabelPresence:判断是否选择备份节点
PodFitsPorts:判断备选节点端口是否被占用

K8S 核心组件- 调度器 scheduler 优选策略
LeastRequestdPriority:从备选节点列表中选出资源消耗最小的节点
CalculateNodeLabelPriority: 计算是否选择备份节点
BalancedResourceAllocation: 从备选节点中选择资源占用最小的

4-5 Go PaaS 平台 Service,deployment,pod的关系

K8S 核心组件- service,deployment,pod的关系

4-6 【扩展阅读】RS和Replicaset 区别

4-7 k8s的安装(上)

GO PaaS 平台 K8S 安装

K8S集群安装说明
K8s的集群安装分为:单Master,多Master
可以使用的机器:阿里云,腾讯云或者自己的虚拟机

K8S集群安装基础
两台2核4G 服务器
CentOS 7.8 或 CentOS Stream 8
Kubernetes v1.21.X

Kubernetes v1.24.2

4-8 k8s的安装(下)

gopaas\k8s-install\k8s 安装指导说明.md

  1. ## Step 1 : 首先在每台机器上设置hostname
  2. #### 1.1 : 修改 hostname master.wu.com 或者 node1.wu.com
  3. `hostnamectl set-hostname xxxxxxx`
  4. #### 1.2 : 查看修改结果
  5. `hostnamectl status`
  6. #### 1.3 : 设置 hostname 解析
  7. `echo "127.0.0.1 $(hostname)" >> /etc/hosts`
  8. ## Step 2 :机器检查
  9. 所有节点必须保证以下条件
  10. - 任意节点 centos 版本为 7.6 , 7.7 , 7.8 或者 centos stream 8
  11. - 任意节点 CPU 内核数量大于等于 2,且内存大于等于 4G
  12. - 任意节点 hostname 不是 localhost,且不包含下划线、小数点、大写字母
  13. - 任意节点都有固定的内网 IP 地址
  14. - 任意节点都只有一个网卡,如果有特殊目的,我可以在完成 K8S 安装后再增加新的网卡
  15. - 任意节点上 Kubelet使用的 IP 地址 可互通(无需 NAT 映射即可相互访问),且没有防火墙、安全组隔离
  16. - 任意节点不会直接使用 docker run 或 docker-compose 运行容器
  17. ## Step 3 :base-install.sh 所有节点基础安装
  18. 把 base-install.sh 拷贝到服务器
  19. - 执行 这是阿里云镜像地址:
  20. `export REGISTRY_MIRROR=https://registry.cn-shanghai.aliyuncs.com`
  21. - 执行 `./base_install.sh 1.21.5`
  22. ## Step 4 : 初始化 Master 节点 (只在 Master 节点执行)
  23. ### 4.1 :设置变量
  24. ```
  25. # 只在 master 节点执行
  26. # 替换 x.x.x.x 为 master 节点实际 IP(请使用内网 IP)
  27. # export 命令只在当前 shell 会话中有效,开启新的 shell 窗口后,如果要继续安装过程,请重新执行此处的 export 命令
  28. export MASTER_IP=x.x.x.x
  29. # 替换 apiserver.wu.com 为 您想要的 dnsName
  30. export APISERVER_NAME=apiserver.wu.com
  31. # Kubernetes 容器组所在的网段,该网段安装完成后,由 kubernetes 创建,事先并不存在于您的物理网络中
  32. export POD_SUBNET=10.100.0.1/16
  33. echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
  34. ```
  35. ### 4.2 :执行 `./install_master.sh 1.21.5`
  36. ### 4.3 : 检查执行结果
  37. ```
  38. # 只在 master 节点执行
  39. # 执行如下命令,等待 3-10 分钟,直到所有的容器组处于 Running 状态
  40. watch kubectl get pod -n kube-system -o wide
  41. # 查看 master 节点初始化结果
  42. kubectl get nodes -o wide
  43. ```
  44. ### 4.4 : 在Master节点上安装 Flannel 网络插件
  45. flannel-v0.14.0.yaml
  46. ```
  47. export POD_SUBNET=10.100.0.0/16
  48. sed -i "s#10.244.0.0/16#${POD_SUBNET}#" flannel-v0.14.0.yaml
  49. kubectl apply -f ./flannel-v0.14.0.yaml
  50. ```
  51. ## Step 5 :初始化 Worker 节点
  52. ### 5.1 : 首先在 Master 节点上执行以下命令
  53. ```
  54. # 只在 master 节点执行
  55. kubeadm token create --print-join-command
  56. ```
  57. 可获取kubeadm join 命令及参数,如下所示
  58. ```
  59. # kubeadm token create 命令的输出,形如:
  60. kubeadm join apiserver.wu.com:6443 --token o5vmo9.bazxuhkyew9rajvi --discovery-token-ca-cert-hash sha256:956583e510265cb6ec4bd5f11f36a05917e822aa7e3fbf950bce0e6d732ad956
  61. ```
  62. >该 token 的有效时间为 2 个小时,2小时内,您可以使用此 token 初始化任意数量的 worker 节点。
  63. ### 5.2 : 初始化 worker (只在worker 节点执行)
  64. ```
  65. # 只在 worker 节点执行
  66. # 替换 x.x.x.x 为 master 节点的内网 IP
  67. # export 命令只在当前 shell 会话中有效,开启新的 shell 窗口后,如果要继续安装过程,请重新执行此处的 export 命令
  68. export MASTER_IP=x.x.x.x
  69. # 替换 apiserver.wu.com 为 您想要的 dnsName
  70. export APISERVER_NAME=apiserver.wu.com
  71. echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
  72. ```
  73. ### 5.3 : 执行 Master 节点上 token 信息加入集群
  74. ```
  75. # 替换为 master 节点上 kubeadm token create 命令的输出
  76. kubeadm join apiserver.wu.com:6443 --token o5vmo9.bazxuhkyew9rajvi --discovery-token-ca-cert-hash sha256:956583e510265cb6ec4bd5f11f36a05917e822aa7e3fbf950bce0e6d732ad956
  77. ```
  78. ### 5.4 :检查初始化结果
  79. 在 master 节点上执行(只在Master上)
  80. `kubectl get nodes -o wide`

D:\Workspace\gopaas\k8s-install\base_install.sh

  1. #!/bin/bash
  2. # 在 master 节点和 node 节点都要执行
  3. # 阿里云 docker hub 镜像
  4. #export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
  5. # 在 master 节点和 node 节点都要执行
  6. # 安装 containerd
  7. # 参考文档如下
  8. # https://kubernetes.io/docs/setup/production-environment/container-runtimes/#containerd
  9. # cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
  10. # overlay
  11. # br_netfilter
  12. # EOF
  13. # sudo modprobe overlay
  14. # sudo modprobe br_netfilter
  15. # # Setup required sysctl params, these persist across reboots.
  16. # cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
  17. # net.bridge.bridge-nf-call-iptables = 1
  18. # net.ipv4.ip_forward = 1
  19. # net.bridge.bridge-nf-call-ip6tables = 1
  20. # EOF
  21. # sysctl --system
  22. # 卸载旧版本
  23. # yum remove -y containerd.io
  24. # 卸载旧版本
  25. yum remove -y docker \
  26. docker-client \
  27. docker-client-latest \
  28. docker-ce-cli \
  29. docker-common \
  30. docker-latest \
  31. docker-latest-logrotate \
  32. docker-logrotate \
  33. docker-selinux \
  34. docker-engine-selinux \
  35. docker-engine
  36. # 设置 yum repository
  37. yum install -y yum-utils device-mapper-persistent-data lvm2
  38. yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  39. # 安装并启动 docker
  40. yum install -y docker-ce docker-ce-cli
  41. # yum install -y containerd.io-1.4.3
  42. mkdir /etc/docker || true
  43. cat > /etc/docker/daemon.json <<EOF
  44. {
  45. "registry-mirrors": ["${REGISTRY_MIRROR}"],
  46. "exec-opts": ["native.cgroupdriver=systemd"],
  47. "log-driver": "json-file",
  48. "log-opts": {
  49. "max-size": "100m"
  50. },
  51. "storage-driver": "overlay2",
  52. "storage-opts": [
  53. "overlay2.override_kernel_check=true"
  54. ]
  55. }
  56. EOF
  57. mkdir -p /etc/systemd/system/docker.service.d
  58. # Restart Docker
  59. systemctl daemon-reload
  60. systemctl enable docker
  61. systemctl restart docker
  62. # mkdir -p /etc/containerd
  63. # containerd config default > /etc/containerd/config.toml
  64. # sed -i "s#k8s.gcr.io#registry.aliyuncs.com/k8sxio#g" /etc/containerd/config.toml
  65. # sed -i '/containerd.runtimes.runc.options/a\ \ \ \ \ \ \ \ \ \ \ \ SystemdCgroup = true' /etc/containerd/config.toml
  66. # sed -i "s#https://registry-1.docker.io#${REGISTRY_MIRROR}#g" /etc/containerd/config.toml
  67. # systemctl daemon-reload
  68. # systemctl enable containerd
  69. # systemctl restart containerd
  70. # 安装 nfs-utils
  71. # 必须先安装 nfs-utils 才能挂载 nfs 网络存储
  72. yum install -y nfs-utils
  73. yum install -y wget
  74. # 关闭 防火墙
  75. systemctl stop firewalld
  76. systemctl disable firewalld
  77. # 关闭 SeLinux
  78. setenforce 0
  79. sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
  80. # 关闭 swap
  81. swapoff -a
  82. yes | cp /etc/fstab /etc/fstab_bak
  83. cat /etc/fstab_bak |grep -v swap > /etc/fstab
  84. # 配置K8S的yum源
  85. cat <<EOF > /etc/yum.repos.d/kubernetes.repo
  86. [kubernetes]
  87. name=Kubernetes
  88. baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
  89. enabled=1
  90. gpgcheck=0
  91. repo_gpgcheck=0
  92. gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
  93. http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
  94. EOF
  95. # 卸载旧版本
  96. yum remove -y kubelet kubeadm kubectl
  97. # 安装kubelet、kubeadm、kubectl
  98. # 将 ${1} 替换为 kubernetes 版本号,例如 1.19.5
  99. yum install -y kubelet-${1} kubeadm-${1} kubectl-${1}
  100. # crictl config runtime-endpoint /run/containerd/containerd.sock
  101. # 重启 docker,并启动 kubelet
  102. systemctl daemon-reload
  103. systemctl restart docker
  104. systemctl enable kubelet && systemctl start kubelet
  105. docker --version
  106. kubelet --version

k8s-install\check_host.sh 

  1. # 在 master 节点和 worker 节点都要执行
  2. cat /etc/redhat-release
  3. # 此处 hostname 的输出将会是该机器在 Kubernetes 集群中的节点名字
  4. # 不能使用 localhost 作为节点的名字
  5. hostname
  6. # 请使用 lscpu 命令,核对 CPU 信息
  7. # Architecture: x86_64 本安装文档不支持 arm 架构
  8. # CPU(s): 2 CPU 内核数量不能低于 2
  9. lscpu

k8s-install\flannel-v0.14.0.yaml

  1. ---
  2. kind: Namespace
  3. apiVersion: v1
  4. metadata:
  5. name: kube-flannel
  6. labels:
  7. pod-security.kubernetes.io/enforce: privileged
  8. ---
  9. kind: ClusterRole
  10. apiVersion: rbac.authorization.k8s.io/v1
  11. metadata:
  12. name: flannel
  13. rules:
  14. - apiGroups:
  15. - ""
  16. resources:
  17. - pods
  18. verbs:
  19. - get
  20. - apiGroups:
  21. - ""
  22. resources:
  23. - nodes
  24. verbs:
  25. - list
  26. - watch
  27. - apiGroups:
  28. - ""
  29. resources:
  30. - nodes/status
  31. verbs:
  32. - patch
  33. ---
  34. kind: ClusterRoleBinding
  35. apiVersion: rbac.authorization.k8s.io/v1
  36. metadata:
  37. name: flannel
  38. roleRef:
  39. apiGroup: rbac.authorization.k8s.io
  40. kind: ClusterRole
  41. name: flannel
  42. subjects:
  43. - kind: ServiceAccount
  44. name: flannel
  45. namespace: kube-flannel
  46. ---
  47. apiVersion: v1
  48. kind: ServiceAccount
  49. metadata:
  50. name: flannel
  51. namespace: kube-flannel
  52. ---
  53. kind: ConfigMap
  54. apiVersion: v1
  55. metadata:
  56. name: kube-flannel-cfg
  57. namespace: kube-flannel
  58. labels:
  59. tier: node
  60. app: flannel
  61. data:
  62. cni-conf.json: |
  63. {
  64. "name": "cbr0",
  65. "cniVersion": "0.3.1",
  66. "plugins": [
  67. {
  68. "type": "flannel",
  69. "delegate": {
  70. "hairpinMode": true,
  71. "isDefaultGateway": true
  72. }
  73. },
  74. {
  75. "type": "portmap",
  76. "capabilities": {
  77. "portMappings": true
  78. }
  79. }
  80. ]
  81. }
  82. net-conf.json: |
  83. {
  84. "Network": "10.244.0.0/16",
  85. "Backend": {
  86. "Type": "vxlan"
  87. }
  88. }
  89. ---
  90. apiVersion: apps/v1
  91. kind: DaemonSet
  92. metadata:
  93. name: kube-flannel-ds
  94. namespace: kube-flannel
  95. labels:
  96. tier: node
  97. app: flannel
  98. spec:
  99. selector:
  100. matchLabels:
  101. app: flannel
  102. template:
  103. metadata:
  104. labels:
  105. tier: node
  106. app: flannel
  107. spec:
  108. affinity:
  109. nodeAffinity:
  110. requiredDuringSchedulingIgnoredDuringExecution:
  111. nodeSelectorTerms:
  112. - matchExpressions:
  113. - key: kubernetes.io/os
  114. operator: In
  115. values:
  116. - linux
  117. hostNetwork: true
  118. priorityClassName: system-node-critical
  119. tolerations:
  120. - operator: Exists
  121. effect: NoSchedule
  122. serviceAccountName: flannel
  123. initContainers:
  124. - name: install-cni-plugin
  125. #image: flannelcni/flannel-cni-plugin:v1.1.0 for ppc64le and mips64le (dockerhub limitations may apply)
  126. image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0
  127. command:
  128. - cp
  129. args:
  130. - -f
  131. - /flannel
  132. - /opt/cni/bin/flannel
  133. volumeMounts:
  134. - name: cni-plugin
  135. mountPath: /opt/cni/bin
  136. - name: install-cni
  137. #image: flannelcni/flannel:v0.19.2 for ppc64le and mips64le (dockerhub limitations may apply)
  138. image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.2
  139. command:
  140. - cp
  141. args:
  142. - -f
  143. - /etc/kube-flannel/cni-conf.json
  144. - /etc/cni/net.d/10-flannel.conflist
  145. volumeMounts:
  146. - name: cni
  147. mountPath: /etc/cni/net.d
  148. - name: flannel-cfg
  149. mountPath: /etc/kube-flannel/
  150. containers:
  151. - name: kube-flannel
  152. #image: flannelcni/flannel:v0.19.2 for ppc64le and mips64le (dockerhub limitations may apply)
  153. image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.2
  154. command:
  155. - /opt/bin/flanneld
  156. args:
  157. - --ip-masq
  158. - --kube-subnet-mgr
  159. resources:
  160. requests:
  161. cpu: "100m"
  162. memory: "50Mi"
  163. limits:
  164. cpu: "100m"
  165. memory: "50Mi"
  166. securityContext:
  167. privileged: false
  168. capabilities:
  169. add: ["NET_ADMIN", "NET_RAW"]
  170. env:
  171. - name: POD_NAME
  172. valueFrom:
  173. fieldRef:
  174. fieldPath: metadata.name
  175. - name: POD_NAMESPACE
  176. valueFrom:
  177. fieldRef:
  178. fieldPath: metadata.namespace
  179. - name: EVENT_QUEUE_DEPTH
  180. value: "5000"
  181. volumeMounts:
  182. - name: run
  183. mountPath: /run/flannel
  184. - name: flannel-cfg
  185. mountPath: /etc/kube-flannel/
  186. - name: xtables-lock
  187. mountPath: /run/xtables.lock
  188. volumes:
  189. - name: run
  190. hostPath:
  191. path: /run/flannel
  192. - name: cni-plugin
  193. hostPath:
  194. path: /opt/cni/bin
  195. - name: cni
  196. hostPath:
  197. path: /etc/cni/net.d
  198. - name: flannel-cfg
  199. configMap:
  200. name: kube-flannel-cfg
  201. - name: xtables-lock
  202. hostPath:
  203. path: /run/xtables.lock
  204. type: FileOrCreate

k8s-install\install_master.sh

  1. #!/bin/bash
  2. # 只在 master 节点执行
  3. # 脚本出错时终止执行
  4. set -e
  5. if [ ${#POD_SUBNET} -eq 0 ] || [ ${#APISERVER_NAME} -eq 0 ]; then
  6. echo -e "\033[31;1m请确保您已经设置了环境变量 POD_SUBNET 和 APISERVER_NAME \033[0m"
  7. echo 当前POD_SUBNET=$POD_SUBNET
  8. echo 当前APISERVER_NAME=$APISERVER_NAME
  9. exit 1
  10. fi
  11. # 查看完整配置选项 https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2
  12. rm -f ./kubeadm-config.yaml
  13. cat <<EOF > ./kubeadm-config.yaml
  14. ---
  15. apiVersion: kubeadm.k8s.io/v1beta2
  16. kind: ClusterConfiguration
  17. kubernetesVersion: v${1}
  18. imageRepository: k8s.gcr.io
  19. controlPlaneEndpoint: "${APISERVER_NAME}:6443"
  20. networking:
  21. serviceSubnet: "10.96.0.0/16"
  22. podSubnet: "${POD_SUBNET}"
  23. dnsDomain: "cluster.local"
  24. dns:
  25. type: CoreDNS
  26. imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
  27. imageTag: 1.8.0
  28. ---
  29. apiVersion: kubelet.config.k8s.io/v1beta1
  30. kind: KubeletConfiguration
  31. cgroupDriver: systemd
  32. EOF
  33. # kubeadm init
  34. # 根据您服务器网速的情况,您需要等候 3 - 10 分钟
  35. echo ""
  36. echo "抓取镜像,请稍候..."
  37. kubeadm config images pull --config=kubeadm-config.yaml
  38. echo ""
  39. echo "初始化 Master 节点"
  40. kubeadm init --config=kubeadm-config.yaml --upload-certs
  41. # 配置 kubectl
  42. rm -rf /root/.kube/
  43. mkdir /root/.kube/
  44. cp -i /etc/kubernetes/admin.conf /root/.kube/config

4-9 总结&思考

主要内容
介绍 k8s 基础概念,核心原理,核心组件
K8s集群化安装

经验之谈
本章K8s 原理,组件原理,安装,简单实用能够带领大家入门k8s
生产环境中k8s还有许多要注意的地方,比如分布式存储

K8s网络通信是啥样?
K8s里面的应用能直接访问外网吗?
K8s网络外的如何访问内部应用?

第5章 云原生 Go PaaS 平台应用服务管理功能开发,产品化创建资源

容器应用的管理为 PaaS 平台的核心内容,更是平时使用最多的模块,该模块对生产使用,动态创建,资源分配都有极大的简化作用,能够帮助研发,运维人员通过改功能,快速创建需要的资源及需要部署的应用,完成相关模块功能的开发,并掌握 K8S 部署的实用技巧。

5-1 PaaS 平台应用开发-Deployment介绍

主要内容
Deployment 原理讲解
POD 原理说明及生命周期介绍
基于POD开发PaaS平台应用管理功能

Deployment 是什么?
Deployment的作用
Deployment 和 ReplicaSet 和 Pod 的关系
Deployment 滚动更新,回滚原理讲解

Deployment的作用
定义一组 Pod 期望数量,Controller 会维持 Pod 数量
能够制定Pod 的发布策略(比如:滚动发布
能够让Pod 发布支持回滚操作

Deployment 与 ReplicaSet 和 Pod 的关系
定义一组 Pod 期望数量,Controller 会维持 Pod 数量
能够制定 Pod 的发布策略(比如:滚动发布)

Deployment 的同步触发条件
Deployment 内容发生了改变
Deployment 关联的 ReplicaSet 发生改变
Deployment 相关的 Pod 数量为0,Pod 的删除事件 

Deployment 滚动更新
更新策略选用 RollingUpdate
滚动更新策略参数:maxUnavailable 最大不可用
滚动更新策略参数:maxSurge 额外创建个数

Deployment 回滚操作
Deployment 资源都会包含有 revision 这个概念,可以回滚
spec.revisionHistoryLimit 数量内的replicaSet版本会保存
保存的replicaset 只是没有对于的pod相关的信息还在 

5-2 PaaS 平台Pod 基本概念依据调度策略介绍

Pod 快速入门
什么是Pod?
Pod 相关基础知识
Pod 高级设置(例:亲和性,反亲和性,污点,容忍)

什么是 Pod ?
Pod 是k8s里面能够被调度的最小逻辑单元(原子单元)
1个Pod 里面可以运行多个容器

Pod 共享哪些资源?
PID命名空间: Pod中的不同应用程序可以看到其他应用程序的进程ID;
网络命名空间: Pod中的多个容器能够访问同一个IP和端口范围;

IPC命名空间:Pod中的多个容器能够使用SystemVIPC或POSIX消息队列进行通信:
UTS命名空间: Pod中的多个容器共享一个主机名:
Volumes(共享存储卷): Pod中的各个容器可以访问在Pod级别定义的Volumes; 

Pod的生命周期

Pending: API Server已经创建了该Pod,但Pod中的一个或多个容器的镜像还没有创建,包括镜像下载过程
Running: Pod内所有容器已创建,且至少一个容器处于运行状态、正在启动状态或正在重启状态

Succeeded:Pod内所有容器均成功执行退出,且不会再重启

Failed:Pod内所有容器均已退出,但至少一个容器退出失败

Unknown:由于某种原因无法获取Pod状态,例如网络通信不畅

Pod 的重启策略
Always:当容器失效时,由kubelet自动重启该容器
OnFailure:当容器终止运行且退出码不为0时重启
Never: 不论容器运行状态如何,kubelet都不会重启该容器

Pod管理控制器: replicat,Job,DaemonSet 及 Kubelet
RC和DaemonSet: 必须设置为Aways,要保证该容器持续运行
Job: OnFailure或Never,确保容器执行完后不再重启

kubelet: Pod失效时重启,并且不进行健康检查

Pod 健康检查
Pod的健康状态由两类探针来检查
LivenessProbe
ReadinessProbe

Pod 健康检查 LivenessProbe 探针
用于判断容器是否存活(running状态)
如果不健康,根据重启策略做响应的处理
不包含LivenessProbe探针,永远返回为“success

initialDelaySeconds: 启动容器后首次进行健康检查的等待时间单位为秒。
timeoutSeconds: 健康检查发送请求后等待响应的时间

Pod 健康检查 ReadinessProbe 探针
用于判断容器是否启动完成(read状态),可以接受请求
如果ReadnessProbe探针检测失败,则Pod的状态将被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Endpoint。

Pod 调度-RC、Deployment:全自动调度策略
系统内置调度算法[最优Node]
NodeSelector[定向调度]: 指定调度到目标类型的机器上

NodeAffinity[亲和性调度]

Pod 调度-NodeAffinity 节点亲和性调度
通过In (属于)、Notln (不属于)
Exists(存在一个条件)、DoesNotExist (不存在)
Gt(大于)、Lt(小于)等操作符来选择Node,使调度更加灵活

Pod 调度 - DaemonSet: 特定场景调度
在每个Node上运行一个GlusterFS存储或者Ceph存储的daemon进程
在每个Node上运行一个日志采集程序,如: logstash
采集该Node的运行性能数据,如: Prometheus Node Exportor

Pod 调度 - Job:批处理调度
Job Template Expansion调度模式
Queue with Pod Per Work Item模式
Queue with Variable Pod Count调度模式

 

Pod 调度-PodAffinity Pod亲和性和反亲和性
pod 亲和性主要解决 pod 可以和哪些 pod 部署在同一个拓扑域中的问题(其中拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的 cluster、zone 等等)
pod 反亲和性主要是解决 pod 不能和哪些 pod 部署在同一个拓扑域中的问题

Pod 调度-污点(Taints) 与容忍(tolerations
Taint (污点)和 Toleration (容忍)可以作用于 node 和 pod 上
其目的是优化 pod 在集群间的调度,这跟节点亲和性相反,
具有 taint 的 node 和 pod 是互斥关系

5-3 基于go mod的相关设置

gomod的配置
设置代理: go env -w GOPROXY=https://goproxy.io,direct
设置私有仓库: go env -w GOPRIVATE=*.xxx.com

Git 的相关设置
go get 内部使用https的git clone 命令默认只支持公有仓库

Git 设置支持 go get 私有仓库
替换https 为ssh 请求,这里设置ssh 是80端口不是默认的22

git config --global url."ssh://git@git.xxx.com:80/".insteadOf
"https://git.xxx.com/"

Git 设置支持 go get 私有仓库
生成 ssh ssh-keygen -t rsa -C"xxxx@xxx.com'

设置git仓库ssh密钥

5-4 GO PaaS 平台开发工程目录创建及说明

代码开发
工程目录结构
服务端和API开发
(网关代码,proto制作方法等网关及相关工具讲解

D:\Workspace\gopaas\pod

5-5 Go PaaS 平台 Pod 模型的开发(上)

D:\Workspace\Go\src\gopaas\pod\domain\model\pod.go

  1. package model
  2. //POD的状态
  3. //挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
  4. //运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
  5. //成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
  6. //失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
  7. //未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。
  8. type Pod struct {
  9. ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
  10. PodName string `gorm:"unique_index;not_null" json:"pod_name"`
  11. PodNamespace string `json:"pod_namespace"`
  12. //POD 所属的团队
  13. PodTeamID string `json:"pod_team_id"`
  14. //POD 使用的CPU最小值
  15. PodCpuMin float32 `json:"pod_cpu_min"`
  16. //POD 使用的CPU最大值
  17. PodCpuMax float32 `json:"pod_cpu_max"`
  18. //副本数量
  19. PodReplicas int32 `json:"pod_replicas"`
  20. //POD 使用的内存最小值
  21. PodMemoryMin float32 `json:"pod_memory_min"`
  22. //POD 使用的内存最大值
  23. PodMemoryMax float32 `json:"pod_memory_max"`
  24. //POD 开放的端口
  25. PodPort []PodPort `gorm:"ForeignKey:PodID" json:"pod_port"`
  26. //POD 使用的环境变量
  27. PodEnv []PodEnv `gorm:"ForeignKey:PodID" json:"pod_env"`
  28. //镜像拉取策略
  29. //Always:总是拉取 pull
  30. //IfNotPresent:默认值,本地有则使用本地镜像,不拉取
  31. //Never:只使用本地镜像,从不拉取
  32. PodPullPolicy string `json:"pod_pull_policy"`
  33. //重启策略
  34. //Always: 当容器失效时, 由kubelet自动重启该容器
  35. //OnFailure: 当容器终止运行且退出码不为0时, 由kubelet自动重启该容器
  36. //Never: 不论容器运行状态如何, kubelet都不会重启该容器
  37. //注意:
  38. //1.kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算, 例如1丶2丶4丶8倍等, 最长延时5min, 并且在重启后的10min后重置该时间
  39. //2.pod的重启策略与控制方式有关
  40. //- RC和DeamonSet必须设置为Always,需要保证该容器持续运行
  41. //- Job: OnFailure或Never, 确保容器执行完成后不再重启
  42. PodRestart string `json:"pod_restart"`
  43. //pod的发布策略
  44. //重建(recreate):停止旧版本部署新版本
  45. //滚动更新(rolling-update):一个接一个地以滚动更新方式发布新版本
  46. //蓝绿(blue/green):新版本与旧版本一起存在,然后切换流量
  47. //金丝雀(canary):将新版本面向一部分用户发布,然后继续全量发布
  48. //A/B测(a/b testing):以精确的方式(HTTP 头、cookie、权重等)向部分用户发布新版本。A/B测实际上是一种基于数据统计做出业务决策的技术。在 Kubernetes 中并不原生支持,需要额外的一些高级组件来完成改设置(比如Istio、Linkerd、Traefik、或者自定义 Nginx/Haproxy 等)。
  49. //Recreate,Custom,Rolling
  50. PodType string `json:"pod_type"`
  51. //使用的镜像名称+tag
  52. PodImage string `json:"pod_image"`
  53. //@TODO 挂盘
  54. //@TODO 域名设置
  55. }

D:\Workspace\Go\src\gopaas\pod\domain\model\pod_port.go

  1. package model
  2. type PodPort struct {
  3. ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
  4. PodID int64 `json:"pod_id"`
  5. ContainerPort int32 `json:"container_port"`
  6. Protocol string `json:"protocol"`
  7. //@TODO HostPort 需要的可以自主添加
  8. }

D:\Workspace\gopaas\pod\domain\model\pod_env.go 

  1. package model
  2. type PodEnv struct {
  3. ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
  4. PodID int64 `json:"pod_id"`
  5. EnvKey string `json:"env_key"`
  6. EnvValue string `json:"env_value"`
  7. }

5-6 Go PaaS 平台 Pod 模型的开发(下)

  1. PodType string `json:"pod_type"`
  2. //使用的镜像名称+tag
  3. PodImage string `json:"pod_image"`
  4. //@TODO 挂盘
  5. //@TODO 域名设置

5-7 GO PaaS 平台 Repository 代码开发(上)

D:\Workspace\Go\src\gopaas\pod\domain\repository\pod_repository.go

  1. PS D:\Workspace\Go\src\gopaas\pod> go mod init github.com/gopaas/pod
  2. go: creating new go.mod: module github.com/gopaas/pod
  3. go: to add module requirements and sums:
  4. go mod tidy
  1. package repository
  2. import (
  3. "github.com/gopaas/pod/domain/model"
  4. "github.com/jinzhu/gorm"
  5. )
  6. //创建需要实现的接口
  7. type IPodRepository interface {
  8. //初始化表
  9. InitTable() error
  10. //根据ID查找数据
  11. FindPodByID(int64) (*model.Pod, error)
  12. //创建一条 Pod 数据
  13. CreatePod(*model.Pod) (int64, error)
  14. //根据ID删除一条 Pod 数据
  15. DeletePodByID(int64) error
  16. //修改一条数据
  17. UpdatePod(*model.Pod) error
  18. //查找Pod所有数据
  19. FindAll() ([]model.Pod, error)
  20. }
  21. //创建 PodRepository
  22. func NewPodRepository(db *gorm.DB) IPodRepository {
  23. return &PodRepository{mysqlDb: db}
  24. }
  25. type PodRepository struct {
  26. mysqlDb *gorm.DB
  27. }
  28. func (u *PodRepository) InitTable() error {
  29. return u.mysqlDb.CreateTable(&model.Pod{}, &model.PodEnv{}, &model.PodPort{}).Error
  30. }
  31. func (u *PodRepository) FindPodByID(podID int64) (pod *model.Pod, err error) {
  32. pod = &model.Pod{}
  33. return pod, u.mysqlDb.Preload("PodEnv").Preload("PodPort").First(pod, podID).Error
  34. }
  35. func (u *PodRepository) CreatePod(pod *model.Pod) (int64, error) {
  36. return pod.ID, u.mysqlDb.Create(pod).Error
  37. }

5-8 GO PaaS 平台 Repository 代码开发(下)

D:\Workspace\Go\src\gopaas\pod\domain\repository\pod_repository.go

  1. package repository
  2. import (
  3. "github.com/gopaas/pod/domain/model"
  4. "github.com/jinzhu/gorm"
  5. )
  6. //创建需要实现的接口
  7. type IPodRepository interface {
  8. //初始化表
  9. InitTable() error
  10. //根据ID查找数据
  11. FindPodByID(int64) (*model.Pod, error)
  12. //创建一条 Pod 数据
  13. CreatePod(*model.Pod) (int64, error)
  14. //根据ID删除一条 Pod 数据
  15. DeletePodByID(int64) error
  16. //修改一条数据
  17. UpdatePod(*model.Pod) error
  18. //查找Pod所有数据
  19. FindAll() ([]model.Pod, error)
  20. }
  21. //创建 PodRepository
  22. func NewPodRepository(db *gorm.DB) IPodRepository {
  23. return &PodRepository{mysqlDb: db}
  24. }
  25. type PodRepository struct {
  26. mysqlDb *gorm.DB
  27. }
  28. //初始化表
  29. func (u *PodRepository) InitTable() error {
  30. return u.mysqlDb.CreateTable(&model.Pod{}, &model.PodEnv{}, &model.PodPort{}).Error
  31. }
  32. //根据ID查找Pod信息
  33. func (u *PodRepository) FindPodByID(podID int64) (pod *model.Pod, err error) {
  34. pod = &model.Pod{}
  35. return pod, u.mysqlDb.Preload("PodEnv").Preload("PodPort").First(pod, podID).Error
  36. }
  37. //创建 Pod
  38. func (u *PodRepository) CreatePod(pod *model.Pod) (int64, error) {
  39. return pod.ID, u.mysqlDb.Create(pod).Error
  40. }
  41. //根据 ID 删除 Pod 信息
  42. func (u *PodRepository) DeletePodByID(podID int64) error {
  43. tx := u.mysqlDb.Begin()
  44. //遇到问题回滚
  45. defer func() {
  46. if r := recover(); r != nil {
  47. tx.Rollback()
  48. }
  49. }()
  50. if tx.Error != nil {
  51. return tx.Error
  52. }
  53. //彻底删除 POD 信息
  54. if err := u.mysqlDb.Where("id = ?", podID).Delete(&model.Pod{}).Error; err != nil {
  55. tx.Rollback()
  56. return err
  57. }
  58. //彻底删除 podenv 信息
  59. if err := u.mysqlDb.Where("pod_id = ?", podID).Delete(&model.PodEnv{}).Error; err != nil {
  60. tx.Rollback()
  61. return err
  62. }
  63. //彻底删除 podport 信息
  64. if err := u.mysqlDb.Where("pod_id = ?", podID).Delete(&model.PodPort{}).Error; err != nil {
  65. tx.Rollback()
  66. return err
  67. }
  68. return tx.Commit().Error
  69. }
  70. //更新Pod信息
  71. func (u *PodRepository) UpdatePod(pod *model.Pod) error {
  72. return u.mysqlDb.Model(pod).Update(pod).Error
  73. }
  74. //获取结果集合
  75. func (u *PodRepository) FindAll() (podAll []model.Pod, err error) {
  76. return podAll, u.mysqlDb.Find(&podAll).Error
  77. }

5-9 GO PaaS 平台 Proto 对外服务开发 

D:\Workspace\Go\src\gopaas\pod\proto\pod\pod.proto

  1. syntax = "proto3";
  2. package pod;
  3. option go_package = "./proto/pod;pod";
  4. service Pod {
  5. rpc AddPod(PodInfo) returns (Response) {}
  6. rpc DeletePod(PodId) returns (Response) {}
  7. rpc FindPodByID(PodId) returns (PodInfo) {}
  8. rpc UpdatePod(PodInfo) returns (Response) {}
  9. rpc FindAllPod(FindAll) returns (AllPod){}
  10. }
  11. message PodInfo {
  12. int64 id = 1;
  13. string pod_namespace = 2;
  14. string pod_name = 3;
  15. string pod_team_id = 4;
  16. float pod_cpu_max = 5;
  17. int32 pod_replicas =6;
  18. float pod_memory_max =7;
  19. repeated PodPort pod_port =8;
  20. repeated PodEnv pod_env =9;
  21. string pod_pull_policy=10;
  22. string pod_restart =11;
  23. string pod_type=12;
  24. string pod_image=13;
  25. }
  26. message PodPort {
  27. int64 pod_id =1;
  28. int32 container_port =2;
  29. string protocol =3;
  30. }
  31. message PodEnv {
  32. int64 pod_id =1;
  33. string env_key =2;
  34. string env_value =3;
  35. }
  36. message PodId {
  37. int64 id =1;
  38. }
  39. message Response {
  40. string msg =1;
  41. }
  42. message FindAll{
  43. }
  44. message AllPod {
  45. repeated PodInfo pod_info =1 ;
  46. }
PS D:\Workspace\Go\bin> D:\Workspace\Go\bin\protoc --proto_path=D:\Workspace\Go\src\gopaas\pod --micro_out=D:\Workspace\Go\src\gopaas\pod --go_out=:D:\Workspace\Go\src\gopaas\pod proto/pod/pod.proto

5-10 GO PaaS 平台 Service 开发(1)

D:\Workspace\Go\src\gopaas\pod\domain\serivce\pod_data_service.go

  1. package serivce
  2. import (
  3. "github.com/gopaas/pod/domain/model"
  4. "github.com/gopaas/pod/domain/repository"
  5. "github.com/gopaas/pod/proto/pod"
  6. v1 "k8s.io/api/apps/v1"
  7. "k8s.io/client-go/kubernetes"
  8. )
  9. type IPodDataService interface {
  10. AddPod(*model.Pod) (int64, error)
  11. DeletePod(int64) error
  12. UpdatePod(*model.Pod) error
  13. FindPodByID(int64) (*model.Pod, error)
  14. FindAllPod() ([]model.Pod, error)
  15. CreateToK8s(*pod.PodInfo) error
  16. DeleteFromK8s(*model.Pod) error
  17. UpdateToK8s(*pod.PodInfo) error
  18. }
  19. func NewPodDataService(podRepository repository.IPodRepository, clientSet *kubernetes.Clientset) IPodDataService {
  20. return &PodDataService{
  21. PodRepository: podRepository,
  22. K8sClientSet: clientSet,
  23. deployment: &v1.Deployment{},
  24. }
  25. }
  26. type PodDataService struct {
  27. PodRepository repository.IPodRepository
  28. K8sClientSet *kubernetes.Clientset
  29. deployment *v1.Deployment
  30. }
  31. //添加Pod
  32. func (u *PodDataService) AddPod(pod2 *model.Pod) (int64, error) {
  33. return u.PodRepository.CreatePod(pod2)
  34. }
  35. //删除
  36. func (u *PodDataService) DeletePod(podID int64) error {
  37. return u.PodRepository.DeletePodByID(podID)
  38. }
  39. //更新
  40. func (u *PodDataService) UpdatePod(pod2 *model.Pod) error {
  41. return u.PodRepository.UpdatePod(pod2)
  42. }
  43. //单个查找
  44. func (u *PodDataService) FindPodByID(podID int64) (*model.Pod, error) {
  45. return u.PodRepository.FindPodByID(podID)
  46. }
  47. //查找所有
  48. func (u *PodDataService) FindAllPod() ([]model.Pod, error) {
  49. return u.PodRepository.FindAll()
  50. }

go get k8s.io/client-go/kubernetes@v0.24.2

5-11 GO PaaS 平台 Service 开发(2)

D:\Workspace\Go\src\gopaas\pod\domain\serivce\pod_data_service.go

  1. package serivce
  2. import (
  3. "strconv"
  4. "github.com/gopaas/pod/domain/model"
  5. "github.com/gopaas/pod/domain/repository"
  6. "github.com/gopaas/pod/proto/pod"
  7. v1 "k8s.io/api/apps/v1"
  8. v13 "k8s.io/api/core/v1"
  9. v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
  10. "k8s.io/client-go/kubernetes"
  11. )
  12. type IPodDataService interface {
  13. AddPod(*model.Pod) (int64, error)
  14. DeletePod(int64) error
  15. UpdatePod(*model.Pod) error
  16. FindPodByID(int64) (*model.Pod, error)
  17. FindAllPod() ([]model.Pod, error)
  18. CreateToK8s(*pod.PodInfo) error
  19. DeleteFromK8s(*model.Pod) error
  20. UpdateToK8s(*pod.PodInfo) error
  21. }
  22. func NewPodDataService(podRepository repository.IPodRepository, clientSet *kubernetes.Clientset) IPodDataService {
  23. return &PodDataService{
  24. PodRepository: podRepository,
  25. K8sClientSet: clientSet,
  26. deployment: &v1.Deployment{},
  27. }
  28. }
  29. type PodDataService struct {
  30. PodRepository repository.IPodRepository
  31. K8sClientSet *kubernetes.Clientset
  32. deployment *v1.Deployment
  33. }
  34. func (u *PodDataService) CreateToK8s(podInfo *pod.PodInfo) (err error) {
  35. }
  36. func (u *PodDataService) SetDeployment(podInfo *pod.PodInfo) {
  37. deployment := &v1.Deployment{}
  38. deployment.TypeMeta = v12.TypeMeta{
  39. Kind: "deployment",
  40. APIVersion: "v1",
  41. }
  42. deployment.ObjectMeta = v12.ObjectMeta{
  43. Name: podInfo.PodName,
  44. Namespace: podInfo.PodNamespace,
  45. Labels: map[string]string{
  46. "app-name": podInfo.PodName,
  47. "author": "wu123",
  48. },
  49. }
  50. deployment.Spec = v1.DeploymentSpec{
  51. Replicas: &podInfo.PodReplicas,
  52. Selector: &v12.LabelSelector{
  53. MatchLabels: map[string]string{
  54. "app-name": podInfo.PodName,
  55. },
  56. MatchExpressions: nil,
  57. },
  58. Template: v13.PodTemplateSpec{
  59. ObjectMeta: v12.ObjectMeta{
  60. Labels: map[string]string{
  61. "app-name": podInfo.PodName,
  62. },
  63. },
  64. Spec: v13.PodSpec{
  65. Containers: []v13.Container{
  66. {
  67. Name: podInfo.PodName,
  68. Image: podInfo.PodImage,
  69. Ports: u.getContainerPort(podInfo),
  70. Env: u.getEnv(podInfo),
  71. Resources: u.getResources(podInfo),
  72. ImagePullPolicy: u.getImagePullPolicy(podInfo),
  73. },
  74. },
  75. },
  76. },
  77. Strategy: v1.DeploymentStrategy{},
  78. MinReadySeconds: 0,
  79. RevisionHistoryLimit: nil,
  80. Paused: false,
  81. ProgressDeadlineSeconds: nil,
  82. }
  83. u.deployment = deployment
  84. }
  85. func (u *PodDataService) getContainerPort(podInfo *pod.PodInfo) (containerPort []v13.ContainerPort) {
  86. for _, v := range podInfo.PodPort {
  87. containerPort = append(containerPort, v13.ContainerPort{
  88. Name: "port-" + strconv.FormatInt(int64(v.ContainerPort), 10),
  89. ContainerPort: v.ContainerPort,
  90. Protocol: u.getProtocol(v.Protocol),
  91. })
  92. }
  93. return
  94. }
  95. func (u *PodDataService) getProtocol(protocol string) v13.Protocol {
  96. switch protocol {
  97. case "TCP":
  98. return "TCP"
  99. case "UDP":
  100. return "UDP"
  101. case "SCTP":
  102. return "SCTP"
  103. default:
  104. return "TCP"
  105. }
  106. }
  107. func (u *PodDataService) getEnv(podInfo *pod.PodInfo) (envVar []v13.EnvVar) {
  108. for _, v := range podInfo.PodEnv {
  109. envVar = append(envVar, v13.EnvVar{
  110. Name: v.EnvKey,
  111. Value: v.EnvValue,
  112. ValueFrom: nil,
  113. })
  114. }
  115. return
  116. }
  117. //添加Pod
  118. func (u *PodDataService) AddPod(pod2 *model.Pod) (int64, error) {
  119. return u.PodRepository.CreatePod(pod2)
  120. }
  121. //删除
  122. func (u *PodDataService) DeletePod(podID int64) error {
  123. return u.PodRepository.DeletePodByID(podID)
  124. }
  125. //更新
  126. func (u *PodDataService) UpdatePod(pod2 *model.Pod) error {
  127. return u.PodRepository.UpdatePod(pod2)
  128. }
  129. //单个查找
  130. func (u *PodDataService) FindPodByID(podID int64) (*model.Pod, error) {
  131. return u.PodRepository.FindPodByID(podID)
  132. }
  133. //查找所有
  134. func (u *PodDataService) FindAllPod() ([]model.Pod, error) {
  135. return u.PodRepository.FindAll()
  136. }

go get k8s.io/apimachinery/pkg/apis/meta/v1@v0.24.2

go get k8s.io/api/core/v1@v0.24.2

5-12 GO PaaS 平台 Service 开发(3)

D:\Workspace\Go\src\gopaas\pod\domain\serivce\pod_data_service.go

  1. type IPodDataService interface {
  2. AddPod(*model.Pod) (int64, error)
  3. DeletePod(int64) error
  4. UpdatePod(*model.Pod) error
  5. FindPodByID(int64) (*model.Pod, error)
  6. FindAllPod() ([]model.Pod, error)
  7. CreateToK8s(*pod.PodInfo) error
  8. DeleteFromK8s(*model.Pod) error
  9. UpdateToK8s(*pod.PodInfo) error
  10. }
  11. func NewPodDataService(podRepository repository.IPodRepository, clientSet *kubernetes.Clientset) IPodDataService {
  12. return &PodDataService{
  13. PodRepository: podRepository,
  14. K8sClientSet: clientSet,
  15. deployment: &v1.Deployment{},
  16. }
  17. }
  18. type PodDataService struct {
  19. PodRepository repository.IPodRepository
  20. K8sClientSet *kubernetes.Clientset
  21. deployment *v1.Deployment
  22. }
  23. //创建pod到k8s中
  24. func (u *PodDataService) CreateToK8s(podInfo *pod.PodInfo) (err error) {
  25. u.SetDeployment(podInfo)
  26. if _, err = u.K8sClientSet.AppsV1().Deployments(podInfo.PodNamespace).Get(context.TODO(), podInfo.PodName, v12.GetOptions{}); err != nil {
  27. if _, err = u.K8sClientSet.AppsV1().Deployments(podInfo.PodNamespace).Create(context.TODO(), u.deployment, v12.CreateOptions{}); err != nil {
  28. common.Error(err)
  29. return err
  30. }
  31. common.Info("创建成功")
  32. return nil
  33. } else {
  34. //可以写自己的业务逻辑
  35. common.Error("Pod " + podInfo.PodName + "已经存在")
  36. return errors.New("Pod " + podInfo.PodName + " 已经存在")
  37. }
  38. }
  39. //更新deployment,pod
  40. func (u *PodDataService) UpdateToK8s(podInfo *pod.PodInfo) (err error) {
  41. u.SetDeployment(podInfo)
  42. if _, err = u.K8sClientSet.AppsV1().Deployments(podInfo.PodNamespace).Get(context.TODO(), podInfo.PodName, v12.GetOptions{}); err != nil {
  43. common.Error(err)
  44. return errors.New("Pod " + podInfo.PodName + " 不存在请先创建")
  45. } else {
  46. //如果存在
  47. if _, err = u.K8sClientSet.AppsV1().Deployments(podInfo.PodNamespace).Update(context.TODO(), u.deployment, v12.UpdateOptions{}); err != nil {
  48. common.Error(err)
  49. return err
  50. }
  51. common.Info(podInfo.PodName + " 更新成功")
  52. return nil
  53. }
  54. }
  55. //删除pod
  56. func (u *PodDataService) DeleteFromK8s(pod *model.Pod) (err error) {
  57. if err = u.K8sClientSet.AppsV1().Deployments(pod.PodNamespace).Delete(context.TODO(), pod.PodName, v12.DeleteOptions{}); err != nil {
  58. common.Error(err)
  59. //写自己的业务逻辑
  60. return err
  61. } else {
  62. if err := u.DeletePod(pod.ID); err != nil {
  63. common.Error(err)
  64. return err
  65. }
  66. common.Info("删除Pod ID:" + strconv.FormatInt(pod.ID, 10) + " 成功!")
  67. }
  68. return
  69. }
  70. func (u *PodDataService) SetDeployment(podInfo *pod.PodInfo) {
  71. deployment := &v1.Deployment{}
  72. deployment.TypeMeta = v12.TypeMeta{
  73. Kind: "deployment",
  74. APIVersion: "v1",
  75. }
  76. deployment.ObjectMeta = v12.ObjectMeta{
  77. Name: podInfo.PodName,
  78. Namespace: podInfo.PodNamespace,
  79. Labels: map[string]string{
  80. "app-name": podInfo.PodName,
  81. "author": "wu123",
  82. },
  83. }
  84. deployment.Name = podInfo.PodName
  85. deployment.Spec = v1.DeploymentSpec{
  86. //副本个数
  87. Replicas: &podInfo.PodReplicas,
  88. Selector: &v12.LabelSelector{
  89. MatchLabels: map[string]string{
  90. "app-name": podInfo.PodName,
  91. },
  92. MatchExpressions: nil,
  93. },
  94. Template: v13.PodTemplateSpec{
  95. ObjectMeta: v12.ObjectMeta{
  96. Labels: map[string]string{
  97. "app-name": podInfo.PodName,
  98. },
  99. },
  100. Spec: v13.PodSpec{
  101. Containers: []v13.Container{
  102. {
  103. Name: podInfo.PodName,
  104. Image: podInfo.PodImage,
  105. Ports: u.getContainerPort(podInfo),
  106. Env: u.getEnv(podInfo),
  107. Resources: u.getResources(podInfo),
  108. ImagePullPolicy: u.getImagePullPolicy(podInfo),
  109. },
  110. },
  111. },
  112. },
  113. Strategy: v1.DeploymentStrategy{},
  114. MinReadySeconds: 0,
  115. RevisionHistoryLimit: nil,
  116. Paused: false,
  117. ProgressDeadlineSeconds: nil,
  118. }
  119. u.deployment = deployment
  120. }
  121. func (u *PodDataService) getContainerPort(podInfo *pod.PodInfo) (containerPort []v13.ContainerPort) {
  122. for _, v := range podInfo.PodPort {
  123. containerPort = append(containerPort, v13.ContainerPort{
  124. Name: "port-" + strconv.FormatInt(int64(v.ContainerPort), 10),
  125. ContainerPort: v.ContainerPort,
  126. Protocol: u.getProtocol(v.Protocol),
  127. })
  128. }
  129. return
  130. }
  131. func (u *PodDataService) getProtocol(protocol string) v13.Protocol {
  132. switch protocol {
  133. case "TCP":
  134. return "TCP"
  135. case "UDP":
  136. return "UDP"
  137. case "SCTP":
  138. return "SCTP"
  139. default:
  140. return "TCP"
  141. }
  142. }
  143. func (u *PodDataService) getEnv(podInfo *pod.PodInfo) (envVar []v13.EnvVar) {
  144. for _, v := range podInfo.PodEnv {
  145. envVar = append(envVar, v13.EnvVar{
  146. Name: v.EnvKey,
  147. Value: v.EnvValue,
  148. ValueFrom: nil,
  149. })
  150. }
  151. return
  152. }
  153. func (u *PodDataService) getResources(podInfo *pod.PodInfo) (source v13.ResourceRequirements) {
  154. //最大能够使用多少资源
  155. source.Limits = v13.ResourceList{
  156. "cpu": resource.MustParse(strconv.FormatFloat(float64(podInfo.PodCpuMax), 'f', 6, 64)),
  157. "memory": resource.MustParse(strconv.FormatFloat(float64(podInfo.PodMemoryMax), 'f', 6, 64)),
  158. }
  159. //满足最少使用的资源量
  160. //@TODO 自己实现动态设置
  161. source.Requests = v13.ResourceList{
  162. "cpu": resource.MustParse(strconv.FormatFloat(float64(podInfo.PodCpuMax), 'f', 6, 64)),
  163. "memory": resource.MustParse(strconv.FormatFloat(float64(podInfo.PodMemoryMax), 'f', 6, 64)),
  164. }
  165. return
  166. }
  167. func (u *PodDataService) getImagePullPolicy(podInfo *pod.PodInfo) v13.PullPolicy {
  168. switch podInfo.PodPullPolicy {
  169. case "Always":
  170. return "Always"
  171. case "Never":
  172. return "Never"
  173. case "IfNotPresent":
  174. return "IfNotPresent"
  175. default:
  176. return "Always"
  177. }
  178. }
  179. //添加Pod
  180. func (u *PodDataService) AddPod(pod2 *model.Pod) (int64, error) {
  181. return u.PodRepository.CreatePod(pod2)
  182. }
  183. //删除
  184. func (u *PodDataService) DeletePod(podID int64) error {
  185. return u.PodRepository.DeletePodByID(podID)
  186. }
  187. //更新
  188. func (u *PodDataService) UpdatePod(pod2 *model.Pod) error {
  189. return u.PodRepository.UpdatePod(pod2)
  190. }
  191. //单个查找
  192. func (u *PodDataService) FindPodByID(podID int64) (*model.Pod, error) {
  193. return u.PodRepository.FindPodByID(podID)
  194. }
  195. //查找所有
  196. func (u *PodDataService) FindAllPod() ([]model.Pod, error) {
  197. return u.PodRepository.FindAll()
  198. }

go get github.com/yunixiangfeng/common@v1.2.1

5-13 GO PaaS 平台 Main 开发、基础中间件创建(上)

D:\Workspace\Go\src\gopaas\pod\main.go

go get github.com/asim/go-micro/plugins/registry/consul/v3

go get github.com/asim/go-micro/v3/registry

  1. package main
  2. import (
  3. "fmt"
  4. "strconv"
  5. "github.com/asim/go-micro/plugins/registry/consul/v3"
  6. "github.com/asim/go-micro/v3/registry"
  7. "github.com/jinzhu/gorm"
  8. "github.com/yunixiangfeng/common"
  9. )
  10. var (
  11. hostIp = "192.168.204.130"
  12. serviceHost = hostIp
  13. servicePort = "8081"
  14. consulHost = hostIp
  15. consulPort int64 = 8500
  16. tracerHost = hostIp
  17. tracerPort = 6831
  18. hystrixPort = 9091
  19. prometheusPort = 9191
  20. )
  21. func main() {
  22. consul := consul.NewRegistry(func(options *registry.Options) {
  23. options.Addrs = []string{
  24. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  25. }
  26. })
  27. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  28. if err != nil {
  29. common.Error(err)
  30. }
  31. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  32. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8mb4&parseTime=True&loc=Local")
  33. if err != nil {
  34. fmt.Println(err)
  35. common.Error(err)
  36. }
  37. defer db.Close()
  38. db.SingularTable(true)
  39. }

5-14 GO PaaS 平台 Main 开发、基础中间件创建(下)

D:\Workspace\Go\src\gopaas\pod\main.go

go get github.com/opentracing/opentracing-go

go get github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "net/http"
  6. "strconv"
  7. "github.com/afex/hystrix-go/hystrix"
  8. "github.com/asim/go-micro/plugins/registry/consul/v3"
  9. "github.com/asim/go-micro/v3/registry"
  10. "github.com/jinzhu/gorm"
  11. "github.com/opentracing/opentracing-go"
  12. "github.com/yunixiangfeng/common"
  13. )
  14. var (
  15. //服务地址
  16. hostIp = "192.168.204.130"
  17. //服务地址
  18. serviceHost = hostIp
  19. //服务端口
  20. servicePort = "8081"
  21. //注册中心配置
  22. consulHost = hostIp
  23. consulPort int64 = 8500
  24. //链路追踪
  25. tracerHost = hostIp
  26. tracerPort = 6831
  27. //熔断器
  28. hystrixPort = 9091
  29. //监控端口
  30. prometheusPort = 9191
  31. )
  32. func main() {
  33. //1.注册中心
  34. consul := consul.NewRegistry(func(options *registry.Options) {
  35. options.Addrs = []string{
  36. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  37. }
  38. })
  39. //2.配置中心,存放经常变动的配置
  40. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  41. if err != nil {
  42. common.Error(err)
  43. }
  44. //3.使用配置中心连接 Mysql
  45. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  46. //初始化数据库
  47. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  48. if err != nil {
  49. fmt.Println(err)
  50. common.Error(err)
  51. }
  52. defer db.Close()
  53. db.SingularTable(true)
  54. //4.添加链路追踪
  55. t, io, err := common.NewTracer("go.micro.service.pod", tracerHost+":"+strconv.Itoa(tracerPort))
  56. if err != nil {
  57. common.Error(err)
  58. }
  59. defer io.Close()
  60. opentracing.SetGlobalTracer(t)
  61. //5.添加熔断器
  62. hystrixStreamHandler := hystrix.NewStreamHandler()
  63. hystrixStreamHandler.Start()
  64. //添加监听程序
  65. go func() {
  66. //http://192.168.0.112:9092/turbine/turbine.stream
  67. //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  68. err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
  69. if err != nil {
  70. common.Error(err)
  71. }
  72. }()
  73. //6.添加日志中心
  74. //1)需要程序日志打入到日志文件中
  75. //2)在程序中添加filebeat.yml 文件
  76. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  77. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  78. //7.添加监控
  79. common.PrometheusBoot(prometheusPort)
  80. }

D:\Workspace\gopaas\pod\filebeat.yml

  1. # 输入
  2. # filebeat 下载地址
  3. # https://www.elastic.co/cn/downloads/past-releases/filebeat-7-9-3/
  4. filebeat.inputs:
  5. - type: log
  6. enabled: true
  7. paths:
  8. - ./*.log
  9. output.logstash:
  10. hosts: ["localhost:5044"]

5-15 创建k8s集群config ,通过kubectl操作k8s集群(上)

D:\Workspace\Go\src\gopaas\pod\main.go

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "path/filepath"
  8. "strconv"
  9. "github.com/afex/hystrix-go/hystrix"
  10. "github.com/asim/go-micro/plugins/registry/consul/v3"
  11. "github.com/asim/go-micro/v3/registry"
  12. "github.com/jinzhu/gorm"
  13. "github.com/opentracing/opentracing-go"
  14. "github.com/yunixiangfeng/common"
  15. "k8s.io/client-go/kubernetes"
  16. "k8s.io/client-go/tools/clientcmd"
  17. "k8s.io/client-go/util/homedir"
  18. )
  19. var (
  20. //服务地址
  21. hostIp = "192.168.204.130"
  22. //服务地址
  23. serviceHost = hostIp
  24. //服务端口
  25. servicePort = "8081"
  26. //注册中心配置
  27. consulHost = hostIp
  28. consulPort int64 = 8500
  29. //链路追踪
  30. tracerHost = hostIp
  31. tracerPort = 6831
  32. //熔断器
  33. hystrixPort = 9091
  34. //监控端口
  35. prometheusPort = 9191
  36. )
  37. func main() {
  38. //1.注册中心
  39. consul := consul.NewRegistry(func(options *registry.Options) {
  40. options.Addrs = []string{
  41. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  42. }
  43. })
  44. //2.配置中心,存放经常变动的配置
  45. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  46. if err != nil {
  47. common.Error(err)
  48. }
  49. //3.使用配置中心连接 Mysql
  50. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  51. //初始化数据库
  52. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  53. if err != nil {
  54. fmt.Println(err)
  55. common.Error(err)
  56. }
  57. defer db.Close()
  58. db.SingularTable(true)
  59. //4.添加链路追踪
  60. t, io, err := common.NewTracer("go.micro.service.pod", tracerHost+":"+strconv.Itoa(tracerPort))
  61. if err != nil {
  62. common.Error(err)
  63. }
  64. defer io.Close()
  65. opentracing.SetGlobalTracer(t)
  66. //5.添加熔断器
  67. hystrixStreamHandler := hystrix.NewStreamHandler()
  68. hystrixStreamHandler.Start()
  69. //添加监听程序
  70. go func() {
  71. //http://192.168.0.112:9092/turbine/turbine.stream
  72. //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  73. err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
  74. if err != nil {
  75. common.Error(err)
  76. }
  77. }()
  78. //6.添加日志中心
  79. //1)需要程序日志打入到日志文件中
  80. //2)在程序中添加filebeat.yml 文件
  81. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  82. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  83. //7.添加监控
  84. common.PrometheusBoot(prometheusPort)
  85. //下载 kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
  86. //macos:
  87. // 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
  88. // 2.chmod +x ./kubectl
  89. // 3.sudo mv ./kubectl /usr/local/bin/kubectl
  90. // 4.sudo chown root: /usr/local/bin/kubectl
  91. // 5.kubectl version --client
  92. // 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
  93. // 注意:- config中的域名要能解析正确
  94. // - 生产环境可以创建另一个证书
  95. // 7.kubectl get ns 查看是否正常
  96. //
  97. //创建k8s连接
  98. //在集群外部使用
  99. //-v /home/wu123/.kube/config:/root/.kube/config
  100. var kubeconfig *string
  101. if home := homedir.HomeDir(); home != "" {
  102. kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "kubeconfig file 在当前系统中的地址")
  103. } else {
  104. kubeconfig = flag.String("kubeconfig", "", "kubeconfig file 在当前系统中的地址")
  105. }
  106. flag.Parse()
  107. //创建 config 实例
  108. config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
  109. if err != nil {
  110. common.Fatal(err.Error())
  111. }
  112. //在集群中使用
  113. //config , err := rest.InClusterConfig()
  114. //if err!=nil {
  115. // panic(err.Error())
  116. //}
  117. //创建程序可操作的客户端
  118. clientset, err := kubernetes.NewForConfig(config)
  119. if err != nil {
  120. common.Fatal(err.Error())
  121. }
  122. }

5-16 创建k8s集群config ,通过kubectl操作k8s集群(下)

D:\Workspace\Go\src\gopaas\pod\main.go

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "path/filepath"
  8. "strconv"
  9. "github.com/afex/hystrix-go/hystrix"
  10. "github.com/asim/go-micro/plugins/registry/consul/v3"
  11. ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
  12. opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
  13. "github.com/asim/go-micro/v3"
  14. "github.com/asim/go-micro/v3/registry"
  15. "github.com/asim/go-micro/v3/server"
  16. "github.com/jinzhu/gorm"
  17. "github.com/opentracing/opentracing-go"
  18. "github.com/yunixiangfeng/common"
  19. "github.com/yunixiangfeng/gopaas/pod/domain/repository"
  20. service2 "github.com/yunixiangfeng/gopaas/pod/domain/service"
  21. "github.com/yunixiangfeng/gopaas/pod/handler"
  22. hystrix2 "github.com/yunixiangfeng/gopaas/pod/plugin/hystrix"
  23. "github.com/yunixiangfeng/gopaas/pod/proto/pod"
  24. "k8s.io/client-go/kubernetes"
  25. "k8s.io/client-go/tools/clientcmd"
  26. "k8s.io/client-go/util/homedir"
  27. _ "github.com/jinzhu/gorm/dialects/mysql"
  28. )
  29. var (
  30. //服务地址
  31. hostIp = "192.168.204.130"
  32. //服务地址
  33. serviceHost = hostIp
  34. //服务端口
  35. servicePort = "8081"
  36. //注册中心配置
  37. consulHost = hostIp
  38. consulPort int64 = 8500
  39. //链路追踪
  40. tracerHost = hostIp
  41. tracerPort = 6831
  42. //熔断器
  43. hystrixPort = 9091
  44. //监控端口
  45. prometheusPort = 9191
  46. )
  47. func main() {
  48. //1.注册中心
  49. consul := consul.NewRegistry(func(options *registry.Options) {
  50. options.Addrs = []string{
  51. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  52. }
  53. })
  54. //2.配置中心,存放经常变动的配置
  55. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  56. if err != nil {
  57. common.Error(err)
  58. }
  59. //3.使用配置中心连接 Mysql
  60. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  61. //初始化数据库
  62. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  63. if err != nil {
  64. fmt.Println(err)
  65. common.Error(err)
  66. }
  67. defer db.Close()
  68. db.SingularTable(true)
  69. //4.添加链路追踪
  70. t, io, err := common.NewTracer("go.micro.service.pod", tracerHost+":"+strconv.Itoa(tracerPort))
  71. if err != nil {
  72. common.Error(err)
  73. }
  74. defer io.Close()
  75. opentracing.SetGlobalTracer(t)
  76. //5.添加熔断器
  77. hystrixStreamHandler := hystrix.NewStreamHandler()
  78. hystrixStreamHandler.Start()
  79. //添加监听程序
  80. go func() {
  81. //http://192.168.0.112:9092/turbine/turbine.stream
  82. //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  83. err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
  84. if err != nil {
  85. common.Error(err)
  86. }
  87. }()
  88. //6.添加日志中心
  89. //1)需要程序日志打入到日志文件中
  90. //2)在程序中添加filebeat.yml 文件
  91. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  92. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  93. //7.添加监控
  94. common.PrometheusBoot(prometheusPort)
  95. //下载 kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
  96. //macos:
  97. // 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
  98. // 2.chmod +x ./kubectl
  99. // 3.sudo mv ./kubectl /usr/local/bin/kubectl
  100. // 4.sudo chown root: /usr/local/bin/kubectl
  101. // 5.kubectl version --client
  102. // 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
  103. // 注意:- config中的域名要能解析正确
  104. // - 生产环境可以创建另一个证书
  105. // 7.kubectl get ns 查看是否正常
  106. //
  107. //创建k8s连接
  108. //在集群外部使用
  109. //-v /home/wu123/.kube/config:/root/.kube/config
  110. var kubeconfig *string
  111. if home := homedir.HomeDir(); home != "" {
  112. kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "kubeconfig file 在当前系统中的地址")
  113. } else {
  114. kubeconfig = flag.String("kubeconfig", "", "kubeconfig file 在当前系统中的地址")
  115. }
  116. flag.Parse()
  117. //创建 config 实例
  118. config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
  119. if err != nil {
  120. common.Fatal(err.Error())
  121. }
  122. //在集群中使用
  123. //config , err := rest.InClusterConfig()
  124. //if err!=nil {
  125. // panic(err.Error())
  126. //}
  127. //创建程序可操作的客户端
  128. clientset, err := kubernetes.NewForConfig(config)
  129. if err != nil {
  130. common.Fatal(err.Error())
  131. }
  132. //创建服务实例
  133. service := micro.NewService(
  134. //自定义服务地址,且必须写在其它参数前面
  135. micro.Server(server.NewServer(func(options *server.Options) {
  136. options.Advertise = serviceHost + ":" + servicePort
  137. })),
  138. micro.Name("go.micro.service.pod"),
  139. micro.Version("latest"),
  140. //指定服务端口
  141. micro.Address(":"+servicePort),
  142. //添加注册中心
  143. micro.Registry(consul),
  144. //添加链路追逐
  145. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  146. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  147. //作为客户端使用,添加熔断
  148. micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  149. //添加限流
  150. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  151. )
  152. //初始化服务
  153. service.Init()
  154. //只能初始化一次,初始化数据表
  155. //err = repository.NewPodRepository(db).InitTable()
  156. //if err != nil {
  157. // common.Fatal(err)
  158. //}
  159. //注册句柄
  160. podDataService := service2.NewPodDataService(repository.NewPodRepository(db), clientset)
  161. pod.RegisterPodHandler(service.Server(), &handler.PodHandler{PodDataService: podDataService})
  162. //启动服务
  163. if err := service.Run(); err != nil {
  164. common.Fatal(err)
  165. }
  166. }

D:\Workspace\gopaas\pod\plugin\hystrix\hystrix.go

  1. package hystrix
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/afex/hystrix-go/hystrix"
  6. "github.com/asim/go-micro/v3/client"
  7. )
  8. type clientWrapper struct {
  9. client.Client
  10. }
  11. //熔断逻辑
  12. func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
  13. return hystrix.Do(req.Service()+"."+req.Endpoint(), func() error {
  14. //正常执行
  15. fmt.Println(req.Service() + "." + req.Endpoint())
  16. return c.Client.Call(ctx, req, rsp, opts...)
  17. }, func(e error) error {
  18. //走熔断逻辑,每个服务都不一样
  19. fmt.Println(req.Service() + "." + req.Endpoint()+"的熔断逻辑")
  20. return e
  21. })
  22. }
  23. func NewClientHystrixWrapper() client.Wrapper {
  24. return func(i client.Client) client.Client {
  25. return &clientWrapper{i}
  26. }
  27. }

5-17 pod handler 对外服务逻辑实现(上)

D:\Workspace\Go\src\gopaas\pod\handler\podHandler.go

  1. package handler
  2. import (
  3. "context"
  4. "github.com/yunixiangfeng/gopaas/common"
  5. "github.com/yunixiangfeng/gopaas/pod/domain/model"
  6. "github.com/yunixiangfeng/gopaas/pod/domain/service"
  7. "github.com/yunixiangfeng/gopaas/pod/proto/pod"
  8. "strconv"
  9. )
  10. type PodHandler struct {
  11. //注意这里的类型实 IPodDataService 接口类型
  12. PodDataService service.IPodDataService
  13. }
  14. //添加创建POD
  15. func (e *PodHandler) AddPod(ctx context.Context, info *pod.PodInfo, rsp *pod.Response) error {
  16. common.Info("添加pod")
  17. podModel := &model.Pod{}
  18. err := common.SwapTo(info, podModel)
  19. if err != nil {
  20. common.Error(err)
  21. rsp.Msg = err.Error()
  22. return err
  23. }
  24. if err := e.PodDataService.CreateToK8s(info); err != nil {
  25. common.Error(err)
  26. rsp.Msg = err.Error()
  27. return err
  28. } else {
  29. //操作数据库写入数据
  30. podID, err := e.PodDataService.AddPod(podModel)
  31. if err != nil {
  32. common.Error(err)
  33. rsp.Msg = err.Error()
  34. return err
  35. }
  36. common.Info("Pod 添加成功数据库ID号为:" + strconv.FormatInt(podID, 10))
  37. rsp.Msg = "Pod 添加成功数据库ID号为:" + strconv.FormatInt(podID, 10)
  38. }
  39. return nil
  40. }
  41. //删除k8s中的pod 和数据库中的数据
  42. func (e *PodHandler) DeletePod(ctx context.Context, req *pod.PodId, rsp *pod.Response) error {
  43. //先查找数据
  44. podModel, err := e.PodDataService.FindPodByID(req.Id)
  45. if err != nil {
  46. common.Error(err)
  47. return err
  48. }
  49. if err := e.PodDataService.DeleteFromK8s(podModel); err != nil {
  50. common.Error(err)
  51. return err
  52. }
  53. return nil
  54. }

5-18 pod handler 对外服务逻辑实现(下) 

 D:\Workspace\Go\src\gopaas\pod\handler\podHandler.go

  1. package handler
  2. import (
  3. "context"
  4. "github.com/yunixiangfeng/gopaas/common"
  5. "github.com/yunixiangfeng/gopaas/pod/domain/model"
  6. service "github.com/yunixiangfeng/gopaas/pod/domain/service"
  7. "github.com/yunixiangfeng/gopaas/pod/proto/pod"
  8. "strconv"
  9. )
  10. type PodHandler struct {
  11. //注意这里的类型实 IPodDataService 接口类型
  12. PodDataService service.IPodDataService
  13. }
  14. //添加创建POD
  15. func (e *PodHandler) AddPod(ctx context.Context, info *pod.PodInfo, rsp *pod.Response) error {
  16. common.Info("添加pod")
  17. podModel := &model.Pod{}
  18. err := common.SwapTo(info, podModel)
  19. if err != nil {
  20. common.Error(err)
  21. rsp.Msg = err.Error()
  22. return err
  23. }
  24. if err := e.PodDataService.CreateToK8s(info); err != nil {
  25. common.Error(err)
  26. rsp.Msg = err.Error()
  27. return err
  28. } else {
  29. //操作数据库写入数据
  30. podID, err := e.PodDataService.AddPod(podModel)
  31. if err != nil {
  32. common.Error(err)
  33. rsp.Msg = err.Error()
  34. return err
  35. }
  36. common.Info("Pod 添加成功数据库ID号为:" + strconv.FormatInt(podID, 10))
  37. rsp.Msg = "Pod 添加成功数据库ID号为:" + strconv.FormatInt(podID, 10)
  38. }
  39. return nil
  40. }
  41. //删除k8s中的pod 和数据库中的数据
  42. func (e *PodHandler) DeletePod(ctx context.Context, req *pod.PodId, rsp *pod.Response) error {
  43. //先查找数据
  44. podModel, err := e.PodDataService.FindPodByID(req.Id)
  45. if err != nil {
  46. common.Error(err)
  47. return err
  48. }
  49. if err := e.PodDataService.DeleteFromK8s(podModel); err != nil {
  50. common.Error(err)
  51. return err
  52. }
  53. return nil
  54. }
  55. //更新指定的pod
  56. func (e *PodHandler) UpdatePod(ctx context.Context, req *pod.PodInfo, rsp *pod.Response) error {
  57. //先更新k8s中的pod信息
  58. err := e.PodDataService.UpdateToK8s(req)
  59. if err != nil {
  60. common.Error(err)
  61. return err
  62. }
  63. //查询数据库中的pod
  64. podModel, err := e.PodDataService.FindPodByID(req.Id)
  65. if err != nil {
  66. common.Error(err)
  67. return err
  68. }
  69. err = common.SwapTo(req, podModel)
  70. if err != nil {
  71. common.Error(err)
  72. return err
  73. }
  74. e.PodDataService.UpdatePod(podModel)
  75. return nil
  76. }
  77. //查询单个信息
  78. func (e *PodHandler) FindPodByID(ctx context.Context, req *pod.PodId, rsp *pod.PodInfo) error {
  79. //查询pod数据
  80. podModel, err := e.PodDataService.FindPodByID(req.Id)
  81. if err != nil {
  82. common.Error(err)
  83. return err
  84. }
  85. err = common.SwapTo(podModel, rsp)
  86. if err != nil {
  87. common.Error(err)
  88. return err
  89. }
  90. return nil
  91. }
  92. //查询所有pod
  93. func (e *PodHandler) FindAllPod(ctx context.Context, req *pod.FindAll, rsp *pod.AllPod) error {
  94. //查询所有pod
  95. allPod, err := e.PodDataService.FindAllPod()
  96. if err != nil {
  97. common.Error(err)
  98. return err
  99. }
  100. //整理格式
  101. for _, v := range allPod {
  102. podInfo := &pod.PodInfo{}
  103. err := common.SwapTo(v, podInfo)
  104. if err != nil {
  105. common.Error(err)
  106. return err
  107. }
  108. rsp.PodInfo = append(rsp.PodInfo, podInfo)
  109. }
  110. return nil
  111. }

验证 gopaas\pod go run main.go

cd chapter3 

docker-compose up 

  1. 日志统一记录在根目录 micro.log 文件中,请点击查看日志!
  2. 2023-05-23 12:24:16 file=v3@v3.7.1/service.go:206 level=info Starting [service] go.micro.service.pod
  3. 2023-05-23 12:24:16 file=server/rpc_server.go:820 level=info Transport [http] Listening on [::]:8081
  4. 2023-05-23 12:24:16 file=server/rpc_server.go:840 level=info Broker [http] Connected to 127.0.0.1:41758
  5. 2023-05-23 12:24:16 file=server/rpc_server.go:654 level=info Registry [consul] Registering node: go.micro.service.pod-fa32e608-c57a-419a-9111-dc7529e1b7eb

5-19 POD 服务打包到docker中的注意事项及代码修改注意事项

pod\Dockerfile

  1. FROM alpine
  2. ADD pod /pod
  3. ENTRYPOINT [ "/pod" ]

进入pod目录

在linux上编译CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o pod *.go

docker build -t wu123/pod . 

docker run -p 8081:8081 -p 9092:9092 -p 9192:9192 -v /home/wu123/.kube/config:/root/.kube/config -v /home/wu123/test/micro.log:/micro.log wu123/pod

5-20 Pod API 工程目录以及 proto 文件开发

Go PaaS 平台应用管理开发

服务API开发

目录

C:\Users\Administrator\Desktop\gopaas\podapi\proto\podApi\podApi.proto

  1. syntax = "proto3";
  2. package podApi;
  3. option go_package = "./proto/podApi;podApi";
  4. service PodApi {
  5. rpc FindPodById (Request) returns (Response) {}
  6. rpc AddPod(Request) returns (Response){}
  7. rpc DeletePodById(Request) returns (Response){}
  8. rpc UpdatePod(Request) returns (Response){}
  9. //默认接口
  10. rpc Call(Request) returns (Response){}
  11. }
  12. message Pair {
  13. string key = 1;
  14. repeated string values = 2;
  15. }
  16. message Request {
  17. string method = 1;
  18. string path = 2;
  19. map<string, Pair> header = 3;
  20. map<string, Pair> get = 4;
  21. map<string, Pair> post = 5;
  22. string body = 6;
  23. string url = 7;
  24. }
  25. message Response {
  26. int32 statusCode = 1;
  27. map<string, Pair> header = 2;
  28. string body = 3;
  29. }
  1. PS D:\Workspace\Go\bin> D:\Workspace\Go\bin\protoc --proto_path=C:\Users\Administrator\Desktop\gopaas\podapi
  2. --micro_out=C:\Users\Administrator\Desktop\gopaas\podapi --go_out=:C:\Users\Administrator\Desktop\gopaas\podapi proto/podApi/podApi.proto

5-21 Pod API Handler 开发

  1. PS C:\Users\Administrator\Desktop\gopaas\podapi> go mod init github.com/yunixiangfeng/gopaas/podapi
  2. go: creating new go.mod: module github.com/yunixiangfeng/gopaas/podapi
  3. go: to add module requirements and sums:
  4. go mod tidy

go get github.com/yunixiangfeng/gopaas/pod/proto/pod

C:\Users\Administrator\Desktop\gopaas\podapi\handler\podApiHandler.go

  1. package handler
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "strconv"
  8. "github.com/yunixiangfeng/gopaas/common"
  9. "github.com/yunixiangfeng/gopaas/pod/proto/pod"
  10. form "github.com/yunixiangfeng/gopaas/podapi/plugin/form"
  11. "github.com/yunixiangfeng/gopaas/podapi/proto/podApi"
  12. )
  13. type PodApi struct {
  14. PodService pod.PodService
  15. }
  16. // podApi.FindPodById 通过API向外暴露为/podApi/findPodById,接收http请求
  17. // 即:/podApi/FindPodById 请求会调用go.micro.api.podApi 服务的podApi.FindPodById 方法
  18. func (e *PodApi) FindPodById(ctx context.Context, req *podApi.Request, rsp *podApi.Response) error {
  19. fmt.Println("接受到 podApi.FindPodById 的请求")
  20. if _, ok := req.Get["pod_id"]; !ok {
  21. rsp.StatusCode = 500
  22. }
  23. //获取podid 参数
  24. podIdString := req.Get["pod_id"].Values[0]
  25. podId, err := strconv.ParseInt(podIdString, 10, 64)
  26. if err != nil {
  27. return err
  28. }
  29. //获取pod相关信息
  30. podInfo, err := e.PodService.FindPodByID(ctx, &pod.PodId{
  31. Id: podId,
  32. })
  33. //json 返回pod信息
  34. rsp.StatusCode = 200
  35. b, _ := json.Marshal(podInfo)
  36. rsp.Body = string(b)
  37. return nil
  38. }
  39. // podApi.AddPod 通过API向外暴露为/podApi/addPod,接收http请求
  40. // 即:/podApi/AddPod 请求会调用go.micro.api.podApi 服务的podApi.AddPod 方法
  41. func (e *PodApi) AddPod(ctx context.Context, req *podApi.Request, rsp *podApi.Response) error {
  42. fmt.Println("接受到 podApi.AddPod 的请求")
  43. addPodInfo := &pod.PodInfo{}
  44. //处理 port
  45. dataSlice, ok := req.Post["pod_port"]
  46. if ok {
  47. //特殊处理
  48. podSlice := []*pod.PodPort{}
  49. for _, V := range dataSlice.Values {
  50. i, err := strconv.ParseInt(V, 10, 32)
  51. if err != nil {
  52. common.Error(err)
  53. }
  54. port := &pod.PodPort{
  55. ContainerPort: int32(i),
  56. Protocol: "TCP",
  57. }
  58. podSlice = append(podSlice, port)
  59. }
  60. addPodInfo.PodPort = podSlice
  61. }
  62. //form类型转化到结构体中
  63. form.FormToPodStruct(req.Post, addPodInfo)
  64. response, err := e.PodService.AddPod(ctx, addPodInfo)
  65. if err != nil {
  66. common.Error(err)
  67. return err
  68. }
  69. rsp.StatusCode = 200
  70. b, _ := json.Marshal(response)
  71. rsp.Body = string(b)
  72. return nil
  73. }
  74. // podApi.DeletePodById 通过API向外暴露为/podApi/deletePodById,接收http请求
  75. // 即:/podApi/DeletePodById 请求会调用go.micro.api.podApi 服务的 podApi.DeletePodById 方法
  76. func (e *PodApi) DeletePodById(ctx context.Context, req *podApi.Request, rsp *podApi.Response) error {
  77. fmt.Println("接受到 podApi.DeletePodById 的请求")
  78. if _, ok := req.Get["pod_id"]; !ok {
  79. return errors.New("参数异常")
  80. }
  81. //获取要删除的ID
  82. podIdString := req.Get["pod_id"].Values[0]
  83. podId, err := strconv.ParseInt(podIdString, 10, 64)
  84. if err != nil {
  85. common.Error(err)
  86. return err
  87. }
  88. //删除指定服务
  89. response, err := e.PodService.DeletePod(ctx, &pod.PodId{
  90. Id: podId,
  91. })
  92. if err != nil {
  93. common.Error(err)
  94. return err
  95. }
  96. rsp.StatusCode = 200
  97. b, _ := json.Marshal(response)
  98. rsp.Body = string(b)
  99. return nil
  100. }
  101. // podApi.UpdatePod 通过API向外暴露为/podApi/updatePod,接收http请求
  102. // 即:/podApi/UpdatePod 请求会调用go.micro.api.podApi 服务的podApi.UpdatePod 方法
  103. func (e *PodApi) UpdatePod(ctx context.Context, req *podApi.Request, rsp *podApi.Response) error {
  104. fmt.Println("接受到 podApi.UpdatePod 的请求")
  105. rsp.StatusCode = 200
  106. b, _ := json.Marshal("{success:'成功访问 /podApi/UpdatePod'}")
  107. rsp.Body = string(b)
  108. return nil
  109. }
  110. // 默认的方法podApi.Call 通过API向外暴露为/podApi/call,接收http请求
  111. // 即:/podApi/call或/podApi/ 请求会调用go.micro.api.podApi 服务的podApi.Call 方法
  112. func (e *PodApi) Call(ctx context.Context, req *podApi.Request, rsp *podApi.Response) error {
  113. fmt.Println("接受到 podApi.Call 的请求")
  114. allPod, err := e.PodService.FindAllPod(ctx, &pod.FindAll{})
  115. if err != nil {
  116. common.Error(err)
  117. return err
  118. }
  119. rsp.StatusCode = 200
  120. b, _ := json.Marshal(allPod)
  121. rsp.Body = string(b)
  122. return nil
  123. }

C:\Users\Administrator\Desktop\gopaas\podapi\plugin\form\form.go

  1. package form
  2. import (
  3. "errors"
  4. "reflect"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/yunixiangfeng/gopaas/common"
  9. "github.com/yunixiangfeng/gopaas/podapi/proto/podApi"
  10. )
  11. //根据结构体中name标签映射数据到结构体中并且转换类型
  12. func FormToPodStruct(data map[string]*podApi.Pair, obj interface{}) {
  13. objValue := reflect.ValueOf(obj).Elem()
  14. for i := 0; i < objValue.NumField(); i++ {
  15. //获取sql对应的值
  16. dataTag := strings.Replace(objValue.Type().Field(i).Tag.Get("json"), ",omitempty", "", -1)
  17. dataSlice, ok := data[dataTag]
  18. if !ok {
  19. continue
  20. }
  21. valueSlice := dataSlice.Values
  22. if len(valueSlice) <= 0 {
  23. continue
  24. }
  25. //排除port和env
  26. if dataTag == "pod_port" || dataTag == "pod_env" {
  27. continue
  28. }
  29. value := valueSlice[0]
  30. //端口,环境变量的单独处理
  31. //获取对应字段的名称
  32. name := objValue.Type().Field(i).Name
  33. //获取对应字段类型
  34. structFieldType := objValue.Field(i).Type()
  35. //获取变量类型,也可以直接写"string类型"
  36. val := reflect.ValueOf(value)
  37. var err error
  38. if structFieldType != val.Type() {
  39. //类型转换
  40. val, err = TypeConversion(value, structFieldType.Name()) //类型转换
  41. if err != nil {
  42. common.Error(err)
  43. }
  44. }
  45. //设置类型值
  46. objValue.FieldByName(name).Set(val)
  47. }
  48. }
  49. //类型转换
  50. func TypeConversion(value string, ntype string) (reflect.Value, error) {
  51. if ntype == "string" {
  52. return reflect.ValueOf(value), nil
  53. } else if ntype == "time.Time" {
  54. t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
  55. return reflect.ValueOf(t), err
  56. } else if ntype == "Time" {
  57. t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
  58. return reflect.ValueOf(t), err
  59. } else if ntype == "int" {
  60. i, err := strconv.Atoi(value)
  61. return reflect.ValueOf(i), err
  62. } else if ntype == "int32" {
  63. i, err := strconv.ParseInt(value, 10, 32)
  64. if err != nil {
  65. return reflect.ValueOf(int32(i)), err
  66. }
  67. return reflect.ValueOf(int32(i)), err
  68. } else if ntype == "int64" {
  69. i, err := strconv.ParseInt(value, 10, 64)
  70. return reflect.ValueOf(i), err
  71. } else if ntype == "float32" {
  72. i, err := strconv.ParseFloat(value, 64)
  73. return reflect.ValueOf(float32(i)), err
  74. } else if ntype == "float64" {
  75. i, err := strconv.ParseFloat(value, 64)
  76. return reflect.ValueOf(i), err
  77. }
  78. //else if .......增加其他一些类型的转换
  79. return reflect.ValueOf(value), errors.New("未知的类型:" + ntype)
  80. }

5-22 Pod main 开发

C:\Users\Administrator\Desktop\gopaas\podapi\main.go

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "net/http"
  6. "strconv"
  7. "github.com/afex/hystrix-go/hystrix"
  8. "github.com/asim/go-micro/plugins/registry/consul/v3"
  9. ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
  10. "github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v3"
  11. opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
  12. "github.com/asim/go-micro/v3"
  13. "github.com/asim/go-micro/v3/registry"
  14. "github.com/asim/go-micro/v3/server"
  15. "github.com/jinzhu/gorm"
  16. "github.com/opentracing/opentracing-go"
  17. "github.com/yunixiangfeng/gopaas/common"
  18. go_micro_service_pod "github.com/yunixiangfeng/gopaas/pod/proto/pod"
  19. "github.com/yunixiangfeng/gopaas/podApi/handler"
  20. hystrix2 "github.com/yunixiangfeng/gopaas/podApi/plugin/hystrix"
  21. "github.com/yunixiangfeng/gopaas/podApi/proto/podApi"
  22. _ "github.com/jinzhu/gorm/dialects/mysql"
  23. )
  24. var (
  25. //服务地址
  26. hostIp = "192.168.204.130"
  27. //服务地址
  28. serviceHost = hostIp
  29. //服务端口
  30. servicePort = "8082"
  31. //注册中心配置
  32. consulHost = hostIp
  33. consulPort int64 = 8500
  34. //链路追踪
  35. tracerHost = hostIp
  36. tracerPort = 6831
  37. //熔断端口,每个服务不能重复
  38. hystrixPort = 9092
  39. //监控端口,每个服务不能重复
  40. prometheusPort = 9192
  41. )
  42. func main() {
  43. //1.注册中心
  44. consul := consul.NewRegistry(func(options *registry.Options) {
  45. options.Addrs = []string{
  46. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  47. }
  48. })
  49. //2.配置中心,存放经常变动的配置
  50. consulConfig, err := common.GetConsulConfig(consulHost, consulPort, "/micro/config")
  51. if err != nil {
  52. common.Error(err)
  53. }
  54. //3.使用配置中心连接 Mysql
  55. mysqlInfo := common.GetMysqlFromConsul(consulConfig, "mysql")
  56. //初始化数据库
  57. db, err := gorm.Open("mysql", mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  58. if err != nil {
  59. fmt.Println(err)
  60. common.Error(err)
  61. }
  62. defer db.Close()
  63. db.SingularTable(true)
  64. //4.添加链路追踪
  65. t, io, err := common.NewTracer("go.micro.service.pod", tracerHost+":"+strconv.Itoa(tracerPort))
  66. if err != nil {
  67. common.Error(err)
  68. }
  69. defer io.Close()
  70. opentracing.SetGlobalTracer(t)
  71. //5.添加熔断器
  72. hystrixStreamHandler := hystrix.NewStreamHandler()
  73. hystrixStreamHandler.Start()
  74. //添加监听程序
  75. go func() {
  76. //http://192.168.204.130:9092/turbine/turbine.stream
  77. //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  78. err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
  79. if err != nil {
  80. common.Error(err)
  81. }
  82. }()
  83. //6.添加日志中心
  84. //1)需要程序日志打入到日志文件中
  85. //2)在程序中添加filebeat.yml 文件
  86. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  87. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  88. //7.添加监控
  89. common.PrometheusBoot(prometheusPort)
  90. //创建服务实例
  91. service := micro.NewService(
  92. //自定义服务地址,且必须写在其它参数前面
  93. micro.Server(server.NewServer(func(options *server.Options) {
  94. options.Advertise = serviceHost + ":" + servicePort
  95. })),
  96. micro.Name("go.micro.api.podApi"),
  97. micro.Version("latest"),
  98. //指定服务端口
  99. micro.Address(":"+servicePort),
  100. //添加注册中心
  101. micro.Registry(consul),
  102. //添加链路追逐
  103. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  104. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  105. //作为客户端使用,添加熔断
  106. micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  107. //添加限流
  108. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  109. //添加负载均衡
  110. micro.WrapClient(roundrobin.NewClientWrapper()),
  111. )
  112. //初始化服务
  113. service.Init()
  114. //注册句柄
  115. podService := go_micro_service_pod.NewPodService("go.micro.service.pod", service.Client())
  116. //注册控制器
  117. if err := podApi.RegisterPodApiHandler(service.Server(), &handler.PodApi{PodService: podService}); err != nil {
  118. common.Error(err)
  119. }
  120. //启动服务
  121. if err := service.Run(); err != nil {
  122. common.Fatal(err)
  123. }
  124. }

C:\Users\Administrator\Desktop\gopaas\podapi\filebeat.yml

  1. # 输入
  2. # filebeat 下载地址
  3. # https://www.elastic.co/cn/downloads/past-releases/filebeat-7-9-3/
  4. filebeat.inputs:
  5. - type: log
  6. enabled: true
  7. paths:
  8. - ./*.log
  9. output.logstash:
  10. hosts: ["localhost:5044"]

C:\Users\Administrator\Desktop\gopaas\podapi\plugin\hystrix\hystrix.go

  1. package hystrix
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/afex/hystrix-go/hystrix"
  6. "github.com/asim/go-micro/v3/client"
  7. )
  8. type clientWrapper struct {
  9. client.Client
  10. }
  11. //熔断逻辑
  12. func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
  13. return hystrix.Do(req.Service()+"."+req.Endpoint(), func() error {
  14. //正常执行
  15. fmt.Println(req.Service() + "." + req.Endpoint())
  16. return c.Client.Call(ctx, req, rsp, opts...)
  17. }, func(e error) error {
  18. //走熔断逻辑,每个服务都不一样
  19. fmt.Println(req.Service() + "." + req.Endpoint()+"的熔断逻辑")
  20. return e
  21. })
  22. }
  23. func NewClientHystrixWrapper() client.Wrapper {
  24. return func(i client.Client) client.Client {
  25. return &clientWrapper{i}
  26. }
  27. }

在podapi目录下执行go run main.go

C:\Users\Administrator\Desktop\gopaas\podapi\Dockerfile

  1. FROM alpine
  2. ADD podApi /podApi
  3. ADD filebeat.yml /filebeat.yml
  4. #Add filebeat /filebeat
  5. ENTRYPOINT [ "/podApi" ]

5-23 统一网关的说明讲解

  1. [root@k8s-worker01 gopaas]# ./api-gateway --help
  2. NAME:
  3. api-gateway - a go-micro service
  4. USAGE:
  5. api-gateway [global options] command [command options] [arguments...]
  6. COMMANDS:
  7. api Run the api gateway
  8. help, h Shows a list of commands or help for one command
  9. GLOBAL OPTIONS:
  10. --client value Client for go-micro; rpc [$MICRO_CLIENT]
  11. --client_request_timeout value Sets the client request timeout. e.g 500ms, 5s, 1m. Default: 5s [$MICRO_CLIENT_REQUEST_TIMEOUT]
  12. --client_retries value Sets the client retries. Default: 1 (default: 1) [$MICRO_CLIENT_RETRIES]
  13. --client_pool_size value Sets the client connection pool size. Default: 1 (default: 0) [$MICRO_CLIENT_POOL_SIZE]
  14. --client_pool_ttl value Sets the client connection pool ttl. e.g 500ms, 5s, 1m. Default: 1m [$MICRO_CLIENT_POOL_TTL]
  15. --register_ttl value Register TTL in seconds (default: 60) [$MICRO_REGISTER_TTL]
  16. --register_interval value Register interval in seconds (default: 30) [$MICRO_REGISTER_INTERVAL]
  17. --server value Server for go-micro; rpc [$MICRO_SERVER]
  18. --server_name value Name of the server. go.micro.srv.example [$MICRO_SERVER_NAME]
  19. --server_version value Version of the server. 1.1.0 [$MICRO_SERVER_VERSION]
  20. --server_id value Id of the server. Auto-generated if not specified [$MICRO_SERVER_ID]
  21. --server_address value Bind address for the server. 127.0.0.1:8080 [$MICRO_SERVER_ADDRESS]
  22. --server_advertise value Used instead of the server_address when registering with discovery. 127.0.0.1:8080 [$MICRO_SERVER_ADVERTISE]
  23. --server_metadata value A list of key-value pairs defining metadata. version=1.0.0 [$MICRO_SERVER_METADATA]
  24. --broker value Broker for pub/sub. http, nats, rabbitmq [$MICRO_BROKER]
  25. --broker_address value Comma-separated list of broker addresses [$MICRO_BROKER_ADDRESS]
  26. --profile value Debug profiler for cpu and memory stats [$MICRO_DEBUG_PROFILE]
  27. --registry value Registry for discovery. etcd, mdns [$MICRO_REGISTRY]
  28. --registry_address value Comma-separated list of registry addresses [$MICRO_REGISTRY_ADDRESS]
  29. --runtime value Runtime for building and running services e.g local, kubernetes [$MICRO_RUNTIME]
  30. --runtime_source value Runtime source for building and running services e.g github.com/micro/service (default: "github.com/micro/services") [$MICRO_RUNTIME_SOURCE]
  31. --selector value Selector used to pick nodes for querying [$MICRO_SELECTOR]
  32. --store value Store used for key-value storage [$MICRO_STORE]
  33. --store_address value Comma-separated list of store addresses [$MICRO_STORE_ADDRESS]
  34. --store_database value Database option for the underlying store [$MICRO_STORE_DATABASE]
  35. --store_table value Table option for the underlying store [$MICRO_STORE_TABLE]
  36. --transport value Transport mechanism used; http [$MICRO_TRANSPORT]
  37. --transport_address value Comma-separated list of transport addresses [$MICRO_TRANSPORT_ADDRESS]
  38. --tracer value Tracer for distributed tracing, e.g. memory, jaeger [$MICRO_TRACER]
  39. --tracer_address value Comma-separated list of tracer addresses [$MICRO_TRACER_ADDRESS]
  40. --auth value Auth for role based access control, e.g. service [$MICRO_AUTH]
  41. --auth_id value Account ID used for client authentication [$MICRO_AUTH_ID]
  42. --auth_secret value Account secret used for client authentication [$MICRO_AUTH_SECRET]
  43. --auth_namespace value Namespace for the services auth account (default: "go.micro") [$MICRO_AUTH_NAMESPACE]
  44. --auth_public_key value Public key for JWT auth (base64 encoded PEM) [$MICRO_AUTH_PUBLIC_KEY]
  45. --auth_private_key value Private key for JWT auth (base64 encoded PEM) [$MICRO_AUTH_PRIVATE_KEY]
  46. --config value The source of the config to be used to get configuration [$MICRO_CONFIG]
  47. --help, -h show help (default: false)
  48. [root@k8s-worker01 gopaas]# ./api-gateway --registry=consul --registry_address=192.168.204.130:8500 api --handler=api

http://127.0.0.1:8080/podApi/addPod  

5-24 API 完善及pod 前端页面开发(上)

Beagle - Responsive Admin Template - Foxy Themes

C:\Users\Administrator\Desktop\gopaas\go-paas-front\pod-index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="description" content="">
  8. <meta name="author" content="">
  9. <link rel="shortcut icon" href="assets/img/logo-fav.png">
  10. <title>CPaaS</title>
  11. <link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
  12. <link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
  13. <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  14. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  15. <![endif]-->
  16. <link rel="stylesheet" type="text/css" href="assets/lib/datatables/css/dataTables.bootstrap.min.css"/>
  17. <link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
  18. </head>
  19. <body>
  20. <div class="be-wrapper">
  21. <nav class="navbar navbar-default navbar-fixed-top be-top-header">
  22. <div class="container-fluid">
  23. <div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
  24. </div>
  25. <div class="be-right-navbar">
  26. <ul class="nav navbar-nav navbar-right be-user-nav">
  27. <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>
  28. <ul role="menu" class="dropdown-menu">
  29. <li>
  30. <div class="user-info">
  31. <div class="user-name">wu123</div>
  32. <div class="user-position online">在线</div>
  33. </div>
  34. </li>
  35. <li><a href="#"><span class="icon mdi mdi-face"></span> 账户</a></li>
  36. <li><a href="#"><span class="icon mdi mdi-settings"></span> 设置</a></li>
  37. <li><a href="#"><span class="icon mdi mdi-power"></span> 推出登录</a></li>
  38. </ul>
  39. </li>
  40. </ul>
  41. <div class="page-title"></div>
  42. <ul class="nav navbar-nav navbar-right be-icons-nav">
  43. <li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
  44. <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>
  45. <ul class="dropdown-menu be-notifications">
  46. <li>
  47. <div class="title">消息提醒<span class="badge">3</span></div>
  48. <div class="list">
  49. <div class="be-scroller">
  50. <div class="content">
  51. <ul>
  52. <li class="notification notification-unread"><a href="#">
  53. <div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
  54. <div class="notification-info">
  55. <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>
  56. </div></a></li>
  57. <li class="notification"><a href="#">
  58. <div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
  59. <div class="notification-info">
  60. <div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
  61. </div></a></li>
  62. <li class="notification"><a href="#">
  63. <div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
  64. <div class="notification-info">
  65. <div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
  66. </div></a></li>
  67. <li class="notification"><a href="#">
  68. <div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
  69. <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>
  70. </ul>
  71. </div>
  72. </div>
  73. </div>
  74. <div class="footer"> <a href="#">View all notifications</a></div>
  75. </li>
  76. </ul>
  77. </li>
  78. <li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
  79. <ul class="dropdown-menu be-connections">
  80. <li>
  81. <div class="list">
  82. <div class="content">
  83. <div class="row">
  84. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
  85. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
  86. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
  87. </div>
  88. <div class="row">
  89. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
  90. <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>
  91. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
  92. </div>
  93. </div>
  94. </div>
  95. <div class="footer"> <a href="#">More</a></div>
  96. </li>
  97. </ul>
  98. </li>
  99. </ul>
  100. </div>
  101. </div>
  102. </nav>
  103. <!--
  104. 侧边栏-开始
  105. -->
  106. <div class="be-left-sidebar">
  107. <div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
  108. <div class="left-sidebar-spacer">
  109. <div class="left-sidebar-scroll">
  110. <div class="left-sidebar-content">
  111. <ul class="sidebar-elements">
  112. <li class="divider">菜单</li>
  113. <li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
  114. </li>
  115. <li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
  116. <ul class="sub-menu">
  117. <li class="active"><a href="pod-Index.html">添加应用</a>
  118. </li>
  119. </ul>
  120. </li>
  121. <li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
  122. <ul class="sub-menu">
  123. <li><a href="svc-index.html">添加服务</a>
  124. </li>
  125. </ul>
  126. </li>
  127. <li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
  128. <ul class="sub-menu">
  129. <li><a href="form-elements.html">Elements</a>
  130. </li>
  131. <li><a href="form-validation.html">Validation</a>
  132. </li>
  133. <li><a href="form-multiselect.html">Multiselect</a>
  134. </li>
  135. <li><a href="form-wizard.html">Wizard</a>
  136. </li>
  137. <li><a href="form-masks.html">Input Masks</a>
  138. </li>
  139. <li><a href="form-wysiwyg.html">WYSIWYG Editor</a>
  140. </li>
  141. <li><a href="form-upload.html">Multi Upload</a>
  142. </li>
  143. <li><a href="form-editable.html">X-editable</a>
  144. </li>
  145. </ul>
  146. </li>
  147. <li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
  148. <ul class="sub-menu">
  149. <li><a href="tables-general.html">General</a>
  150. </li>
  151. <li><a href="tables-datatables.html">Data Tables</a>
  152. </li>
  153. <li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
  154. </li>
  155. </ul>
  156. </li>
  157. <li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
  158. <ul class="sub-menu">
  159. <li><a href="pages-blank.html">Blank Page</a>
  160. </li>
  161. <li><a href="pages-blank-header.html">Blank Page Header</a>
  162. </li>
  163. <li><a href="pages-login.html">Login</a>
  164. </li>
  165. <li><a href="pages-login2.html">Login v2</a>
  166. </li>
  167. <li><a href="pages-404.html">404 Page</a>
  168. </li>
  169. <li><a href="pages-sign-up.html">Sign Up</a>
  170. </li>
  171. <li><a href="pages-forgot-password.html">Forgot Password</a>
  172. </li>
  173. <li><a href="pages-profile.html">Profile</a>
  174. </li>
  175. <li><a href="pages-pricing-tables.html">Pricing Tables</a>
  176. </li>
  177. <li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
  178. </li>
  179. <li><a href="pages-timeline.html">Timeline</a>
  180. </li>
  181. <li><a href="pages-timeline2.html">Timeline v2</a>
  182. </li>
  183. <li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
  184. </li>
  185. <li><a href="pages-calendar.html">Calendar</a>
  186. </li>
  187. <li><a href="pages-gallery.html">Gallery</a>
  188. </li>
  189. <li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
  190. </li>
  191. <li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
  192. </li>
  193. <li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
  194. </li>
  195. </ul>
  196. </li>
  197. </ul>
  198. </div>
  199. </div>
  200. </div>
  201. <div class="progress-widget">
  202. <div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
  203. <div class="progress">
  204. <div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
  205. </div>
  206. </div>
  207. </div>
  208. </div>
  209. <!--
  210. 侧边栏-结束
  211. -->
  212. <div class="be-content">
  213. <div class="page-head">
  214. <h2 class="page-head-title">应用管理</h2>
  215. <ol class="breadcrumb page-head-nav">
  216. <li><a href="#">控制台</a></li>
  217. <li><a href="#">应用管理</a></li>
  218. <li class="active">应用列表</li>
  219. </ol>
  220. </div>
  221. <div class="main-content container-fluid">
  222. <div class="row">
  223. <div class="col-sm-12">
  224. <div class="panel panel-default panel-table">
  225. <div class="panel-heading">
  226. <a href="pod-create.html"><button class="btn btn-space btn-primary">创建应用</button></a>
  227. <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>
  228. <ul role="menu" class="dropdown-menu pull-right">
  229. <li><a href="#">Action</a></li>
  230. <li><a href="#">Another action</a></li>
  231. <li><a href="#">Something else here</a></li>
  232. <li class="divider"></li>
  233. <li><a href="#">Separated link</a></li>
  234. </ul>
  235. </div>
  236. </div>
  237. <div class="panel-body">
  238. <table id="table1" class="table table-striped table-hover table-fw-widget">
  239. <thead>
  240. <tr>
  241. <th>ID</th>
  242. <th>应用名称</th>
  243. <th>应用域</th>
  244. <th>CPU</th>
  245. <th>内存</th>
  246. <th>副本数量</th>
  247. <th>操作</th>
  248. </tr>
  249. </thead>
  250. <tbody id="table-data">
  251. </tbody>
  252. </table>
  253. </div>
  254. </div>
  255. </div>
  256. </div>
  257. </div>
  258. </div>
  259. <nav class="be-right-sidebar">
  260. <div class="sb-content">
  261. <div class="tab-navigation">
  262. <ul role="tablist" class="nav nav-tabs nav-justified">
  263. <li role="presentation" class="active"><a href="#tab1" aria-controls="tab1" role="tab" data-toggle="tab">Chat</a></li>
  264. <li role="presentation"><a href="#tab2" aria-controls="tab2" role="tab" data-toggle="tab">Todo</a></li>
  265. <li role="presentation"><a href="#tab3" aria-controls="tab3" role="tab" data-toggle="tab">Settings</a></li>
  266. </ul>
  267. </div>
  268. <div class="tab-panel">
  269. <div class="tab-content">
  270. <div id="tab1" role="tabpanel" class="tab-pane tab-chat active">
  271. <div class="chat-contacts">
  272. <div class="chat-sections">
  273. <div class="be-scroller">
  274. <div class="content">
  275. <h2>Recent</h2>
  276. <div class="contact-list contact-list-recent">
  277. <div class="user"><a href="#"><img src="assets/img/avatar1.png" alt="Avatar">
  278. <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>
  279. <div class="user"><a href="#"><img src="assets/img/avatar2.png" alt="Avatar">
  280. <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>
  281. <div class="user"><a href="#"><img src="assets/img/avatar3.png" alt="Avatar">
  282. <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>
  283. </div>
  284. <h2>Contacts</h2>
  285. <div class="contact-list">
  286. <div class="user"><a href="#"><img src="assets/img/avatar4.png" alt="Avatar">
  287. <div class="user-data2"><span class="status"></span><span class="name">Mike Bolthort</span></div></a></div>
  288. <div class="user"><a href="#"><img src="assets/img/avatar5.png" alt="Avatar">
  289. <div class="user-data2"><span class="status"></span><span class="name">Maggie jackson</span></div></a></div>
  290. <div class="user"><a href="#"><img src="assets/img/avatar6.png" alt="Avatar">
  291. <div class="user-data2"><span class="status offline"></span><span class="name">Jhon Voltemar</span></div></a></div>
  292. </div>
  293. </div>
  294. </div>
  295. </div>
  296. <div class="bottom-input">
  297. <input type="text" placeholder="Search..." name="q"><span class="mdi mdi-search"></span>
  298. </div>
  299. </div>
  300. <div class="chat-window">
  301. <div class="title">
  302. <div class="user"><img src="assets/img/avatar2.png" alt="Avatar">
  303. <h2>Maggie jackson</h2><span>Active 1h ago</span>
  304. </div><span class="icon return mdi mdi-chevron-left"></span>
  305. </div>
  306. <div class="chat-messages">
  307. <div class="be-scroller">
  308. <div class="content">
  309. <ul>
  310. <li class="friend">
  311. <div class="msg">Hello</div>
  312. </li>
  313. <li class="self">
  314. <div class="msg">Hi, how are you?</div>
  315. </li>
  316. <li class="friend">
  317. <div class="msg">Good, I'll need support with my pc</div>
  318. </li>
  319. <li class="self">
  320. <div class="msg">Sure, just tell me what is going on with your computer?</div>
  321. </li>
  322. <li class="friend">
  323. <div class="msg">I don't know it just turns off suddenly</div>
  324. </li>
  325. </ul>
  326. </div>
  327. </div>
  328. </div>
  329. <div class="chat-input">
  330. <div class="input-wrapper"><span class="photo mdi mdi-camera"></span>
  331. <input type="text" placeholder="Message..." name="q" autocomplete="off"><span class="send-msg mdi mdi-mail-send"></span>
  332. </div>
  333. </div>
  334. </div>
  335. </div>
  336. <div id="tab2" role="tabpanel" class="tab-pane tab-todo">
  337. <div class="todo-container">
  338. <div class="todo-wrapper">
  339. <div class="be-scroller">
  340. <div class="todo-content"><span class="category-title">Today</span>
  341. <ul class="todo-list">
  342. <li>
  343. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  344. <input id="todo1" type="checkbox" checked="">
  345. <label for="todo1">Initialize the project</label>
  346. </div>
  347. </li>
  348. <li>
  349. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  350. <input id="todo2" type="checkbox">
  351. <label for="todo2">Create the main structure</label>
  352. </div>
  353. </li>
  354. <li>
  355. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  356. <input id="todo3" type="checkbox">
  357. <label for="todo3">Updates changes to GitHub</label>
  358. </div>
  359. </li>
  360. </ul><span class="category-title">Tomorrow</span>
  361. <ul class="todo-list">
  362. <li>
  363. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  364. <input id="todo4" type="checkbox">
  365. <label for="todo4">Initialize the project</label>
  366. </div>
  367. </li>
  368. <li>
  369. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  370. <input id="todo5" type="checkbox">
  371. <label for="todo5">Create the main structure</label>
  372. </div>
  373. </li>
  374. <li>
  375. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  376. <input id="todo6" type="checkbox">
  377. <label for="todo6">Updates changes to GitHub</label>
  378. </div>
  379. </li>
  380. <li>
  381. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  382. <input id="todo7" type="checkbox">
  383. <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>
  384. </div>
  385. </li>
  386. </ul>
  387. </div>
  388. </div>
  389. </div>
  390. <div class="bottom-input">
  391. <input type="text" placeholder="Create new task..." name="q"><span class="mdi mdi-plus"></span>
  392. </div>
  393. </div>
  394. </div>
  395. <div id="tab3" role="tabpanel" class="tab-pane tab-settings">
  396. <div class="settings-wrapper">
  397. <div class="be-scroller"><span class="category-title">General</span>
  398. <ul class="settings-list">
  399. <li>
  400. <div class="switch-button switch-button-sm">
  401. <input type="checkbox" checked="" name="st1" id="st1"><span>
  402. <label for="st1"></label></span>
  403. </div><span class="name">Available</span>
  404. </li>
  405. <li>
  406. <div class="switch-button switch-button-sm">
  407. <input type="checkbox" checked="" name="st2" id="st2"><span>
  408. <label for="st2"></label></span>
  409. </div><span class="name">Enable notifications</span>
  410. </li>
  411. <li>
  412. <div class="switch-button switch-button-sm">
  413. <input type="checkbox" checked="" name="st3" id="st3"><span>
  414. <label for="st3"></label></span>
  415. </div><span class="name">Login with Facebook</span>
  416. </li>
  417. </ul><span class="category-title">Notifications</span>
  418. <ul class="settings-list">
  419. <li>
  420. <div class="switch-button switch-button-sm">
  421. <input type="checkbox" name="st4" id="st4"><span>
  422. <label for="st4"></label></span>
  423. </div><span class="name">Email notifications</span>
  424. </li>
  425. <li>
  426. <div class="switch-button switch-button-sm">
  427. <input type="checkbox" checked="" name="st5" id="st5"><span>
  428. <label for="st5"></label></span>
  429. </div><span class="name">Project updates</span>
  430. </li>
  431. <li>
  432. <div class="switch-button switch-button-sm">
  433. <input type="checkbox" checked="" name="st6" id="st6"><span>
  434. <label for="st6"></label></span>
  435. </div><span class="name">New comments</span>
  436. </li>
  437. <li>
  438. <div class="switch-button switch-button-sm">
  439. <input type="checkbox" name="st7" id="st7"><span>
  440. <label for="st7"></label></span>
  441. </div><span class="name">Chat messages</span>
  442. </li>
  443. </ul><span class="category-title">Workflow</span>
  444. <ul class="settings-list">
  445. <li>
  446. <div class="switch-button switch-button-sm">
  447. <input type="checkbox" name="st8" id="st8"><span>
  448. <label for="st8"></label></span>
  449. </div><span class="name">Deploy on commit</span>
  450. </li>
  451. </ul>
  452. </div>
  453. </div>
  454. </div>
  455. </div>
  456. </div>
  457. </div>
  458. </nav>
  459. </div>
  460. <script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
  461. <script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
  462. <script src="assets/js/main.js" type="text/javascript"></script>
  463. <script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
  464. <script src="assets/lib/datatables/js/jquery.dataTables.min.js" type="text/javascript"></script>
  465. <script src="assets/lib/datatables/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
  466. <script src="assets/lib/datatables/plugins/buttons/js/dataTables.buttons.js" type="text/javascript"></script>
  467. <script src="assets/lib/datatables/plugins/buttons/js/buttons.html5.js" type="text/javascript"></script>
  468. <script src="assets/lib/datatables/plugins/buttons/js/buttons.flash.js" type="text/javascript"></script>
  469. <script src="assets/lib/datatables/plugins/buttons/js/buttons.print.js" type="text/javascript"></script>
  470. <script src="assets/lib/datatables/plugins/buttons/js/buttons.colVis.js" type="text/javascript"></script>
  471. <script src="assets/lib/datatables/plugins/buttons/js/buttons.bootstrap.js" type="text/javascript"></script>
  472. <script src="assets/js/app-tables-datatables.js" type="text/javascript"></script>
  473. <script type="text/javascript">
  474. $(document).ready(function(){
  475. //initialize the javascript
  476. App.init();
  477. App.dataTables();
  478. $.ajax({
  479. type:"get",
  480. url:"http://127.0.0.1:8080/podApi/",
  481. success: function(data){
  482. console.log(data);
  483. $("#table-data").html("");
  484. $.each(data['pod_info'],function (i,item) {
  485. $("#table-data").append(' <tr class="gradeA">\
  486. <td>'+item.id+'</td>\
  487. <td>'+item.pod_name+'</td>\
  488. <td>'+item.pod_namespace+'</td>\
  489. <td class="center">'+item.pod_cpu_max+'</td>\
  490. <td class="center">'+item.pod_memory_max+'</td>\
  491. <td class="center">'+item.pod_replicas+'</td>\
  492. <td class="center"><a href="pod-detail.html?pod_id='+item.id+'">详情</a> <a href="http://localhost:8080/podApi/deletePodById?pod_id='+item.id+'" style="color:red;" >删除</a></td>\
  493. </tr>'
  494. );
  495. })
  496. },
  497. error: function(result){
  498. console.log(result);
  499. }
  500. });
  501. });
  502. </script>
  503. </body>
  504. </html>

C:\Users\Administrator\Desktop\gopaas\go-paas-front\pod-detail.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="description" content="">
  8. <meta name="author" content="">
  9. <link rel="shortcut icon" href="assets/img/logo-fav.png">
  10. <title>CPaaS</title>
  11. <link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
  12. <link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
  13. <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  14. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  15. <![endif]-->
  16. <link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
  17. </head>
  18. <body>
  19. <div class="be-wrapper">
  20. <nav class="navbar navbar-default navbar-fixed-top be-top-header">
  21. <div class="container-fluid">
  22. <div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
  23. </div>
  24. <div class="be-right-navbar">
  25. <ul class="nav navbar-nav navbar-right be-user-nav">
  26. <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>
  27. <ul role="menu" class="dropdown-menu">
  28. <li>
  29. <div class="user-info">
  30. <div class="user-name">Túpac Amaru</div>
  31. <div class="user-position online">Available</div>
  32. </div>
  33. </li>
  34. <li><a href="#"><span class="icon mdi mdi-face"></span> Account</a></li>
  35. <li><a href="#"><span class="icon mdi mdi-settings"></span> Settings</a></li>
  36. <li><a href="#"><span class="icon mdi mdi-power"></span> Logout</a></li>
  37. </ul>
  38. </li>
  39. </ul>
  40. <div class="page-title"><span>Form Validation</span></div>
  41. <ul class="nav navbar-nav navbar-right be-icons-nav">
  42. <li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
  43. <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>
  44. <ul class="dropdown-menu be-notifications">
  45. <li>
  46. <div class="title">Notifications<span class="badge">3</span></div>
  47. <div class="list">
  48. <div class="be-scroller">
  49. <div class="content">
  50. <ul>
  51. <li class="notification notification-unread"><a href="#">
  52. <div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
  53. <div class="notification-info">
  54. <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>
  55. </div></a></li>
  56. <li class="notification"><a href="#">
  57. <div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
  58. <div class="notification-info">
  59. <div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
  60. </div></a></li>
  61. <li class="notification"><a href="#">
  62. <div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
  63. <div class="notification-info">
  64. <div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
  65. </div></a></li>
  66. <li class="notification"><a href="#">
  67. <div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
  68. <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>
  69. </ul>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="footer"> <a href="#">View all notifications</a></div>
  74. </li>
  75. </ul>
  76. </li>
  77. <li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
  78. <ul class="dropdown-menu be-connections">
  79. <li>
  80. <div class="list">
  81. <div class="content">
  82. <div class="row">
  83. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
  84. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
  85. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
  86. </div>
  87. <div class="row">
  88. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
  89. <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>
  90. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="footer"> <a href="#">More</a></div>
  95. </li>
  96. </ul>
  97. </li>
  98. </ul>
  99. </div>
  100. </div>
  101. </nav>
  102. <!--
  103. 侧边栏-开始
  104. -->
  105. <div class="be-left-sidebar">
  106. <div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
  107. <div class="left-sidebar-spacer">
  108. <div class="left-sidebar-scroll">
  109. <div class="left-sidebar-content">
  110. <ul class="sidebar-elements">
  111. <li class="divider">菜单</li>
  112. <li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
  113. </li>
  114. <li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
  115. <ul class="sub-menu">
  116. <li class="active"><a href="pod-Index.html">添加应用</a>
  117. </li>
  118. </ul>
  119. </li>
  120. <li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
  121. <ul class="sub-menu">
  122. <li><a href="svc-index.html">添加服务</a>
  123. </li>
  124. </ul>
  125. </li>
  126. <li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
  127. <ul class="sub-menu">
  128. <li><a href="form-elements.html">Elements</a>
  129. </li>
  130. <li><a href="form-validation.html">Validation</a>
  131. </li>
  132. <li><a href="form-multiselect.html">Multiselect</a>
  133. </li>
  134. <li><a href="form-wizard.html">Wizard</a>
  135. </li>
  136. <li><a href="form-masks.html">Input Masks</a>
  137. </li>
  138. <li><a href="form-wysiwyg.html">WYSIWYG Editor</a>
  139. </li>
  140. <li><a href="form-upload.html">Multi Upload</a>
  141. </li>
  142. <li><a href="form-editable.html">X-editable</a>
  143. </li>
  144. </ul>
  145. </li>
  146. <li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
  147. <ul class="sub-menu">
  148. <li><a href="tables-general.html">General</a>
  149. </li>
  150. <li><a href="tables-datatables.html">Data Tables</a>
  151. </li>
  152. <li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
  153. </li>
  154. </ul>
  155. </li>
  156. <li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
  157. <ul class="sub-menu">
  158. <li><a href="pages-blank.html">Blank Page</a>
  159. </li>
  160. <li><a href="pages-blank-header.html">Blank Page Header</a>
  161. </li>
  162. <li><a href="pages-login.html">Login</a>
  163. </li>
  164. <li><a href="pages-login2.html">Login v2</a>
  165. </li>
  166. <li><a href="pages-404.html">404 Page</a>
  167. </li>
  168. <li><a href="pages-sign-up.html">Sign Up</a>
  169. </li>
  170. <li><a href="pages-forgot-password.html">Forgot Password</a>
  171. </li>
  172. <li><a href="pages-profile.html">Profile</a>
  173. </li>
  174. <li><a href="pages-pricing-tables.html">Pricing Tables</a>
  175. </li>
  176. <li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
  177. </li>
  178. <li><a href="pages-timeline.html">Timeline</a>
  179. </li>
  180. <li><a href="pages-timeline2.html">Timeline v2</a>
  181. </li>
  182. <li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
  183. </li>
  184. <li><a href="pages-calendar.html">Calendar</a>
  185. </li>
  186. <li><a href="pages-gallery.html">Gallery</a>
  187. </li>
  188. <li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
  189. </li>
  190. <li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
  191. </li>
  192. <li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
  193. </li>
  194. </ul>
  195. </li>
  196. </ul>
  197. </div>
  198. </div>
  199. </div>
  200. <div class="progress-widget">
  201. <div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
  202. <div class="progress">
  203. <div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
  204. </div>
  205. </div>
  206. </div>
  207. </div>
  208. <!--
  209. 侧边栏-结束
  210. -->
  211. <div class="be-content">
  212. <div class="main-content container-fluid">
  213. <div class="row">
  214. <div class="col-md-12">
  215. <div class="panel panel-default panel-border-color panel-border-color-primary">
  216. <div class="panel-heading panel-heading-divider">应用详情<span class="panel-subtitle">查看应用详情信息</span></div>
  217. <div class="panel-body">
  218. <form action="#" class="form-horizontal group-border-dashed">
  219. <div class="form-group">
  220. <label class="col-sm-3 control-label">应用ID:</label>
  221. <div class="col-sm-6">
  222. <input type="text" required="" readonly class="form-control" id="pod_id" name="pod_id">
  223. </div>
  224. </div>
  225. <div class="form-group">
  226. <label class="col-sm-3 control-label">应用名称:</label>
  227. <div class="col-sm-6">
  228. <input type="text" required="" readonly class="form-control" id="pod_name" name="pod_name">
  229. </div>
  230. </div>
  231. <div class="form-group">
  232. <label class="col-sm-3 control-label">命名空间:</label>
  233. <div class="col-sm-6">
  234. <input type="text" required="" readonly class="form-control" id="pod_namespace" name="pod_namespace">
  235. </div>
  236. </div>
  237. <div class="form-group">
  238. <label class="col-sm-3 control-label">Pod 拉取策略:</label>
  239. <div class="col-sm-6">
  240. <input type="text" required="" readonly class="form-control" id="pod_pull_policy" name="pod_pull_policy">
  241. </div>
  242. </div>
  243. <div class="form-group">
  244. <label class="col-sm-3 control-label">副本个数:</label>
  245. <div class="col-sm-6">
  246. <input type="text" required="" readonly class="form-control" id="pod_replicas" name="pod_replicas">
  247. </div>
  248. </div>
  249. <div class="form-group">
  250. <label class="col-sm-3 control-label">重启策略:</label>
  251. <div class="col-sm-6">
  252. <input type="text" required="" readonly class="form-control" id="pod_restart" name="pod_restart">
  253. </div>
  254. </div>
  255. <div class="form-group">
  256. <label class="col-sm-3 control-label">团队ID:</label>
  257. <div class="col-sm-6">
  258. <input type="text" required="" readonly class="form-control" id="pod_team_id" name="pod_team_id">
  259. </div>
  260. </div>
  261. <div class="form-group">
  262. <label class="col-sm-3 control-label">更新策略:</label>
  263. <div class="col-sm-6">
  264. <input type="text" required="" readonly class="form-control" id="pod_type" name="pod_type">
  265. </div>
  266. </div>
  267. <div class="form-group">
  268. <label class="col-sm-3 control-label">Image镜像:</label>
  269. <div class="col-sm-6">
  270. <input type="text" required="" readonly class="form-control" id="pod_image" name="pod_image">
  271. </div>
  272. </div>
  273. </form>
  274. </div>
  275. </div>
  276. </div>
  277. </div>
  278. </div>
  279. </div>
  280. </div>
  281. <script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
  282. <script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
  283. <script src="assets/js/main.js" type="text/javascript"></script>
  284. <script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
  285. <script src="assets/lib/parsley/parsley.min.js" type="text/javascript"></script>
  286. <script type="text/javascript">
  287. $(document).ready(function(){
  288. App.init();
  289. $('form').parsley();
  290. $.ajax({
  291. type:"get",
  292. url:"http://127.0.0.1:8080/podApi/findPodById?pod_id="+getUrlParam('pod_id'),
  293. success: function(data){
  294. console.log(data);
  295. if(data.id != "" || data.id != null || data.id != undefined){
  296. $('#pod_id').val(data.id);
  297. $("#pod_name").val(data.pod_name);
  298. $('#pod_namespace').val(data.pod_namespace);
  299. $('#pod_pull_policy').val(data.pod_pull_policy);
  300. $('#pod_replicas').val(data.pod_replicas);
  301. $('#pod_restart').val(data.pod_restart);
  302. $('#pod_team_id').val(data.pod_team_id);
  303. $('#pod_type').val(data.pod_type);
  304. $('#pod_image').val(data.pod_image);
  305. }else{
  306. console.log(data);
  307. }
  308. },
  309. error: function(result){
  310. console.log(result);
  311. }
  312. });
  313. });
  314. //获取url中的参数
  315. function getUrlParam(name) {
  316. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
  317. var r = window.location.search.substr(1).match(reg); //匹配目标参数
  318. if (r != null) return unescape(r[2]); return null; //返回参数值
  319. }
  320. </script>
  321. </body>
  322. </html>

C:\Users\Administrator\Desktop\gopaas\go-paas-front\pod-create.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="description" content="">
  8. <meta name="author" content="">
  9. <link rel="shortcut icon" href="assets/img/logo-fav.png">
  10. <title>CPaaS</title>
  11. <link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
  12. <link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
  13. <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  14. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  15. <![endif]-->
  16. <link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
  17. </head>
  18. <body>
  19. <div class="be-wrapper">
  20. <nav class="navbar navbar-default navbar-fixed-top be-top-header">
  21. <div class="container-fluid">
  22. <div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
  23. </div>
  24. <div class="be-right-navbar">
  25. <ul class="nav navbar-nav navbar-right be-user-nav">
  26. <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>
  27. <ul role="menu" class="dropdown-menu">
  28. <li>
  29. <div class="user-info">
  30. <div class="user-name">Túpac Amaru</div>
  31. <div class="user-position online">Available</div>
  32. </div>
  33. </li>
  34. <li><a href="#"><span class="icon mdi mdi-face"></span> Account</a></li>
  35. <li><a href="#"><span class="icon mdi mdi-settings"></span> Settings</a></li>
  36. <li><a href="#"><span class="icon mdi mdi-power"></span> Logout</a></li>
  37. </ul>
  38. </li>
  39. </ul>
  40. <div class="page-title"><span>Form Validation</span></div>
  41. <ul class="nav navbar-nav navbar-right be-icons-nav">
  42. <li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
  43. <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>
  44. <ul class="dropdown-menu be-notifications">
  45. <li>
  46. <div class="title">Notifications<span class="badge">3</span></div>
  47. <div class="list">
  48. <div class="be-scroller">
  49. <div class="content">
  50. <ul>
  51. <li class="notification notification-unread"><a href="#">
  52. <div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
  53. <div class="notification-info">
  54. <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>
  55. </div></a></li>
  56. <li class="notification"><a href="#">
  57. <div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
  58. <div class="notification-info">
  59. <div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
  60. </div></a></li>
  61. <li class="notification"><a href="#">
  62. <div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
  63. <div class="notification-info">
  64. <div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
  65. </div></a></li>
  66. <li class="notification"><a href="#">
  67. <div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
  68. <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>
  69. </ul>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="footer"> <a href="#">View all notifications</a></div>
  74. </li>
  75. </ul>
  76. </li>
  77. <li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
  78. <ul class="dropdown-menu be-connections">
  79. <li>
  80. <div class="list">
  81. <div class="content">
  82. <div class="row">
  83. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
  84. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
  85. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
  86. </div>
  87. <div class="row">
  88. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
  89. <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>
  90. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="footer"> <a href="#">More</a></div>
  95. </li>
  96. </ul>
  97. </li>
  98. </ul>
  99. </div>
  100. </div>
  101. </nav>
  102. <!--
  103. 侧边栏-开始
  104. -->
  105. <div class="be-left-sidebar">
  106. <div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
  107. <div class="left-sidebar-spacer">
  108. <div class="left-sidebar-scroll">
  109. <div class="left-sidebar-content">
  110. <ul class="sidebar-elements">
  111. <li class="divider">菜单</li>
  112. <li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
  113. </li>
  114. <li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
  115. <ul class="sub-menu">
  116. <li class="active"><a href="pod-Index.html">添加应用</a>
  117. </li>
  118. </ul>
  119. </li>
  120. <li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
  121. <ul class="sub-menu">
  122. <li><a href="svc-index.html">添加服务</a>
  123. </li>
  124. </ul>
  125. </li>
  126. <li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
  127. <ul class="sub-menu">
  128. <li><a href="form-elements.html">Elements</a>
  129. </li>
  130. <li><a href="form-validation.html">Validation</a>
  131. </li>
  132. <li><a href="form-multiselect.html">Multiselect</a>
  133. </li>
  134. <li><a href="form-wizard.html">Wizard</a>
  135. </li>
  136. <li><a href="form-masks.html">Input Masks</a>
  137. </li>
  138. <li><a href="form-wysiwyg.html">WYSIWYG Editor</a>
  139. </li>
  140. <li><a href="form-upload.html">Multi Upload</a>
  141. </li>
  142. <li><a href="form-editable.html">X-editable</a>
  143. </li>
  144. </ul>
  145. </li>
  146. <li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
  147. <ul class="sub-menu">
  148. <li><a href="tables-general.html">General</a>
  149. </li>
  150. <li><a href="tables-datatables.html">Data Tables</a>
  151. </li>
  152. <li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
  153. </li>
  154. </ul>
  155. </li>
  156. <li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
  157. <ul class="sub-menu">
  158. <li><a href="pages-blank.html">Blank Page</a>
  159. </li>
  160. <li><a href="pages-blank-header.html">Blank Page Header</a>
  161. </li>
  162. <li><a href="pages-login.html">Login</a>
  163. </li>
  164. <li><a href="pages-login2.html">Login v2</a>
  165. </li>
  166. <li><a href="pages-404.html">404 Page</a>
  167. </li>
  168. <li><a href="pages-sign-up.html">Sign Up</a>
  169. </li>
  170. <li><a href="pages-forgot-password.html">Forgot Password</a>
  171. </li>
  172. <li><a href="pages-profile.html">Profile</a>
  173. </li>
  174. <li><a href="pages-pricing-tables.html">Pricing Tables</a>
  175. </li>
  176. <li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
  177. </li>
  178. <li><a href="pages-timeline.html">Timeline</a>
  179. </li>
  180. <li><a href="pages-timeline2.html">Timeline v2</a>
  181. </li>
  182. <li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
  183. </li>
  184. <li><a href="pages-calendar.html">Calendar</a>
  185. </li>
  186. <li><a href="pages-gallery.html">Gallery</a>
  187. </li>
  188. <li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
  189. </li>
  190. <li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
  191. </li>
  192. <li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
  193. </li>
  194. </ul>
  195. </li>
  196. </ul>
  197. </div>
  198. </div>
  199. </div>
  200. <div class="progress-widget">
  201. <div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
  202. <div class="progress">
  203. <div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
  204. </div>
  205. </div>
  206. </div>
  207. </div>
  208. <!--
  209. 侧边栏-结束
  210. -->
  211. <div class="be-content">
  212. <div class="main-content container-fluid">
  213. <div class="row">
  214. <div class="col-md-12">
  215. <div class="panel panel-default panel-border-color panel-border-color-primary">
  216. <div class="panel-heading panel-heading-divider">创建应用<span class="panel-subtitle"></span></div>
  217. <div class="panel-body">
  218. <form action="http://localhost:8080/podApi/AddPod" class="form-horizontal group-border-dashed" method="post" >
  219. <div class="form-group">
  220. <label class="col-sm-3 control-label">应用名称:</label>
  221. <div class="col-sm-6">
  222. <input type="text" required="" class="form-control" id="pod_name" name="pod_name">
  223. </div>
  224. </div>
  225. <div class="form-group">
  226. <label class="col-sm-3 control-label">命名空间:</label>
  227. <div class="col-sm-6">
  228. <input type="text" required="" class="form-control" id="pod_namespace" name="pod_namespace" value="default">
  229. </div>
  230. </div>
  231. <div class="form-group">
  232. <label class="col-sm-3 control-label">Pod 拉取策略:</label>
  233. <div class="col-sm-6">
  234. <input type="text" required="" class="form-control" id="pod_pull_policy" name="pod_pull_policy" value="Always">
  235. </div>
  236. </div>
  237. <div class="form-group">
  238. <label class="col-sm-3 control-label">副本个数:</label>
  239. <div class="col-sm-6">
  240. <input type="text" required="" class="form-control" id="pod_replicas" name="pod_replicas">
  241. </div>
  242. </div>
  243. <div class="form-group">
  244. <label class="col-sm-3 control-label">端口:</label>
  245. <div class="col-sm-6">
  246. <input type="text" required="" class="form-control" name="pod_port">
  247. <input type="text" required="" class="form-control" name="pod_port">
  248. </div>
  249. </div>
  250. <div class="form-group">
  251. <label class="col-sm-3 control-label">重启策略:</label>
  252. <div class="col-sm-6">
  253. <input type="text" required="" class="form-control" id="pod_restart" name="pod_restart" value="Always">
  254. </div>
  255. </div>
  256. <div class="form-group">
  257. <label class="col-sm-3 control-label">团队ID:</label>
  258. <div class="col-sm-6">
  259. <input type="text" required="" class="form-control" id="pod_team_id" name="pod_team_id">
  260. </div>
  261. </div>
  262. <div class="form-group">
  263. <label class="col-sm-3 control-label">更新策略:</label>
  264. <div class="col-sm-6">
  265. <input type="text" required="" class="form-control" id="pod_type" name="pod_type" value="Rolling">
  266. </div>
  267. </div>
  268. <div class="form-group">
  269. <label class="col-sm-3 control-label">Image镜像:</label>
  270. <div class="col-sm-6">
  271. <input type="text" required="" class="form-control" id="pod_image" name="pod_image">
  272. </div>
  273. </div>
  274. <div class="form-group">
  275. <div class="col-sm-2 col-sm-10">
  276. <button type="submit" class="btn btn-space btn-primary">创建应用</button>
  277. <button class="btn btn-space btn-default">Cancel</button>
  278. </div>
  279. </div>
  280. </form>
  281. </div>
  282. </div>
  283. </div>
  284. </div>
  285. </div>
  286. </div>
  287. </div>
  288. <script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
  289. <script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
  290. <script src="assets/js/main.js" type="text/javascript"></script>
  291. <script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
  292. <script src="assets/lib/parsley/parsley.min.js" type="text/javascript"></script>
  293. <script type="text/javascript">
  294. $(document).ready(function(){
  295. App.init();
  296. });
  297. //获取url中的参数
  298. function getUrlParam(name) {
  299. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
  300. var r = window.location.search.substr(1).match(reg); //匹配目标参数
  301. if (r != null) return unescape(r[2]); return null; //返回参数值
  302. }
  303. </script>
  304. </body>
  305. </html>

5-25 API 完善及pod 前端页面开发(下)

5-26 总结&思考

主要内容
Deplyment 和Pod 直接的关系
Pod开发的整体路线
开发过程中网关的说明

经验之谈
Pod 云原生 PaaS 平台里面的最小单位,概念特性要熟记。
开发微服务应用一定要合理分层,避免业务改动代码大调。

为什么Pod中能放多个容器?
网关跨域怎么解决的?
Deployment 带来的好处有哪些?

5-27 【扩展阅读】Kubernetes Pod 优先级和抢占源码解析

5-28 【扩展阅读】POD 节点压力驱逐策略详解

5-29 【扩展阅读】K8s 调度器 kube-scheduler 详解

第6章 云原生 Go PaaS 平台服务管理功能开发,学习服务与底层的关系

PaaS 平台中服务起着至关重要的作用,负责控制多种发布策略,是保证服务负载均衡,蓝绿发布,金丝雀发布的基础,通过 Service 服务的管理功能,讲解 Service 与 Pod 的关联关系。同时介绍快速开发框架 yu-tool,yu-v3 的使用说明,也能复用于日常工作,提高开发效能.

6-1 Service 类型原理介绍

Go PaaS 平台服务管理开发
主要内容
Service 类型讲解
Service ,Endpoints,Pod 关系讲解
开发 Service管理功能

Service 简介
Service 的作用
Service 四种类型

Service 的作用
Service是一种可以访问 Pod逻辑分组的策略
Service通常是通过 Label Selector访问 Pod组
Service能够提供负载均衡的能力

Service ClusterIP 模式
可以让服务长时在线达到热更的目的
可以内网调用通过服务名称DNS的方式,集群内访问

提供负载均衡策略:随机和轮询策略

Service NodePort 模式
集群外部访问POD
端口数量有限,范围:30000-32767 

访问方式node主机IP+端口: 10.12.21.1:31021

 Service LoadBalancer 模式
单独的IP访问
会自动创建NodePort,ClusterlP两个服务
需要云厂商支持

Service ExternalName 模式
主要面向集群外部的服务
可以把外部服务映射进入集群内部,当成内部服务管理
重定向依赖DNS

 Service ,Endpoints,Pod 的关系

6-2 yu-v3,yu-tool,yu-api-gateway 工具说明

GitHub - go-micro/api: Go Micro API Gateway

启动Micro API网关

micro --registry=consul --registry_address=xxxxx api --handler=api

api-gateway --registry=consul --registry_address=192.168.204.130:8500 api --handler=api

C:\Users\Administrator\Desktop\gopaas\yu-v3

 C:\Users\Administrator\Desktop\gopaas\yu-v3\Dockerfile

  1. FROM alpine:latest
  2. RUN apk update && \
  3. # apk add ca-certificates && \
  4. apk add protoc && \
  5. rm -rf /var/cache/apk/*
  6. COPY protoc-gen-go protoc-gen-micro /usr/bin/
  7. ENTRYPOINT ["protoc"]

C:\Users\Administrator\Desktop\gopaas\yu-v3\readme.md

  1. # 工具制作说明
  2. 工具可执行文件基于 linux 环境制作,go版本1.16
  3. ## protoc 和 protoc-gen-go 的安装
  4. ### 1.下载对应版本的 protoc
  5. ```
  6. 镜像中使用如下命令下在 dockerfile 中
  7. apk add protoc
  8. ```
  9. ### 2.下载安装 go 的插件protoc-gen-go
  10. ```
  11. go install github.com/golang/protobuf/protoc-gen-go@v1.27
  12. ```
  13. 注意:要用protoc-gen-go@v1.27 版本
  14. ### 3.安装gen-micro
  15. 这里选择的是 v3 的版本
  16. 在课程制作的过程中 go-micro v4 刚出来测试过和proto 还有兼容问题等稳定可以切换
  17. ```
  18. go get -u github.com/asim/go-micro/cmd/protoc-gen-micro/v3
  19. ```
  20. ### 4.安装完成后在安装的机器上运行
  21. protoc

C:\Users\Administrator\Desktop\gopaas\yu-tool

6-3 Service 服务端 model 模型开发

PS C:\Users\Administrator\Desktop\gopaas\yu-tool> ./yu-tool.exe newService github.com/yunixiangfeng/gopaas/svc

C:\Users\Administrator\Desktop\gopaas\svc\main.go

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/yunixiangfeng/gopaas/common"
  6. "github.com/yunixiangfeng/gopaas/svc/domain/repository"
  7. "path/filepath"
  8. //"github.com/afex/hystrix-go/hystrix"
  9. "github.com/asim/go-micro/plugins/registry/consul/v3"
  10. service2 "github.com/yunixiangfeng/gopaas/svc/domain/service"
  11. ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
  12. opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
  13. "github.com/asim/go-micro/v3"
  14. "github.com/asim/go-micro/v3/registry"
  15. "github.com/asim/go-micro/v3/server"
  16. "github.com/jinzhu/gorm"
  17. _ "github.com/jinzhu/gorm/dialects/mysql"
  18. "github.com/opentracing/opentracing-go"
  19. "github.com/yunixiangfeng/gopaas/svc/handler"
  20. //hystrix2 "github.com/yunixiangfeng/gopaas/svc/plugin/hystrix"
  21. "strconv"
  22. "k8s.io/client-go/kubernetes"
  23. "k8s.io/client-go/tools/clientcmd"
  24. "k8s.io/client-go/util/homedir"
  25. svc "github.com/yunixiangfeng/gopaas/svc/proto/svc"
  26. )
  27. var (
  28. //服务地址
  29. hostIp = "192.168.204.130"
  30. //服务地址
  31. serviceHost = hostIp
  32. //服务端口
  33. servicePort = "8083"
  34. //注册中心配置
  35. consulHost = hostIp
  36. consulPort int64 = 8500
  37. //链路追踪
  38. tracerHost = hostIp
  39. tracerPort = 6831
  40. //熔断端口,每个服务不能重复
  41. //hystrixPort = 9092
  42. //监控端口,每个服务不能重复
  43. prometheusPort = 9192
  44. )
  45. func main() {
  46. //需要本地启动,mysql,consul中间件服务
  47. //1.注册中心
  48. consul:=consul.NewRegistry(func(options *registry.Options) {
  49. options.Addrs = []string{
  50. consulHost+":"+strconv.FormatInt(consulPort,10),
  51. }
  52. })
  53. //2.配置中心,存放经常变动的变量
  54. consulConfig,err := common.GetConsulConfig(consulHost,consulPort,"/micro/config")
  55. if err !=nil {
  56. common.Error(err)
  57. }
  58. //3.使用配置中心连接 mysql
  59. mysqlInfo := common.GetMysqlFromConsul(consulConfig,"mysql")
  60. //初始化数据库
  61. db,err := gorm.Open("mysql",mysqlInfo.User+":"+mysqlInfo.Pwd+"@("+mysqlInfo.Host+":3306)/"+mysqlInfo.Database+"?charset=utf8&parseTime=True&loc=Local")
  62. if err !=nil {
  63. //命令行输出下,方便查看错误
  64. fmt.Println(err)
  65. common.Fatal(err)
  66. }
  67. defer db.Close()
  68. //禁止复表
  69. db.SingularTable(true)
  70. //4.添加链路追踪
  71. t,io,err := common.NewTracer("go.micro.service.svc",tracerHost+":"+strconv.Itoa(tracerPort))
  72. if err !=nil {
  73. common.Error(err)
  74. }
  75. defer io.Close()
  76. opentracing.SetGlobalTracer(t)
  77. //添加熔断器,作为客户端需要启用
  78. //hystrixStreamHandler := hystrix.NewStreamHandler()
  79. //hystrixStreamHandler.Start()
  80. //添加日志中心
  81. //1)需要程序日志打入到日志文件中
  82. //2)在程序中添加filebeat.yml 文件
  83. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  84. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  85. //启动监听程序
  86. //go func() {
  87. // //http://192.168.204.130:9092/turbine/turbine.stream
  88. // //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  89. // err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",strconv.Itoa(hystrixPort)),hystrixStreamHandler)
  90. // if err !=nil {
  91. // common.Error(err)
  92. // }
  93. //}()
  94. //5.添加监控
  95. common.PrometheusBoot(prometheusPort)
  96. //下载kubectl:https://kubernetes.io/docs/tasks/tools/#tabset-2
  97. //macos:
  98. // 1.curl -LO "https://dl.k8s.io/release/v1.21.0/bin/darwin/amd64/kubectl"
  99. // 2.chmod +x ./kubectl
  100. // 3.sudo mv ./kubectl /usr/local/bin/kubectl
  101. // sudo chown root: /usr/local/bin/kubectl
  102. // 5.kubectl version --client
  103. // 6.集群模式下直接拷贝服务端~/.kube/config 文件到本机 ~/.kube/confg 中
  104. // 注意:- config中的域名要能解析正确
  105. // - 生产环境可以创建另一个证书
  106. // 7.kubectl get ns 查看是否正常
  107. //
  108. //6.创建k8s连接
  109. //在集群外面连接
  110. var kubeconfig *string
  111. if home := homedir.HomeDir(); home != "" {
  112. kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
  113. } else {
  114. kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
  115. }
  116. flag.Parse()
  117. config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
  118. if err != nil {
  119. common.Fatal(err.Error())
  120. }
  121. //在集群中外的配置
  122. //config, err := rest.InClusterConfig()
  123. //if err != nil {
  124. // panic(err.Error())
  125. //}
  126. // create the clientset
  127. clientset, err := kubernetes.NewForConfig(config)
  128. if err != nil {
  129. common.Fatal(err.Error())
  130. }
  131. //7.创建服务
  132. service := micro.NewService(
  133. //自定义服务地址,且必须写在其它参数前面
  134. micro.Server(server.NewServer(func(options *server.Options) {
  135. options.Advertise =serviceHost+":"+servicePort
  136. })),
  137. micro.Name("go.micro.service.svc"),
  138. micro.Version("latest"),
  139. //指定服务端口
  140. micro.Address(":"+servicePort),
  141. //添加注册中心
  142. micro.Registry(consul),
  143. //添加链路追踪
  144. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  145. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  146. //只作为客户端的时候起作用,如果存在调用别人的情况,原则上不去主动调用
  147. //micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  148. //添加限流
  149. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  150. )
  151. service.Init()
  152. //只能执行一遍
  153. //err = repository.NewSvcRepository(db).InitTable()
  154. //if err != nil {
  155. // common.Fatal(err)
  156. //}
  157. // 注册句柄,可以快速操作已开发的服务
  158. svcDataService:=service2.NewSvcDataService(repository.NewSvcRepository(db),clientset)
  159. svc.RegisterSvcHandler(service.Server(), &handler.SvcHandler{ SvcDataService:svcDataService})
  160. // 启动服务
  161. if err := service.Run(); err != nil {
  162. //输出启动失败信息
  163. common.Fatal(err)
  164. }
  165. }

C:\Users\Administrator\Desktop\gopaas\svc\domain\model\svc.go

  1. package model
  2. type Svc struct {
  3. ID int64 `gorm:"primary_key;not_null;auto_increment"`
  4. //服务名称
  5. SvcName string `gorm:"unique_index;not_null" json:"svc_name"`
  6. //服务名称命名空间
  7. SvcNamespace string `gorm:"not_null" json:"svc_namespace"`
  8. //绑定的POD名称
  9. SvcPodName string `gorm:"not_null" json:"svc_pod_name"`
  10. //ClusterIP,NodePort,LoadBalancer,ExternalName
  11. SvcType string `json:"svc_type"`
  12. //type类型为:ExternalName 时候启用该字段
  13. SvcExternalName string `json:"svc_external_name"`
  14. //业务侧的团队ID
  15. SvcTeamId string `json:"svc_team_id"`
  16. //服务上的端口设置
  17. SvcPort []SvcPort `gorm:"ForeignKey:SvcID" json:"svc_port"`
  18. }

C:\Users\Administrator\Desktop\gopaas\svc\domain\model\svc_port.go 

  1. package model
  2. type SvcPort struct {
  3. ID int64 `gorm:"primary_key;not_null;auto_increment"`
  4. SvcID int64 `json:"svc_id"`
  5. //服务的port
  6. SvcPort int32 `json:"svc_port"`
  7. //pod 中需要映射的port地址
  8. SvcTargetPort int32 `json:"svc_target_port"`
  9. //开启NodePort的模式下进行设置
  10. SvcNodePort int32 `json:"svc_node_port"`
  11. //端口协议
  12. SvcPortProtocol string `json:"svc_port_protocol"`
  13. }

6-4 service 服务端proto 文件开发及代码生成

C:\Users\Administrator\Desktop\gopaas\svc\proto\svc\svc.proto

  1. syntax = "proto3";
  2. package svc;
  3. option go_package = "./proto/svc;svc";
  4. service Svc {
  5. //对外提供添加服务
  6. rpc AddSvc(SvcInfo) returns (Response) {}
  7. rpc DeleteSvc(SvcId) returns (Response) {}
  8. rpc UpdateSvc(SvcInfo) returns (Response) {}
  9. rpc FindSvcByID(SvcId) returns (SvcInfo) {}
  10. rpc FindAllSvc(FindAll) returns (AllSvc) {}
  11. }
  12. message SvcInfo {
  13. int64 id = 1;
  14. string svc_namespace=2;
  15. string svc_name=3;
  16. string svc_pod_name=4;
  17. string svc_type=5;
  18. string svc_external_name=6;
  19. string svc_team_id=7;
  20. repeated SvcPort svc_port=8;
  21. }
  22. message SvcPort{
  23. int64 id =1 ;
  24. int64 svc_id =2;
  25. int32 svc_port=3;
  26. int32 svc_target_port=4;
  27. int32 svc_node_port=5;
  28. string svc_port_protocol=6;
  29. }
  30. message SvcId {
  31. int64 id = 1;
  32. }
  33. message FindAll {
  34. }
  35. message Response {
  36. string msg =1 ;
  37. }
  38. message AllSvc {
  39. repeated SvcInfo svc_info = 1;
  40. }
PS D:\Workspace\Go\bin> D:\Workspace\Go\bin\protoc.exe --proto_path=C:\Users\Administrator\Desktop\gopaas\svc --micro_out=C:\Users\Administrator\Desktop\gopaas\svc --go_out=:C:\Users\Administrator\Desktop\gopaas\svc proto/svc/svc.proto

 proto\svc\svc.pb.go proto\svc\svc.pb.micro.go

6-5 Service 服务开发

PS C:\Users\Administrator\Desktop\gopaas\svc> go mod tidy 

C:\Users\Administrator\Desktop\gopaas\svc\domain\service\svc_data_service.go

  1. package service
  2. import (
  3. "context"
  4. "errors"
  5. "strconv"
  6. "github.com/yunixiangfeng/gopaas/common"
  7. "github.com/yunixiangfeng/gopaas/svc/domain/model"
  8. "github.com/yunixiangfeng/gopaas/svc/domain/repository"
  9. "github.com/yunixiangfeng/gopaas/svc/proto/svc"
  10. v1 "k8s.io/api/core/v1"
  11. v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
  12. "k8s.io/apimachinery/pkg/util/intstr"
  13. "k8s.io/client-go/kubernetes"
  14. )
  15. //这里是接口类型
  16. type ISvcDataService interface {
  17. AddSvc(*model.Svc) (int64, error)
  18. DeleteSvc(int64) error
  19. UpdateSvc(*model.Svc) error
  20. FindSvcByID(int64) (*model.Svc, error)
  21. FindAllSvc() ([]model.Svc, error)
  22. CreateSvcToK8s(*svc.SvcInfo) error
  23. UpdateSvcToK8s(*svc.SvcInfo) error
  24. DeleteFromK8s(*model.Svc) error
  25. }
  26. //创建
  27. //注意:返回值 ISvcDataService 接口类型
  28. func NewSvcDataService(svcRepository repository.ISvcRepository, clientSet *kubernetes.Clientset) ISvcDataService {
  29. return &SvcDataService{SvcRepository: svcRepository, K8sClientSet: clientSet}
  30. }
  31. type SvcDataService struct {
  32. //注意:这里是 ISvcRepository 类型
  33. SvcRepository repository.ISvcRepository
  34. K8sClientSet *kubernetes.Clientset
  35. }
  36. //创建服务到K8s中
  37. func (u *SvcDataService) CreateSvcToK8s(svcInfo *svc.SvcInfo) (err error) {
  38. service := u.setService(svcInfo)
  39. //查找是否存在指定的服务
  40. if _, err = u.K8sClientSet.CoreV1().Services(svcInfo.SvcNamespace).Get(context.TODO(), svcInfo.SvcName, v12.GetOptions{}); err != nil {
  41. //查找不到,就创建
  42. if _, err = u.K8sClientSet.CoreV1().Services(svcInfo.SvcNamespace).Create(context.TODO(), service, v12.CreateOptions{}); err != nil {
  43. common.Error(err)
  44. return err
  45. }
  46. return nil
  47. } else {
  48. common.Error("Service " + svcInfo.SvcName + "已经存在")
  49. return errors.New("Service " + svcInfo.SvcName + "已经存在")
  50. }
  51. }
  52. //根据svcnfo 设置Iservice 信息
  53. func (u *SvcDataService) setService(svcInfo *svc.SvcInfo) *v1.Service {
  54. service := &v1.Service{}
  55. //设置服务类型
  56. service.TypeMeta = v12.TypeMeta{
  57. Kind: "v1",
  58. APIVersion: "service",
  59. }
  60. //设置服务基础信息
  61. service.ObjectMeta = v12.ObjectMeta{
  62. Name: svcInfo.SvcName,
  63. Namespace: svcInfo.SvcNamespace,
  64. Labels: map[string]string{
  65. "app-name": svcInfo.SvcPodName,
  66. "author": "wu123",
  67. },
  68. Annotations: map[string]string{
  69. "k8s/generated-by-yu": "由代码创建",
  70. },
  71. }
  72. //设置服务的spec信息,采用ClusterIP模式
  73. service.Spec = v1.ServiceSpec{
  74. Ports: u.getSvcPort(svcInfo),
  75. Selector: map[string]string{
  76. "app-name": svcInfo.SvcPodName,
  77. },
  78. Type: "ClusterIP",
  79. }
  80. return service
  81. }
  82. func (u *SvcDataService) getSvcPort(svcInfo *svc.SvcInfo) (servicePort []v1.ServicePort) {
  83. for _, v := range svcInfo.SvcPort {
  84. servicePort = append(servicePort, v1.ServicePort{
  85. Name: "port-" + strconv.FormatInt(int64(v.SvcPort), 10),
  86. Protocol: v1.Protocol(v.SvcPortProtocol),
  87. Port: v.SvcPort,
  88. TargetPort: intstr.FromInt(int(v.SvcTargetPort)),
  89. })
  90. }
  91. return
  92. }
  93. func (u *SvcDataService) UpdateSvcToK8s(svcInfo *svc.SvcInfo) (err error) {
  94. service := u.setService(svcInfo)
  95. //查找是否存在指定的服务
  96. if _, err = u.K8sClientSet.CoreV1().Services(svcInfo.SvcNamespace).Get(context.TODO(), svcInfo.SvcName, v12.GetOptions{}); err != nil {
  97. //查找不到
  98. common.Error(err)
  99. return errors.New("Service" + svcInfo.SvcName + "不存在请先创建")
  100. } else {
  101. if _, err = u.K8sClientSet.CoreV1().Services(svcInfo.SvcNamespace).Update(context.TODO(), service, v12.UpdateOptions{}); err != nil {
  102. common.Error(err)
  103. return err
  104. }
  105. common.Info("Service " + svcInfo.SvcName + "更新成功")
  106. return nil
  107. }
  108. }
  109. func (u *SvcDataService) DeleteFromK8s(svc *model.Svc) (err error) {
  110. if err = u.K8sClientSet.CoreV1().Services(svc.SvcNamespace).Delete(context.TODO(), svc.SvcName, v12.DeleteOptions{}); err != nil {
  111. common.Error(err)
  112. return err
  113. } else {
  114. if err := u.DeleteSvc(svc.ID); err != nil {
  115. common.Error(err)
  116. return err
  117. }
  118. common.Info("删除Service ID:" + strconv.FormatInt(svc.ID, 10) + "成功!")
  119. }
  120. return
  121. }
  122. //插入
  123. func (u *SvcDataService) AddSvc(svc *model.Svc) (int64, error) {
  124. return u.SvcRepository.CreateSvc(svc)
  125. }
  126. //删除
  127. func (u *SvcDataService) DeleteSvc(svcID int64) error {
  128. return u.SvcRepository.DeleteSvcByID(svcID)
  129. }
  130. //更新
  131. func (u *SvcDataService) UpdateSvc(svc *model.Svc) error {
  132. return u.SvcRepository.UpdateSvc(svc)
  133. }
  134. //查找
  135. func (u *SvcDataService) FindSvcByID(svcID int64) (*model.Svc, error) {
  136. return u.SvcRepository.FindSvcByID(svcID)
  137. }
  138. //查找
  139. func (u *SvcDataService) FindAllSvc() ([]model.Svc, error) {
  140. return u.SvcRepository.FindAll()
  141. }

6-6 svc API 工程创建及接口业务逻辑开发

PS C:\Users\Administrator\Desktop\gopaas> ./yu-tool/yu-tool.exe createApi github.com/yunixiangfeng/gopaas/svcApi

C:\Users\Administrator\Desktop\gopaas\svcApi

PS D:\Workspace\Go\bin> D:\Workspace\Go\bin\protoc.exe --proto_path=C:\Users\Administrator\Desktop\gopaas\svcapi --micro_out=C:\Users\Administrator\Desktop\gopaas\svcapi --go_out=:C:\Users\Administrator\Desktop\gopaas\svcapi proto/svcApi/svcApi.proto

C:\Users\Administrator\Desktop\gopaas\svcApi\handler\svcApiHandler.go

  1. package handler
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "strconv"
  7. log "github.com/asim/go-micro/v3/logger"
  8. "github.com/yunixiangfeng/gopaas/common"
  9. svc "github.com/yunixiangfeng/gopaas/svc/proto/svc"
  10. form "github.com/yunixiangfeng/gopaas/svcApi/plugin/form"
  11. svcApi "github.com/yunixiangfeng/gopaas/svcApi/proto/svcApi"
  12. )
  13. type SvcApi struct {
  14. SvcService svc.SvcService
  15. }
  16. // svcApi.FindSvcById 通过API向外暴露为/svcApi/findSvcById,接收http请求
  17. // 即:/svcApi/FindSvcById 请求会调用go.micro.api.svcApi 服务的svcApi.FindSvcById 方法
  18. func (e *SvcApi) FindSvcById(ctx context.Context, req *svcApi.Request, rsp *svcApi.Response) error {
  19. log.Info("Received svcApi.FindSvcById request")
  20. if _, ok := req.Get["svc_id"]; !ok {
  21. rsp.StatusCode = 500
  22. return errors.New("参数异常")
  23. }
  24. //获取 svcId 参数
  25. svcIdString := req.Get["svc_id"].Values[0]
  26. svcId, err := strconv.ParseInt(svcIdString, 10, 64)
  27. if err != nil {
  28. common.Error(err)
  29. return err
  30. }
  31. //获取svc相关信息
  32. svcInfo, err := e.SvcService.FindSvcByID(ctx, &svc.SvcId{
  33. Id: svcId,
  34. })
  35. if err != nil {
  36. common.Error(err)
  37. return err
  38. }
  39. //json 返回svc信息
  40. rsp.StatusCode = 200
  41. b, _ := json.Marshal(svcInfo)
  42. rsp.Body = string(b)
  43. return nil
  44. }
  45. // svcApi.AddSvc 通过API向外暴露为/svcApi/AddSvc,接收http请求
  46. // 即:/svcApi/AddSvc 请求会调用go.micro.api.svcApi 服务的svcApi.AddSvc 方法
  47. func (e *SvcApi) AddSvc(ctx context.Context, req *svcApi.Request, rsp *svcApi.Response) error {
  48. log.Info("Received svcApi.AddSvc request")
  49. //处理port
  50. addSvcInfo := &svc.SvcInfo{}
  51. svcType, ok := req.Post["svc_type"]
  52. if ok && len(svcType.Values) > 0 {
  53. svcPort := &svc.SvcPort{}
  54. switch svcType.Values[0] {
  55. case "ClusterIP":
  56. port, err := strconv.ParseInt(req.Post["svc_port"].Values[0], 10, 64)
  57. if err != nil {
  58. common.Error(err)
  59. return err
  60. }
  61. svcPort.SvcPort = int32(port)
  62. targetPort, err := strconv.ParseInt(req.Post["svc_target_port"].Values[0], 10, 32)
  63. if err != nil {
  64. common.Error(err)
  65. return err
  66. }
  67. svcPort.SvcTargetPort = int32(targetPort)
  68. svcPort.SvcPortProtocol = req.Post["svc_port_protocol"].Values[0]
  69. addSvcInfo.SvcPort = append(addSvcInfo.SvcPort, svcPort)
  70. default:
  71. return errors.New("类型不支持")
  72. }
  73. }
  74. //form 类型转换到结构体中
  75. form.FormToSvcStruct(req.Post, addSvcInfo)
  76. response, err := e.SvcService.AddSvc(ctx, addSvcInfo)
  77. if err != nil {
  78. common.Error(err)
  79. return err
  80. }
  81. rsp.StatusCode = 200
  82. b, _ := json.Marshal(response)
  83. rsp.Body = string(b)
  84. return nil
  85. }
  86. // svcApi.DeleteSvcById 通过API向外暴露为/svcApi/DeleteSvcById,接收http请求
  87. // 即:/svcApi/DeleteSvcById 请求会调用go.micro.api.svcApi 服务的 svcApi.DeleteSvcById 方法
  88. func (e *SvcApi) DeleteSvcById(ctx context.Context, req *svcApi.Request, rsp *svcApi.Response) error {
  89. log.Info("Received svcApi.DeleteSvcById request")
  90. if _, ok := req.Get["svc_id"]; !ok {
  91. return errors.New("参数异常")
  92. }
  93. //获取需要删除的ID
  94. svcIdString := req.Get["svc_id"].Values[0]
  95. svcId, err := strconv.ParseInt(svcIdString, 10, 64)
  96. if err != nil {
  97. common.Error(err)
  98. return err
  99. }
  100. //调用后端服务删除
  101. response, err := e.SvcService.DeleteSvc(ctx, &svc.SvcId{
  102. Id: svcId,
  103. })
  104. if err != nil {
  105. common.Error(err)
  106. return err
  107. }
  108. rsp.StatusCode = 200
  109. b, _ := json.Marshal(response)
  110. rsp.Body = string(b)
  111. return nil
  112. }
  113. // svcApi.UpdateSvc 通过API向外暴露为/svcApi/UpdateSvc,接收http请求
  114. // 即:/svcApi/UpdateSvc 请求会调用go.micro.api.svcApi 服务的svcApi.UpdateSvc 方法
  115. func (e *SvcApi) UpdateSvc(ctx context.Context, req *svcApi.Request, rsp *svcApi.Response) error {
  116. log.Info("Received svcApi.UpdateSvc request")
  117. rsp.StatusCode = 200
  118. b, _ := json.Marshal("{success:'成功访问/svcApi/UpdateSvc'}")
  119. rsp.Body = string(b)
  120. return nil
  121. }
  122. // 默认的方法svcApi.Call 通过API向外暴露为/svcApi/call,接收http请求
  123. // 即:/svcApi/call或/svcApi/ 请求会调用go.micro.api.svcApi 服务的svcApi.FindSvcById 方法
  124. func (e *SvcApi) Call(ctx context.Context, req *svcApi.Request, rsp *svcApi.Response) error {
  125. log.Info("Received svcApi.Call request")
  126. allSvc, err := e.SvcService.FindAllSvc(ctx, &svc.FindAll{})
  127. if err != nil {
  128. common.Error(err)
  129. return err
  130. }
  131. rsp.StatusCode = 200
  132. b, _ := json.Marshal(allSvc)
  133. rsp.Body = string(b)
  134. return nil
  135. }

C:\Users\Administrator\Desktop\gopaas\svcApi\plugin\form\form.go

  1. package form
  2. import (
  3. "errors"
  4. "reflect"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/yunixiangfeng/gopaas/common"
  9. "github.com/yunixiangfeng/gopaas/svcApi/proto/svcApi"
  10. )
  11. //根据结构体中name标签映射数据到结构体中并且转换类型
  12. func FormToSvcStruct(data map[string]*svcApi.Pair, obj interface{}) {
  13. objValue := reflect.ValueOf(obj).Elem()
  14. for i := 0; i < objValue.NumField(); i++ {
  15. //获取sql对应的值
  16. dataTag := strings.Replace(objValue.Type().Field(i).Tag.Get("json"), ",omitempty", "", -1)
  17. dataSlice, ok := data[dataTag]
  18. if !ok {
  19. continue
  20. }
  21. valueSlice := dataSlice.Values
  22. if len(valueSlice) <= 0 {
  23. continue
  24. }
  25. //排除port和env
  26. if dataTag == "svc_port" || dataTag == "svc_target_port" {
  27. continue
  28. }
  29. value := valueSlice[0]
  30. //端口,环境变量的单独处理
  31. //获取对应字段的名称
  32. name := objValue.Type().Field(i).Name
  33. //获取对应字段类型
  34. structFieldType := objValue.Field(i).Type()
  35. //获取变量类型,也可以直接写"string类型"
  36. val := reflect.ValueOf(value)
  37. var err error
  38. if structFieldType != val.Type() {
  39. //类型转换
  40. val, err = TypeConversion(value, structFieldType.Name()) //类型转换
  41. if err != nil {
  42. common.Error(err)
  43. }
  44. }
  45. //设置类型值
  46. objValue.FieldByName(name).Set(val)
  47. }
  48. }
  49. //类型转换
  50. func TypeConversion(value string, ntype string) (reflect.Value, error) {
  51. if ntype == "string" {
  52. return reflect.ValueOf(value), nil
  53. } else if ntype == "time.Time" {
  54. t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
  55. return reflect.ValueOf(t), err
  56. } else if ntype == "Time" {
  57. t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
  58. return reflect.ValueOf(t), err
  59. } else if ntype == "int" {
  60. i, err := strconv.Atoi(value)
  61. return reflect.ValueOf(i), err
  62. } else if ntype == "int32" {
  63. i, err := strconv.ParseInt(value, 10, 32)
  64. if err != nil {
  65. return reflect.ValueOf(int32(i)), err
  66. }
  67. return reflect.ValueOf(int32(i)), err
  68. } else if ntype == "int64" {
  69. i, err := strconv.ParseInt(value, 10, 64)
  70. return reflect.ValueOf(i), err
  71. } else if ntype == "float32" {
  72. i, err := strconv.ParseFloat(value, 64)
  73. return reflect.ValueOf(float32(i)), err
  74. } else if ntype == "float64" {
  75. i, err := strconv.ParseFloat(value, 64)
  76. return reflect.ValueOf(i), err
  77. }
  78. //else if .......增加其他一些类型的转换
  79. return reflect.ValueOf(value), errors.New("未知的类型:" + ntype)
  80. }

C:\Users\Administrator\Desktop\gopaas\svcApi\main.go

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/afex/hystrix-go/hystrix"
  5. "github.com/asim/go-micro/plugins/registry/consul/v3"
  6. ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
  7. "github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v3"
  8. opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
  9. "github.com/asim/go-micro/v3"
  10. "github.com/asim/go-micro/v3/registry"
  11. "github.com/asim/go-micro/v3/server"
  12. "github.com/yunixiangfeng/gopaas/common"
  13. go_micro_service_svc "github.com/yunixiangfeng/gopaas/svc/proto/svc"
  14. "net"
  15. "net/http"
  16. "strconv"
  17. _ "github.com/jinzhu/gorm/dialects/mysql"
  18. "github.com/opentracing/opentracing-go"
  19. "github.com/yunixiangfeng/gopaas/svcApi/handler"
  20. hystrix2 "github.com/yunixiangfeng/gopaas/svcApi/plugin/hystrix"
  21. svcApi "github.com/yunixiangfeng/gopaas/svcApi/proto/svcApi"
  22. )
  23. var (
  24. //服务地址
  25. hostIp = "192.168.204.130"
  26. //服务地址
  27. serviceHost = hostIp
  28. //服务端口
  29. servicePort = "8084"
  30. //注册中心配置
  31. consulHost = hostIp
  32. consulPort int64 = 8500
  33. //链路追踪
  34. tracerHost = hostIp
  35. tracerPort = 6831
  36. //熔断端口,每个服务不能重复
  37. hystrixPort = 9094
  38. //监控端口,每个服务不能重复
  39. prometheusPort = 9194
  40. )
  41. func main() {
  42. //需要本地启动,mysql,consul中间件服务
  43. //1.注册中心
  44. consul := consul.NewRegistry(func(options *registry.Options) {
  45. options.Addrs = []string{
  46. consulHost + ":" + strconv.FormatInt(consulPort, 10),
  47. }
  48. })
  49. //2.添加链路追踪
  50. t, io, err := common.NewTracer("go.micro.api.svcApi", tracerHost+":"+strconv.Itoa(tracerPort))
  51. if err != nil {
  52. common.Error(err)
  53. }
  54. defer io.Close()
  55. opentracing.SetGlobalTracer(t)
  56. //3.添加熔断器
  57. hystrixStreamHandler := hystrix.NewStreamHandler()
  58. hystrixStreamHandler.Start()
  59. //添加日志中心
  60. //1)需要程序日志打入到日志文件中
  61. //2)在程序中添加filebeat.yml 文件
  62. //3) 启动filebeat,启动命令 ./filebeat -e -c filebeat.yml
  63. fmt.Println("日志统一记录在根目录 micro.log 文件中,请点击查看日志!")
  64. //启动监听程序
  65. go func() {
  66. //http://192.168.204.130:9092/turbine/turbine.stream
  67. //看板访问地址 http://127.0.0.1:9002/hystrix,url后面一定要带 /hystrix
  68. err = http.ListenAndServe(net.JoinHostPort("0.0.0.0", strconv.Itoa(hystrixPort)), hystrixStreamHandler)
  69. if err != nil {
  70. common.Error(err)
  71. }
  72. }()
  73. //4.添加监控
  74. common.PrometheusBoot(prometheusPort)
  75. //5.创建服务
  76. service := micro.NewService(
  77. //自定义服务地址,且必须写在其它参数前面
  78. micro.Server(server.NewServer(func(opts *server.Options) {
  79. opts.Advertise = serviceHost + ":" + servicePort
  80. })),
  81. micro.Name("go.micro.api.svcApi"),
  82. micro.Version("latest"),
  83. //指定服务端口
  84. micro.Address(":"+servicePort),
  85. //添加注册中心
  86. micro.Registry(consul),
  87. //添加链路追踪
  88. micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
  89. micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
  90. //只作为客户端的时候起作用
  91. micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
  92. //添加限流
  93. micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
  94. //增加负载均衡
  95. micro.WrapClient(roundrobin.NewClientWrapper()),
  96. )
  97. service.Init()
  98. // 指定需要访问的服务,可以快速操作已开发的服务,
  99. // 默认API服务名称带有"Api",程序会自动替换
  100. // 如果不带有特定字符会使用默认"XXX" 请自行替换
  101. svcService := go_micro_service_svc.NewSvcService("go.micro.service.svc", service.Client())
  102. // 注册控制器
  103. if err := svcApi.RegisterSvcApiHandler(service.Server(), &handler.SvcApi{SvcService: svcService}); err != nil {
  104. common.Error(err)
  105. }
  106. // 启动服务
  107. if err := service.Run(); err != nil {
  108. //输出启动失败信息
  109. common.Fatal(err)
  110. }
  111. }

[root@k8s-worker01 gopaas]# ./api-gateway --registry=consul --registry_address=192.168.204.130:8500 api --handler=api

6-7 服务管理前端效果展示及删除接口完善

C:\Users\Administrator\Desktop\gopaas\go-paas-front\svc-create.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="description" content="">
  8. <meta name="author" content="">
  9. <link rel="shortcut icon" href="assets/img/logo-fav.png">
  10. <title>CPaaS</title>
  11. <link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
  12. <link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
  13. <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  14. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  15. <![endif]-->
  16. <link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
  17. </head>
  18. <body>
  19. <div class="be-wrapper">
  20. <nav class="navbar navbar-default navbar-fixed-top be-top-header">
  21. <div class="container-fluid">
  22. <div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
  23. </div>
  24. <div class="be-right-navbar">
  25. <ul class="nav navbar-nav navbar-right be-user-nav">
  26. <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>
  27. <ul role="menu" class="dropdown-menu">
  28. <li>
  29. <div class="user-info">
  30. <div class="user-name">Túpac Amaru</div>
  31. <div class="user-position online">Available</div>
  32. </div>
  33. </li>
  34. <li><a href="#"><span class="icon mdi mdi-face"></span> Account</a></li>
  35. <li><a href="#"><span class="icon mdi mdi-settings"></span> Settings</a></li>
  36. <li><a href="#"><span class="icon mdi mdi-power"></span> Logout</a></li>
  37. </ul>
  38. </li>
  39. </ul>
  40. <div class="page-title"><span>Form Validation</span></div>
  41. <ul class="nav navbar-nav navbar-right be-icons-nav">
  42. <li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
  43. <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>
  44. <ul class="dropdown-menu be-notifications">
  45. <li>
  46. <div class="title">Notifications<span class="badge">3</span></div>
  47. <div class="list">
  48. <div class="be-scroller">
  49. <div class="content">
  50. <ul>
  51. <li class="notification notification-unread"><a href="#">
  52. <div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
  53. <div class="notification-info">
  54. <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>
  55. </div></a></li>
  56. <li class="notification"><a href="#">
  57. <div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
  58. <div class="notification-info">
  59. <div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
  60. </div></a></li>
  61. <li class="notification"><a href="#">
  62. <div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
  63. <div class="notification-info">
  64. <div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
  65. </div></a></li>
  66. <li class="notification"><a href="#">
  67. <div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
  68. <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>
  69. </ul>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="footer"> <a href="#">View all notifications</a></div>
  74. </li>
  75. </ul>
  76. </li>
  77. <li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
  78. <ul class="dropdown-menu be-connections">
  79. <li>
  80. <div class="list">
  81. <div class="content">
  82. <div class="row">
  83. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
  84. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
  85. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
  86. </div>
  87. <div class="row">
  88. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
  89. <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>
  90. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="footer"> <a href="#">More</a></div>
  95. </li>
  96. </ul>
  97. </li>
  98. </ul>
  99. </div>
  100. </div>
  101. </nav>
  102. <!--
  103. 侧边栏-开始
  104. -->
  105. <div class="be-left-sidebar">
  106. <div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
  107. <div class="left-sidebar-spacer">
  108. <div class="left-sidebar-scroll">
  109. <div class="left-sidebar-content">
  110. <ul class="sidebar-elements">
  111. <li class="divider">菜单</li>
  112. <li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
  113. </li>
  114. <li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
  115. <ul class="sub-menu">
  116. <li><a href="pod-index.html">添加应用</a>
  117. </li>
  118. </li>
  119. </ul>
  120. </li>
  121. <li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
  122. <ul class="sub-menu">
  123. <li class="active"><a href="svc-index.html">添加服务</a>
  124. </li>
  125. </ul>
  126. </li>
  127. <li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
  128. <ul class="sub-menu">
  129. <li><a href="form-elements.html">Elements</a>
  130. </li>
  131. <li><a href="form-validation.html">Validation</a>
  132. </li>
  133. <li><a href="form-multiselect.html">Multiselect</a>
  134. </li>
  135. <li><a href="form-wizard.html">Wizard</a>
  136. </li>
  137. <li><a href="form-masks.html">Input Masks</a>
  138. </li>
  139. <li><a href="form-wysiwyg.html">WYSIWYG Editor</a>
  140. </li>
  141. <li><a href="form-upload.html">Multi Upload</a>
  142. </li>
  143. <li><a href="form-editable.html">X-editable</a>
  144. </li>
  145. </ul>
  146. </li>
  147. <li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
  148. <ul class="sub-menu">
  149. <li><a href="tables-general.html">General</a>
  150. </li>
  151. <li><a href="tables-datatables.html">Data Tables</a>
  152. </li>
  153. <li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
  154. </li>
  155. </ul>
  156. </li>
  157. <li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
  158. <ul class="sub-menu">
  159. <li><a href="pages-blank.html">Blank Page</a>
  160. </li>
  161. <li><a href="pages-blank-header.html">Blank Page Header</a>
  162. </li>
  163. <li><a href="pages-login.html">Login</a>
  164. </li>
  165. <li><a href="pages-login2.html">Login v2</a>
  166. </li>
  167. <li><a href="pages-404.html">404 Page</a>
  168. </li>
  169. <li><a href="pages-sign-up.html">Sign Up</a>
  170. </li>
  171. <li><a href="pages-forgot-password.html">Forgot Password</a>
  172. </li>
  173. <li><a href="pages-profile.html">Profile</a>
  174. </li>
  175. <li><a href="pages-pricing-tables.html">Pricing Tables</a>
  176. </li>
  177. <li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
  178. </li>
  179. <li><a href="pages-timeline.html">Timeline</a>
  180. </li>
  181. <li><a href="pages-timeline2.html">Timeline v2</a>
  182. </li>
  183. <li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
  184. </li>
  185. <li><a href="pages-calendar.html">Calendar</a>
  186. </li>
  187. <li><a href="pages-gallery.html">Gallery</a>
  188. </li>
  189. <li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
  190. </li>
  191. <li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
  192. </li>
  193. <li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
  194. </li>
  195. </ul>
  196. </li>
  197. </ul>
  198. </div>
  199. </div>
  200. </div>
  201. <div class="progress-widget">
  202. <div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
  203. <div class="progress">
  204. <div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
  205. </div>
  206. </div>
  207. </div>
  208. </div>
  209. <!--
  210. 侧边栏-结束
  211. -->
  212. <div class="be-content">
  213. <div class="main-content container-fluid">
  214. <div class="row">
  215. <div class="col-md-12">
  216. <div class="panel panel-default panel-border-color panel-border-color-primary">
  217. <div class="panel-heading panel-heading-divider">创建服务<span class="panel-subtitle"></span></div>
  218. <div class="panel-body">
  219. <form action="http://localhost:8080/svcApi/addSvc" class="form-horizontal group-border-dashed" method="post" >
  220. <div class="form-group">
  221. <label class="col-sm-3 control-label">服务名称:</label>
  222. <div class="col-sm-6">
  223. <input type="text" required="" class="form-control" id="svc_name" name="svc_name">
  224. </div>
  225. </div>
  226. <div class="form-group">
  227. <label class="col-sm-3 control-label">命名空间:</label>
  228. <div class="col-sm-6">
  229. <input type="text" required="" class="form-control" id="svc_namespace" name="svc_namespace">
  230. </div>
  231. </div>
  232. <div class="form-group">
  233. <label class="col-sm-3 control-label">服务类型:</label>
  234. <div class="col-sm-6">
  235. <input type="text" required="" class="form-control" id="svc_type" name="svc_type" value="ClusterIP">
  236. </div>
  237. </div>
  238. <div class="form-group">
  239. <label class="col-sm-3 control-label">服务端口:</label>
  240. <div class="col-sm-6">
  241. <input type="text" required="" class="form-control" name="svc_port">
  242. </div>
  243. </div>
  244. <div class="form-group">
  245. <label class="col-sm-3 control-label">关联的 POD:</label>
  246. <div class="col-sm-6">
  247. <input type="text" required="" class="form-control" id="" name="svc_pod_name" id="svc_pod_name">
  248. </div>
  249. </div>
  250. <div class="form-group">
  251. <label class="col-sm-3 control-label">目标POD端口:</label>
  252. <div class="col-sm-6">
  253. <input type="text" required="" class="form-control" name="svc_target_port" id="svc_target_port">
  254. </div>
  255. </div>
  256. <div class="form-group">
  257. <label class="col-sm-3 control-label">端口协议:</label>
  258. <div class="col-sm-6">
  259. <input type="text" required="" class="form-control" id="svc_port_protocol" name="svc_port_protocol">
  260. </div>
  261. </div>
  262. <div class="form-group">
  263. <label class="col-sm-3 control-label">团队ID:</label>
  264. <div class="col-sm-6">
  265. <input type="text" required="" class="form-control" id="svc_team_id" name="svc_team_id">
  266. </div>
  267. </div>
  268. <div class="form-group">
  269. <div class="col-sm-2 col-sm-10">
  270. <button type="submit" class="btn btn-space btn-primary">创建服务</button>
  271. <button class="btn btn-space btn-default">Cancel</button>
  272. </div>
  273. </div>
  274. </form>
  275. </div>
  276. </div>
  277. </div>
  278. </div>
  279. </div>
  280. </div>
  281. </div>
  282. <script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
  283. <script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
  284. <script src="assets/js/main.js" type="text/javascript"></script>
  285. <script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
  286. <script src="assets/lib/parsley/parsley.min.js" type="text/javascript"></script>
  287. <script type="text/javascript">
  288. $(document).ready(function(){
  289. App.init();
  290. });
  291. //获取url中的参数
  292. function getUrlParam(name) {
  293. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
  294. var r = window.location.search.substr(1).match(reg); //匹配目标参数
  295. if (r != null) return unescape(r[2]); return null; //返回参数值
  296. }
  297. </script>
  298. </body>
  299. </html>

 C:\Users\Administrator\Desktop\gopaas\go-paas-front\svc-detail.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="description" content="">
  8. <meta name="author" content="">
  9. <link rel="shortcut icon" href="assets/img/logo-fav.png">
  10. <title>CPaaS</title>
  11. <link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
  12. <link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
  13. <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  14. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  15. <![endif]-->
  16. <link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
  17. </head>
  18. <body>
  19. <div class="be-wrapper">
  20. <nav class="navbar navbar-default navbar-fixed-top be-top-header">
  21. <div class="container-fluid">
  22. <div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
  23. </div>
  24. <div class="be-right-navbar">
  25. <ul class="nav navbar-nav navbar-right be-user-nav">
  26. <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>
  27. <ul role="menu" class="dropdown-menu">
  28. <li>
  29. <div class="user-info">
  30. <div class="user-name">Túpac Amaru</div>
  31. <div class="user-position online">Available</div>
  32. </div>
  33. </li>
  34. <li><a href="#"><span class="icon mdi mdi-face"></span> Account</a></li>
  35. <li><a href="#"><span class="icon mdi mdi-settings"></span> Settings</a></li>
  36. <li><a href="#"><span class="icon mdi mdi-power"></span> Logout</a></li>
  37. </ul>
  38. </li>
  39. </ul>
  40. <div class="page-title"><span>Form Validation</span></div>
  41. <ul class="nav navbar-nav navbar-right be-icons-nav">
  42. <li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
  43. <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>
  44. <ul class="dropdown-menu be-notifications">
  45. <li>
  46. <div class="title">Notifications<span class="badge">3</span></div>
  47. <div class="list">
  48. <div class="be-scroller">
  49. <div class="content">
  50. <ul>
  51. <li class="notification notification-unread"><a href="#">
  52. <div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
  53. <div class="notification-info">
  54. <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>
  55. </div></a></li>
  56. <li class="notification"><a href="#">
  57. <div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
  58. <div class="notification-info">
  59. <div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
  60. </div></a></li>
  61. <li class="notification"><a href="#">
  62. <div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
  63. <div class="notification-info">
  64. <div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
  65. </div></a></li>
  66. <li class="notification"><a href="#">
  67. <div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
  68. <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>
  69. </ul>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="footer"> <a href="#">View all notifications</a></div>
  74. </li>
  75. </ul>
  76. </li>
  77. <li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
  78. <ul class="dropdown-menu be-connections">
  79. <li>
  80. <div class="list">
  81. <div class="content">
  82. <div class="row">
  83. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
  84. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
  85. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
  86. </div>
  87. <div class="row">
  88. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
  89. <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>
  90. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="footer"> <a href="#">More</a></div>
  95. </li>
  96. </ul>
  97. </li>
  98. </ul>
  99. </div>
  100. </div>
  101. </nav>
  102. <!--
  103. 侧边栏-开始
  104. -->
  105. <div class="be-left-sidebar">
  106. <div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
  107. <div class="left-sidebar-spacer">
  108. <div class="left-sidebar-scroll">
  109. <div class="left-sidebar-content">
  110. <ul class="sidebar-elements">
  111. <li class="divider">菜单</li>
  112. <li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
  113. </li>
  114. <li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
  115. <ul class="sub-menu">
  116. <li ><a href="pod-index.html">添加应用</a>
  117. </li>
  118. </ul>
  119. </li>
  120. <li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
  121. <ul class="sub-menu">
  122. <li class="active"><a href="svc-index.html">添加服务</a>
  123. </li>
  124. </ul>
  125. </li>
  126. <li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
  127. <ul class="sub-menu">
  128. <li><a href="form-elements.html">Elements</a>
  129. </li>
  130. <li><a href="form-validation.html">Validation</a>
  131. </li>
  132. <li><a href="form-multiselect.html">Multiselect</a>
  133. </li>
  134. <li><a href="form-wizard.html">Wizard</a>
  135. </li>
  136. <li><a href="form-masks.html">Input Masks</a>
  137. </li>
  138. <li><a href="form-wysiwyg.html">WYSIWYG Editor</a>
  139. </li>
  140. <li><a href="form-upload.html">Multi Upload</a>
  141. </li>
  142. <li><a href="form-editable.html">X-editable</a>
  143. </li>
  144. </ul>
  145. </li>
  146. <li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
  147. <ul class="sub-menu">
  148. <li><a href="tables-general.html">General</a>
  149. </li>
  150. <li><a href="tables-datatables.html">Data Tables</a>
  151. </li>
  152. <li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
  153. </li>
  154. </ul>
  155. </li>
  156. <li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
  157. <ul class="sub-menu">
  158. <li><a href="pages-blank.html">Blank Page</a>
  159. </li>
  160. <li><a href="pages-blank-header.html">Blank Page Header</a>
  161. </li>
  162. <li><a href="pages-login.html">Login</a>
  163. </li>
  164. <li><a href="pages-login2.html">Login v2</a>
  165. </li>
  166. <li><a href="pages-404.html">404 Page</a>
  167. </li>
  168. <li><a href="pages-sign-up.html">Sign Up</a>
  169. </li>
  170. <li><a href="pages-forgot-password.html">Forgot Password</a>
  171. </li>
  172. <li><a href="pages-profile.html">Profile</a>
  173. </li>
  174. <li><a href="pages-pricing-tables.html">Pricing Tables</a>
  175. </li>
  176. <li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
  177. </li>
  178. <li><a href="pages-timeline.html">Timeline</a>
  179. </li>
  180. <li><a href="pages-timeline2.html">Timeline v2</a>
  181. </li>
  182. <li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
  183. </li>
  184. <li><a href="pages-calendar.html">Calendar</a>
  185. </li>
  186. <li><a href="pages-gallery.html">Gallery</a>
  187. </li>
  188. <li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
  189. </li>
  190. <li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
  191. </li>
  192. <li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
  193. </li>
  194. </ul>
  195. </li>
  196. </ul>
  197. </div>
  198. </div>
  199. </div>
  200. <div class="progress-widget">
  201. <div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
  202. <div class="progress">
  203. <div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
  204. </div>
  205. </div>
  206. </div>
  207. </div>
  208. <!--
  209. 侧边栏-结束
  210. -->
  211. <div class="be-content">
  212. <div class="main-content container-fluid">
  213. <div class="row">
  214. <div class="col-md-12">
  215. <div class="panel panel-default panel-border-color panel-border-color-primary">
  216. <div class="panel-heading panel-heading-divider">服务详情<span class="panel-subtitle">查看服务详情信息</span></div>
  217. <div class="panel-body">
  218. <form action="#" class="form-horizontal group-border-dashed">
  219. <div class="form-group">
  220. <label class="col-sm-3 control-label">服务ID:</label>
  221. <div class="col-sm-6">
  222. <input type="text" required="" readonly class="form-control" id="svc_id" name="pod_id">
  223. </div>
  224. </div>
  225. <div class="form-group">
  226. <label class="col-sm-3 control-label">服务名称:</label>
  227. <div class="col-sm-6">
  228. <input type="text" required="" readonly class="form-control" id="svc_name" name="pod_name">
  229. </div>
  230. </div>
  231. <div class="form-group">
  232. <label class="col-sm-3 control-label">命名空间:</label>
  233. <div class="col-sm-6">
  234. <input type="text" required="" readonly class="form-control" id="svc_namespace" name="pod_namespace">
  235. </div>
  236. </div>
  237. <div class="form-group">
  238. <label class="col-sm-3 control-label">服务类型:</label>
  239. <div class="col-sm-6">
  240. <input type="text" required="" readonly class="form-control" id="svc_type" name="svc_type">
  241. </div>
  242. </div>
  243. <div class="form-group">
  244. <label class="col-sm-3 control-label">关联的POD:</label>
  245. <div class="col-sm-6">
  246. <input type="text" required="" readonly class="form-control" id="svc_pod_name" name="svc_pod_name">
  247. </div>
  248. </div>
  249. <div class="form-group">
  250. <label class="col-sm-3 control-label">团队ID:</label>
  251. <div class="col-sm-6">
  252. <input type="text" required="" readonly class="form-control" id="svc_team_id" name="svc_team_id">
  253. </div>
  254. </div>
  255. </form>
  256. </div>
  257. </div>
  258. </div>
  259. </div>
  260. </div>
  261. </div>
  262. </div>
  263. <script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
  264. <script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
  265. <script src="assets/js/main.js" type="text/javascript"></script>
  266. <script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
  267. <script src="assets/lib/parsley/parsley.min.js" type="text/javascript"></script>
  268. <script type="text/javascript">
  269. $(document).ready(function(){
  270. App.init();
  271. $('form').parsley();
  272. $.ajax({
  273. type:"get",
  274. url:"http://127.0.0.1:8080/svcApi/findSvcById?svc_id="+getUrlParam('svc_id'),
  275. success: function(data){
  276. console.log(data);
  277. if(data.id != "" || data.id != null || data.id != undefined){
  278. $('#svc_id').val(data.id);
  279. $("#svc_name").val(data.svc_name);
  280. $('#svc_namespace').val(data.svc_namespace);
  281. $('#svc_type').val(data.svc_type);
  282. $('#svc_pod_name').val(data.svc_pod_name);
  283. $('#svc_team_id').val(data.svc_team_id);
  284. }else{
  285. console.log(data);
  286. }
  287. },
  288. error: function(result){
  289. console.log(result);
  290. }
  291. });
  292. });
  293. //获取url中的参数
  294. function getUrlParam(name) {
  295. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
  296. var r = window.location.search.substr(1).match(reg); //匹配目标参数
  297. if (r != null) return unescape(r[2]); return null; //返回参数值
  298. }
  299. </script>
  300. </body>
  301. </html>

C:\Users\Administrator\Desktop\gopaas\go-paas-front\svc-index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="description" content="">
  8. <meta name="author" content="">
  9. <link rel="shortcut icon" href="assets/img/logo-fav.png">
  10. <title>CPaaS</title>
  11. <link rel="stylesheet" type="text/css" href="assets/lib/perfect-scrollbar/css/perfect-scrollbar.min.css"/>
  12. <link rel="stylesheet" type="text/css" href="assets/lib/material-design-icons/css/material-design-iconic-font.min.css"/><!--[if lt IE 9]>
  13. <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  14. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  15. <![endif]-->
  16. <link rel="stylesheet" type="text/css" href="assets/lib/datatables/css/dataTables.bootstrap.min.css"/>
  17. <link rel="stylesheet" href="assets/css/style.css" type="text/css"/>
  18. </head>
  19. <body>
  20. <div class="be-wrapper">
  21. <nav class="navbar navbar-default navbar-fixed-top be-top-header">
  22. <div class="container-fluid">
  23. <div class="navbar-header"><a href="index.html" class="navbar-brand"></a>
  24. </div>
  25. <div class="be-right-navbar">
  26. <ul class="nav navbar-nav navbar-right be-user-nav">
  27. <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>
  28. <ul role="menu" class="dropdown-menu">
  29. <li>
  30. <div class="user-info">
  31. <div class="user-name">wu123</div>
  32. <div class="user-position online">在线</div>
  33. </div>
  34. </li>
  35. <li><a href="#"><span class="icon mdi mdi-face"></span> 账户</a></li>
  36. <li><a href="#"><span class="icon mdi mdi-settings"></span> 设置</a></li>
  37. <li><a href="#"><span class="icon mdi mdi-power"></span> 推出登录</a></li>
  38. </ul>
  39. </li>
  40. </ul>
  41. <div class="page-title"></div>
  42. <ul class="nav navbar-nav navbar-right be-icons-nav">
  43. <li class="dropdown"><a href="#" role="button" aria-expanded="false" class="be-toggle-right-sidebar"><span class="icon mdi mdi-settings"></span></a></li>
  44. <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>
  45. <ul class="dropdown-menu be-notifications">
  46. <li>
  47. <div class="title">消息提醒<span class="badge">3</span></div>
  48. <div class="list">
  49. <div class="be-scroller">
  50. <div class="content">
  51. <ul>
  52. <li class="notification notification-unread"><a href="#">
  53. <div class="image"><img src="assets/img/avatar2.png" alt="Avatar"></div>
  54. <div class="notification-info">
  55. <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>
  56. </div></a></li>
  57. <li class="notification"><a href="#">
  58. <div class="image"><img src="assets/img/avatar3.png" alt="Avatar"></div>
  59. <div class="notification-info">
  60. <div class="text"><span class="user-name">Joel King</span> is now following you</div><span class="date">2 days ago</span>
  61. </div></a></li>
  62. <li class="notification"><a href="#">
  63. <div class="image"><img src="assets/img/avatar4.png" alt="Avatar"></div>
  64. <div class="notification-info">
  65. <div class="text"><span class="user-name">John Doe</span> is watching your main repository</div><span class="date">2 days ago</span>
  66. </div></a></li>
  67. <li class="notification"><a href="#">
  68. <div class="image"><img src="assets/img/avatar5.png" alt="Avatar"></div>
  69. <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>
  70. </ul>
  71. </div>
  72. </div>
  73. </div>
  74. <div class="footer"> <a href="#">View all notifications</a></div>
  75. </li>
  76. </ul>
  77. </li>
  78. <li class="dropdown"><a href="#" data-toggle="dropdown" role="button" aria-expanded="false" class="dropdown-toggle"><span class="icon mdi mdi-apps"></span></a>
  79. <ul class="dropdown-menu be-connections">
  80. <li>
  81. <div class="list">
  82. <div class="content">
  83. <div class="row">
  84. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/github.png" alt="Github"><span>GitHub</span></a></div>
  85. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/bitbucket.png" alt="Bitbucket"><span>Bitbucket</span></a></div>
  86. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/slack.png" alt="Slack"><span>Slack</span></a></div>
  87. </div>
  88. <div class="row">
  89. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dribbble.png" alt="Dribbble"><span>Dribbble</span></a></div>
  90. <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>
  91. <div class="col-xs-4"><a href="#" class="connection-item"><img src="assets/img/dropbox.png" alt="Dropbox"><span>Dropbox</span></a></div>
  92. </div>
  93. </div>
  94. </div>
  95. <div class="footer"> <a href="#">More</a></div>
  96. </li>
  97. </ul>
  98. </li>
  99. </ul>
  100. </div>
  101. </div>
  102. </nav>
  103. <!--
  104. 侧边栏-开始
  105. -->
  106. <div class="be-left-sidebar">
  107. <div class="left-sidebar-wrapper"><a href="#" class="left-sidebar-toggle">看版</a>
  108. <div class="left-sidebar-spacer">
  109. <div class="left-sidebar-scroll">
  110. <div class="left-sidebar-content">
  111. <ul class="sidebar-elements">
  112. <li class="divider">菜单</li>
  113. <li class="parent"><a href="#"><i class="icon mdi mdi-home"></i><span>控制台</span></a>
  114. </li>
  115. <li class="parent"><a href="#"><i class="icon mdi mdi-face"></i><span>应用管理</span></a>
  116. <ul class="sub-menu">
  117. <li ><a href="pod-index.html">添加应用</a>
  118. </li>
  119. </ul>
  120. </li>
  121. <li class="parent"><a href="charts.html"><i class="icon mdi mdi-chart-donut"></i><span>服务管理</span></a>
  122. <ul class="sub-menu">
  123. <li class="active"><a href="svc-index.html">添加服务</a>
  124. </li>
  125. </ul>
  126. </li>
  127. <li class="parent"><a href="#"><i class="icon mdi mdi-dot-circle"></i><span>域名管理</span></a>
  128. <ul class="sub-menu">
  129. <li ><a href="route-index.html">添加路由</a>
  130. </li>
  131. </ul>
  132. </li>
  133. <li class="parent"><a href="#"><i class="icon mdi mdi-border-all"></i><span>中间件</span></a>
  134. <ul class="sub-menu">
  135. <li><a href="tables-general.html">General</a>
  136. </li>
  137. <li><a href="tables-datatables.html">Data Tables</a>
  138. </li>
  139. <li><a href="tables-filters.html"><span class="label label-primary pull-right">New</span>Table Filters</a>
  140. </li>
  141. </ul>
  142. </li>
  143. <li class="parent"><a href="#"><i class="icon mdi mdi-layers"></i><span>应用市场</span></a>
  144. <ul class="sub-menu">
  145. <li><a href="pages-blank.html">Blank Page</a>
  146. </li>
  147. <li><a href="pages-blank-header.html">Blank Page Header</a>
  148. </li>
  149. <li><a href="pages-login.html">Login</a>
  150. </li>
  151. <li><a href="pages-login2.html">Login v2</a>
  152. </li>
  153. <li><a href="pages-404.html">404 Page</a>
  154. </li>
  155. <li><a href="pages-sign-up.html">Sign Up</a>
  156. </li>
  157. <li><a href="pages-forgot-password.html">Forgot Password</a>
  158. </li>
  159. <li><a href="pages-profile.html">Profile</a>
  160. </li>
  161. <li><a href="pages-pricing-tables.html">Pricing Tables</a>
  162. </li>
  163. <li><a href="pages-pricing-tables2.html">Pricing Tables v2</a>
  164. </li>
  165. <li><a href="pages-timeline.html">Timeline</a>
  166. </li>
  167. <li><a href="pages-timeline2.html">Timeline v2</a>
  168. </li>
  169. <li><a href="pages-invoice.html"><span class="label label-primary pull-right">New</span>Invoice</a>
  170. </li>
  171. <li><a href="pages-calendar.html">Calendar</a>
  172. </li>
  173. <li><a href="pages-gallery.html">Gallery</a>
  174. </li>
  175. <li><a href="pages-code-editor.html"><span class="label label-primary pull-right">New </span>Code Editor</a>
  176. </li>
  177. <li><a href="pages-booking.html"><span class="label label-primary pull-right">New</span>Booking</a>
  178. </li>
  179. <li><a href="pages-loaders.html"><span class="label label-primary pull-right">New</span>Loaders</a>
  180. </li>
  181. </ul>
  182. </li>
  183. </ul>
  184. </div>
  185. </div>
  186. </div>
  187. <div class="progress-widget">
  188. <div class="progress-data"><span class="progress-value">60%</span><span class="name">Current Project</span></div>
  189. <div class="progress">
  190. <div style="width: 60%;" class="progress-bar progress-bar-primary"></div>
  191. </div>
  192. </div>
  193. </div>
  194. </div>
  195. <!--
  196. 侧边栏-结束
  197. -->
  198. <div class="be-content">
  199. <div class="page-head">
  200. <h2 class="page-head-title">服务管理</h2>
  201. <ol class="breadcrumb page-head-nav">
  202. <li><a href="#">控制台</a></li>
  203. <li><a href="#">服务管理</a></li>
  204. <li class="active">服务列表</li>
  205. </ol>
  206. </div>
  207. <div class="main-content container-fluid">
  208. <div class="row">
  209. <div class="col-sm-12">
  210. <div class="panel panel-default panel-table">
  211. <div class="panel-heading">
  212. <a href="svc-create.html"><button class="btn btn-space btn-primary">创建服务</button></a>
  213. <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>
  214. <ul role="menu" class="dropdown-menu pull-right">
  215. <li><a href="#">Action</a></li>
  216. <li><a href="#">Another action</a></li>
  217. <li><a href="#">Something else here</a></li>
  218. <li class="divider"></li>
  219. <li><a href="#">Separated link</a></li>
  220. </ul>
  221. </div>
  222. </div>
  223. <div class="panel-body">
  224. <table id="table1" class="table table-striped table-hover table-fw-widget">
  225. <thead>
  226. <tr>
  227. <th>ID</th>
  228. <th>服务名称</th>
  229. <th>命名空间</th>
  230. <th>服务类型</th>
  231. <th>绑定POD</th>
  232. <th>操作</th>
  233. </tr>
  234. </thead>
  235. <tbody id="table-data">
  236. </tbody>
  237. </table>
  238. </div>
  239. </div>
  240. </div>
  241. </div>
  242. </div>
  243. </div>
  244. <nav class="be-right-sidebar">
  245. <div class="sb-content">
  246. <div class="tab-navigation">
  247. <ul role="tablist" class="nav nav-tabs nav-justified">
  248. <li role="presentation" class="active"><a href="#tab1" aria-controls="tab1" role="tab" data-toggle="tab">Chat</a></li>
  249. <li role="presentation"><a href="#tab2" aria-controls="tab2" role="tab" data-toggle="tab">Todo</a></li>
  250. <li role="presentation"><a href="#tab3" aria-controls="tab3" role="tab" data-toggle="tab">Settings</a></li>
  251. </ul>
  252. </div>
  253. <div class="tab-panel">
  254. <div class="tab-content">
  255. <div id="tab1" role="tabpanel" class="tab-pane tab-chat active">
  256. <div class="chat-contacts">
  257. <div class="chat-sections">
  258. <div class="be-scroller">
  259. <div class="content">
  260. <h2>Recent</h2>
  261. <div class="contact-list contact-list-recent">
  262. <div class="user"><a href="#"><img src="assets/img/avatar1.png" alt="Avatar">
  263. <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>
  264. <div class="user"><a href="#"><img src="assets/img/avatar2.png" alt="Avatar">
  265. <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>
  266. <div class="user"><a href="#"><img src="assets/img/avatar3.png" alt="Avatar">
  267. <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>
  268. </div>
  269. <h2>Contacts</h2>
  270. <div class="contact-list">
  271. <div class="user"><a href="#"><img src="assets/img/avatar4.png" alt="Avatar">
  272. <div class="user-data2"><span class="status"></span><span class="name">Mike Bolthort</span></div></a></div>
  273. <div class="user"><a href="#"><img src="assets/img/avatar5.png" alt="Avatar">
  274. <div class="user-data2"><span class="status"></span><span class="name">Maggie jackson</span></div></a></div>
  275. <div class="user"><a href="#"><img src="assets/img/avatar6.png" alt="Avatar">
  276. <div class="user-data2"><span class="status offline"></span><span class="name">Jhon Voltemar</span></div></a></div>
  277. </div>
  278. </div>
  279. </div>
  280. </div>
  281. <div class="bottom-input">
  282. <input type="text" placeholder="Search..." name="q"><span class="mdi mdi-search"></span>
  283. </div>
  284. </div>
  285. <div class="chat-window">
  286. <div class="title">
  287. <div class="user"><img src="assets/img/avatar2.png" alt="Avatar">
  288. <h2>Maggie jackson</h2><span>Active 1h ago</span>
  289. </div><span class="icon return mdi mdi-chevron-left"></span>
  290. </div>
  291. <div class="chat-messages">
  292. <div class="be-scroller">
  293. <div class="content">
  294. <ul>
  295. <li class="friend">
  296. <div class="msg">Hello</div>
  297. </li>
  298. <li class="self">
  299. <div class="msg">Hi, how are you?</div>
  300. </li>
  301. <li class="friend">
  302. <div class="msg">Good, I'll need support with my pc</div>
  303. </li>
  304. <li class="self">
  305. <div class="msg">Sure, just tell me what is going on with your computer?</div>
  306. </li>
  307. <li class="friend">
  308. <div class="msg">I don't know it just turns off suddenly</div>
  309. </li>
  310. </ul>
  311. </div>
  312. </div>
  313. </div>
  314. <div class="chat-input">
  315. <div class="input-wrapper"><span class="photo mdi mdi-camera"></span>
  316. <input type="text" placeholder="Message..." name="q" autocomplete="off"><span class="send-msg mdi mdi-mail-send"></span>
  317. </div>
  318. </div>
  319. </div>
  320. </div>
  321. <div id="tab2" role="tabpanel" class="tab-pane tab-todo">
  322. <div class="todo-container">
  323. <div class="todo-wrapper">
  324. <div class="be-scroller">
  325. <div class="todo-content"><span class="category-title">Today</span>
  326. <ul class="todo-list">
  327. <li>
  328. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  329. <input id="todo1" type="checkbox" checked="">
  330. <label for="todo1">Initialize the project</label>
  331. </div>
  332. </li>
  333. <li>
  334. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  335. <input id="todo2" type="checkbox">
  336. <label for="todo2">Create the main structure</label>
  337. </div>
  338. </li>
  339. <li>
  340. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  341. <input id="todo3" type="checkbox">
  342. <label for="todo3">Updates changes to GitHub</label>
  343. </div>
  344. </li>
  345. </ul><span class="category-title">Tomorrow</span>
  346. <ul class="todo-list">
  347. <li>
  348. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  349. <input id="todo4" type="checkbox">
  350. <label for="todo4">Initialize the project</label>
  351. </div>
  352. </li>
  353. <li>
  354. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  355. <input id="todo5" type="checkbox">
  356. <label for="todo5">Create the main structure</label>
  357. </div>
  358. </li>
  359. <li>
  360. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  361. <input id="todo6" type="checkbox">
  362. <label for="todo6">Updates changes to GitHub</label>
  363. </div>
  364. </li>
  365. <li>
  366. <div class="be-checkbox be-checkbox-sm"><span class="delete mdi mdi-delete"></span>
  367. <input id="todo7" type="checkbox">
  368. <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>
  369. </div>
  370. </li>
  371. </ul>
  372. </div>
  373. </div>
  374. </div>
  375. <div class="bottom-input">
  376. <input type="text" placeholder="Create new task..." name="q"><span class="mdi mdi-plus"></span>
  377. </div>
  378. </div>
  379. </div>
  380. <div id="tab3" role="tabpanel" class="tab-pane tab-settings">
  381. <div class="settings-wrapper">
  382. <div class="be-scroller"><span class="category-title">General</span>
  383. <ul class="settings-list">
  384. <li>
  385. <div class="switch-button switch-button-sm">
  386. <input type="checkbox" checked="" name="st1" id="st1"><span>
  387. <label for="st1"></label></span>
  388. </div><span class="name">Available</span>
  389. </li>
  390. <li>
  391. <div class="switch-button switch-button-sm">
  392. <input type="checkbox" checked="" name="st2" id="st2"><span>
  393. <label for="st2"></label></span>
  394. </div><span class="name">Enable notifications</span>
  395. </li>
  396. <li>
  397. <div class="switch-button switch-button-sm">
  398. <input type="checkbox" checked="" name="st3" id="st3"><span>
  399. <label for="st3"></label></span>
  400. </div><span class="name">Login with Facebook</span>
  401. </li>
  402. </ul><span class="category-title">Notifications</span>
  403. <ul class="settings-list">
  404. <li>
  405. <div class="switch-button switch-button-sm">
  406. <input type="checkbox" name="st4" id="st4"><span>
  407. <label for="st4"></label></span>
  408. </div><span class="name">Email notifications</span>
  409. </li>
  410. <li>
  411. <div class="switch-button switch-button-sm">
  412. <input type="checkbox" checked="" name="st5" id="st5"><span>
  413. <label for="st5"></label></span>
  414. </div><span class="name">Project updates</span>
  415. </li>
  416. <li>
  417. <div class="switch-button switch-button-sm">
  418. <input type="checkbox" checked="" name="st6" id="st6"><span>
  419. <label for="st6"></label></span>
  420. </div><span class="name">New comments</span>
  421. </li>
  422. <li>
  423. <div class="switch-button switch-button-sm">
  424. <input type="checkbox" name="st7" id="st7"><span>
  425. <label for="st7"></label></span>
  426. </div><span class="name">Chat messages</span>
  427. </li>
  428. </ul><span class="category-title">Workflow</span>
  429. <ul class="settings-list">
  430. <li>
  431. <div class="switch-button switch-button-sm">
  432. <input type="checkbox" name="st8" id="st8"><span>
  433. <label for="st8"></label></span>
  434. </div><span class="name">Deploy on commit</span>
  435. </li>
  436. </ul>
  437. </div>
  438. </div>
  439. </div>
  440. </div>
  441. </div>
  442. </div>
  443. </nav>
  444. </div>
  445. <script src="assets/lib/jquery/jquery.min.js" type="text/javascript"></script>
  446. <script src="assets/lib/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" type="text/javascript"></script>
  447. <script src="assets/js/main.js" type="text/javascript"></script>
  448. <script src="assets/lib/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
  449. <script src="assets/lib/datatables/js/jquery.dataTables.min.js" type="text/javascript"></script>
  450. <script src="assets/lib/datatables/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
  451. <script src="assets/lib/datatables/plugins/buttons/js/dataTables.buttons.js" type="text/javascript"></script>
  452. <script src="assets/lib/datatables/plugins/buttons/js/buttons.html5.js" type="text/javascript"></script>
  453. <script src="assets/lib/datatables/plugins/buttons/js/buttons.flash.js" type="text/javascript"></script>
  454. <script src="assets/lib/datatables/plugins/buttons/js/buttons.print.js" type="text/javascript"></script>
  455. <script src="assets/lib/datatables/plugins/buttons/js/buttons.colVis.js" type="text/javascript"></script>
  456. <script src="assets/lib/datatables/plugins/buttons/js/buttons.bootstrap.js" type="text/javascript"></script>
  457. <script src="assets/js/app-tables-datatables.js" type="text/javascript"></script>
  458. <script type="text/javascript">
  459. $(document).ready(function(){
  460. //initialize the javascript
  461. App.init();
  462. App.dataTables();
  463. $.ajax({
  464. type:"get",
  465. url:"http://127.0.0.1:8080/svcApi/",
  466. success: function(data){
  467. console.log(data);
  468. $("#table-data").html("");
  469. $.each(data['svc_info'],function (i,item) {
  470. $("#table-data").append(' <tr class="gradeA">\
  471. <td>'+item.id+'</td>\
  472. <td>'+item.svc_name+'</td>\
  473. <td>'+item.svc_namespace+'</td>\
  474. <td class="center">'+item.svc_type+'</td>\
  475. <td class="center">'+item.svc_pod_name+'</td>\
  476. <td class="center"><a href="svc-detail.html?svc_id='+item.id+'">详情</a> <a href="http://localhost:8080/svcApi/deleteSvcById?svc_id='+item.id+'" style="color:red;" >删除</a></td>\
  477. </tr>'
  478. );
  479. })
  480. },
  481. error: function(result){
  482. console.log(result);
  483. }
  484. });
  485. });
  486. </script>
  487. </body>
  488. </html>

C:\Users\Administrator\Desktop\gopaas\svc\domain\repository\svc_repository.go 

  1. //根据ID删除Svc信息
  2. func (u *SvcRepository) DeleteSvcByID(svcID int64) error {
  3. tx := u.mysqlDb.Begin()
  4. //遇到问题回滚
  5. defer func() {
  6. if r := recover(); r != nil {
  7. tx.Rollback()
  8. }
  9. }()
  10. if tx.Error != nil {
  11. common.Error(tx.Error)
  12. return tx.Error
  13. }
  14. //删除svc
  15. if err := u.mysqlDb.Where("id = ?", svcID).Delete(&model.Svc{}).Error; err != nil {
  16. tx.Rollback()
  17. common.Error(err)
  18. return err
  19. }
  20. //删除相关的port
  21. if err := u.mysqlDb.Where("svc_id = ?", svcID).Delete(&model.SvcPort{}).Error; err != nil {
  22. tx.Rollback()
  23. common.Error(err)
  24. return err
  25. }
  26. return tx.Commit().Error
  27. }

测试删除svc

6-8 总结&思考

主要内容
介绍了service的四中类型
介绍了Service与Deployment的关系
说明Service,Endpoint,pod之间的关系

经验之谈
Service可以创建多个指到同一个Pod来满足不同需求
程序调用的地址通常写Service地址而不是具体pod

Service的其它类型还能在哪些场景?
Service与ReplicationController有无关系?

6-9 【扩展阅读】深度剖析 K8S DNS 的 Service 与 Pod

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/622392
推荐阅读
相关标签
  

闽ICP备14008679号