diff --git a/cmd/create/createCluster.go b/cmd/create/createCluster.go index 22094ae5..2f047c01 100644 --- a/cmd/create/createCluster.go +++ b/cmd/create/createCluster.go @@ -84,8 +84,9 @@ func NewCmdCreateCluster() *cobra.Command { if runtime.GOOS == "windows" { log.Debugf("GOOS is %s", runtime.GOOS) fmt.Printf("$env:KUBECONFIG=(%s get kubeconfig %s)\n", os.Args[0], cluster.Name) + } else { + fmt.Printf("export KUBECONFIG=$(%s get kubeconfig %s)\n", os.Args[0], cluster.Name) } - fmt.Printf("export KUBECONFIG=$(%s get kubeconfig %s)\n", os.Args[0], cluster.Name) fmt.Println("kubectl cluster-info") }, } diff --git a/cmd/get/getKubeconfig.go b/cmd/get/getKubeconfig.go index 6afe4244..42557d50 100644 --- a/cmd/get/getKubeconfig.go +++ b/cmd/get/getKubeconfig.go @@ -58,7 +58,7 @@ func NewCmdGetKubeconfig() *cobra.Command { } // add flags - cmd.Flags().StringP("output", "o", clientcmd.RecommendedHomeFile, "Define output [ - | FILE ]") + cmd.Flags().StringP("output", "o", "", fmt.Sprintf("Define output [ - | FILE ] (default from $KUBECONFIG or %s", clientcmd.RecommendedHomeFile)) if err := cmd.MarkFlagFilename("output"); err != nil { log.Fatalln("Failed to mark flag --output as filename") } diff --git a/docs/documentation.md b/docs/documentation.md index 61d202b5..ffbbd170 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -10,3 +10,7 @@ * all other master nodes will refer to the initializing master node via `--server https://:6443` * API-Ports * by default, we don't expose any API-Port (no host port mapping) +* kubeconfig + * if no output is set explicitly (via the `--output` flag), we use the default loading rules to get the default kubeconfig: + * First: kubeconfig specified via the KUBECONFIG environment variable (error out if multiple are specified) + * Second: default kubeconfig in home directory (e.g. `$HOME/.kube/config`) diff --git a/pkg/cluster/kubeconfig.go b/pkg/cluster/kubeconfig.go index 413dc43d..29c61711 100644 --- a/pkg/cluster/kubeconfig.go +++ b/pkg/cluster/kubeconfig.go @@ -54,6 +54,15 @@ func GetAndWriteKubeConfig(runtime runtimes.Runtime, cluster *k3d.Cluster, outpu return err } + // empty output parameter = write to default + if output == "" { + defaultKubeConfigLoadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + if len(defaultKubeConfigLoadingRules.GetLoadingPrecedence()) > 1 { + return fmt.Errorf("Multiple kubeconfigs specified via KUBECONFIG env var: Please reduce to one entry, unset KUBECONFIG or explicitly choose an output") + } + output = defaultKubeConfigLoadingRules.GetDefaultFilename() + } + // simply write to the output, ignoring existing contents if writeKubeConfigOptions.OverwriteExisting || output == "-" { return WriteKubeConfigToPath(kubeconfig, output) @@ -176,7 +185,7 @@ func GetKubeconfig(runtime runtimes.Runtime, cluster *k3d.Cluster) (*clientcmdap return kc, nil } -// WriteKubeConfigToPath uses GetKubeConfig to grab the kubeconfig from the cluster master node, writes it to a file and outputs the path +// WriteKubeConfigToPath takes a kubeconfig and writes it to some path, which can be '-' for os.Stdout func WriteKubeConfigToPath(kubeconfig *clientcmdapi.Config, path string) error { var output *os.File defer output.Close() @@ -209,7 +218,7 @@ func WriteKubeConfigToPath(kubeconfig *clientcmdapi.Config, path string) error { } -// UpdateKubeConfig merges a new kubeconfig into the existing default kubeconfig +// UpdateKubeConfig merges a new kubeconfig into an existing kubeconfig and returns the result func UpdateKubeConfig(newKubeConfig *clientcmdapi.Config, existingKubeConfig *clientcmdapi.Config, outPath string, overwriteConflicting bool, updateCurrentContext bool) error { log.Debugf("Merging new KubeConfig:\n%+v\n>>> into existing KubeConfig:\n%+v", newKubeConfig, existingKubeConfig) @@ -268,10 +277,3 @@ func UpdateKubeConfig(newKubeConfig *clientcmdapi.Config, existingKubeConfig *cl return nil } - -/*func UpdateKubeConfigOrCreate(outPath string) error { - _, err := os.Stat(outPath) - if os.IsNotExist(err) { - Create - } -}*/ diff --git a/thoughts.md b/thoughts.md index ca93f7e8..161f12b4 100644 --- a/thoughts.md +++ b/thoughts.md @@ -39,6 +39,9 @@ - --no-headers - kubeconfig NAME - --output + - --overwrite + - --switch + - --update - start - cluster NAME - --all @@ -72,7 +75,7 @@ - --env -> planned - --label -> planned - --workers -> implemented - - --auto-restart -> planned + - --auto-restart -> dropped (docker's `unless-stopped` is set by default) - --enable-registry -> planned (possible consolidation into less registry-related commands?) - --registry-name -> TBD - --registry-port -> TBD @@ -105,7 +108,7 @@ - get-kubeconfig -> `k3d get kubeconfig CLUSTERNAME` - --name -> dropped, implemented as arg - --all -> planned - - --overwrite -> planned + - --overwrite -> implemented - import-images -> `k3d load image [--cluster CLUSTERNAME] [--keep] IMAGES` - --name -> implemented as `--cluster` - --no-remove -> implemented as `--keep` @@ -201,9 +204,14 @@ Here's how k3d types should translate to a runtime type: ## [WIP] Multi-Master Setup -- if `--masters` > 1 deploy a load-balancer in front of them as an extra container +- to make this possible, we always deploy a load-balancer (nginx) in front of the master nodes as an extra container - consider that in the kubeconfig file and `--tls-san` - - make this the default, but provide a `--no-lb` flag + +### Variants + +- [x] embedded datastore (dqlite) + - if `--masters` > 1 deploy a load-balancer in front of them as an extra container +- [ ] external datastore ## [DONE] Keep State in Docker Labels @@ -222,7 +230,7 @@ Here's how k3d types should translate to a runtime type: - let's you set tools container version - `k3d tools --image k3d-tools:v2 import-images` - add `k3d create --image-vol NAME` flag to re-use existing image volume - - will add `k3d.volumes.imagevolume.external: true` label to nodes + - will add `k3d.volumes.imageVolume.external: true` label to nodes - should not be deleted with cluster - possibly add `k3d create volume` and `k3d create network` to create external volumes/networks? @@ -256,4 +264,3 @@ Here's how k3d types should translate to a runtime type: ### Possible Enhancements - [!] remove/add nodes -> needs to remove line in `/var/lib/rancher/k3s/server/cred/node-passwd` for the deleted node -- directly use cluster struct in `createClusterCmd` filled by flag values