Skip to content

Commit

Permalink
finish readme description
Browse files Browse the repository at this point in the history
  • Loading branch information
shynome committed May 11, 2021
1 parent bb35134 commit b4cdf76
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# output
/dcip

# Created by https://www.toptal.com/developers/gitignore/api/go
# Edit at https://www.toptal.com/developers/gitignore?templates=go

### Go ###
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

### Go Patch ###
/vendor/
/Godeps/

# End of https://www.toptal.com/developers/gitignore/api/go
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 简介

通过 ssh 转发容器未暴露的端口到本地进行操作. 比如: 数据库端口转发到本地进行管理之类的.

# 使用

## 获取容器的主机可访问 ip

获取本机上的容器 ip

```sh
dcip of main_pg
```

获取远程 ssh 主机上的容器 ip

```sh
dcip of [email protected] main_pg
```

## 端口转发到本地

基于命令 `ssh -NT -L 0.0.0.0:5432:172.17.0.5:5432 [email protected]`

```sh
# main_pg 可以是容器名或服务名, 但只会选中最新的容器
dcip export [email protected] main_pg:5432 0.0.0.0:5432
# 可省略本地端口以及监听地址, 监听地址默认是 0.0.0.0, 本地端口默认为容器端口
dcip export [email protected] main_pg:5432
```
105 changes: 105 additions & 0 deletions cmd/dcip/dcip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package main

import (
"fmt"
"os"
"os/exec"
"strings"

"github.com/alecthomas/kong"
"github.com/shynome/dcip"
)

var CLI struct {
Of struct {
Host string `arg name:"[host|name]" passthrough help:"remote host optional or just a container name"`
Container string `arg name:"name" optional help:"container name"`
} `cmd help:"get container ip."`
Export struct {
Host string `arg name:"host" passthrough help:"ssh host. example: [email protected]"`
ContainerPort string `arg name:"cport" help:"remote container name and port. example: pg:5432"`
LocalAddr string `arg name:"lport" optional help:"local bind address and port. default bind address is 0.0.0.0, default port is remote container port. example: 127.0.0.1:5432 or 5432"`
} `cmd help:"export remote container port to local host."`
Debug bool `name:"debug" short:"D" optional`
Version kong.VersionFlag `short:"V"`
}

func reportError(err error) {
os.Stderr.WriteString(err.Error())
os.Stderr.WriteString("\r\n")
os.Exit(1)
}

func main() {
ctx := kong.Parse(&CLI,
kong.Vars{"version": "0.1.0"},
)
switch ctx.Command() {
case "of <[host|name]>":
fallthrough
case "of <[host|name]> <name>":
params := CLI.Of
if params.Container == "" {
params.Container = params.Host
params.Host = ""
}
cmdStr := dcip.MakeGetContainerIPCmd(params.Container)
var cmd *exec.Cmd
if params.Host == "" {
cmd = RunCommand(cmdStr)
} else {
cmd = RunSSHCommand(params.Host, cmdStr)
}
PrintCmd(cmd)
result, err := cmd.CombinedOutput()
if err != nil {
reportError(err)
return
}
fmt.Print(string(result))
case "export <host> <cport>":
fallthrough
case "export <host> <cport> <lport>":
params := CLI.Export
var container string
var cport string
var lbind string = "0.0.0.0"
var lport string
ContainerPortArr := strings.Split(params.ContainerPort, ":")
container = ContainerPortArr[0]
cport = ContainerPortArr[1]
if container == "" || cport == "" {
reportError(fmt.Errorf("container name and port is required"))
return
}
localAddrArr := strings.Split(params.LocalAddr, ":")
if params.LocalAddr == "" {
lport = cport
} else if len(localAddrArr) == 1 {
lport = localAddrArr[0]
} else {
lbind = localAddrArr[0]
lport = localAddrArr[1]
}
getIPCmd := RunSSHCommand(params.Host, dcip.MakeGetContainerIPCmd(container))
PrintCmd(getIPCmd)
cipBytes, err := getIPCmd.CombinedOutput()
cip := strings.Replace(string(cipBytes), "\n", "", 1)
if err != nil {
reportError(err)
return
}
cmdStr := dcip.MakeForwardPortCmd(params.Host, string(cip)+":"+cport, lbind+":"+lport)
cmd := RunSSHCommand(cmdStr, "")
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
PrintCmd(cmd)
if err := cmd.Run(); err != nil {
reportError(err)
return
}
default:
panic(ctx.Command())
}
}
32 changes: 32 additions & 0 deletions cmd/dcip/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"fmt"
"os/exec"
)

func PrintCmd(cmd *exec.Cmd) {
if !CLI.Debug {
return
}
fmt.Print("+ ")
fmt.Println(cmd)
}

func RunCommand(command string) *exec.Cmd {
cmd := exec.Command("bash", "-c", command)
return cmd
}

func RunSSHCommand(host interface{}, command string) *exec.Cmd {
var cmd *exec.Cmd
switch host.(type) {
case string:
cmd = exec.Command("ssh", host.(string), command)
default:
params := host.([]string)
params = append(params, command)
cmd = exec.Command("ssh", params...)
}
return cmd
}
12 changes: 12 additions & 0 deletions export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dcip

import "fmt"

// ssh -NT -L 0.0.0.0:5432:172.17.0.5:5432 [email protected]
func MakeForwardPortCmd(host string, cport string, lport string) []string {
return []string{
"-NT",
"-L", fmt.Sprintf("%s:%s", lport, cport),
host,
}
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/shynome/dcip

go 1.16

require github.com/alecthomas/kong v0.2.16 // indirect
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/alecthomas/kong v0.2.16 h1:F232CiYSn54Tnl1sJGTeHmx4vJDNLVP2b9yCVMOQwHQ=
github.com/alecthomas/kong v0.2.16/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
13 changes: 13 additions & 0 deletions ip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dcip

import "fmt"

var getNetworks = "docker network ls --format='{{.Name}}' | grep -E 'bridge|docker_gwbridge'"
var getAllConatinersIP = fmt.Sprintf("for dn in $(%s);do docker network inspect $dn --format '{{range $k,$c:=.Containers}}{{$k}}/{{.IPv4Address}}{{println}}{{end}}';done", getNetworks)
var getContainerID = "docker ps --latest -q --no-trunc --filter='name=%s'"
var getIPOnly = "awk -F '/' '{print $2}'"
var getContainerIPCmdFormat = fmt.Sprintf("%s | grep $(%s) | %s", getAllConatinersIP, getContainerID, getIPOnly)

func MakeGetContainerIPCmd(name string) string {
return fmt.Sprintf(getContainerIPCmdFormat, name)
}

0 comments on commit b4cdf76

Please sign in to comment.