mirror of https://github.com/docker/docs.git
ssh tunnel to docker daemon
Docker-DCO-1.1-Signed-off-by: Aaron Feng <aaron.feng@gmail.com> (github: aaronfeng)
This commit is contained in:
parent
d79ce93346
commit
acf1b88de5
105
backends/ec2.go
105
backends/ec2.go
|
@ -1,9 +1,16 @@
|
||||||
package backends
|
package backends
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"path"
|
||||||
|
"os/user"
|
||||||
"time"
|
"time"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"errors"
|
||||||
|
"os/exec"
|
||||||
"github.com/docker/libswarm/beam"
|
"github.com/docker/libswarm/beam"
|
||||||
|
|
||||||
"launchpad.net/goamz/aws"
|
"launchpad.net/goamz/aws"
|
||||||
|
@ -11,20 +18,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ec2Config struct {
|
type ec2Config struct {
|
||||||
securityGroup string
|
securityGroup string
|
||||||
instanceType string
|
instanceType string
|
||||||
keypair string
|
|
||||||
zone string
|
zone string
|
||||||
ami string
|
ami string
|
||||||
tag string
|
tag string
|
||||||
|
sshUser string
|
||||||
|
sshKey string
|
||||||
|
sshLocalPort string
|
||||||
|
sshRemotePort string
|
||||||
|
keypair string
|
||||||
region aws.Region
|
region aws.Region
|
||||||
}
|
}
|
||||||
|
|
||||||
type ec2Client struct {
|
type ec2Client struct {
|
||||||
config *ec2Config
|
config *ec2Config
|
||||||
ec2Conn *ec2.EC2
|
ec2Conn *ec2.EC2
|
||||||
Server *beam.Server
|
Server *beam.Server
|
||||||
instance *ec2.Instance
|
instance *ec2.Instance
|
||||||
|
sshTunnel *os.Process
|
||||||
dockerInstance *beam.Object
|
dockerInstance *beam.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +66,9 @@ func (c *ec2Client) start(ctx *beam.Message) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.initDockerClientInstance(c.instance)
|
c.initDockerClientInstance(c.instance)
|
||||||
|
c.startSshTunnel()
|
||||||
ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
|
ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,11 +120,22 @@ func (c *ec2Client) attach(ctx *beam.Message) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func defaultSshKeyPath() (string) {
|
||||||
|
usr, _ := user.Current()
|
||||||
|
dir := usr.HomeDir
|
||||||
|
return path.Join(dir, ".ssh", "id_rsa")
|
||||||
|
}
|
||||||
|
|
||||||
func defaultConfigValues() (config *ec2Config) {
|
func defaultConfigValues() (config *ec2Config) {
|
||||||
config = new(ec2Config)
|
config = new(ec2Config)
|
||||||
config.region = aws.USEast
|
config.region = aws.USEast
|
||||||
|
config.ami = "ami-7c807d14"
|
||||||
config.instanceType = "t1.micro"
|
config.instanceType = "t1.micro"
|
||||||
config.zone = "us-east-1a"
|
config.zone = "us-east-1a"
|
||||||
|
config.sshUser = "ec2-user"
|
||||||
|
config.sshLocalPort = "4910"
|
||||||
|
config.sshRemotePort = "4243"
|
||||||
|
config.sshKey = defaultSshKeyPath()
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +166,10 @@ func newConfig(args []string) (config *ec2Config, err error) {
|
||||||
config.securityGroup = val
|
config.securityGroup = val
|
||||||
case "--instance_type":
|
case "--instance_type":
|
||||||
config.instanceType = val
|
config.instanceType = val
|
||||||
|
case "--ssh_user":
|
||||||
|
config.sshUser = val
|
||||||
|
case "--ssh_key":
|
||||||
|
config.sshKey = val
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Unrecognizable option: %s value: %s", opt, val)
|
fmt.Printf("Unrecognizable option: %s value: %s", opt, val)
|
||||||
}
|
}
|
||||||
|
@ -250,11 +279,11 @@ func (c *ec2Client) startInstance() error {
|
||||||
func (c *ec2Client) initDockerClientInstance(instance *ec2.Instance) error {
|
func (c *ec2Client) initDockerClientInstance(instance *ec2.Instance) error {
|
||||||
dockerClient := DockerClientWithConfig(&DockerClientConfig{
|
dockerClient := DockerClientWithConfig(&DockerClientConfig{
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
URLHost: instance.IPAddress,
|
URLHost: "localhost",
|
||||||
})
|
})
|
||||||
|
|
||||||
dockerBackend := beam.Obj(dockerClient)
|
dockerBackend := beam.Obj(dockerClient)
|
||||||
url := fmt.Sprintf("tcp://%s:4243", instance.IPAddress)
|
url := fmt.Sprintf("tcp://localhost:%s", c.config.sshLocalPort)
|
||||||
dockerInstance, err := dockerBackend.Spawn(url)
|
dockerInstance, err := dockerBackend.Spawn(url)
|
||||||
c.dockerInstance = dockerInstance
|
c.dockerInstance = dockerInstance
|
||||||
|
|
||||||
|
@ -264,6 +293,17 @@ func (c *ec2Client) initDockerClientInstance(instance *ec2.Instance) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signalHandler(client *ec2Client) {
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
signal.Notify(c, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-c
|
||||||
|
client.Close()
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func Ec2() beam.Sender {
|
func Ec2() beam.Sender {
|
||||||
backend := beam.NewServer()
|
backend := beam.NewServer()
|
||||||
backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
|
backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
|
||||||
|
@ -278,7 +318,7 @@ func Ec2() beam.Sender {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &ec2Client{config, ec2Conn, beam.NewServer(), nil, nil}
|
client := &ec2Client{config, ec2Conn, beam.NewServer(), nil, nil, nil}
|
||||||
client.Server.OnSpawn(beam.Handler(client.spawn))
|
client.Server.OnSpawn(beam.Handler(client.spawn))
|
||||||
client.Server.OnStart(beam.Handler(client.start))
|
client.Server.OnStart(beam.Handler(client.start))
|
||||||
client.Server.OnStop(beam.Handler(client.stop))
|
client.Server.OnStop(beam.Handler(client.stop))
|
||||||
|
@ -288,6 +328,7 @@ func Ec2() beam.Sender {
|
||||||
client.Server.OnLs(beam.Handler(client.ls))
|
client.Server.OnLs(beam.Handler(client.ls))
|
||||||
client.Server.OnGet(beam.Handler(client.get))
|
client.Server.OnGet(beam.Handler(client.get))
|
||||||
|
|
||||||
|
signalHandler(client)
|
||||||
_, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: client.Server})
|
_, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: client.Server})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -295,6 +336,50 @@ func Ec2() beam.Sender {
|
||||||
return backend
|
return backend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ec2Client) Close() {
|
||||||
|
if c.sshTunnel != nil {
|
||||||
|
c.sshTunnel.Kill()
|
||||||
|
if state, err := c.sshTunnel.Wait(); err != nil {
|
||||||
|
fmt.Printf("Wait result: state:%v, err:%s\n", state, err)
|
||||||
|
}
|
||||||
|
c.sshTunnel = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// thx to the rax.go :)
|
||||||
|
func (c *ec2Client) startSshTunnel() error {
|
||||||
|
if c.instance == nil {
|
||||||
|
return errors.New("no valid ec2 instance found.")
|
||||||
|
}
|
||||||
|
|
||||||
|
options := []string {
|
||||||
|
"-o", "PasswordAuthentication=no",
|
||||||
|
"-o", "LogLevel=quiet",
|
||||||
|
"-o", "UserKnownHostsFile=/dev/null",
|
||||||
|
"-o", "CheckHostIP=no",
|
||||||
|
"-o", "StrictHostKeyChecking=no",
|
||||||
|
"-i", c.config.sshKey,
|
||||||
|
"-A",
|
||||||
|
"-p", "22",
|
||||||
|
fmt.Sprintf("%s@%s", c.config.sshUser, c.instance.IPAddress),
|
||||||
|
"-N",
|
||||||
|
"-f",
|
||||||
|
"-L", fmt.Sprintf("%s:localhost:%s", c.config.sshLocalPort, c.config.sshRemotePort),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("ssh", options...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.sshTunnel = cmd.Process
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (aaron): load this externally
|
// TODO (aaron): load this externally
|
||||||
const userdata = `
|
const userdata = `
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
Loading…
Reference in New Issue