mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
Merge pull request #3831 from dgageot/support-docker-over-ssh
Support remote docker over ssh
This commit is contained in:
commit
07adfa2bb8
@ -5,23 +5,49 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/reference"
|
||||
"github.com/docker/cli/cli/connhelper"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
clientOnce sync.Once
|
||||
memoizedClient *client.Client
|
||||
errClient error
|
||||
)
|
||||
|
||||
// Client get a docker client.
|
||||
func Client() (*client.Client, error) {
|
||||
// for maximum compatibility as we use nothing new
|
||||
// 1.30 corresponds to Docker 17.06, supported until 2020.
|
||||
err := os.Setenv("DOCKER_API_VERSION", "1.30")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
clientOnce.Do(func() {
|
||||
memoizedClient, errClient = createClient()
|
||||
})
|
||||
return memoizedClient, errClient
|
||||
}
|
||||
|
||||
func createClient() (*client.Client, error) {
|
||||
options := []client.Opt{
|
||||
client.WithAPIVersionNegotiation(),
|
||||
client.WithTLSClientConfigFromEnv(),
|
||||
client.WithHostFromEnv(),
|
||||
}
|
||||
return client.NewEnvClient()
|
||||
|
||||
// Support connection over ssh.
|
||||
if host := os.Getenv(client.EnvOverrideHost); host != "" {
|
||||
helper, err := connhelper.GetConnectionHelper(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if helper != nil {
|
||||
options = append(options, client.WithDialContext(helper.Dialer))
|
||||
}
|
||||
}
|
||||
|
||||
return client.NewClientWithOpts(options...)
|
||||
}
|
||||
|
||||
// HasImage check if the provided ref is available in the docker cache.
|
||||
|
68
src/cmd/linuxkit/vendor/github.com/docker/cli/cli/connhelper/connhelper.go
generated
vendored
Normal file
68
src/cmd/linuxkit/vendor/github.com/docker/cli/cli/connhelper/connhelper.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// Package connhelper provides helpers for connecting to a remote daemon host with custom logic.
|
||||
package connhelper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/cli/cli/connhelper/commandconn"
|
||||
"github.com/docker/cli/cli/connhelper/ssh"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ConnectionHelper allows to connect to a remote host with custom stream provider binary.
|
||||
type ConnectionHelper struct {
|
||||
Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
Host string // dummy URL used for HTTP requests. e.g. "http://docker"
|
||||
}
|
||||
|
||||
// GetConnectionHelper returns Docker-specific connection helper for the given URL.
|
||||
// GetConnectionHelper returns nil without error when no helper is registered for the scheme.
|
||||
//
|
||||
// ssh://<user>@<host> URL requires Docker 18.09 or later on the remote host.
|
||||
func GetConnectionHelper(daemonURL string) (*ConnectionHelper, error) {
|
||||
return getConnectionHelper(daemonURL, nil)
|
||||
}
|
||||
|
||||
// GetConnectionHelperWithSSHOpts returns Docker-specific connection helper for
|
||||
// the given URL, and accepts additional options for ssh connections. It returns
|
||||
// nil without error when no helper is registered for the scheme.
|
||||
//
|
||||
// Requires Docker 18.09 or later on the remote host.
|
||||
func GetConnectionHelperWithSSHOpts(daemonURL string, sshFlags []string) (*ConnectionHelper, error) {
|
||||
return getConnectionHelper(daemonURL, sshFlags)
|
||||
}
|
||||
|
||||
func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper, error) {
|
||||
u, err := url.Parse(daemonURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch scheme := u.Scheme; scheme {
|
||||
case "ssh":
|
||||
sp, err := ssh.ParseURL(daemonURL)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ssh host connection is not valid")
|
||||
}
|
||||
return &ConnectionHelper{
|
||||
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return commandconn.New(ctx, "ssh", append(sshFlags, sp.Args("docker", "system", "dial-stdio")...)...)
|
||||
},
|
||||
Host: "http://docker.example.com",
|
||||
}, nil
|
||||
}
|
||||
// Future version may support plugins via ~/.docker/config.json. e.g. "dind"
|
||||
// See docker/cli#889 for the previous discussion.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetCommandConnectionHelper returns Docker-specific connection helper constructed from an arbitrary command.
|
||||
func GetCommandConnectionHelper(cmd string, flags ...string) (*ConnectionHelper, error) {
|
||||
return &ConnectionHelper{
|
||||
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return commandconn.New(ctx, cmd, flags...)
|
||||
},
|
||||
Host: "http://docker.example.com",
|
||||
}, nil
|
||||
}
|
64
src/cmd/linuxkit/vendor/github.com/docker/cli/cli/connhelper/ssh/ssh.go
generated
vendored
Normal file
64
src/cmd/linuxkit/vendor/github.com/docker/cli/cli/connhelper/ssh/ssh.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
// Package ssh provides the connection helper for ssh:// URL.
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ParseURL parses URL
|
||||
func ParseURL(daemonURL string) (*Spec, error) {
|
||||
u, err := url.Parse(daemonURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Scheme != "ssh" {
|
||||
return nil, errors.Errorf("expected scheme ssh, got %q", u.Scheme)
|
||||
}
|
||||
|
||||
var sp Spec
|
||||
|
||||
if u.User != nil {
|
||||
sp.User = u.User.Username()
|
||||
if _, ok := u.User.Password(); ok {
|
||||
return nil, errors.New("plain-text password is not supported")
|
||||
}
|
||||
}
|
||||
sp.Host = u.Hostname()
|
||||
if sp.Host == "" {
|
||||
return nil, errors.Errorf("no host specified")
|
||||
}
|
||||
sp.Port = u.Port()
|
||||
if u.Path != "" {
|
||||
return nil, errors.Errorf("extra path after the host: %q", u.Path)
|
||||
}
|
||||
if u.RawQuery != "" {
|
||||
return nil, errors.Errorf("extra query after the host: %q", u.RawQuery)
|
||||
}
|
||||
if u.Fragment != "" {
|
||||
return nil, errors.Errorf("extra fragment after the host: %q", u.Fragment)
|
||||
}
|
||||
return &sp, err
|
||||
}
|
||||
|
||||
// Spec of SSH URL
|
||||
type Spec struct {
|
||||
User string
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
// Args returns args except "ssh" itself combined with optional additional command args
|
||||
func (sp *Spec) Args(add ...string) []string {
|
||||
var args []string
|
||||
if sp.User != "" {
|
||||
args = append(args, "-l", sp.User)
|
||||
}
|
||||
if sp.Port != "" {
|
||||
args = append(args, "-p", sp.Port)
|
||||
}
|
||||
args = append(args, "--", sp.Host)
|
||||
args = append(args, add...)
|
||||
return args
|
||||
}
|
2
src/cmd/linuxkit/vendor/modules.txt
vendored
2
src/cmd/linuxkit/vendor/modules.txt
vendored
@ -160,7 +160,9 @@ github.com/docker/cli/cli/config
|
||||
github.com/docker/cli/cli/config/configfile
|
||||
github.com/docker/cli/cli/config/credentials
|
||||
github.com/docker/cli/cli/config/types
|
||||
github.com/docker/cli/cli/connhelper
|
||||
github.com/docker/cli/cli/connhelper/commandconn
|
||||
github.com/docker/cli/cli/connhelper/ssh
|
||||
# github.com/docker/distribution v2.8.1+incompatible
|
||||
github.com/docker/distribution
|
||||
github.com/docker/distribution/digestset
|
||||
|
Loading…
Reference in New Issue
Block a user