support reproxy.port #21

defines which of exposed ports will be used for the destination in case if multiple ports exposed from the container
This commit is contained in:
Umputun 2021-04-13 12:01:54 -05:00
parent af02a41147
commit f6491246f8
3 changed files with 43 additions and 13 deletions

View File

@ -66,6 +66,7 @@ This default can be changed with labels:
- `reproxy.server` - server (hostname) to match. Also can be a list of comma-separated servers.
- `reproxy.route` - source route (location)
- `reproxy.dest` - destination path. Note: this is not full url, but just the path which will be appended to container's ip:port
- `reproxy.port` - destination port for the discovered container
- `reproxy.ping` - ping path for the destination container.
- `reproxy.enabled` - enable (`yes`, `true`, `1`) or disable (`no`, `false`, `0`) container from reproxy destinations.

View File

@ -5,6 +5,7 @@ import (
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"time"
@ -43,7 +44,7 @@ type containerInfo struct {
TS time.Time
Labels map[string]string
IP string
Port int
Ports []int
}
// Events gets eventsCh with all containers-related docker events events
@ -79,10 +80,16 @@ func (d *Docker) List() ([]discovery.URLMapper, error) {
if d.AutoAPI {
enabled = true
srcURL = fmt.Sprintf("^/api/%s/(.*)", c.Name)
}
destURL := fmt.Sprintf("http://%s:%d/$1", c.IP, c.Port)
pingURL := fmt.Sprintf("http://%s:%d/ping", c.IP, c.Port)
port, err := d.matchedPort(c)
if err != nil {
log.Printf("[DEBUG] container %s disabled, %v", c.Name, err)
continue
}
destURL := fmt.Sprintf("http://%s:%d/$1", c.IP, port)
pingURL := fmt.Sprintf("http://%s:%d/ping", c.IP, port)
server := "*"
// we don't care about value because disabled will be filtered before
@ -97,7 +104,7 @@ func (d *Docker) List() ([]discovery.URLMapper, error) {
if v, ok := c.Labels["reproxy.dest"]; ok {
enabled = true
destURL = fmt.Sprintf("http://%s:%d%s", c.IP, c.Port, v)
destURL = fmt.Sprintf("http://%s:%d%s", c.IP, port, v)
}
if v, ok := c.Labels["reproxy.server"]; ok {
@ -107,7 +114,7 @@ func (d *Docker) List() ([]discovery.URLMapper, error) {
if v, ok := c.Labels["reproxy.ping"]; ok {
enabled = true
pingURL = fmt.Sprintf("http://%s:%d%s", c.IP, c.Port, v)
pingURL = fmt.Sprintf("http://%s:%d%s", c.IP, port, v)
}
if !enabled {
@ -136,6 +143,24 @@ func (d *Docker) List() ([]discovery.URLMapper, error) {
return res, nil
}
func (d *Docker) matchedPort(c containerInfo) (port int, err error) {
port = c.Ports[0] // by default use the first exposed port
if v, ok := c.Labels["reproxy.port"]; ok {
rp, err := strconv.Atoi(v)
if err != nil {
return 0, errors.Wrapf(err, "invalid reproxy.port %s", v)
}
for _, p := range c.Ports {
// set port to reproxy.port if matched with one of exposed
if p == rp {
port = rp
break
}
}
}
return port, nil
}
// activate starts blocking listener for all docker events
// filters everything except "container" type, detects stop/start events and publishes signals to eventsCh
func (d *Docker) events(ctx context.Context, client DockerClient, eventsCh chan discovery.ProviderID) error {
@ -171,11 +196,14 @@ func (d *Docker) events(ctx context.Context, client DockerClient, eventsCh chan
func (d *Docker) listContainers() (res []containerInfo, err error) {
portExposed := func(c dc.APIContainers) (int, bool) {
portsExposed := func(c dc.APIContainers) (ports []int) {
if len(c.Ports) == 0 {
return 0, false
return nil
}
return int(c.Ports[0].PrivatePort), true
for _, p := range c.Ports {
ports = append(ports, int(p.PrivatePort))
}
return ports
}
containers, err := d.DockerClient.ListContainers(dc.ListContainersOptions{All: false})
@ -214,8 +242,8 @@ func (d *Docker) listContainers() (res []containerInfo, err error) {
continue
}
port, ok := portExposed(c)
if !ok {
ports := portsExposed(c)
if len(ports) == 0 {
log.Printf("[DEBUG] skip container %s, no exposed ports", c.Names[0])
continue
}
@ -226,7 +254,7 @@ func (d *Docker) listContainers() (res []containerInfo, err error) {
TS: time.Unix(c.Created/1000, 0),
Labels: c.Labels,
IP: ip,
Port: port,
Ports: ports,
}
log.Printf("[DEBUG] running container added, %+v", ci)

View File

@ -95,10 +95,11 @@ func TestDocker_ListWithAutoAPI(t *testing.T) {
Networks: map[string]dc.ContainerNetwork{"bridge": {IPAddress: "127.0.0.2"}},
},
Ports: []dc.APIPort{
{PrivatePort: 1345},
{PrivatePort: 12345},
},
Labels: map[string]string{"reproxy.route": "^/api/123/(.*)", "reproxy.dest": "/blah/$1",
"reproxy.server": "example.com, example2.com", "reproxy.ping": "/ping"},
"reproxy.port": "12345", "reproxy.server": "example.com, example2.com", "reproxy.ping": "/ping"},
},
{Names: []string{"c2"}, State: "running",
Networks: dc.NetworkList{