Skip to content

Commit 8bfb441

Browse files
dockerEnv vs podmanEnv detection
1 parent 78989b9 commit 8bfb441

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

cmd/minikube/cmd/docker-env.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ type DockerShellConfig struct {
121121
SSHAgentPID string
122122
}
123123

124+
// DockerBackendDetector is a function variable for backend detection, allowing injection/mocking in tests.
125+
var DockerBackendDetector = DetectDockerBackend
124126
var (
125127
noProxy bool
126128
sshHost bool
@@ -382,6 +384,18 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
382384
sshAgentPID: co.Config.SSHAgentPID,
383385
}
384386

387+
// Detect backend (docker vs podman) and set ec.driver accordingly.
388+
// This allows robust detection and is injectable/mocked for tests.
389+
backend, err := DockerBackendDetector(func(name string, args ...string) ([]byte, error) {
390+
cmd := exec.Command(name, args...)
391+
return cmd.CombinedOutput()
392+
})
393+
if err != nil {
394+
klog.Warningf("Failed to detect Docker backend, defaulting to driver: %v", err)
395+
} else {
396+
ec.driver = backend
397+
}
398+
385399
dockerPath, err := exec.LookPath("docker")
386400
if err != nil {
387401
klog.Warningf("Unable to find docker in path - skipping connectivity check: %v", err)
@@ -586,7 +600,8 @@ func dockerEnvVars(ec DockerEnvConfig) map[string]string {
586600
} else {
587601
rt = envTCP
588602
}
589-
if os.Getenv(constants.MinikubeActiveDockerdEnv) == "" {
603+
// Only add "existing" envs if the driver is podman
604+
if ec.driver == "podman" && os.Getenv(constants.MinikubeActiveDockerdEnv) == "" {
590605
for _, env := range constants.DockerDaemonEnvs {
591606
if v := oci.InitialEnv(env); v != "" {
592607
key := constants.MinikubeExistingPrefix + env
@@ -688,4 +703,36 @@ func init() {
688703
dockerEnvCmd.Flags().StringVar(&shell.ForceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
689704
dockerEnvCmd.Flags().StringVarP(&outputFormat, "output", "o", "", "One of 'text', 'yaml' or 'json'.")
690705
dockerEnvCmd.Flags().BoolVarP(&dockerUnset, "unset", "u", false, "Unset variables instead of setting them")
706+
}
707+
/*
708+
DetectDockerBackend probes the Docker CLI backend by running `docker info` and parsing the output
709+
for Podman signatures. Returns "docker" or "podman" as backend type.
710+
711+
The detection logic looks for "Podman Engine" or "podman" in the "Server" or "Operating System" fields.
712+
The commandRunner argument allows injection/mocking for tests.
713+
*/
714+
func DetectDockerBackend(commandRunner func(name string, args ...string) ([]byte, error)) (string, error) {
715+
output, err := commandRunner("docker", "info", "--format", "{{json .}}")
716+
if err != nil {
717+
return "", fmt.Errorf("failed to run docker info: %w", err)
718+
}
719+
// Try to parse as JSON and look for podman signatures
720+
var info map[string]interface{}
721+
if err := json.Unmarshal(output, &info); err == nil {
722+
// Check "ServerVersion" or "OperatingSystem" fields for podman
723+
if osField, ok := info["OperatingSystem"].(string); ok && strings.Contains(strings.ToLower(osField), "podman") {
724+
return "podman", nil
725+
}
726+
if sv, ok := info["ServerVersion"].(string); ok && strings.Contains(strings.ToLower(sv), "podman") {
727+
return "podman", nil
728+
}
729+
if sv, ok := info["Server"].(string); ok && strings.Contains(strings.ToLower(sv), "podman") {
730+
return "podman", nil
731+
}
732+
}
733+
// Fallback: look for "Podman" in raw output
734+
if strings.Contains(strings.ToLower(string(output)), "podman") {
735+
return "podman", nil
736+
}
737+
return "docker", nil
691738
}

cmd/minikube/cmd/docker-env_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,17 @@ SSH_AGENT_PID: "29228"
429429
}
430430
for _, tc := range tests {
431431
t.Run(tc.config.profile, func(t *testing.T) {
432+
origDetector := DockerBackendDetector
433+
defer func() { DockerBackendDetector = origDetector }()
434+
435+
// If this is the podman scenario, mock the backend detector
436+
if tc.config.profile == "podmandriver" {
437+
DockerBackendDetector = func(_ func(string, ...string) ([]byte, error)) (string, error) {
438+
return "podman", nil
439+
}
440+
tc.config.driver = "docker" // initial value, will be overridden by detector
441+
}
442+
432443
tc.config.EnvConfig.Shell = tc.shell
433444
// set global variable
434445
outputFormat = tc.output
@@ -454,6 +465,36 @@ SSH_AGENT_PID: "29228"
454465

455466
})
456467
}
468+
469+
// Add a Podman scenario test case
470+
t.Run("podmandriver", func(t *testing.T) {
471+
origDetector := DockerBackendDetector
472+
defer func() { DockerBackendDetector = origDetector }()
473+
DockerBackendDetector = func(_ func(string, ...string) ([]byte, error)) (string, error) {
474+
return "podman", nil
475+
}
476+
config := DockerEnvConfig{profile: "podmandriver", driver: "docker", hostIP: "127.0.0.1", port: 32842, certsDir: "/certs"}
477+
config.EnvConfig.Shell = "bash"
478+
var b []byte
479+
buf := bytes.NewBuffer(b)
480+
if err := dockerSetScript(config, buf); err != nil {
481+
t.Errorf("setScript(%+v) error: %v", config, err)
482+
}
483+
got := buf.String()
484+
// Podman should still output the same envs, but may add "existing" envs if present in the environment.
485+
// For this test, just check the main envs are present.
486+
wantSet := `export DOCKER_TLS_VERIFY="1"
487+
export DOCKER_HOST="tcp://127.0.0.1:32842"
488+
export DOCKER_CERT_PATH="/certs"
489+
export MINIKUBE_ACTIVE_DOCKERD="podmandriver"
490+
491+
# To point your shell to minikube's docker-daemon, run:
492+
# eval $(minikube -p podmandriver docker-env)
493+
`
494+
if diff := cmp.Diff(wantSet, got); diff != "" {
495+
t.Errorf("setScript(podmandriver) mismatch (-want +got):\n%s\n\nraw output:\n%s\nquoted: %q", diff, got, got)
496+
}
497+
})
457498
}
458499

459500
func TestValidDockerProxy(t *testing.T) {

site/content/en/docs/commands/podman-env.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ description: >
44
Configure environment to use minikube's Podman service
55
---
66

7+
## Requirements
8+
9+
- **Podman version 4.9.2 or newer is required.**
10+
- Support for Podman v3 and varlink-based communication has been removed. The `podman-env` command now configures your environment to use the Podman REST API socket, as required by Podman v4+.
11+
12+
{{% pageinfo color="warning" %}}
13+
**Note:** If you are using an older version of Podman, please upgrade to at least v4.9.2 to use `minikube podman-env`. Legacy varlink-based workflows are no longer supported.
14+
{{% /pageinfo %}}
715

816
## minikube podman-env
917

@@ -30,7 +38,7 @@ minikube podman-env [flags]
3038
--add_dir_header If true, adds the file directory to the header of the log messages
3139
--alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
3240
-b, --bootstrapper string The name of the cluster bootstrapper that will set up the Kubernetes cluster. (default "kubeadm")
33-
-h, --help
41+
-h, --help
3442
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
3543
--log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
3644
--log_file string If non-empty, use this log file (no effect when -logtostderr=true)

0 commit comments

Comments
 (0)