diff --git a/cli/connhelper/connhelper.go b/cli/connhelper/connhelper.go index 1797abaed4c7..2a36e0ca6dec 100644 --- a/cli/connhelper/connhelper.go +++ b/cli/connhelper/connhelper.go @@ -5,8 +5,11 @@ import ( "context" "net" "net/url" + "os" + "strconv" "strings" + "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/connhelper/commandconn" "github.com/docker/cli/cli/connhelper/ssh" "github.com/pkg/errors" @@ -52,6 +55,7 @@ func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper args = append(args, "--host", "unix://"+sp.Path) } sshFlags = addSSHTimeout(sshFlags) + sshFlags = addMultiplexingArgs(sshFlags) args = append(args, "system", "dial-stdio") return commandconn.New(ctx, "ssh", append(sshFlags, sp.Args(args...)...)...) }, @@ -73,6 +77,22 @@ func GetCommandConnectionHelper(cmd string, flags ...string) (*ConnectionHelper, }, nil } +func addMultiplexingArgs(sshFlags []string) []string { + if v := os.Getenv("DOCKER_SSH_NO_MUX"); v != "" { + if b, err := strconv.ParseBool(v); err == nil && b { + return nil + } + } + if err := os.MkdirAll(config.Dir(), 0o700); err != nil { + return nil + } + sshFlags = append(sshFlags, "-o", "ControlMaster=auto", "-o", "ControlPath="+config.Dir()+"/%r@%h:%p") + if v := os.Getenv("DOCKER_SSH_MUX_PERSIST"); v != "" { + sshFlags = append(sshFlags, "-o", "ControlPersist="+v) + } + return sshFlags +} + func addSSHTimeout(sshFlags []string) []string { if !strings.Contains(strings.Join(sshFlags, ""), "ConnectTimeout") { sshFlags = append(sshFlags, "-o ConnectTimeout=30") diff --git a/docs/reference/commandline/cli.md b/docs/reference/commandline/cli.md index cf4bbc680123..7384661bf9dc 100644 --- a/docs/reference/commandline/cli.md +++ b/docs/reference/commandline/cli.md @@ -135,6 +135,8 @@ line: | `DOCKER_HIDE_LEGACY_COMMANDS` | When set, Docker hides "legacy" top-level commands (such as `docker rm`, and `docker pull`) in `docker help` output, and only `Management commands` per object-type (e.g., `docker container`) are printed. This may become the default in a future release. | | `DOCKER_HOST` | Daemon socket to connect to. | | `DOCKER_TLS` | Enable TLS for connections made by the `docker` CLI (equivalent of the `--tls` command-line option). Set to a non-empty value to enable TLS. Note that TLS is enabled automatically if any of the other TLS options are set. | +| `DOCKER_SSH_NO_MUX` | If set will turn off SSH multiplexing when connecting to daemon through SSH. | +| `DOCKER_SSH_MUX_PERSIST` | Set a duration for keeping SSH multiplexing socket alive between commands (e.g `60s`). | | `DOCKER_TLS_VERIFY` | When set Docker uses TLS and verifies the remote. This variable is used both by the `docker` CLI and the [`dockerd` daemon](dockerd.md) | | `BUILDKIT_PROGRESS` | Set type of progress output (`auto`, `plain`, `tty`) when [building](build.md) with [BuildKit backend](https://docs.docker.com/build/buildkit/). Use plain to show container output (default `auto`). |