Skip to content

Commit 877f155

Browse files
authored
Merge pull request #9548 from afbjorklund/docker-env-ssh
Optionally use ssh for docker-env instead of tcp
2 parents 6be118f + 45befa0 commit 877f155

File tree

3 files changed

+122
-19
lines changed

3 files changed

+122
-19
lines changed

cmd/minikube/cmd/docker-env.go

+104-19
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import (
4545
"k8s.io/minikube/pkg/minikube/sysinit"
4646
)
4747

48-
var dockerSetEnvTmpl = fmt.Sprintf(
48+
var dockerEnvTCPTmpl = fmt.Sprintf(
4949
"{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}"+
5050
"{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}"+
5151
"{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}"+
@@ -70,6 +70,12 @@ var dockerSetEnvTmpl = fmt.Sprintf(
7070
constants.ExistingDockerHostEnv,
7171
constants.ExistingDockerCertPathEnv,
7272
constants.MinikubeActiveDockerdEnv)
73+
var dockerEnvSSHTmpl = fmt.Sprintf(
74+
"{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}"+
75+
"{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}"+
76+
"{{ .UsageHint }}",
77+
constants.DockerHostEnv,
78+
constants.MinikubeActiveDockerdEnv)
7379

7480
// DockerShellConfig represents the shell config for Docker
7581
type DockerShellConfig struct {
@@ -88,6 +94,8 @@ type DockerShellConfig struct {
8894

8995
var (
9096
noProxy bool
97+
sshHost bool
98+
sshAdd bool
9199
dockerUnset bool
92100
defaultNoProxyGetter NoProxyGetter
93101
)
@@ -105,12 +113,19 @@ func dockerShellCfgSet(ec DockerEnvConfig, envMap map[string]string) *DockerShel
105113
profile := ec.profile
106114
const usgPlz = "To point your shell to minikube's docker-daemon, run:"
107115
usgCmd := fmt.Sprintf("minikube -p %s docker-env", profile)
116+
if ec.ssh {
117+
usgCmd += " --ssh-host"
118+
}
108119
s := &DockerShellConfig{
109120
Config: *shell.CfgSet(ec.EnvConfig, usgPlz, usgCmd),
110121
}
111-
s.DockerCertPath = envMap[constants.DockerCertPathEnv]
122+
if !ec.ssh {
123+
s.DockerCertPath = envMap[constants.DockerCertPathEnv]
124+
}
112125
s.DockerHost = envMap[constants.DockerHostEnv]
113-
s.DockerTLSVerify = envMap[constants.DockerTLSVerifyEnv]
126+
if !ec.ssh {
127+
s.DockerTLSVerify = envMap[constants.DockerTLSVerifyEnv]
128+
}
114129

115130
s.ExistingDockerCertPath = envMap[constants.ExistingDockerCertPathEnv]
116131
s.ExistingDockerHost = envMap[constants.ExistingDockerHostEnv]
@@ -226,8 +241,10 @@ var dockerEnvCmd = &cobra.Command{
226241
out.V{"runtime": co.Config.KubernetesConfig.ContainerRuntime})
227242
}
228243

229-
ensureDockerd(cname, co.CP.Runner)
244+
r := co.CP.Runner
245+
ensureDockerd(cname, r)
230246

247+
d := co.CP.Host.Driver
231248
port := constants.DockerDaemonPort
232249
if driver.NeedsPortForward(driverName) {
233250
port, err = oci.ForwardedPort(driverName, cname, port)
@@ -236,14 +253,30 @@ var dockerEnvCmd = &cobra.Command{
236253
}
237254
}
238255

256+
hostname, err := d.GetSSHHostname()
257+
if err != nil {
258+
exit.Error(reason.IfSSHClient, "Error getting ssh client", err)
259+
}
260+
261+
sshport, err := d.GetSSHPort()
262+
if err != nil {
263+
exit.Error(reason.IfSSHClient, "Error getting ssh client", err)
264+
}
265+
266+
hostIP := co.CP.IP.String()
239267
ec := DockerEnvConfig{
240268
EnvConfig: sh,
241269
profile: cname,
242270
driver: driverName,
243-
hostIP: co.CP.IP.String(),
271+
ssh: sshHost,
272+
hostIP: hostIP,
244273
port: port,
245274
certsDir: localpath.MakeMiniPath("certs"),
246275
noProxy: noProxy,
276+
username: d.GetSSHUsername(),
277+
hostname: hostname,
278+
sshport: sshport,
279+
keypath: d.GetSSHKeyPath(),
247280
}
248281

249282
dockerPath, err := exec.LookPath("docker")
@@ -265,6 +298,22 @@ var dockerEnvCmd = &cobra.Command{
265298
if err := dockerSetScript(ec, os.Stdout); err != nil {
266299
exit.Error(reason.InternalDockerScript, "Error generating set output", err)
267300
}
301+
302+
if sshAdd {
303+
klog.Infof("Adding %v", d.GetSSHKeyPath())
304+
305+
path, err := exec.LookPath("ssh-add")
306+
if err != nil {
307+
exit.Error(reason.IfSSHClient, "Error with ssh-add", err)
308+
}
309+
310+
cmd := exec.Command(path, d.GetSSHKeyPath())
311+
cmd.Stderr = os.Stderr
312+
err = cmd.Run()
313+
if err != nil {
314+
exit.Error(reason.IfSSHClient, "Error with ssh-add", err)
315+
}
316+
}
268317
},
269318
}
270319

@@ -273,33 +322,32 @@ type DockerEnvConfig struct {
273322
shell.EnvConfig
274323
profile string
275324
driver string
325+
ssh bool
276326
hostIP string
277327
port int
278328
certsDir string
279329
noProxy bool
330+
username string
331+
hostname string
332+
sshport int
333+
keypath string
280334
}
281335

282336
// dockerSetScript writes out a shell-compatible 'docker-env' script
283337
func dockerSetScript(ec DockerEnvConfig, w io.Writer) error {
338+
var dockerSetEnvTmpl string
339+
if ec.ssh {
340+
dockerSetEnvTmpl = dockerEnvSSHTmpl
341+
} else {
342+
dockerSetEnvTmpl = dockerEnvTCPTmpl
343+
}
284344
envVars := dockerEnvVars(ec)
285345
return shell.SetScript(ec.EnvConfig, w, dockerSetEnvTmpl, dockerShellCfgSet(ec, envVars))
286346
}
287347

288348
// dockerSetScript writes out a shell-compatible 'docker-env unset' script
289349
func dockerUnsetScript(ec DockerEnvConfig, w io.Writer) error {
290-
vars := []string{
291-
constants.DockerTLSVerifyEnv,
292-
constants.DockerHostEnv,
293-
constants.DockerCertPathEnv,
294-
constants.MinikubeActiveDockerdEnv,
295-
}
296-
297-
if ec.noProxy {
298-
k, _ := defaultNoProxyGetter.GetNoProxyVar()
299-
if k != "" {
300-
vars = append(vars, k)
301-
}
302-
}
350+
vars := dockerEnvNames(ec)
303351
return shell.UnsetScript(ec.EnvConfig, w, vars)
304352
}
305353

@@ -308,14 +356,31 @@ func dockerURL(ip string, port int) string {
308356
return fmt.Sprintf("tcp://%s", net.JoinHostPort(ip, strconv.Itoa(port)))
309357
}
310358

359+
// sshURL returns the docker endpoint URL when using socket over ssh.
360+
func sshURL(username string, hostname string, port int) string {
361+
// assumes standard /var/run/docker.sock as the path (not possible to set it at the moment)
362+
return fmt.Sprintf("ssh://%s@%s", username, net.JoinHostPort(hostname, strconv.Itoa(port)))
363+
}
364+
311365
// dockerEnvVars gets the necessary docker env variables to allow the use of minikube's docker daemon
312366
func dockerEnvVars(ec DockerEnvConfig) map[string]string {
313-
rt := map[string]string{
367+
envTCP := map[string]string{
314368
constants.DockerTLSVerifyEnv: "1",
315369
constants.DockerHostEnv: dockerURL(ec.hostIP, ec.port),
316370
constants.DockerCertPathEnv: ec.certsDir,
317371
constants.MinikubeActiveDockerdEnv: ec.profile,
318372
}
373+
envSSH := map[string]string{
374+
constants.DockerHostEnv: sshURL(ec.username, ec.hostname, ec.sshport),
375+
constants.MinikubeActiveDockerdEnv: ec.profile,
376+
}
377+
378+
var rt map[string]string
379+
if ec.ssh {
380+
rt = envSSH
381+
} else {
382+
rt = envTCP
383+
}
319384
if os.Getenv(constants.MinikubeActiveDockerdEnv) == "" {
320385
for _, env := range constants.DockerDaemonEnvs {
321386
if v := oci.InitialEnv(env); v != "" {
@@ -327,6 +392,24 @@ func dockerEnvVars(ec DockerEnvConfig) map[string]string {
327392
return rt
328393
}
329394

395+
// dockerEnvNames gets the necessary docker env variables to reset after using minikube's docker daemon
396+
func dockerEnvNames(ec DockerEnvConfig) []string {
397+
vars := []string{
398+
constants.DockerTLSVerifyEnv,
399+
constants.DockerHostEnv,
400+
constants.DockerCertPathEnv,
401+
constants.MinikubeActiveDockerdEnv,
402+
}
403+
404+
if ec.noProxy {
405+
k, _ := defaultNoProxyGetter.GetNoProxyVar()
406+
if k != "" {
407+
vars = append(vars, k)
408+
}
409+
}
410+
return vars
411+
}
412+
330413
// dockerEnvVarsList gets the necessary docker env variables to allow the use of minikube's docker daemon to be used in a exec.Command
331414
func dockerEnvVarsList(ec DockerEnvConfig) []string {
332415
return []string{
@@ -348,6 +431,8 @@ func tryDockerConnectivity(bin string, ec DockerEnvConfig) ([]byte, error) {
348431
func init() {
349432
defaultNoProxyGetter = &EnvNoProxyGetter{}
350433
dockerEnvCmd.Flags().BoolVar(&noProxy, "no-proxy", false, "Add machine IP to NO_PROXY environment variable")
434+
dockerEnvCmd.Flags().BoolVar(&sshHost, "ssh-host", false, "Use SSH connection instead of HTTPS (port 2376)")
435+
dockerEnvCmd.Flags().BoolVar(&sshAdd, "ssh-add", false, "Add SSH identity key to SSH authentication agent")
351436
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")
352437
dockerEnvCmd.Flags().BoolVarP(&dockerUnset, "unset", "u", false, "Unset variables instead of setting them")
353438
}

cmd/minikube/cmd/docker-env_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ export MINIKUBE_ACTIVE_DOCKERD="dockerdriver"
5656
unset DOCKER_HOST;
5757
unset DOCKER_CERT_PATH;
5858
unset MINIKUBE_ACTIVE_DOCKERD;
59+
`,
60+
},
61+
{
62+
"bash",
63+
DockerEnvConfig{profile: "dockerdriver", driver: "docker", ssh: true, username: "root", hostname: "host", sshport: 22},
64+
nil,
65+
`export DOCKER_HOST="ssh://root@host:22"
66+
export MINIKUBE_ACTIVE_DOCKERD="dockerdriver"
67+
68+
# To point your shell to minikube's docker-daemon, run:
69+
# eval $(minikube -p dockerdriver docker-env --ssh-host)
70+
`,
71+
`unset DOCKER_TLS_VERIFY;
72+
unset DOCKER_HOST;
73+
unset DOCKER_CERT_PATH;
74+
unset MINIKUBE_ACTIVE_DOCKERD;
5975
`,
6076
},
6177
{

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

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ minikube docker-env [flags]
2222
```
2323
--no-proxy Add machine IP to NO_PROXY environment variable
2424
--shell string Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect
25+
--ssh-add Add SSH identity key to SSH authentication agent
26+
--ssh-host Use SSH connection instead of HTTPS (port 2376)
2527
-u, --unset Unset variables instead of setting them
2628
```
2729

0 commit comments

Comments
 (0)