Merge pull request #9951 from hashicorp/b-8284

drivers/docker: support mapping multiple host ports to the same container port
This commit is contained in:
Nick Ethier 2021-02-03 15:04:05 -05:00 committed by GitHub
commit 8c4481287b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 13 deletions

View file

@ -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: 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 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)] * 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 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: 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)] * 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)]

View file

@ -7,8 +7,8 @@ import (
docker "github.com/fsouza/go-dockerclient" docker "github.com/fsouza/go-dockerclient"
) )
func getPortBinding(ip string, port string) []docker.PortBinding { func getPortBinding(ip string, port string) docker.PortBinding {
return []docker.PortBinding{{HostIP: ip, HostPort: port}} return docker.PortBinding{HostIP: ip, HostPort: port}
} }
func tweakCapabilities(basics, adds, drops []string) ([]string, error) { func tweakCapabilities(basics, adds, drops []string) ([]string, error) {

View file

@ -3,8 +3,8 @@ package docker
import docker "github.com/fsouza/go-dockerclient" import docker "github.com/fsouza/go-dockerclient"
//Currently Windows containers don't support host ip in port binding. //Currently Windows containers don't support host ip in port binding.
func getPortBinding(ip string, port string) []docker.PortBinding { func getPortBinding(ip string, port string) docker.PortBinding {
return []docker.PortBinding{{HostIP: "", HostPort: port}} return docker.PortBinding{HostIP: "", HostPort: port}
} }
func tweakCapabilities(basics, adds, drops []string) ([]string, error) { func tweakCapabilities(basics, adds, drops []string) ([]string, error) {

View file

@ -8,6 +8,9 @@ import (
"github.com/hashicorp/nomad/helper/pluginutils/hclutils" "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 { type publishedPorts struct {
logger hclog.Logger logger hclog.Logger
publishedPorts map[docker.Port][]docker.PortBinding publishedPorts map[docker.Port][]docker.PortBinding
@ -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) { 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 // By default we will map the allocated port 1:1 to the container
containerPortInt := port containerPortInt := port
@ -35,18 +38,29 @@ func (p *publishedPorts) addMapped(label, ip string, port int, portMap hclutils.
p.add(label, ip, port, containerPortInt) 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) { 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 { if to == 0 {
to = port to = port
} }
hostPortStr := strconv.Itoa(port)
containerPort := docker.Port(strconv.Itoa(to))
p.publishedPorts[containerPort+"/tcp"] = getPortBinding(ip, hostPortStr) // two docker port bindings are created for each port for tcp and udp
p.publishedPorts[containerPort+"/udp"] = getPortBinding(ip, hostPortStr) cPortTCP := docker.Port(strconv.Itoa(to) + "/tcp")
p.logger.Debug("allocated static port", "ip", ip, "port", port) cPortUDP := docker.Port(strconv.Itoa(to) + "/udp")
binding := getPortBinding(ip, strconv.Itoa(port))
p.exposedPorts[containerPort+"/tcp"] = struct{}{} if _, ok := p.publishedPorts[cPortTCP]; !ok {
p.exposedPorts[containerPort+"/udp"] = struct{}{} // initialize both tcp and udp binding slices since they are always created together
p.logger.Debug("exposed port", "port", port) 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)
} }

View file

@ -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)
}