Skip to content

Commit

Permalink
Add support to install ks in kind (#46)
Browse files Browse the repository at this point in the history
* Add support to install ks in kind

* Add typoci config file

* Add more exclude words for spell checking

* Fix the typo from file kind.go
  • Loading branch information
LinuxSuRen authored Jan 30, 2021
1 parent 5e8f983 commit 2c40776
Show file tree
Hide file tree
Showing 5 changed files with 298 additions and 14 deletions.
9 changes: 9 additions & 0 deletions .github/.typo-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
dictionaries:
- en
- en_GB
exclude_fiels:
- ".github/**/*"
excluded_words:
- KubeSphere
- kubespheredev
- minio
22 changes: 11 additions & 11 deletions kubectl-plugin/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
extver "github.com/linuxsuren/cobra-extension/version"
"github.com/linuxsuren/ks/kubectl-plugin/auth"
"github.com/linuxsuren/ks/kubectl-plugin/component"
"github.com/linuxsuren/ks/kubectl-plugin/install"
"github.com/linuxsuren/ks/kubectl-plugin/registry"
token2 "github.com/linuxsuren/ks/kubectl-plugin/token"
"github.com/linuxsuren/ks/kubectl-plugin/tool"
Expand Down Expand Up @@ -39,17 +40,15 @@ See also https://github.com/kubesphere/kubesphere`,
var clientSet *kubernetes.Clientset

if config, err = clientcmd.BuildConfigFromFlags("", kubeconfig); err != nil {
panic(err)
return
}
if client, err = dynamic.NewForConfig(config); err != nil {
panic(err)
return
}
fmt.Println(err)
} else {
if client, err = dynamic.NewForConfig(config); err != nil {
fmt.Println(err)
}

if clientSet, err = kubernetes.NewForConfig(config); err != nil {
panic(err)
return
if clientSet, err = kubernetes.NewForConfig(config); err != nil {
fmt.Println(err)
}
}

cmd.AddCommand(NewUserCmd(client),
Expand All @@ -61,7 +60,8 @@ See also https://github.com/kubesphere/kubesphere`,
token2.NewTokenCmd(client, clientSet),
registry.NewRegistryCmd(client),
auth.NewAuthCmd(client),
tool.NewToolCmd())
tool.NewToolCmd(),
install.NewInstallCmd())
return
}

Expand Down
11 changes: 8 additions & 3 deletions kubectl-plugin/component/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ func NewComponentResetCmd(client dynamic.Interface) (cmd *cobra.Command) {
},
}
cmd = &cobra.Command{
Use: "reset",
Short: "reset the component by name",
Use: "reset",
Short: "reset the component by name",
Example: `'kubectl ks com reset -r=false -a' will reset ks-apiserver, ks-controller-manager, ks-console to the latest
kubectl ks com reset -a --nightly latest`,
RunE: opt.resetRunE,
RunE: opt.resetRunE,
}

flags := cmd.Flags()
Expand Down Expand Up @@ -94,6 +94,11 @@ func (o *ResetOption) resetRunE(cmd *cobra.Command, args []string) (err error) {
if err = o.updateBy(imageOrg, o.Tag); err != nil {
return
}

o.Name = "installer"
if err = o.updateBy(imageOrg, o.Tag); err != nil {
return
}
} else {
err = o.updateBy(imageOrg, o.Tag)
}
Expand Down
256 changes: 256 additions & 0 deletions kubectl-plugin/install/kind.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
package install

import (
"fmt"
"github.com/spf13/cobra"
"html/template"
"io"
"os"
"os/exec"
"sync"
"time"
)

func newInstallWithKindCmd() (cmd *cobra.Command) {
opt := &kindOption{}
cmd = &cobra.Command{
Use: "kind",
Short: "install KubeSphere with kind",
RunE: opt.runE,
}

flags := cmd.Flags()
flags.StringVarP(&opt.name, "name", "n", "kind",
"The name of kind")
flags.StringVarP(&opt.version, "version", "v", "v1.18.2",
"The version for Kubernetes")
flags.StringToStringVarP(&opt.portMappings, "portMappings", "", nil,
"The extraPortMappings")
flags.StringVarP(&opt.ksVersion, "ksVersion", "", "v3.0.0",
"The version of KubeSphere")
flags.StringSliceVarP(&opt.components, "components", "", []string{},
"Which components will enable")
flags.BoolVarP(&opt.Reset, "reset", "", false, "")
flags.StringVarP(&opt.Nightly, "nightly", "", "", "")
return
}

func (o *kindOption) reset(cmd *cobra.Command, args []string) (err error) {
var tag string
// try to parse the nightly date
if o.Nightly == "latest" {
tag = fmt.Sprintf("nightly-%s", time.Now().AddDate(0, 0, -1).Format("20060102"))
} else if o.Nightly != "" {
layout := "2006-01-02"
var targetDate time.Time
if targetDate, err = time.Parse(layout, o.Nightly); err == nil {
tag = fmt.Sprintf("nightly-%s", targetDate.Format("20060102"))
}
}

if err = pullAndLoadImage(fmt.Sprintf("kubespheredev/ks-installer:%s", tag)); err != nil {
return
}
if err = pullAndLoadImage(fmt.Sprintf("kubespheredev/ks-apiserver:%s", tag)); err != nil {
return
}
if err = pullAndLoadImage(fmt.Sprintf("kubespheredev/ks-controller-manager:%s", tag)); err != nil {
return
}
if err = pullAndLoadImage(fmt.Sprintf("kubespheredev/ks-console:%s", tag)); err != nil {
return
}
if err = execCommand("kubectl", "ks", "reset", "com", "--nightly", "latest", "-a"); err != nil {
return
}
return
}

