mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #15399 from Microsoft/10662-portmapping
Windows: [TP3] Enable NAT port mapping
This commit is contained in:
commit
72e55cb0ec
8 changed files with 126 additions and 53 deletions
|
@ -55,19 +55,23 @@ func (container *Container) setupWorkingDirectory() error {
|
|||
|
||||
func populateCommand(c *Container, env []string) error {
|
||||
en := &execdriver.Network{
|
||||
Mtu: c.daemon.config.Mtu,
|
||||
Interface: nil,
|
||||
}
|
||||
|
||||
parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
|
||||
switch parts[0] {
|
||||
|
||||
case "none":
|
||||
case "default", "": // empty string to support existing containers
|
||||
if !c.Config.NetworkDisabled {
|
||||
en.Interface = &execdriver.NetworkInterface{
|
||||
MacAddress: c.Config.MacAddress,
|
||||
Bridge: c.daemon.config.Bridge.VirtualSwitchName,
|
||||
MacAddress: c.Config.MacAddress,
|
||||
Bridge: c.daemon.config.Bridge.VirtualSwitchName,
|
||||
PortBindings: c.hostConfig.PortBindings,
|
||||
|
||||
// TODO Windows. Include IPAddress. There already is a
|
||||
// property IPAddress on execDrive.CommonNetworkInterface,
|
||||
// but there is no CLI option in docker to pass through
|
||||
// an IPAddress on docker run.
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -91,15 +91,6 @@ type Driver interface {
|
|||
Stats(id string) (*ResourceStats, error)
|
||||
}
|
||||
|
||||
// Network settings of the container
|
||||
type Network struct {
|
||||
Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
|
||||
Mtu int `json:"mtu"`
|
||||
ContainerID string `json:"container_id"` // id of the container to join network.
|
||||
NamespacePath string `json:"namespace_path"`
|
||||
HostNetworking bool `json:"host_networking"`
|
||||
}
|
||||
|
||||
// Ipc settings of the container
|
||||
// It is for IPC namespace setting. Usually different containers
|
||||
// have their own IPC namespace, however this specifies to use
|
||||
|
@ -130,20 +121,6 @@ type UTS struct {
|
|||
HostUTS bool `json:"host_uts"`
|
||||
}
|
||||
|
||||
// NetworkInterface contains all network configs for a driver
|
||||
type NetworkInterface struct {
|
||||
Gateway string `json:"gateway"`
|
||||
IPAddress string `json:"ip"`
|
||||
IPPrefixLen int `json:"ip_prefix_len"`
|
||||
MacAddress string `json:"mac"`
|
||||
Bridge string `json:"bridge"`
|
||||
GlobalIPv6Address string `json:"global_ipv6"`
|
||||
LinkLocalIPv6Address string `json:"link_local_ipv6"`
|
||||
GlobalIPv6PrefixLen int `json:"global_ipv6_prefix_len"`
|
||||
IPv6Gateway string `json:"ipv6_gateway"`
|
||||
HairpinMode bool `json:"hairpin_mode"`
|
||||
}
|
||||
|
||||
// Resources contains all resource configs for a driver.
|
||||
// Currently these are all for cgroup configs.
|
||||
// TODO Windows: Factor out ulimit.Rlimit
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !windows
|
||||
|
||||
package execdriver
|
||||
|
||||
import (
|
||||
|
@ -15,6 +17,14 @@ import (
|
|||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
// Network settings of the container
|
||||
type Network struct {
|
||||
Mtu int `json:"mtu"`
|
||||
ContainerID string `json:"container_id"` // id of the container to join network.
|
||||
NamespacePath string `json:"namespace_path"`
|
||||
HostNetworking bool `json:"host_networking"`
|
||||
}
|
||||
|
||||
// InitContainer is the initialization of a container config.
|
||||
// It returns the initial configs for a container. It's mostly
|
||||
// defined by the default template.
|
20
daemon/execdriver/driver_windows.go
Normal file
20
daemon/execdriver/driver_windows.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package execdriver
|
||||
|
||||
import "github.com/docker/docker/pkg/nat"
|
||||
|
||||
// Network settings of the container
|
||||
type Network struct {
|
||||
Interface *NetworkInterface `json:"interface"`
|
||||
ContainerID string `json:"container_id"` // id of the container to join network.
|
||||
}
|
||||
|
||||
// NetworkInterface contains network configs for a driver
|
||||
type NetworkInterface struct {
|
||||
MacAddress string `json:"mac"`
|
||||
Bridge string `json:"bridge"`
|
||||
IPAddress string `json:"ip"`
|
||||
|
||||
// PortBindings is the port mapping between the exposed port in the
|
||||
// container and the port on the host.
|
||||
PortBindings nat.PortMap `json:"port_bindings"`
|
||||
}
|
|
@ -128,17 +128,6 @@ lxc.{{$value}}
|
|||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .Network.Interface}}
|
||||
{{if .Network.Interface.IPAddress}}
|
||||
lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}}
|
||||
{{end}}
|
||||
{{if .Network.Interface.Gateway}}
|
||||
lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
|
||||
{{end}}
|
||||
{{if .Network.Interface.MacAddress}}
|
||||
lxc.network.hwaddr = {{.Network.Interface.MacAddress}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ProcessConfig.Env}}
|
||||
lxc.utsname = {{getHostname .ProcessConfig.Env}}
|
||||
{{end}}
|
||||
|
|
|
@ -50,8 +50,7 @@ func TestLXCConfig(t *testing.T) {
|
|||
CPUShares: int64(cpu),
|
||||
},
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
Interface: nil,
|
||||
Mtu: 1500,
|
||||
},
|
||||
AllowedDevices: make([]*configs.Device, 0),
|
||||
ProcessConfig: execdriver.ProcessConfig{},
|
||||
|
@ -90,8 +89,7 @@ func TestCustomLxcConfig(t *testing.T) {
|
|||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
},
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
Interface: nil,
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
}
|
||||
|
@ -222,8 +220,7 @@ func TestCustomLxcConfigMounts(t *testing.T) {
|
|||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
},
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
Interface: nil,
|
||||
Mtu: 1500,
|
||||
},
|
||||
Mounts: mounts,
|
||||
ProcessConfig: processConfig,
|
||||
|
@ -264,8 +261,7 @@ func TestCustomLxcConfigMisc(t *testing.T) {
|
|||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
},
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
Interface: nil,
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
CapAdd: []string{"net_admin", "syslog"},
|
||||
|
@ -317,8 +313,7 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
|
|||
"lxc.network.ipv4 = 172.0.0.1",
|
||||
},
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
Interface: nil,
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
CapAdd: []string{"NET_ADMIN", "SYSLOG"},
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
@ -16,6 +18,10 @@ import (
|
|||
"github.com/natefinch/npipe"
|
||||
)
|
||||
|
||||
// defaultContainerNAT is the default name of the container NAT device that is
|
||||
// preconfigured on the server.
|
||||
const defaultContainerNAT = "ContainerNAT"
|
||||
|
||||
type layer struct {
|
||||
ID string
|
||||
Path string
|
||||
|
@ -25,9 +31,23 @@ type defConfig struct {
|
|||
DefFile string
|
||||
}
|
||||
|
||||
type portBinding struct {
|
||||
Protocol string
|
||||
InternalPort int
|
||||
ExternalPort int
|
||||
}
|
||||
|
||||
type natSettings struct {
|
||||
Name string
|
||||
PortBindings []portBinding
|
||||
}
|
||||
|
||||
type networkConnection struct {
|
||||
NetworkName string
|
||||
EnableNat bool
|
||||
// TODO Windows: Add Ip4Address string to this structure when hooked up in
|
||||
// docker CLI. This is present in the HCS JSON handler.
|
||||
EnableNat bool
|
||||
Nat natSettings
|
||||
}
|
||||
type networkSettings struct {
|
||||
MacAddress string
|
||||
|
@ -81,12 +101,72 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
|||
})
|
||||
}
|
||||
|
||||
// TODO Windows. At some point, when there is CLI on docker run to
|
||||
// enable the IP Address of the container to be passed into docker run,
|
||||
// the IP Address needs to be wired through to HCS in the JSON. It
|
||||
// would be present in c.Network.Interface.IPAddress. See matching
|
||||
// TODO in daemon\container_windows.go, function populateCommand.
|
||||
|
||||
if c.Network.Interface != nil {
|
||||
|
||||
var pbs []portBinding
|
||||
|
||||
// Enumerate through the port bindings specified by the user and convert
|
||||
// them into the internal structure matching the JSON blob that can be
|
||||
// understood by the HCS.
|
||||
for i, v := range c.Network.Interface.PortBindings {
|
||||
proto := strings.ToUpper(i.Proto())
|
||||
if proto != "TCP" && proto != "UDP" {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("invalid protocol %s", i.Proto())
|
||||
}
|
||||
|
||||
if len(v) > 1 {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("Windows does not support more than one host port in NAT settings")
|
||||
}
|
||||
|
||||
for _, v2 := range v {
|
||||
var (
|
||||
iPort, ePort int
|
||||
err error
|
||||
)
|
||||
if len(v2.HostIP) != 0 {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
|
||||
}
|
||||
if ePort, err = strconv.Atoi(v2.HostPort); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("invalid container port %s: %s", v2.HostPort, err)
|
||||
}
|
||||
if iPort, err = strconv.Atoi(i.Port()); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("invalid internal port %s: %s", i.Port(), err)
|
||||
}
|
||||
if iPort < 0 || iPort > 65535 || ePort < 0 || ePort > 65535 {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("specified NAT port is not in allowed range")
|
||||
}
|
||||
pbs = append(pbs,
|
||||
portBinding{ExternalPort: ePort,
|
||||
InternalPort: iPort,
|
||||
Protocol: proto})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Windows: TP3 workaround. Allow the user to override the name of
|
||||
// the Container NAT device through an environment variable. This will
|
||||
// ultimately be a global daemon parameter on Windows, similar to -b
|
||||
// for the name of the virtual switch (aka bridge).
|
||||
cn := os.Getenv("DOCKER_CONTAINER_NAT")
|
||||
if len(cn) == 0 {
|
||||
cn = defaultContainerNAT
|
||||
}
|
||||
|
||||
dev := device{
|
||||
DeviceType: "Network",
|
||||
Connection: &networkConnection{
|
||||
NetworkName: c.Network.Interface.Bridge,
|
||||
EnableNat: false,
|
||||
// TODO Windows: Fixme, next line. Needs HCS fix.
|
||||
EnableNat: false,
|
||||
Nat: natSettings{
|
||||
Name: cn,
|
||||
PortBindings: pbs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -97,9 +177,6 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
|||
MacAddress: windowsStyleMAC,
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("Virtual switch '%s', mac='%s'", c.Network.Interface.Bridge, c.Network.Interface.MacAddress)
|
||||
|
||||
cu.Devices = append(cu.Devices, dev)
|
||||
} else {
|
||||
logrus.Debugln("No network interface")
|
||||
|
|
|
@ -9,6 +9,7 @@ type Address struct {
|
|||
}
|
||||
|
||||
// Settings stores configuration details about the daemon network config
|
||||
// TODO Windows. Many of these fields can be factored out.,
|
||||
type Settings struct {
|
||||
Bridge string
|
||||
EndpointID string
|
||||
|
|
Loading…
Reference in a new issue