Merge pull request #13829 from AkihiroSuda/rootless-podman-take2
Support rootless Podman driver, take 2 (Usage: `minikube config set rootless true`)pull/13952/head
commit
ad5c964e6b
|
@ -163,6 +163,10 @@ var settings = []Setting{
|
|||
name: "native-ssh",
|
||||
set: SetBool,
|
||||
},
|
||||
{
|
||||
name: config.Rootless,
|
||||
set: SetBool,
|
||||
},
|
||||
}
|
||||
|
||||
// ConfigCmd represents the config command
|
||||
|
|
|
@ -72,6 +72,12 @@ var RootCmd = &cobra.Command{
|
|||
out.WarningT("User name '{{.username}}' is not valid", out.V{"username": userName})
|
||||
exit.Message(reason.Usage, "User name must be 60 chars or less.")
|
||||
}
|
||||
// viper maps $MINIKUBE_ROOTLESS to "rootless" property automatically, but it does not do vice versa,
|
||||
// so we map "rootless" property to $MINIKUBE_ROOTLESS expliclity here.
|
||||
// $MINIKUBE_ROOTLESS is referred by KIC runner, which is decoupled from viper.
|
||||
if viper.GetBool(config.Rootless) {
|
||||
os.Setenv(constants.MinikubeRootlessEnv, "true")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -206,6 +212,7 @@ func init() {
|
|||
RootCmd.PersistentFlags().StringP(config.ProfileName, "p", constants.DefaultClusterName, `The name of the minikube VM being used. This can be set to allow having multiple instances of minikube independently.`)
|
||||
RootCmd.PersistentFlags().StringP(configCmd.Bootstrapper, "b", "kubeadm", "The name of the cluster bootstrapper that will set up the Kubernetes cluster.")
|
||||
RootCmd.PersistentFlags().String(config.UserFlag, "", "Specifies the user executing the operation. Useful for auditing operations executed by 3rd party tools. Defaults to the operating system username.")
|
||||
RootCmd.PersistentFlags().Bool(config.Rootless, false, "Force to use rootless driver (docker and podman driver only)")
|
||||
|
||||
groups := templates.CommandGroups{
|
||||
{
|
||||
|
|
|
@ -555,12 +555,22 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
|
|||
exit.Message(reason.Usage, "Ensure your {{.driver_name}} is running and is healthy.", out.V{"driver_name": driver.FullName(drvName)})
|
||||
}
|
||||
if si.Rootless {
|
||||
out.Styled(style.Notice, "Using rootless {{.driver_name}} driver", out.V{"driver_name": driver.FullName(drvName)})
|
||||
if cc.KubernetesConfig.ContainerRuntime == constants.Docker {
|
||||
exit.Message(reason.Usage, "--container-runtime must be set to \"containerd\" or \"cri-o\" for rootless")
|
||||
}
|
||||
// KubeletInUserNamespace feature gate is essential for rootless driver.
|
||||
// See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-in-userns/
|
||||
cc.KubernetesConfig.FeatureGates = addFeatureGate(cc.KubernetesConfig.FeatureGates, "KubeletInUserNamespace=true")
|
||||
} else {
|
||||
if oci.IsRootlessForced() {
|
||||
if driver.IsDocker(drvName) {
|
||||
exit.Message(reason.Usage, "Using rootless Docker driver was required, but the current Docker does not seem rootless. Try 'docker context use rootless' .")
|
||||
} else {
|
||||
exit.Message(reason.Usage, "Using rootless driver was required, but the current driver does not seem rootless")
|
||||
}
|
||||
}
|
||||
out.Styled(style.Notice, "Using {{.driver_name}} driver with the root privilege", out.V{"driver_name": driver.FullName(drvName)})
|
||||
}
|
||||
if si.StorageDriver == "btrfs" {
|
||||
klog.Info("auto-setting LocalStorageCapacityIsolation to false because using btrfs storage driver")
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
"k8s.io/minikube/pkg/minikube/out"
|
||||
"k8s.io/minikube/pkg/minikube/style"
|
||||
)
|
||||
|
@ -72,10 +73,40 @@ func (rr RunResult) Output() string {
|
|||
return sb.String()
|
||||
}
|
||||
|
||||
// IsRootlessForced returns whether rootless mode is explicitly required.
|
||||
func IsRootlessForced() bool {
|
||||
s := os.Getenv(constants.MinikubeRootlessEnv)
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
v, err := strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "failed to parse", "env", constants.MinikubeRootlessEnv, "value", s)
|
||||
return false
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
type prefixCmdOptions struct {
|
||||
sudoFlags []string
|
||||
}
|
||||
|
||||
type PrefixCmdOption func(*prefixCmdOptions)
|
||||
|
||||
func WithSudoFlags(ss ...string) PrefixCmdOption {
|
||||
return func(o *prefixCmdOptions) {
|
||||
o.sudoFlags = ss
|
||||
}
|
||||
}
|
||||
|
||||
// PrefixCmd adds any needed prefix (such as sudo) to the command
|
||||
func PrefixCmd(cmd *exec.Cmd) *exec.Cmd {
|
||||
if cmd.Args[0] == Podman && runtime.GOOS == "linux" { // want sudo when not running podman-remote
|
||||
cmdWithSudo := exec.Command("sudo", append([]string{"-n"}, cmd.Args...)...)
|
||||
func PrefixCmd(cmd *exec.Cmd, opt ...PrefixCmdOption) *exec.Cmd {
|
||||
var o prefixCmdOptions
|
||||
for _, f := range opt {
|
||||
f(&o)
|
||||
}
|
||||
if cmd.Args[0] == Podman && runtime.GOOS == "linux" && !IsRootlessForced() { // want sudo when not running podman-remote
|
||||
cmdWithSudo := exec.Command("sudo", append(append([]string{"-n"}, o.sudoFlags...), cmd.Args...)...)
|
||||
cmdWithSudo.Env = cmd.Env
|
||||
cmdWithSudo.Dir = cmd.Dir
|
||||
cmdWithSudo.Stdin = cmd.Stdin
|
||||
|
|
|
@ -59,7 +59,7 @@ func CachedDaemonInfo(ociBin string) (SysInfo, error) {
|
|||
func DaemonInfo(ociBin string) (SysInfo, error) {
|
||||
if ociBin == Podman {
|
||||
p, err := podmanSystemInfo()
|
||||
cachedSysInfo = &SysInfo{CPUs: p.Host.Cpus, TotalMemory: p.Host.MemTotal, OSType: p.Host.Os, Swarm: false, StorageDriver: p.Store.GraphDriverName}
|
||||
cachedSysInfo = &SysInfo{CPUs: p.Host.Cpus, TotalMemory: p.Host.MemTotal, OSType: p.Host.Os, Swarm: false, Rootless: p.Host.Security.Rootless, StorageDriver: p.Store.GraphDriverName}
|
||||
return *cachedSysInfo, err
|
||||
}
|
||||
d, err := dockerSystemInfo()
|
||||
|
@ -213,8 +213,10 @@ type podmanSysInfo struct {
|
|||
Hostname string `json:"hostname"`
|
||||
Kernel string `json:"kernel"`
|
||||
Os string `json:"os"`
|
||||
Rootless bool `json:"rootless"`
|
||||
Uptime string `json:"uptime"`
|
||||
Security struct {
|
||||
Rootless bool `json:"rootless"`
|
||||
} `json:"security"`
|
||||
Uptime string `json:"uptime"`
|
||||
} `json:"host"`
|
||||
Registries struct {
|
||||
Search []string `json:"search"`
|
||||
|
|
|
@ -312,7 +312,7 @@ func createContainer(ociBin string, image string, opts ...createOpt) error {
|
|||
|
||||
// to run nested container from privileged container in podman https://bugzilla.redhat.com/show_bug.cgi?id=1687713
|
||||
// only add when running locally (linux), when running remotely it needs to be configured on server in libpod.conf
|
||||
if ociBin == Podman && runtime.GOOS == "linux" {
|
||||
if ociBin == Podman && runtime.GOOS == "linux" && !IsRootlessForced() {
|
||||
args = append(args, "--cgroup-manager", "cgroupfs")
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ func StartContainer(ociBin string, container string) error {
|
|||
|
||||
// to run nested container from privileged container in podman https://bugzilla.redhat.com/show_bug.cgi?id=1687713
|
||||
// only add when running locally (linux), when running remotely it needs to be configured on server in libpod.conf
|
||||
if ociBin == Podman && runtime.GOOS == "linux" {
|
||||
if ociBin == Podman && runtime.GOOS == "linux" && !IsRootlessForced() {
|
||||
args = append(args, "--cgroup-manager", "cgroupfs")
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ const (
|
|||
ProfileName = "profile"
|
||||
// UserFlag is the key for the global user flag (ex. --user=user1)
|
||||
UserFlag = "user"
|
||||
// Rootless is the key for the global rootless parameter (boolean)
|
||||
Rootless = "rootless"
|
||||
// AddonImages stores custom addon images config
|
||||
AddonImages = "addon-images"
|
||||
// AddonRegistries stores custom addon images config
|
||||
|
|
|
@ -99,6 +99,8 @@ const (
|
|||
TestDiskUsedEnv = "MINIKUBE_TEST_STORAGE_CAPACITY"
|
||||
// TestDiskAvailableEnv is used in integration tests for insufficient storage with 'minikube status' (in GiB)
|
||||
TestDiskAvailableEnv = "MINIKUBE_TEST_AVAILABLE_STORAGE"
|
||||
// MinikubeRootlessEnv is used to force Rootless Docker/Podman driver
|
||||
MinikubeRootlessEnv = "MINIKUBE_ROOTLESS"
|
||||
|
||||
// scheduled stop constants
|
||||
|
||||
|
|
|
@ -113,7 +113,8 @@ func status() registry.State {
|
|||
cmd := exec.CommandContext(ctx, oci.Podman, "version", "--format", "{{.Server.Version}}")
|
||||
// Run with sudo on linux (local), otherwise podman-remote (as podman)
|
||||
if runtime.GOOS == "linux" {
|
||||
cmd = exec.CommandContext(ctx, "sudo", "-k", "-n", oci.Podman, "version", "--format", "{{.Version}}")
|
||||
cmd = exec.CommandContext(ctx, oci.Podman, "version", "--format", "{{.Version}}")
|
||||
cmd = oci.PrefixCmd(cmd, oci.WithSudoFlags("-k"))
|
||||
cmd.Env = append(os.Environ(), "LANG=C", "LC_ALL=C") // sudo is localized
|
||||
}
|
||||
o, err := cmd.Output()
|
||||
|
@ -151,7 +152,7 @@ func status() registry.State {
|
|||
newErr := fmt.Errorf(`%q %v: %s`, strings.Join(cmd.Args, " "), exitErr, stderr)
|
||||
|
||||
if strings.Contains(stderr, "a password is required") && runtime.GOOS == "linux" {
|
||||
return registry.State{Error: newErr, Installed: true, Healthy: false, Fix: fmt.Sprintf("Add your user to the 'sudoers' file: '%s ALL=(ALL) NOPASSWD: %s'", username, podman), Doc: "https://podman.io"}
|
||||
return registry.State{Error: newErr, Installed: true, Healthy: false, Fix: fmt.Sprintf("Add your user to the 'sudoers' file: '%s ALL=(ALL) NOPASSWD: %s' , or run 'minikube config set rootless true'", username, podman), Doc: "https://podman.io"}
|
||||
}
|
||||
|
||||
// Typical low-level errors from running podman-remote:
|
||||
|
|
|
@ -46,6 +46,9 @@ docker context use rootless
|
|||
minikube start --driver=docker --container-runtime=containerd
|
||||
```
|
||||
|
||||
Unlike Podman driver, it is not necessary to set the `rootless` property of minikube (`minikube config set rootless true`).
|
||||
When the `rootless` property is explicitly set but the current Docker host is not rootless, minikube fails with an error.
|
||||
|
||||
The `--container-runtime` flag must be set to "containerd" or "cri-o".
|
||||
{{% /tab %}}
|
||||
{{% /tabs %}}
|
||||
|
|
|
@ -21,3 +21,14 @@ To make podman the default driver:
|
|||
```shell
|
||||
minikube config set driver podman
|
||||
```
|
||||
|
||||
## Rootless Podman
|
||||
|
||||
By default, minikube executes Podman with `sudo`.
|
||||
To use Podman without `sudo` (i.e., Rootless Podman), set the `rootless` property to `true`:
|
||||
|
||||
```shell
|
||||
minikube config set rootless true
|
||||
```
|
||||
|
||||
See the [Rootless Docker](https://minikube.sigs.k8s.io/docs/drivers/docker/#rootless-docker) section for the requirements and the restrictions.
|
||||
|
|
Loading…
Reference in New Issue