Merge pull request #288 from rancher/kubeconfig-default

[Enhancement] New kubeconfig defaults
pull/297/head
Thorsten Klein 4 years ago committed by GitHub
commit 9332f32ead
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      cmd/create/createCluster.go
  2. 19
      cmd/delete/deleteCluster.go
  3. 34
      cmd/get/getKubeconfig.go
  4. 2
      docs/index.md
  5. 20
      docs/internals/defaults.md
  6. 7
      docs/usage/commands.md
  7. 2
      docs/usage/guides/exposing_services.md
  8. 26
      docs/usage/kubeconfig.md
  9. 4
      tests/common.sh

@ -51,7 +51,7 @@ Every cluster will consist of at least 2 containers:
func NewCmdCreateCluster() *cobra.Command {
createClusterOpts := &k3d.CreateClusterOpts{}
var updateKubeconfig, updateCurrentContext bool
var updateDefaultKubeconfig, updateCurrentContext bool
// create new command
cmd := &cobra.Command{
@ -69,8 +69,8 @@ func NewCmdCreateCluster() *cobra.Command {
}
// create cluster
if updateKubeconfig || updateCurrentContext {
log.Debugln("'--update-kubeconfig set: enabling wait-for-master")
if updateDefaultKubeconfig || updateCurrentContext {
log.Debugln("'--update-default-kubeconfig set: enabling wait-for-master")
cluster.CreateClusterOpts.WaitForMaster = true
}
if err := k3dCluster.CreateCluster(cmd.Context(), runtimes.SelectedRuntime, cluster); err != nil {
@ -85,16 +85,16 @@ func NewCmdCreateCluster() *cobra.Command {
}
log.Infof("Cluster '%s' created successfully!", cluster.Name)
if updateKubeconfig || updateCurrentContext {
if updateDefaultKubeconfig || updateCurrentContext {
log.Debugf("Updating default kubeconfig with a new context for cluster %s", cluster.Name)
if _, err := k3dCluster.GetAndWriteKubeConfig(cmd.Context(), runtimes.SelectedRuntime, cluster, "", &k3dCluster.WriteKubeConfigOptions{UpdateExisting: true, OverwriteExisting: false, UpdateCurrentContext: updateCurrentContext}); err != nil {
log.Fatalln(err)
log.Warningln(err)
}
}
// print information on how to use the cluster with kubectl
log.Infoln("You can now use it like this:")
if updateKubeconfig && !updateCurrentContext {
if updateDefaultKubeconfig && !updateCurrentContext {
fmt.Printf("kubectl config use-context %s\n", fmt.Sprintf("%s-%s", k3d.DefaultObjectNamePrefix, cluster.Name))
} else if !updateCurrentContext {
if runtime.GOOS == "windows" {
@ -120,8 +120,8 @@ func NewCmdCreateCluster() *cobra.Command {
cmd.Flags().StringArrayP("port", "p", nil, "Map ports from the node containers to the host (Format: `[HOST:][HOSTPORT:]CONTAINERPORT[/PROTOCOL][@NODEFILTER]`)\n - Example: `k3d create -w 2 -p 8080:80@worker[0] -p 8081@worker[1]`")
cmd.Flags().BoolVar(&createClusterOpts.WaitForMaster, "wait", true, "Wait for the master(s) to be ready before returning. Use '--timeout DURATION' to not wait forever.")
cmd.Flags().DurationVar(&createClusterOpts.Timeout, "timeout", 0*time.Second, "Rollback changes if cluster couldn't be created in specified duration.")
cmd.Flags().BoolVar(&updateKubeconfig, "update-kubeconfig", false, "Directly update the default kubeconfig with the new cluster's context")
cmd.Flags().BoolVar(&updateCurrentContext, "switch", false, "Directly switch the default kubeconfig's current-context to the new cluster's context (implies --update-kubeconfig)")
cmd.Flags().BoolVar(&updateDefaultKubeconfig, "update-default-kubeconfig", true, "Directly update the default kubeconfig with the new cluster's context")
cmd.Flags().BoolVar(&updateCurrentContext, "switch-context", true, "Directly switch the default kubeconfig's current-context to the new cluster's context (implies --update-default-kubeconfig)")
cmd.Flags().BoolVar(&createClusterOpts.DisableLoadBalancer, "no-lb", false, "Disable the creation of a LoadBalancer in front of the master nodes")
/* Image Importing */

@ -22,10 +22,15 @@ THE SOFTWARE.
package delete
import (
"fmt"
"os"
"path"
"github.com/rancher/k3d/v3/cmd/util"
"github.com/rancher/k3d/v3/pkg/cluster"
"github.com/rancher/k3d/v3/pkg/runtimes"
k3d "github.com/rancher/k3d/v3/pkg/types"
k3dutil "github.com/rancher/k3d/v3/pkg/util"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -51,11 +56,23 @@ func NewCmdDeleteCluster() *cobra.Command {
if err := cluster.DeleteCluster(cmd.Context(), runtimes.SelectedRuntime, c); err != nil {
log.Fatalln(err)
}
log.Infoln("Removing cluster details from default kubeconfig")
log.Infoln("Removing cluster details from default kubeconfig...")
if err := cluster.RemoveClusterFromDefaultKubeConfig(cmd.Context(), c); err != nil {
log.Warnln("Failed to remove cluster details from default kubeconfig")
log.Warnln(err)
}
log.Infoln("Removing standalone kubeconfig file (if there is one)...")
configDir, err := k3dutil.GetConfigDirOrCreate()
if err != nil {
log.Warnf("Failed to delete kubeconfig file: %+v", err)
} else {
kubeconfigfile := path.Join(configDir, fmt.Sprintf("kubeconfig-%s.yaml", c.Name))
if err := os.Remove(kubeconfigfile); err != nil {
if !os.IsNotExist(err) {
log.Warnf("Failed to delete kubeconfig file '%s'", kubeconfigfile)
}
}
}
log.Infof("Successfully deleted cluster %s!", c.Name)
}

@ -24,11 +24,14 @@ package get
import (
"fmt"
"os"
"path"
"strings"
"github.com/rancher/k3d/v3/cmd/util"
"github.com/rancher/k3d/v3/pkg/cluster"
"github.com/rancher/k3d/v3/pkg/runtimes"
k3d "github.com/rancher/k3d/v3/pkg/types"
k3dutil "github.com/rancher/k3d/v3/pkg/util"
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
@ -36,8 +39,9 @@ import (
)
type getKubeconfigFlags struct {
all bool
output string
all bool
output string
targetDefault bool
}
// NewCmdGetKubeconfig returns a new cobra command
@ -63,6 +67,10 @@ func NewCmdGetKubeconfig() *cobra.Command {
var clusters []*k3d.Cluster
var err error
if getKubeconfigFlags.targetDefault && getKubeconfigFlags.output != "" {
log.Fatalln("Cannot use both '--output' and '--merge-default-kubeconfig' at the same time")
}
// generate list of clusters
if getKubeconfigFlags.all {
clusters, err = cluster.GetClusters(cmd.Context(), runtimes.SelectedRuntime)
@ -81,17 +89,30 @@ func NewCmdGetKubeconfig() *cobra.Command {
// get kubeconfigs from all clusters
errorGettingKubeconfig := false
var outputs []string
outputDir, err := k3dutil.GetConfigDirOrCreate()
if err != nil {
log.Errorln(err)
log.Fatalln("Failed to save kubeconfig to local directory")
}
for _, c := range clusters {
log.Debugf("Getting kubeconfig for cluster '%s'", c.Name)
if getKubeconfigFlags.output, err = cluster.GetAndWriteKubeConfig(cmd.Context(), runtimes.SelectedRuntime, c, getKubeconfigFlags.output, &writeKubeConfigOptions); err != nil {
output := getKubeconfigFlags.output
if output == "" && !getKubeconfigFlags.targetDefault {
output = path.Join(outputDir, fmt.Sprintf("kubeconfig-%s.yaml", c.Name))
}
output, err = cluster.GetAndWriteKubeConfig(cmd.Context(), runtimes.SelectedRuntime, c, output, &writeKubeConfigOptions)
if err != nil {
log.Errorln(err)
errorGettingKubeconfig = true
} else {
outputs = append(outputs, output)
}
}
// only print kubeconfig file path if output is not stdout ("-")
if getKubeconfigFlags.output != "-" {
fmt.Println(getKubeconfigFlags.output)
fmt.Println(strings.Join(outputs, ":"))
}
// return with non-zero exit code, if there was an error for one of the clusters
@ -106,8 +127,9 @@ func NewCmdGetKubeconfig() *cobra.Command {
if err := cmd.MarkFlagFilename("output"); err != nil {
log.Fatalln("Failed to mark flag --output as filename")
}
cmd.Flags().BoolVarP(&writeKubeConfigOptions.UpdateExisting, "update", "u", true, "Update conflicting fields in existing KubeConfig")
cmd.Flags().BoolVarP(&writeKubeConfigOptions.UpdateCurrentContext, "switch", "s", false, "Switch to new context")
cmd.Flags().BoolVarP(&getKubeconfigFlags.targetDefault, "merge-default-kubeconfig", "d", false, fmt.Sprintf("Merge into the default kubeconfig ($KUBECONFIG or %s)", clientcmd.RecommendedHomeFile))
cmd.Flags().BoolVarP(&writeKubeConfigOptions.UpdateExisting, "update", "u", true, "Update conflicting fields in existing kubeconfig")
cmd.Flags().BoolVarP(&writeKubeConfigOptions.UpdateCurrentContext, "switch-context", "s", true, "Switch to new context")
cmd.Flags().BoolVar(&writeKubeConfigOptions.OverwriteExisting, "overwrite", false, "[Careful!] Overwrite existing file, ignoring its contents")
cmd.Flags().BoolVarP(&getKubeconfigFlags.all, "all", "a", false, "Get kubeconfigs from all existing clusters")

@ -67,4 +67,4 @@ kubectl get nodes
## Related Projects
* [k3x](https://github.com/inercia/k3x): a graphics interface (for Linux) to k3d.
- [k3x](https://github.com/inercia/k3x): a graphics interface (for Linux) to k3d.

@ -1,12 +1,12 @@
# Defaults
* multiple master nodes
* by default, when `--master` > 1 and no `--datastore-x` option is set, the first master node (master-0) will be the initializing master node
* the initializing master node will have the `--cluster-init` flag appended
* all other master nodes will refer to the initializing master node via `--server https://<init-node>: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`)
- multiple master nodes
- by default, when `--master` > 1 and no `--datastore-x` option is set, the first master node (master-0) will be the initializing master node
- the initializing master node will have the `--cluster-init` flag appended
- all other master nodes will refer to the initializing master node via `--server https://<init-node>:6443`
- API-Ports
- by default, we don't expose any API-Port (no host port mapping)
- kubeconfig
- if `--[update|merge]-default-kubeconfig` is set, 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`)

@ -16,8 +16,8 @@ k3d
-p, --port # add some more port mappings
--token # specify a cluster token (default: auto-generated)
--timeout # specify a timeout, after which the cluster creation will be interrupted and changes rolled back
--update-kubeconfig # enable the automated update of the default kubeconfig with the details of the newly created cluster (also sets '--wait=true')
--switch # (implies --update-kubeconfig) automatically sets the current-context of your default kubeconfig to the new cluster's context
--update-default-kubeconfig # enable the automated update of the default kubeconfig with the details of the newly created cluster (also sets '--wait=true')
--switch-context # (implies --update-default-kubeconfig) automatically sets the current-context of your default kubeconfig to the new cluster's context
-v, --volume # specify additional bind-mounts
--wait # enable waiting for all master nodes to be ready before returning
-w, --workers # specify how many worker nodes you want to create
@ -53,8 +53,9 @@ k3d
-a, --all # get kubeconfigs from all clusters
--output # specify the output file where the kubeconfig should be written to
--overwrite # [Careful!] forcefully overwrite the output file, ignoring existing contents
-s, --switch # switch current-context in kubeconfig to the new context
-s, --switch-context # switch current-context in kubeconfig to the new context
-u, --update # update conflicting fields in existing kubeconfig (default: true)
-d, --merge-default-kubeconfig # update the default kubeconfig (usually $KUBECONFIG or $HOME/.kube/config)
load
image [IMAGE | ARCHIVE [IMAGE | ARCHIVE ...]] # Load one or more images from the local runtime environment or tar-archives into k3d clusters
-c, --cluster # clusters to load the image into

@ -18,7 +18,7 @@ Therefore, we have to create the cluster in a way, that the internal port 80 (wh
2. Get the kubeconfig file
`#!bash export KUBECONFIG="$(k3d get-kubeconfig --name='k3s-default')"`
`#!bash export KUBECONFIG="$(k3d get kubeconfig k3s-default)"`
3. Create a nginx deployment

@ -11,28 +11,34 @@ To get a kubeconfig set up for you to connect to a k3d cluster, you can go diffe
## Getting the kubeconfig for a newly created cluster
1. Update your default kubeconfig **upon** cluster creation
- `#!bash k3d create cluster mycluster --update-kubeconfig`
- *Note:* this won't switch the current-context
2. Update your default kubeconfig **after** cluster creation
1. Create a new kubeconfig file **after** cluster creation
- `#!bash k3d get kubeconfig mycluster`
- *Note:* this won't switch the current-context
3. Update a different kubeconfig **after** cluster creation
- *Note:* this will create (or update) the file `$HOME/.k3d/kubeconfig-mycluster.yaml`
- *Tip:* Use it: `#!bash export KUBECONFIG=$(k3d get kubeconfig mycluster)`
2. Update your default kubeconfig **upon** cluster creation
- `#!bash k3d create cluster mycluster --update-kubeconfig`
- *Note:* this won't switch the current-context (append `--switch-context` to do so)
3. Update your default kubeconfig **after** cluster creation
- `#!bash k3d get kubeconfig mycluster --merge-default-kubeconfig`
- *Note:* this won't switch the current-context (append `--switch-context` to do so)
4. Update a different kubeconfig **after** cluster creation
- `#!bash k3d get kubeconfig mycluster --output some/other/file.yaml`
- *Note:* this won't switch the current-context
- The file will be created if it doesn't exist
!!! info "Switching the current context"
None of the above options switch the current-context.
None of the above options switch the current-context by default.
This is intended to be least intrusive, since the current-context has a global effect.
You can switch the current-context directly with the `get kubeconfig` command by adding the `--switch` flag.
You can switch the current-context directly with the `get kubeconfig` command by adding the `--switch-context` flag.
## Removing cluster details from the kubeconfig
`#!bash k3d delete cluster mycluster` will always remove the details for `mycluster` from the default kubeconfig.
It will also delete the respective kubeconfig file in `$HOME/.k3d/` if it exists.
## Handling multiple clusters
`k3d get kubeconfig` let's you specify one or more clusters via arguments _or_ all via `--all`.
All kubeconfigs will then be merged into a single file, which is either the default kubeconfig or the kubeconfig specified via `--output FILE`.
Note, that with multiple cluster specified, the `--switch` flag will change the current context to the cluster which was last in the list.
All kubeconfigs will then be merged into a single file if `--merge-default-kubeconfig` or `--output` is specified.
If none of those two flags was specified, a new file will be created per cluster and the merged path (e.g. `$HOME/.k3d/kubeconfig-cluster1.yaml:$HOME/.k3d/cluster2.yaml`) will be returned.
Note, that with multiple cluster specified, the `--switch-context` flag will change the current context to the cluster which was last in the list.

@ -61,7 +61,7 @@ check_url() {
check_clusters() {
[ -n "$EXE" ] || abort "EXE is not defined"
for c in "$@" ; do
$EXE get kubeconfig "$c" --switch
$EXE get kubeconfig "$c" --merge-default-kubeconfig --switch-context
if kubectl cluster-info ; then
passed "cluster $c is reachable"
else
@ -87,7 +87,7 @@ check_cluster_count() {
check_multi_node() {
cluster=$1
expectedNodeCount=$2
$EXE get kubeconfig "$cluster" --switch
$EXE get kubeconfig "$cluster" --merge-default-kubeconfig --switch-context
nodeCount=$(kubectl get nodes -o=custom-columns=NAME:.metadata.name --no-headers | wc -l)
if [[ $nodeCount == $expectedNodeCount ]]; then
passed "cluster $cluster has $expectedNodeCount nodes, as expected"

Loading…
Cancel
Save