Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop K8s if running, when '--no-kubernetes' flag used #13072

Merged
merged 11 commits into from
Dec 6, 2021
7 changes: 7 additions & 0 deletions cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ func provisionWithDriver(cmd *cobra.Command, ds registry.DriverState, existing *
updateDriver(driverName)
}

// Check whether we may need to stop Kubernetes.
var stopk8s bool
if existing != nil && viper.GetBool(noKubernetes) {
stopk8s = true
}

k8sVersion := getKubernetesVersion(existing)
cc, n, err := generateClusterConfig(cmd, existing, k8sVersion, driverName)
if err != nil {
Expand Down Expand Up @@ -337,6 +343,7 @@ func provisionWithDriver(cmd *cobra.Command, ds registry.DriverState, existing *
return node.Starter{
Runner: mRunner,
PreExists: preExists,
StopK8s: stopk8s,
MachineAPI: mAPI,
Host: host,
ExistingAddons: existingAddons,
Expand Down
48 changes: 33 additions & 15 deletions pkg/minikube/bootstrapper/kubeadm/kubeadm.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,38 @@ func (k *Bootstrapper) GenerateToken(cc config.ClusterConfig) (string, error) {
return joinCmd, nil
}

// StopKubernetes attempts to stop existing kubernetes.
func StopKubernetes(runner command.Runner, cr cruntime.Manager) {
// Verify that Kubernetes is still running.
stk := kverify.ServiceStatus(runner, "kubelet")
if stk.String() != "Running" {
return
}

out.Infof("Kubernetes: Stopping ...")

// Force stop "Kubelet".
if err := sysinit.New(runner).ForceStop("kubelet"); err != nil {
klog.Warningf("stop kubelet: %v", err)
}

// Stop each Kubernetes container.
containers, err := cr.ListContainers(cruntime.ListContainersOptions{Namespaces: []string{"kube-system"}})
if err != nil {
klog.Warningf("unable to list kube-system containers: %v", err)
}
if len(containers) > 0 {
klog.Warningf("found %d kube-system containers to stop", len(containers))
if err := cr.StopContainers(containers); err != nil {
klog.Warningf("error stopping containers: %v", err)
}
}

// Verify that Kubernetes has stopped.
stk = kverify.ServiceStatus(runner, "kubelet")
out.Infof("Kubernetes: {{.status}}", out.V{"status": stk.String()})
}

// DeleteCluster removes the components that were started earlier
func (k *Bootstrapper) DeleteCluster(k8s config.KubernetesConfig) error {
cr, err := cruntime.New(cruntime.Config{Type: k8s.ContainerRuntime, Runner: k.c, Socket: k8s.CRISocket})
Expand Down Expand Up @@ -828,21 +860,7 @@ func (k *Bootstrapper) DeleteCluster(k8s config.KubernetesConfig) error {
klog.Warningf("%s: %v", rr.Command(), err)
}

if err := sysinit.New(k.c).ForceStop("kubelet"); err != nil {
klog.Warningf("stop kubelet: %v", err)
}

containers, err := cr.ListContainers(cruntime.ListContainersOptions{Namespaces: []string{"kube-system"}})
if err != nil {
klog.Warningf("unable to list kube-system containers: %v", err)
}
if len(containers) > 0 {
klog.Warningf("found %d kube-system containers to stop", len(containers))
if err := cr.StopContainers(containers); err != nil {
klog.Warningf("error stopping containers: %v", err)
}
}

StopKubernetes(k.c, cr)
return derr
}

Expand Down
22 changes: 21 additions & 1 deletion pkg/minikube/node/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/cni"
"k8s.io/minikube/pkg/minikube/command"
Expand Down Expand Up @@ -79,6 +80,7 @@ var (
type Starter struct {
Runner command.Runner
PreExists bool
StopK8s bool
MachineAPI libmachine.API
Host *host.Host
Cfg *config.ClusterConfig
Expand All @@ -89,9 +91,10 @@ type Starter struct {
// Start spins up a guest and starts the Kubernetes node.
func Start(starter Starter, apiServer bool) (*kubeconfig.Settings, error) {
var kcs *kubeconfig.Settings
if starter.Node.KubernetesVersion == constants.NoKubernetesVersion { // do not bootstrap cluster if --no-kubernetes
if err := handleNoKubernetes(starter); err != nil {
return kcs, config.Write(viper.GetString(config.ProfileName), starter.Cfg)
}

// wait for preloaded tarball to finish downloading before configuring runtimes
waitCacheRequiredImages(&cacheGroup)

Expand Down Expand Up @@ -238,6 +241,23 @@ func Start(starter Starter, apiServer bool) (*kubeconfig.Settings, error) {
return kcs, config.Write(viper.GetString(config.ProfileName), starter.Cfg)
}

// handleNoKubernetes handles starting minikube without Kubernetes.
func handleNoKubernetes(starter Starter) error {
// Do not bootstrap cluster if --no-kubernetes.
if starter.Node.KubernetesVersion == constants.NoKubernetesVersion {
// Stop existing Kubernetes node if applicable.
if starter.StopK8s {
cr, err := cruntime.New(cruntime.Config{Type: starter.Cfg.KubernetesConfig.ContainerRuntime, Runner: starter.Runner, Socket: starter.Cfg.KubernetesConfig.CRISocket})
if err != nil {
return err
}
kubeadm.StopKubernetes(starter.Runner, cr)
}
return errors.New("stop kubernetes")
}
return nil
}

// joinCluster adds new or prepares and then adds existing node to the cluster.
func joinCluster(starter Starter, cpBs bootstrapper.Bootstrapper, bs bootstrapper.Bootstrapper) error {
start := time.Now()
Expand Down
59 changes: 58 additions & 1 deletion test/integration/no_kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package integration

import (
"context"
"encoding/json"
"fmt"
"os/exec"
"strings"
"testing"
Expand All @@ -46,6 +48,8 @@ func TestNoKubernetes(t *testing.T) {
validator validateFunc
}{
{"StartNoK8sWithVersion", validateStartNoK8sWithVersion},
{"StartWithK8s", validateStartWithK8S},
{"StartWithStopK8s", validateStartWithStopK8s},
{"Start", validateStartNoK8S},
{"VerifyK8sNotRunning", validateK8SNotRunning},
{"ProfileList", validateProfileListNoK8S},
Expand Down Expand Up @@ -82,6 +86,42 @@ func validateStartNoK8sWithVersion(ctx context.Context, t *testing.T, profile st
}
}

// validateStartWithK8S starts a minikube cluster with Kubernetes started/configured.
func validateStartWithK8S(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)

args := append([]string{"start", "-p", profile}, StartArgs()...)
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to start minikube with args: %q : %v", rr.Command(), err)
}

if k8sStatus := getK8sStatus(ctx, t, profile); k8sStatus != "Running" {
t.Errorf("Kubernetes status, got: %s, want: Running", k8sStatus)
}
}

// validateStartWithStopK8s starts a minikube cluster while stopping Kubernetes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add more comment of all the thing this test does
Since it's used in auto generated docs.
This test also deletes . So comment should say all things it does in the test and maybe rename subtest to include delete in it too

func validateStartWithStopK8s(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)

args := append([]string{"start", "-p", profile, "--no-kubernetes"}, StartArgs()...)
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to start minikube with args: %q : %v", rr.Command(), err)
}

if k8sStatus := getK8sStatus(ctx, t, profile); k8sStatus != "Stopped" {
t.Errorf("Kubernetes status, got: %s, want: Stopped", k8sStatus)
}

args = []string{"delete", "-p", profile}
rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to delete minikube profile with args: %q : %v", rr.Command(), err)
}
}

// validateStartNoK8S starts a minikube cluster without kubernetes started/configured
func validateStartNoK8S(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)
Expand Down Expand Up @@ -137,7 +177,7 @@ func validateProfileListNoK8S(ctx context.Context, t *testing.T, profile string)

}

// validateStartNoArgs valides that minikube start with no args works
// validateStartNoArgs validates that minikube start with no args works.
func validateStartNoArgs(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)

Expand All @@ -146,5 +186,22 @@ func validateStartNoArgs(ctx context.Context, t *testing.T, profile string) {
if err != nil {
t.Fatalf("failed to start minikube with args: %q : %v", rr.Command(), err)
}
}

// getK8sStatus returns whether Kubernetes is running.
func getK8sStatus(ctx context.Context, t *testing.T, profile string) string {
// Run `minikube status` as JSON output.
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status", "-o", "json"))
// We expect Kubernetes config to come back as configured, since we started Kubernetes in a previous test.
if err != nil && rr.ExitCode != 2 {
t.Errorf("failed to run minikube status with json output. args %q : %v", rr.Command(), err)
}

// Unmarshal JSON output.
var jsonObject map[string]interface{}
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonObject)
if err != nil {
t.Errorf("failed to decode json from minikube status. args %q. %v", rr.Command(), err)
}
return fmt.Sprintf("%s", jsonObject["Kubelet"])
}