add some comments

pull/26/head
iwilltry42 5 years ago
parent 705ef69dd9
commit 942e667b24
  1. 22
      cli/commands.go
  2. 23
      cli/container.go
  3. 5
      cli/network.go
  4. 1
      cli/util.go
  5. 27
      main.go

@ -1,5 +1,9 @@
package run
/*
* This file contains the "backend" functionality for the CLI commands (and flags)
*/
import (
"bytes"
"context"
@ -19,7 +23,7 @@ import (
"github.com/urfave/cli"
)
// CheckTools checks if the installed tools work correctly
// CheckTools checks if the docker API server is responding
func CheckTools(c *cli.Context) error {
log.Print("Checking docker...")
ctx := context.Background()
@ -67,7 +71,7 @@ func CreateCluster(c *cli.Context) error {
k3sServerArgs = append(k3sServerArgs, c.StringSlice("server-arg")...)
}
// let's go
// create the server
log.Printf("Creating cluster [%s]", c.String("name"))
dockerID, err := createServer(
c.GlobalBool("verbose"),
@ -88,10 +92,13 @@ func CreateCluster(c *cli.Context) error {
return err
}
// wait for k3s to be up and running if we want it
// Wait for k3s to be up and running if wanted.
// We're simply scanning the container logs for a line that tells us that everything's up and running
// TODO: also wait for worker nodes
start := time.Now()
timeout := time.Duration(c.Int("timeout")) * time.Second
for c.IsSet("wait") {
// not running after timeout exceeded? Rollback and delete everything.
if timeout != 0 && !time.Now().After(start.Add(timeout)) {
err := DeleteCluster(c)
if err != nil {
@ -100,6 +107,7 @@ func CreateCluster(c *cli.Context) error {
return errors.New("Cluster creation exceeded specified timeout")
}
// scan container logs for a line that tells us that the required services are up and running
out, err := docker.ContainerLogs(ctx, dockerID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
if err != nil {
out.Close()
@ -116,9 +124,12 @@ func CreateCluster(c *cli.Context) error {
time.Sleep(1 * time.Second)
}
// create the directory where we will put the kubeconfig file by default (when running `k3d get-config`)
// TODO: this can probably be moved to `k3d get-config` or be removed in a different approach
createClusterDir(c.String("name"))
// worker nodes
// spin up the worker nodes
// TODO: do this concurrently in different goroutines
if c.Int("workers") > 0 {
k3sWorkerArgs := []string{}
env := []string{k3sClusterSecret}
@ -150,7 +161,7 @@ kubectl cluster-info`, os.Args[0], c.String("name"))
return nil
}
// DeleteCluster removes the cluster container and its cluster directory
// DeleteCluster removes the containers belonging to a cluster and its local directory
func DeleteCluster(c *cli.Context) error {
// operate on one or all clusters
@ -177,6 +188,7 @@ func DeleteCluster(c *cli.Context) error {
for _, cluster := range clusters {
log.Printf("Removing cluster [%s]", cluster.name)
if len(cluster.workers) > 0 {
// TODO: this could be done in goroutines
log.Printf("...Removing %d workers\n", len(cluster.workers))
for _, worker := range cluster.workers {
if err := removeContainer(worker.ID); err != nil {

@ -1,5 +1,10 @@
package run
/*
* The functions in this file take care of spinning up the
* k3s server and worker containers as well as deleting them.
*/
import (
"context"
"fmt"
@ -17,6 +22,7 @@ import (
"github.com/docker/docker/client"
)
// createServer creates and starts a k3s server container
func createServer(verbose bool, image string, port string, args []string, env []string, name string, volumes []string) (string, error) {
log.Printf("Creating server using %s...\n", image)
ctx := context.Background()
@ -24,6 +30,8 @@ func createServer(verbose bool, image string, port string, args []string, env []
if err != nil {
return "", fmt.Errorf("ERROR: couldn't create docker client\n%+v", err)
}
// pull the required docker image
reader, err := docker.ImagePull(ctx, image, types.ImagePullOptions{})
if err != nil {
return "", fmt.Errorf("ERROR: couldn't pull image %s\n%+v", image, err)
@ -40,6 +48,7 @@ func createServer(verbose bool, image string, port string, args []string, env []
}
}
// configure container options (host/network configuration, labels, env vars, etc.)
containerLabels := make(map[string]string)
containerLabels["app"] = "k3d"
containerLabels["component"] = "server"
@ -74,6 +83,7 @@ func createServer(verbose bool, image string, port string, args []string, env []
},
}
// create the container
resp, err := docker.ContainerCreate(ctx, &container.Config{
Image: image,
Cmd: append([]string{"server"}, args...),
@ -87,6 +97,7 @@ func createServer(verbose bool, image string, port string, args []string, env []
return "", fmt.Errorf("ERROR: couldn't create container %s\n%+v", containerName, err)
}
// start the container
if err := docker.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
return "", fmt.Errorf("ERROR: couldn't start container %s\n%+v", containerName, err)
}
@ -95,6 +106,7 @@ func createServer(verbose bool, image string, port string, args []string, env []
}
// createWorker creates/starts a k3s agent node that connects to the server
func createWorker(verbose bool, image string, args []string, env []string, name string, volumes []string, postfix string, serverPort string) (string, error) {
ctx := context.Background()
docker, err := client.NewEnvClient()
@ -102,6 +114,7 @@ func createWorker(verbose bool, image string, args []string, env []string, name
return "", fmt.Errorf("ERROR: couldn't create docker client\n%+v", err)
}
// pull the required docker image
reader, err := docker.ImagePull(ctx, image, types.ImagePullOptions{})
if err != nil {
return "", fmt.Errorf("ERROR: couldn't pull image %s\n%+v", image, err)
@ -113,6 +126,7 @@ func createWorker(verbose bool, image string, args []string, env []string, name
}
}
// configure container options (host/network configuration, labels, env vars, etc.)
containerLabels := make(map[string]string)
containerLabels["app"] = "k3d"
containerLabels["component"] = "worker"
@ -143,6 +157,7 @@ func createWorker(verbose bool, image string, args []string, env []string, name
},
}
// create the container
resp, err := docker.ContainerCreate(ctx, &container.Config{
Image: image,
Env: env,
@ -152,6 +167,7 @@ func createWorker(verbose bool, image string, args []string, env []string, name
return "", fmt.Errorf("ERROR: couldn't create container %s\n%+v", containerName, err)
}
// start the container
if err := docker.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
return "", fmt.Errorf("ERROR: couldn't start container %s\n%+v", containerName, err)
}
@ -159,13 +175,20 @@ func createWorker(verbose bool, image string, args []string, env []string, name
return resp.ID, nil
}
// removeContainer tries to rm a container, selected by Docker ID, and does a rm -f if it fails (e.g. if container is still running)
func removeContainer(ID string) error {
// TODO: first check if container is running, then try to stop it with a timeout before trying to remove it
// if it does not terminate gracefully, try a force remove
ctx := context.Background()
docker, err := client.NewEnvClient()
if err != nil {
return fmt.Errorf("ERROR: couldn't create docker client\n%+v", err)
}
// first, try a soft remove
if err := docker.ContainerRemove(ctx, ID, types.ContainerRemoveOptions{}); err != nil {
// if soft remove didn't succeed, force remove the container
log.Printf("WARNING: couldn't delete container [%s], trying a force remove now.", ID)
if err := docker.ContainerRemove(ctx, ID, types.ContainerRemoveOptions{Force: true}); err != nil {
return fmt.Errorf("FAILURE: couldn't delete container [%s] -> %+v", ID, err)

@ -11,6 +11,8 @@ import (
"github.com/docker/docker/client"
)
// createClusterNetwork creates a docker network for a cluster that will be used
// to let the server and worker containers communicate with each other easily.
func createClusterNetwork(clusterName string) (string, error) {
ctx := context.Background()
docker, err := client.NewEnvClient()
@ -18,6 +20,7 @@ func createClusterNetwork(clusterName string) (string, error) {
return "", fmt.Errorf("ERROR: couldn't create docker client\n%+v", err)
}
// create the network with a set of labels and the cluster name as network name
resp, err := docker.NetworkCreate(ctx, clusterName, types.NetworkCreate{
Labels: map[string]string{
"app": "k3d",
@ -31,6 +34,7 @@ func createClusterNetwork(clusterName string) (string, error) {
return resp.ID, nil
}
// deleteClusterNetwork deletes a docker network based on the name of a cluster it belongs to
func deleteClusterNetwork(clusterName string) error {
ctx := context.Background()
docker, err := client.NewEnvClient()
@ -49,6 +53,7 @@ func deleteClusterNetwork(clusterName string) error {
return fmt.Errorf("ERROR: couldn't find network for cluster %s\n%+v", clusterName, err)
}
// there should be only one network that matches the name... but who knows?
for _, network := range networks {
if err := docker.NetworkRemove(ctx, network.ID); err != nil {
log.Printf("WARNING: couldn't remove network for cluster %s\n%+v", clusterName, err)

@ -16,6 +16,7 @@ const (
var src = rand.NewSource(time.Now().UnixNano())
// GenerateRandomString thanks to https://stackoverflow.com/a/31832326/6450189
// GenerateRandomString is used to generate a random string that is used as a cluster secret
func GenerateRandomString(n int) string {
sb := strings.Builder{}

@ -41,10 +41,10 @@ func main() {
Action: run.CheckTools,
},
{
// create creates a new k3s cluster in a container
// create creates a new k3s cluster in docker containers
Name: "create",
Aliases: []string{"c"},
Usage: "Create a single node k3s cluster in a container",
Usage: "Create a single- or multi-node k3s cluster in docker containers",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name, n",
@ -53,7 +53,7 @@ func main() {
},
cli.StringFlag{
Name: "volume, v",
Usage: "Mount one or more volumes into the cluster node (Docker notation: `source:destination[,source:destination]`)",
Usage: "Mount one or more volumes into every node of the cluster (Docker notation: `source:destination[,source:destination]`)",
},
cli.StringFlag{
Name: "version",
@ -63,7 +63,7 @@ func main() {
cli.IntFlag{
Name: "port, p",
Value: 6443,
Usage: "Set a port on which the ApiServer will listen",
Usage: "Map the Kubernetes ApiServer port to a local port",
},
cli.IntFlag{
Name: "timeout, t",
@ -72,7 +72,7 @@ func main() {
},
cli.BoolFlag{
Name: "wait, w",
Usage: "Wait for the cluster to come up",
Usage: "Wait for the cluster to come up before returning",
},
cli.StringSliceFlag{
Name: "server-arg, x",
@ -103,7 +103,7 @@ func main() {
},
cli.BoolFlag{
Name: "all, a",
Usage: "delete all existing clusters (this ignores the --name/-n flag)",
Usage: "Delete all existing clusters (this ignores the --name/-n flag)",
},
},
Action: run.DeleteCluster,
@ -116,11 +116,11 @@ func main() {
cli.StringFlag{
Name: "name, n",
Value: "k3s_default",
Usage: "name of the cluster",
Usage: "Name of the cluster",
},
cli.BoolFlag{
Name: "all, a",
Usage: "stop all running clusters (this ignores the --name/-n flag)",
Usage: "Stop all running clusters (this ignores the --name/-n flag)",
},
},
Action: run.StopCluster,
@ -133,11 +133,11 @@ func main() {
cli.StringFlag{
Name: "name, n",
Value: "k3s_default",
Usage: "name of the cluster",
Usage: "Name of the cluster",
},
cli.BoolFlag{
Name: "all, a",
Usage: "start all stopped clusters (this ignores the --name/-n flag)",
Usage: "Start all stopped clusters (this ignores the --name/-n flag)",
},
},
Action: run.StartCluster,
@ -150,7 +150,7 @@ func main() {
Flags: []cli.Flag{
cli.BoolFlag{
Name: "all, a",
Usage: "also show non-running clusters",
Usage: "Also show non-running clusters",
},
},
Action: run.ListClusters,
@ -163,17 +163,18 @@ func main() {
cli.StringFlag{
Name: "name, n",
Value: "k3s_default",
Usage: "name of the cluster",
Usage: "Name of the cluster",
},
cli.BoolFlag{
Name: "all, a",
Usage: "get kubeconfig for all clusters (this ignores the --name/-n flag)",
Usage: "Get kubeconfig for all clusters (this ignores the --name/-n flag)",
},
},
Action: run.GetKubeConfig,
},
}
// Global flags
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "verbose",

Loading…
Cancel
Save