Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/docker: support mapping multiple host ports to the same container port #9951

Merged
merged 2 commits into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ BUG FIXES:
* consul: Fixed a bug where failing tasks with group services would only cause the allocation to restart once instead of respecting the `restart` field. [[GH-9869](https://github.com/hashicorp/nomad/issues/9869)]
* consul/connect: Fixed a bug where gateway proxy connection default timeout not set [[GH-9851](https://github.com/hashicorp/nomad/pull/9851)]
* consul/connect: Fixed a bug preventing more than one connect gateway per Nomad client [[GH-9849](https://github.com/hashicorp/nomad/pull/9849)]
* drivers/docker: Fixed a bug preventing multiple ports to be mapped to the same container port [[GH-9951](https://github.com/hashicorp/nomad/issues/9951)]
* scheduler: Fixed a bug where shared ports were not persisted during inplace updates for service jobs. [[GH-9830](https://github.com/hashicorp/nomad/issues/9830)]
* scheduler: Fixed a bug where job statuses and summaries where duplicated and miscalculated when registering a job. [[GH-9768](https://github.com/hashicorp/nomad/issues/9768)]
* scheduler (Enterprise): Fixed a bug where the deprecated network `mbits` field was being considered as part of quota enforcement. [[GH-9920](https://github.com/hashicorp/nomad/issues/9920)]
Expand Down
4 changes: 2 additions & 2 deletions drivers/docker/driver_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
docker "github.com/fsouza/go-dockerclient"
)

func getPortBinding(ip string, port string) []docker.PortBinding {
return []docker.PortBinding{{HostIP: ip, HostPort: port}}
func getPortBinding(ip string, port string) docker.PortBinding {
return docker.PortBinding{HostIP: ip, HostPort: port}
}

func tweakCapabilities(basics, adds, drops []string) ([]string, error) {
Expand Down
4 changes: 2 additions & 2 deletions drivers/docker/driver_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package docker
import docker "github.com/fsouza/go-dockerclient"

//Currently Windows containers don't support host ip in port binding.
func getPortBinding(ip string, port string) []docker.PortBinding {
return []docker.PortBinding{{HostIP: "", HostPort: port}}
func getPortBinding(ip string, port string) docker.PortBinding {
return docker.PortBinding{HostIP: "", HostPort: port}
}

func tweakCapabilities(basics, adds, drops []string) ([]string, error) {
Expand Down
32 changes: 23 additions & 9 deletions drivers/docker/ports.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
"github.com/hashicorp/nomad/helper/pluginutils/hclutils"
)

// publishedPorts is a utility struct to keep track of the port bindings to publish.
// After calling add for each port, the publishedPorts and exposedPorts fields can be
// used in the docker container and host configs
type publishedPorts struct {
logger hclog.Logger
publishedPorts map[docker.Port][]docker.PortBinding
Expand All @@ -22,7 +25,7 @@ func newPublishedPorts(logger hclog.Logger) *publishedPorts {
}
}

// adds the port to the structures the Docker API expects for declaring mapped ports
// addMapped adds the port to the structures the Docker API expects for declaring mapped ports
func (p *publishedPorts) addMapped(label, ip string, port int, portMap hclutils.MapStrInt) {
// By default we will map the allocated port 1:1 to the container
containerPortInt := port
Expand All @@ -35,18 +38,29 @@ func (p *publishedPorts) addMapped(label, ip string, port int, portMap hclutils.
p.add(label, ip, port, containerPortInt)
}

// add adds a port binding for the given port mapping
func (p *publishedPorts) add(label, ip string, port, to int) {
// if to is not set, use the port value per default docker functionality
if to == 0 {
to = port
}
hostPortStr := strconv.Itoa(port)
containerPort := docker.Port(strconv.Itoa(to))

p.publishedPorts[containerPort+"/tcp"] = getPortBinding(ip, hostPortStr)
p.publishedPorts[containerPort+"/udp"] = getPortBinding(ip, hostPortStr)
p.logger.Debug("allocated static port", "ip", ip, "port", port)
// two docker port bindings are created for each port for tcp and udp
cPortTCP := docker.Port(strconv.Itoa(to) + "/tcp")
cPortUDP := docker.Port(strconv.Itoa(to) + "/udp")
binding := getPortBinding(ip, strconv.Itoa(port))

p.exposedPorts[containerPort+"/tcp"] = struct{}{}
p.exposedPorts[containerPort+"/udp"] = struct{}{}
p.logger.Debug("exposed port", "port", port)
if _, ok := p.publishedPorts[cPortTCP]; !ok {
// initialize both tcp and udp binding slices since they are always created together
p.publishedPorts[cPortTCP] = []docker.PortBinding{}
p.publishedPorts[cPortUDP] = []docker.PortBinding{}
}

p.publishedPorts[cPortTCP] = append(p.publishedPorts[cPortTCP], binding)
p.publishedPorts[cPortUDP] = append(p.publishedPorts[cPortUDP], binding)
p.logger.Debug("allocated static port", "ip", ip, "port", port, "label", label)

p.exposedPorts[cPortTCP] = struct{}{}
p.exposedPorts[cPortUDP] = struct{}{}
p.logger.Debug("exposed port", "port", port, "label", label)
}
19 changes: 19 additions & 0 deletions drivers/docker/ports_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package docker

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/hashicorp/nomad/helper/testlog"
)

func TestPublishedPorts_add(t *testing.T) {
p := newPublishedPorts(testlog.HCLogger(t))
p.add("label", "10.0.0.1", 1234, 80)
p.add("label", "10.0.0.1", 5678, 80)
for _, bindings := range p.publishedPorts {
require.Len(t, bindings, 2)
}
require.Len(t, p.exposedPorts, 2)
}