func (o *kindOption) runE(cmd *cobra.Command, args []string) (err error) {
if o.Reset {
return o.reset(cmd, args)
}

writeConfigFile("config.yaml", o.portMappings)
if err = execCommand("kind", "create", "cluster", "--image", "kindest/node:v1.18.2", "--config", "config.yaml", "--name", o.name); err != nil {
return
}

if err = execCommand("kubectl", "cluster-info", " --context", fmt.Sprintf("kind-%s", o.name)); err != nil {
return
}

if err = loadCoreImageOfKS(); err != nil {
return
}

if err = execCommand("kubectl", "apply", "-f", fmt.Sprintf("https://github.com/kubesphere/ks-installer/releases/download/%s/kubesphere-installer.yaml", o.ksVersion)); err != nil {
return
}

if err = execCommand("kubectl", "apply", "-f", fmt.Sprintf("https://github.com/kubesphere/ks-installer/releases/download/%s/cluster-configuration.yaml", o.ksVersion)); err != nil {
return
}

fmt.Println(`kubectl -n kubesphere-system patch deploy ks-installer -type=json -p='[{"op":"replace","path":"/spec/template/spec/containers/0/imagePullPolicy","value":"IfNotPresent"}]'`)

for _, com := range o.components {
switch com {
case "devops":
err = loadImagesOfDevOps()
}
}
return
}

func loadImagesOfDevOps() (err error) {
if err = pullAndLoadImage("kubesphere/jenkins-uc:v3.0.0"); err != nil {
return
}
if err = pullAndLoadImage("jenkins/jenkins:2.176.2"); err != nil {
return
}
if err = pullAndLoadImage("jenkins/jnlp-slave:3.27-1"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/builder-base:v2.1.0"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/builder-nodejs:v2.1.0"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/builder-go:v2.1.0"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/builder-maven:v2.1.0"); err != nil {
return
}
return
}

func loadCoreImageOfKS() (err error) {
if err = pullAndLoadImage("kubesphere/ks-installer:v3.0.0"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/ks-apiserver:v3.0.0"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/ks-controller-manager:v3.0.0"); err != nil {
return
}
if err = pullAndLoadImage("kubesphere/ks-console:v3.0.0"); err != nil {
return
}
if err = pullAndLoadImage("redis:5.0.5-alpine"); err != nil {
return
}
if err = pullAndLoadImage("osixia/openldap:1.3.0"); err != nil {
return
}
if err = pullAndLoadImage("minio/minio:RELEASE.2019-08-07T01-59-21Z"); err != nil {
return
}
if err = pullAndLoadImage("mysql:8.0.11"); err != nil {
return
}
return
}

func pullAndLoadImage(image string) (err error) {
if err = execCommand("docker", "pull", image); err == nil {
err = execCommand("kind", "load", "docker-image", image)
}
return
}

func writeConfigFile(filename string, portMapping map[string]string) {
kindTemplate, err := template.New("config").Parse(`
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
{{- range $k, $v := . }}
- containerPort: {{$k}}
hostPort: {{$v}}
protocol: TCP
{{- end }}
`)
if err != nil {
fmt.Println("failed to write kind config file", err)
}
f, _ := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0600)
if err := kindTemplate.Execute(f, portMapping); err != nil {
fmt.Println("failed to render kind template", err)
}
}

type kindOption struct {
name string
version string
portMappings map[string]string
ksVersion string
components []string

Reset bool
Nightly string
}

func execCommand(name string, arg ...string) (err error) {
command := exec.Command(name, arg...)

//var stdout []byte
//var errStdout error
stdoutIn, _ := command.StdoutPipe()
stderrIn, _ := command.StderrPipe()
err = command.Start()
if err != nil {
return err
}

// cmd.Wait() should be called only after we finish reading
// from stdoutIn and stderrIn.
// wg ensures that we finish
var wg sync.WaitGroup
wg.Add(1)
go func() {
_, _ = copyAndCapture(os.Stdout, stdoutIn)
wg.Done()
}()

_, _ = copyAndCapture(os.Stderr, stderrIn)

wg.Wait()

err = command.Wait()
return
}

func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
var out []byte
buf := make([]byte, 1024, 1024)
for {
n, err := r.Read(buf[:])
if n > 0 {
d := buf[:n]
out = append(out, d...)
_, err := w.Write(d)
if err != nil {
return out, err
}
}
if err != nil {
// Read returns io.EOF at the end of file, which is not an error for us
if err == io.EOF {
err = nil
}
return out, err
}
}
}
14 changes: 14 additions & 0 deletions kubectl-plugin/install/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package install

import "github.com/spf13/cobra"

// NewInstallCmd returns the command of install kubesphere
func NewInstallCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "install",
Short: "install KubeSphere",
}

cmd.AddCommand(newInstallWithKindCmd())
return
}

0 comments on commit 2c40776

Please sign in to comment.