support k8s deployment yaml generation (#247)
* simplify code, format makefile * simplify code * some optimize by kevwan and benying (#240) Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn> * optimization (#241) * optimize docker file generation, make docker build faster * support k8s deployment yaml generation Co-authored-by: benying <31179034+benyingY@users.noreply.github.com> Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn> Co-authored-by: bittoy <bittoy@qq.com>
This commit is contained in:
@@ -556,7 +556,7 @@ func TestRedis_SortedSet(t *testing.T) {
|
||||
val, err = client.Zscore("key", "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(5), val)
|
||||
val, err = NewRedis(client.Addr, "").Zadds("key")
|
||||
_, err = NewRedis(client.Addr, "").Zadds("key")
|
||||
assert.NotNil(t, err)
|
||||
val, err = client.Zadds("key", Pair{
|
||||
Key: "value2",
|
||||
@@ -567,9 +567,9 @@ func TestRedis_SortedSet(t *testing.T) {
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(2), val)
|
||||
pairs, err := NewRedis(client.Addr, "").ZRevRangeWithScores("key", 1, 3)
|
||||
_, err = NewRedis(client.Addr, "").ZRevRangeWithScores("key", 1, 3)
|
||||
assert.NotNil(t, err)
|
||||
pairs, err = client.ZRevRangeWithScores("key", 1, 3)
|
||||
pairs, err := client.ZRevRangeWithScores("key", 1, 3)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []Pair{
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ type ServiceContext struct {
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
return &ServiceContext{
|
||||
c: c,
|
||||
c: c,
|
||||
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type ServiceContext struct {
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
return &ServiceContext{
|
||||
c: c,
|
||||
c: c,
|
||||
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQa
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -49,6 +50,7 @@ github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819 h1:9778zj477h/VauD8
|
||||
github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc=
|
||||
github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -131,6 +133,7 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
|
||||
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
|
||||
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
@@ -220,6 +223,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
@@ -252,6 +256,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
|
||||
2
go.mod
2
go.mod
@@ -58,7 +58,7 @@ require (
|
||||
google.golang.org/protobuf v1.25.0
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||
gopkg.in/h2non/gock.v1 v1.0.15
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
honnef.co/go/tools v0.0.1-2020.1.4 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
2
go.sum
2
go.sum
@@ -452,6 +452,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
|
||||
@@ -43,8 +43,8 @@ func GenConfigCommand(c *cli.Context) error {
|
||||
return errors.New("abs failed: " + c.String("path"))
|
||||
}
|
||||
|
||||
goModPath, hasFound := util.FindGoModPath(path)
|
||||
if !hasFound {
|
||||
goModPath, found := util.FindGoModPath(path)
|
||||
if !found {
|
||||
return errors.New("go mod not initial")
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package docker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -33,12 +34,29 @@ func DockerCommand(c *cli.Context) error {
|
||||
return errors.New("-go can't be empty")
|
||||
}
|
||||
|
||||
if !util.FileExists(goFile) {
|
||||
return fmt.Errorf("file %q not found", goFile)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(etcDir); os.IsNotExist(err) {
|
||||
return generateDockerfile(goFile)
|
||||
}
|
||||
|
||||
cfg, err := findConfig(goFile, etcDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return generateDockerfile(goFile, "-f", "etc/"+cfg)
|
||||
if err := generateDockerfile(goFile, "-f", "etc/"+cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projDir, ok := util.FindProjectPath(goFile)
|
||||
if ok {
|
||||
fmt.Printf("Run \"docker build ...\" command in dir %q\n", projDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findConfig(file, dir string) (string, error) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/validate"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/configgen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/docker"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/kube"
|
||||
model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
|
||||
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/tpl"
|
||||
@@ -198,6 +199,94 @@ var (
|
||||
},
|
||||
Action: docker.DockerCommand,
|
||||
},
|
||||
{
|
||||
Name: "kube",
|
||||
Usage: "generate kubernetes files",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "deploy",
|
||||
Usage: "generate deployment yaml file",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "the name of deployment",
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "namespace",
|
||||
Usage: "the namespace of deployment",
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "image",
|
||||
Usage: "the docker image of deployment",
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "secret",
|
||||
Usage: "the image pull secret",
|
||||
Required: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "requestCpu",
|
||||
Usage: "the request cpu to deploy",
|
||||
Value: 500,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "requestMem",
|
||||
Usage: "the request memory to deploy",
|
||||
Value: 512,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "limitCpu",
|
||||
Usage: "the limit cpu to deploy",
|
||||
Value: 1000,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "limitMem",
|
||||
Usage: "the limit memory to deploy",
|
||||
Value: 1024,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "o",
|
||||
Usage: "the output yaml file",
|
||||
Required: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "replicas",
|
||||
Usage: "the number of replicas to deploy",
|
||||
Value: 3,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "revisions",
|
||||
Usage: "the number of revision history to limit",
|
||||
Value: 5,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Usage: "the port of the deployment to listen on pod",
|
||||
Required: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "nodePort",
|
||||
Usage: "the nodePort of the deployment to expose",
|
||||
Value: 0,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "minReplicas",
|
||||
Usage: "the min replicas to deploy",
|
||||
Value: 3,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "maxReplicas",
|
||||
Usage: "the max replicas of deploy",
|
||||
Value: 10,
|
||||
},
|
||||
},
|
||||
Action: kube.DeploymentCommand,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "rpc",
|
||||
Usage: "generate rpc code",
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
package k8s
|
||||
|
||||
var apiRpcTmeplate = `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{.name}}
|
||||
namespace: {{.namespace}}
|
||||
labels:
|
||||
app: {{.name}}
|
||||
spec:
|
||||
replicas: {{.replicas}}
|
||||
revisionHistoryLimit: {{.revisionHistoryLimit}}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{.name}}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{.name}}
|
||||
spec:{{if .envIsDev}}
|
||||
terminationGracePeriodSeconds: 60{{end}}
|
||||
containers:
|
||||
- name: {{.name}}
|
||||
image: registry-vpc.cn-hangzhou.aliyuncs.com/{{.namespace}}/
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["sh","-c","sleep 5"]
|
||||
ports:
|
||||
- containerPort: {{.port}}
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: {{.port}}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{.port}}
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
env:
|
||||
- name: aliyun_logs_k8slog
|
||||
value: "stdout"
|
||||
- name: aliyun_logs_k8slog_tags
|
||||
value: "stage={{.env}}"
|
||||
- name: aliyun_logs_k8slog_format
|
||||
value: "json"
|
||||
resources:
|
||||
limits:
|
||||
cpu: {{.limitCpu}}m
|
||||
memory: {{.limitMem}}Mi
|
||||
requests:
|
||||
cpu: {{.requestCpu}}m
|
||||
memory: {{.requestMem}}Mi
|
||||
command:
|
||||
- ./{{.serviceName}}
|
||||
- -f
|
||||
- ./{{.name}}.json
|
||||
volumeMounts:
|
||||
- name: timezone
|
||||
mountPath: /etc/localtime
|
||||
imagePullSecrets:
|
||||
- name: {{.namespace}}
|
||||
volumes:
|
||||
- name: timezone
|
||||
hostPath:
|
||||
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{.name}}-svc
|
||||
namespace: {{.namespace}}
|
||||
spec:
|
||||
ports:
|
||||
- nodePort: 3{{.port}}
|
||||
port: {{.port}}
|
||||
protocol: TCP
|
||||
targetPort: {{.port}}
|
||||
selector:
|
||||
app: {{.name}}
|
||||
sessionAffinity: None
|
||||
type: NodePort{{if .envIsPreOrPro}}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{.name}}-hpa-c
|
||||
namespace: {{.namespace}}
|
||||
labels:
|
||||
app: {{.name}}-hpa-c
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
name: di-api
|
||||
minReplicas: {{.minReplicas}}
|
||||
maxReplicas: {{.maxReplicas}}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: 80
|
||||
|
||||
---
|
||||
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{.name}}-hpa-m
|
||||
namespace: {{.namespace}}
|
||||
labels:
|
||||
app: {{.name}}-hpa-m
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
name: {{.name}}
|
||||
minReplicas: {{.minReplicas}}
|
||||
maxReplicas: {{.maxReplicas}}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: 80{{end}}
|
||||
`
|
||||
@@ -1,46 +0,0 @@
|
||||
package k8s
|
||||
|
||||
var jobTmeplate = `apiVersion: batch/v1beta1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: {{.name}}
|
||||
namespace: {{.namespace}}
|
||||
spec:
|
||||
successfulJobsHistoryLimit: {{.successfulJobsHistoryLimit}}
|
||||
schedule: "{{.schedule}}"
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: {{.name}}
|
||||
image: registry-vpc.cn-hangzhou.aliyuncs.com/{{.namespace}}/
|
||||
env:
|
||||
- name: aliyun_logs_k8slog
|
||||
value: "stdout"
|
||||
- name: aliyun_logs_k8slog_tags
|
||||
value: "stage={{.env}}"
|
||||
- name: aliyun_logs_k8slog_format
|
||||
value: "json"
|
||||
resources:
|
||||
limits:
|
||||
cpu: {{.limitCpu}}m
|
||||
memory: {{.limitMem}}Mi
|
||||
requests:
|
||||
cpu: {{.requestCpu}}m
|
||||
memory: {{.requestMem}}Mi
|
||||
command:
|
||||
- ./{{.serviceName}}
|
||||
- -f
|
||||
- ./{{.name}}.json
|
||||
volumeMounts:
|
||||
- name: timezone
|
||||
mountPath: /etc/localtime
|
||||
imagePullSecrets:
|
||||
- name: {{.namespace}}
|
||||
restartPolicy: OnFailure
|
||||
volumes:
|
||||
- name: timezone
|
||||
hostPath:
|
||||
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||
`
|
||||
@@ -1,103 +0,0 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceTypeApi ServiceType = "api"
|
||||
ServiceTypeRpc ServiceType = "rpc"
|
||||
ServiceTypeJob ServiceType = "job"
|
||||
envDev = "dev"
|
||||
)
|
||||
|
||||
var errUnknownServiceType = errors.New("unknown service type")
|
||||
|
||||
type (
|
||||
ServiceType string
|
||||
|
||||
KubeRequest struct {
|
||||
Env string
|
||||
ServiceName string
|
||||
ServiceType ServiceType
|
||||
Namespace string
|
||||
Schedule string
|
||||
Replicas int
|
||||
RevisionHistoryLimit int
|
||||
Port int
|
||||
LimitCpu int
|
||||
LimitMem int
|
||||
RequestCpu int
|
||||
RequestMem int
|
||||
SuccessfulJobsHistoryLimit int
|
||||
HpaMinReplicas int
|
||||
HpaMaxReplicas int
|
||||
}
|
||||
)
|
||||
|
||||
func Gen(req KubeRequest) (string, error) {
|
||||
switch req.ServiceType {
|
||||
case ServiceTypeApi, ServiceTypeRpc:
|
||||
return genApiRpc(req)
|
||||
case ServiceTypeJob:
|
||||
return genJob(req)
|
||||
default:
|
||||
return "", errUnknownServiceType
|
||||
}
|
||||
}
|
||||
|
||||
func genApiRpc(req KubeRequest) (string, error) {
|
||||
t, err := template.New("api_rpc").Parse(apiRpcTmeplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buffer := new(bytes.Buffer)
|
||||
err = t.Execute(buffer, map[string]interface{}{
|
||||
"name": fmt.Sprintf("%s-%s", req.ServiceName, req.ServiceType),
|
||||
"namespace": req.Namespace,
|
||||
"replicas": req.Replicas,
|
||||
"revisionHistoryLimit": req.RevisionHistoryLimit,
|
||||
"port": req.Port,
|
||||
"limitCpu": req.LimitCpu,
|
||||
"limitMem": req.LimitMem,
|
||||
"requestCpu": req.RequestCpu,
|
||||
"requestMem": req.RequestMem,
|
||||
"serviceName": req.ServiceName,
|
||||
"env": req.Env,
|
||||
"envIsPreOrPro": req.Env != envDev,
|
||||
"envIsDev": req.Env == envDev,
|
||||
"minReplicas": req.HpaMinReplicas,
|
||||
"maxReplicas": req.HpaMaxReplicas,
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
func genJob(req KubeRequest) (string, error) {
|
||||
t, err := template.New("job").Parse(jobTmeplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buffer := new(bytes.Buffer)
|
||||
err = t.Execute(buffer, map[string]interface{}{
|
||||
"name": fmt.Sprintf("%s-%s", req.ServiceName, req.ServiceType),
|
||||
"namespace": req.Namespace,
|
||||
"schedule": req.Schedule,
|
||||
"successfulJobsHistoryLimit": req.SuccessfulJobsHistoryLimit,
|
||||
"limitCpu": req.LimitCpu,
|
||||
"limitMem": req.LimitMem,
|
||||
"requestCpu": req.RequestCpu,
|
||||
"requestMem": req.RequestMem,
|
||||
"serviceName": req.ServiceName,
|
||||
"env": req.Env,
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
117
tools/goctl/kube/deployment.go
Normal file
117
tools/goctl/kube/deployment.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package kube
|
||||
|
||||
var deploymentTemplate = `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{.Name}}
|
||||
namespace: {{.Namespace}}
|
||||
labels:
|
||||
app: {{.Name}}
|
||||
spec:
|
||||
replicas: {{.Replicas}}
|
||||
revisionHistoryLimit: {{.Revisions}}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{.Name}}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{.Name}}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{.Name}}
|
||||
image: {{.Image}}
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["sh","-c","sleep 5"]
|
||||
ports:
|
||||
- containerPort: {{.Port}}
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: {{.Port}}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{.Port}}
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
resources:
|
||||
requests:
|
||||
cpu: {{.RequestCpu}}m
|
||||
memory: {{.RequestMem}}Mi
|
||||
limits:
|
||||
cpu: {{.LimitCpu}}m
|
||||
memory: {{.LimitMem}}Mi
|
||||
volumeMounts:
|
||||
- name: timezone
|
||||
mountPath: /etc/localtime
|
||||
imagePullSecrets:
|
||||
- name: {{.Secret}}
|
||||
volumes:
|
||||
- name: timezone
|
||||
hostPath:
|
||||
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{.Name}}-svc
|
||||
namespace: {{.Namespace}}
|
||||
spec:
|
||||
ports:
|
||||
{{if .UseNodePort}}- nodePort: {{.NodePort}}
|
||||
port: {{.Port}}
|
||||
protocol: TCP
|
||||
targetPort: {{.Port}}
|
||||
type: NodePort{{else}}- port: {{.Port}}{{end}}
|
||||
selector:
|
||||
app: {{.Name}}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{.Name}}-hpa-c
|
||||
namespace: {{.Namespace}}
|
||||
labels:
|
||||
app: {{.Name}}-hpa-c
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{.Name}}
|
||||
minReplicas: {{.MinReplicas}}
|
||||
maxReplicas: {{.MaxReplicas}}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: 80
|
||||
|
||||
---
|
||||
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{.Name}}-hpa-m
|
||||
namespace: {{.Namespace}}
|
||||
labels:
|
||||
app: {{.Name}}-hpa-m
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{.Name}}
|
||||
minReplicas: {{.MinReplicas}}
|
||||
maxReplicas: {{.MaxReplicas}}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: 80
|
||||
`
|
||||
39
tools/goctl/kube/job.go
Normal file
39
tools/goctl/kube/job.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package kube
|
||||
|
||||
var jobTmeplate = `apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: {{.Name}}
|
||||
namespace: {{.Namespace}}
|
||||
spec:
|
||||
successfulJobsHistoryLimit: {{.SuccessfulJobsHistoryLimit}}
|
||||
schedule: "{{.Schedule}}"
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: {{.Name}}
|
||||
image: # todo image url
|
||||
resources:
|
||||
requests:
|
||||
cpu: {{.RequestCpu}}m
|
||||
memory: {{.RequestMem}}Mi
|
||||
limits:
|
||||
cpu: {{.LimitCpu}}m
|
||||
memory: {{.LimitMem}}Mi
|
||||
command:
|
||||
- ./{{.ServiceName}}
|
||||
- -f
|
||||
- ./{{.Name}}.yaml
|
||||
volumeMounts:
|
||||
- name: timezone
|
||||
mountPath: /etc/localtime
|
||||
imagePullSecrets:
|
||||
- name: # registry secret, if no, remove this
|
||||
restartPolicy: OnFailure
|
||||
volumes:
|
||||
- name: timezone
|
||||
hostPath:
|
||||
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||
`
|
||||
104
tools/goctl/kube/kube.go
Normal file
104
tools/goctl/kube/kube.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package kube
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"text/template"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
category = "kube"
|
||||
deployTemplateFile = "deployment.tpl"
|
||||
jobTemplateFile = "job.tpl"
|
||||
basePort = 30000
|
||||
portLimit = 32767
|
||||
)
|
||||
|
||||
var errUnknownServiceType = errors.New("unknown service type")
|
||||
|
||||
type (
|
||||
ServiceType string
|
||||
|
||||
KubeRequest struct {
|
||||
Env string
|
||||
ServiceName string
|
||||
ServiceType ServiceType
|
||||
Namespace string
|
||||
Schedule string
|
||||
Replicas int
|
||||
RevisionHistoryLimit int
|
||||
Port int
|
||||
LimitCpu int
|
||||
LimitMem int
|
||||
RequestCpu int
|
||||
RequestMem int
|
||||
SuccessfulJobsHistoryLimit int
|
||||
HpaMinReplicas int
|
||||
HpaMaxReplicas int
|
||||
}
|
||||
|
||||
Deployment struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Image string
|
||||
Secret string
|
||||
Replicas int
|
||||
Revisions int
|
||||
Port int
|
||||
NodePort int
|
||||
UseNodePort bool
|
||||
RequestCpu int
|
||||
RequestMem int
|
||||
LimitCpu int
|
||||
LimitMem int
|
||||
MinReplicas int
|
||||
MaxReplicas int
|
||||
}
|
||||
)
|
||||
|
||||
func DeploymentCommand(c *cli.Context) error {
|
||||
nodePort := c.Int("nodePort")
|
||||
// 0 to disable the nodePort type
|
||||
if nodePort != 0 && (nodePort < basePort || nodePort > portLimit) {
|
||||
return errors.New("nodePort should be between 30000 and 32767")
|
||||
}
|
||||
|
||||
text, err := util.LoadTemplate(category, deployTemplateFile, deploymentTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := util.CreateIfNotExist(c.String("o"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
t := template.Must(template.New("deploymentTemplate").Parse(text))
|
||||
return t.Execute(out, Deployment{
|
||||
Name: c.String("name"),
|
||||
Namespace: c.String("namespace"),
|
||||
Image: c.String("image"),
|
||||
Secret: c.String("secret"),
|
||||
Replicas: c.Int("replicas"),
|
||||
Revisions: c.Int("revisions"),
|
||||
Port: c.Int("port"),
|
||||
NodePort: nodePort,
|
||||
UseNodePort: nodePort > 0,
|
||||
RequestCpu: c.Int("requestCpu"),
|
||||
RequestMem: c.Int("requestMem"),
|
||||
LimitCpu: c.Int("limitCpu"),
|
||||
LimitMem: c.Int("limitMem"),
|
||||
MinReplicas: c.Int("minReplicas"),
|
||||
MaxReplicas: c.Int("maxReplicas"),
|
||||
})
|
||||
}
|
||||
|
||||
func GenTemplates(_ *cli.Context) error {
|
||||
return util.InitTemplates(category, map[string]string{
|
||||
deployTemplateFile: deploymentTemplate,
|
||||
jobTemplateFile: jobTmeplate,
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/errorx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/docker"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/kube"
|
||||
modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
|
||||
rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/generator"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
@@ -29,6 +30,9 @@ func GenTemplates(ctx *cli.Context) error {
|
||||
func() error {
|
||||
return docker.GenTemplates(ctx)
|
||||
},
|
||||
func() error {
|
||||
return kube.GenTemplates(ctx)
|
||||
},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -80,3 +80,30 @@ func FindGoModPath(dir string) (string, bool) {
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func FindProjectPath(loc string) (string, bool) {
|
||||
var dir string
|
||||
if strings.IndexByte(loc, '/') == 0 {
|
||||
dir = loc
|
||||
} else {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
dir = filepath.Join(wd, loc)
|
||||
}
|
||||
|
||||
for {
|
||||
if FileExists(filepath.Join(dir, goModeIdentifier)) {
|
||||
return dir, true
|
||||
}
|
||||
|
||||
dir = filepath.Dir(dir)
|
||||
if dir == "/" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user