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>
master
Kevin Wan 4 years ago committed by GitHub
parent f997aee3ba
commit 7a82cf80ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -556,7 +556,7 @@ func TestRedis_SortedSet(t *testing.T) {
val, err = client.Zscore("key", "value1") val, err = client.Zscore("key", "value1")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(5), val) assert.Equal(t, int64(5), val)
val, err = NewRedis(client.Addr, "").Zadds("key") _, err = NewRedis(client.Addr, "").Zadds("key")
assert.NotNil(t, err) assert.NotNil(t, err)
val, err = client.Zadds("key", Pair{ val, err = client.Zadds("key", Pair{
Key: "value2", Key: "value2",
@ -567,9 +567,9 @@ func TestRedis_SortedSet(t *testing.T) {
}) })
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(2), val) 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) assert.NotNil(t, err)
pairs, err = client.ZRevRangeWithScores("key", 1, 3) pairs, err := client.ZRevRangeWithScores("key", 1, 3)
assert.Nil(t, err) assert.Nil(t, err)
assert.EqualValues(t, []Pair{ assert.EqualValues(t, []Pair{
{ {

@ -14,7 +14,7 @@ type ServiceContext struct {
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{ return &ServiceContext{
c: c, c: c,
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table), Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table),
} }
} }

@ -14,7 +14,7 @@ type ServiceContext struct {
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{ return &ServiceContext{
c: c, c: c,
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table), 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/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 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-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/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/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/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 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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/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.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= 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/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 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= 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/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= 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/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 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.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/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/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= 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.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 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 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/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 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=

@ -58,7 +58,7 @@ require (
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.0.15 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 honnef.co/go/tools v0.0.1-2020.1.4 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect sigs.k8s.io/yaml v1.2.0 // indirect
) )

@ -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.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 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.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-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.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= 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")) return errors.New("abs failed: " + c.String("path"))
} }
goModPath, hasFound := util.FindGoModPath(path) goModPath, found := util.FindGoModPath(path)
if !hasFound { if !found {
return errors.New("go mod not initial") return errors.New("go mod not initial")
} }

@ -2,6 +2,7 @@ package docker
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -33,12 +34,29 @@ func DockerCommand(c *cli.Context) error {
return errors.New("-go can't be empty") 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) cfg, err := findConfig(goFile, etcDir)
if err != nil { if err != nil {
return err 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) { 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/api/validate"
"github.com/tal-tech/go-zero/tools/goctl/configgen" "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/docker"
"github.com/tal-tech/go-zero/tools/goctl/kube"
model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command" model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli" rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli"
"github.com/tal-tech/go-zero/tools/goctl/tpl" "github.com/tal-tech/go-zero/tools/goctl/tpl"
@ -198,6 +199,94 @@ var (
}, },
Action: docker.DockerCommand, 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", Name: "rpc",
Usage: "generate rpc code", 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
}

@ -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
`

@ -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
`

@ -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/core/errorx"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen" "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/docker"
"github.com/tal-tech/go-zero/tools/goctl/kube"
modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen" modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/generator" rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/generator"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
@ -29,6 +30,9 @@ func GenTemplates(ctx *cli.Context) error {
func() error { func() error {
return docker.GenTemplates(ctx) return docker.GenTemplates(ctx)
}, },
func() error {
return kube.GenTemplates(ctx)
},
); err != nil { ); err != nil {
return err return err
} }

@ -80,3 +80,30 @@ func FindGoModPath(dir string) (string, bool) {
} }
return "", false 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
}

Loading…
Cancel
Save