diff --git a/cmd/minikube/cmd/start_flags.go b/cmd/minikube/cmd/start_flags.go index cd22134918bf..329403622828 100644 --- a/cmd/minikube/cmd/start_flags.go +++ b/cmd/minikube/cmd/start_flags.go @@ -99,6 +99,7 @@ const ( nodes = "nodes" preload = "preload" deleteOnFailure = "delete-on-failure" + forceSystemd = "force-systemd" kicBaseImage = "base-image" ) @@ -138,6 +139,7 @@ func initMinikubeFlags() { startCmd.Flags().IntP(nodes, "n", 1, "The number of nodes to spin up. Defaults to 1.") startCmd.Flags().Bool(preload, true, "If set, download tarball of preloaded images if available to improve start time. Defaults to true.") startCmd.Flags().Bool(deleteOnFailure, false, "If set, delete the current cluster if start fails and try again. Defaults to false.") + startCmd.Flags().Bool(forceSystemd, false, "If set, force the container runtime to use sytemd as cgroup manager. Currently available for docker and crio. Defaults to false.") } // initKubernetesFlags inits the commandline flags for kubernetes related options diff --git a/hack/preload-images/generate.go b/hack/preload-images/generate.go index daa9e77f092a..54c680bc480c 100644 --- a/hack/preload-images/generate.go +++ b/hack/preload-images/generate.go @@ -87,7 +87,7 @@ func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string if err != nil { return errors.Wrap(err, "failed create new runtime") } - if err := cr.Enable(true); err != nil { + if err := cr.Enable(true, false); err != nil { return errors.Wrap(err, "enable container runtime") } diff --git a/pkg/minikube/cruntime/containerd.go b/pkg/minikube/cruntime/containerd.go index 73261c98190c..9dabf8a4668c 100644 --- a/pkg/minikube/cruntime/containerd.go +++ b/pkg/minikube/cruntime/containerd.go @@ -197,7 +197,7 @@ func generateContainerdConfig(cr CommandRunner, imageRepository string, kv semve } // Enable idempotently enables containerd on a host -func (r *Containerd) Enable(disOthers bool) error { +func (r *Containerd) Enable(disOthers, _ bool) error { if disOthers { if err := disableOthers(r, r.Runner); err != nil { glog.Warningf("disableOthers: %v", err) diff --git a/pkg/minikube/cruntime/crio.go b/pkg/minikube/cruntime/crio.go index 250d765df4fc..8caa5cda972e 100644 --- a/pkg/minikube/cruntime/crio.go +++ b/pkg/minikube/cruntime/crio.go @@ -110,7 +110,7 @@ func (r *CRIO) Active() bool { } // Enable idempotently enables CRIO on a host -func (r *CRIO) Enable(disOthers bool) error { +func (r *CRIO) Enable(disOthers, _ bool) error { if disOthers { if err := disableOthers(r, r.Runner); err != nil { glog.Warningf("disableOthers: %v", err) diff --git a/pkg/minikube/cruntime/cruntime.go b/pkg/minikube/cruntime/cruntime.go index f1866ff1aacc..3ba208a47a81 100644 --- a/pkg/minikube/cruntime/cruntime.go +++ b/pkg/minikube/cruntime/cruntime.go @@ -63,7 +63,7 @@ type Manager interface { // Version retrieves the current version of this runtime Version() (string, error) // Enable idempotently enables this runtime on a host - Enable(bool) error + Enable(bool, bool) error // Disable idempotently disables this runtime on a host Disable() error // Active returns whether or not a runtime is active on a host diff --git a/pkg/minikube/cruntime/cruntime_test.go b/pkg/minikube/cruntime/cruntime_test.go index aef420cf8496..c2a5b4324d56 100644 --- a/pkg/minikube/cruntime/cruntime_test.go +++ b/pkg/minikube/cruntime/cruntime_test.go @@ -581,7 +581,7 @@ func TestEnable(t *testing.T) { if err != nil { t.Fatalf("New(%s): %v", tc.runtime, err) } - err = cr.Enable(true) + err = cr.Enable(true, false) if err != nil { t.Errorf("%s disable unexpected error: %v", tc.runtime, err) } diff --git a/pkg/minikube/cruntime/docker.go b/pkg/minikube/cruntime/docker.go index eb11b58e839f..bbc5b7ffcf1a 100644 --- a/pkg/minikube/cruntime/docker.go +++ b/pkg/minikube/cruntime/docker.go @@ -103,13 +103,20 @@ func (r *Docker) Active() bool { } // Enable idempotently enables Docker on a host -func (r *Docker) Enable(disOthers bool) error { +func (r *Docker) Enable(disOthers, forceSystemd bool) error { if disOthers { if err := disableOthers(r, r.Runner); err != nil { glog.Warningf("disableOthers: %v", err) } } + if forceSystemd { + if err := r.forceSystemd(); err != nil { + return err + } + return r.Init.Restart("docker") + } + return r.Init.Start("docker") } @@ -274,6 +281,22 @@ func (r *Docker) SystemLogCmd(len int) string { return fmt.Sprintf("sudo journalctl -u docker -n %d", len) } +// ForceSystemd forces the docker daemon to use systemd as cgroup manager +func (r *Docker) forceSystemd() error { + glog.Infof("Forcing docker to use systemd as cgroup manager...") + daemonConfig := `{ +"exec-opts": ["native.cgroupdriver=systemd"], +"log-driver": "json-file", +"log-opts": { + "max-size": "100m" +}, +"storage-driver": "overlay2" +} +` + ma := assets.NewMemoryAsset([]byte(daemonConfig), "/etc/docker", "daemon.json", "0644") + return r.Runner.Copy(ma) +} + // Preload preloads docker with k8s images: // 1. Copy over the preloaded tarball into the VM // 2. Extract the preloaded tarball to the correct directory diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index 5f2aecb0d96c..aa6a908e0b0b 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -255,7 +255,7 @@ func configureRuntimes(runner cruntime.CommandRunner, cc config.ClusterConfig, k } } - err = cr.Enable(disableOthers) + err = cr.Enable(disableOthers, viper.GetBool("force-systemd")) if err != nil { debug.PrintStack() exit.WithError("Failed to enable container runtime", err) diff --git a/site/content/en/docs/commands/start.md b/site/content/en/docs/commands/start.md index cba4a6d79935..ede8a83f0ba3 100644 --- a/site/content/en/docs/commands/start.md +++ b/site/content/en/docs/commands/start.md @@ -50,6 +50,7 @@ minikube start [flags] Valid kubeadm parameters: ignore-preflight-errors, dry-run, kubeconfig, kubeconfig-dir, node-name, cri-socket, experimental-upload-certs, certificate-key, rootfs, skip-phases, pod-network-cidr --feature-gates string A set of key=value pairs that describe feature gates for alpha/experimental features. --force Force minikube to perform possibly dangerous operations + --force-systemd If set, force the container runtime to use sytemd as cgroup manager. Currently available for docker and crio. Defaults to false. -h, --help help for start --host-dns-resolver Enable host resolver for NAT DNS requests (virtualbox driver only) (default true) --host-only-cidr string The CIDR to be used for the minikube VM (virtualbox driver only) (default "192.168.99.1/24") diff --git a/test/integration/docker_test.go b/test/integration/docker_test.go index dd0a27de06af..25d0da8eb4cd 100644 --- a/test/integration/docker_test.go +++ b/test/integration/docker_test.go @@ -63,3 +63,30 @@ func TestDockerFlags(t *testing.T) { } } } + +func TestForceSystemd(t *testing.T) { + if NoneDriver() { + t.Skip("skipping: none driver does not support ssh or bundle docker") + } + MaybeParallel(t) + + profile := UniqueProfileName("force-systemd") + ctx, cancel := context.WithTimeout(context.Background(), Minutes(30)) + defer CleanupWithLogs(t, profile, cancel) + + // Use the most verbose logging for the simplest test. If it fails, something is very wrong. + args := append([]string{"start", "-p", profile, "--force-systemd", "--alsologtostderr", "-v=5"}, StartArgs()...) + rr, err := Run(t, exec.CommandContext(ctx, Target(), args...)) + if err != nil { + t.Errorf("failed to start minikube with args: %q : %v", rr.Command(), err) + } + + rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", "docker info --format {{.CgroupDriver}}")) + if err != nil { + t.Errorf("failed to get docker cgroup driver. args %q: %v", rr.Command(), err) + } + + if !strings.Contains(rr.Output(), "systemd") { + t.Fatalf("expected systemd cgroup driver, got: %v", rr.Output()) + } +}