mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Choose which TCP frontend port to allocate with '-p :PORT'
This commit is contained in:
parent
a5fb1d6c01
commit
2aad4a3478
2 changed files with 50 additions and 17 deletions
12
container.go
12
container.go
|
@ -55,7 +55,7 @@ type Config struct {
|
||||||
AttachStdin bool
|
AttachStdin bool
|
||||||
AttachStdout bool
|
AttachStdout bool
|
||||||
AttachStderr bool
|
AttachStderr bool
|
||||||
Ports []int
|
PortSpecs []string
|
||||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||||
OpenStdin bool // Open stdin
|
OpenStdin bool // Open stdin
|
||||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||||
|
@ -79,7 +79,7 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
||||||
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
||||||
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
||||||
|
|
||||||
var flPorts ports
|
var flPorts ListOpts
|
||||||
cmd.Var(&flPorts, "p", "Expose a container's port to the host (use 'docker port' to see the actual mapping)")
|
cmd.Var(&flPorts, "p", "Expose a container's port to the host (use 'docker port' to see the actual mapping)")
|
||||||
|
|
||||||
var flEnv ListOpts
|
var flEnv ListOpts
|
||||||
|
@ -112,7 +112,7 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
||||||
}
|
}
|
||||||
config := &Config{
|
config := &Config{
|
||||||
Hostname: *flHostname,
|
Hostname: *flHostname,
|
||||||
Ports: flPorts,
|
PortSpecs: flPorts,
|
||||||
User: *flUser,
|
User: *flUser,
|
||||||
Tty: *flTty,
|
Tty: *flTty,
|
||||||
OpenStdin: *flStdin,
|
OpenStdin: *flStdin,
|
||||||
|
@ -482,12 +482,12 @@ func (container *Container) allocateNetwork() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
container.NetworkSettings.PortMapping = make(map[string]string)
|
container.NetworkSettings.PortMapping = make(map[string]string)
|
||||||
for _, port := range container.Config.Ports {
|
for _, spec := range container.Config.PortSpecs {
|
||||||
if extPort, err := iface.AllocatePort(port); err != nil {
|
if nat, err := iface.AllocatePort(spec); err != nil {
|
||||||
iface.Release()
|
iface.Release()
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
container.NetworkSettings.PortMapping[strconv.Itoa(port)] = strconv.Itoa(extPort)
|
container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.network = iface
|
container.network = iface
|
||||||
|
|
55
network.go
55
network.go
|
@ -161,9 +161,9 @@ func newPortMapper() (*PortMapper, error) {
|
||||||
|
|
||||||
// Port allocator: Atomatically allocate and release networking ports
|
// Port allocator: Atomatically allocate and release networking ports
|
||||||
type PortAllocator struct {
|
type PortAllocator struct {
|
||||||
inUse map[int]struct{}
|
inUse map[int]struct{}
|
||||||
fountain chan (int)
|
fountain chan (int)
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (alloc *PortAllocator) runFountain() {
|
func (alloc *PortAllocator) runFountain() {
|
||||||
|
@ -207,7 +207,7 @@ func (alloc *PortAllocator) Acquire(port int) (int, error) {
|
||||||
|
|
||||||
func newPortAllocator() (*PortAllocator, error) {
|
func newPortAllocator() (*PortAllocator, error) {
|
||||||
allocator := &PortAllocator{
|
allocator := &PortAllocator{
|
||||||
inUse: make(map[int]struct{}),
|
inUse: make(map[int]struct{}),
|
||||||
}
|
}
|
||||||
go allocator.runFountain()
|
go allocator.runFountain()
|
||||||
return allocator, nil
|
return allocator, nil
|
||||||
|
@ -318,17 +318,50 @@ type NetworkInterface struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate an external TCP port and map it to the interface
|
// Allocate an external TCP port and map it to the interface
|
||||||
func (iface *NetworkInterface) AllocatePort(port int) (int, error) {
|
func (iface *NetworkInterface) AllocatePort(spec string) (*Nat, error) {
|
||||||
extPort, err := iface.manager.portAllocator.Acquire(0)
|
nat, err := parseNat(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := iface.manager.portMapper.Map(extPort, net.TCPAddr{IP: iface.IPNet.IP, Port: port}); err != nil {
|
// Allocate a random port if Frontend==0
|
||||||
iface.manager.portAllocator.Release(extPort)
|
if extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend); err != nil {
|
||||||
return -1, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
nat.Frontend = extPort
|
||||||
}
|
}
|
||||||
iface.extPorts = append(iface.extPorts, extPort)
|
if err := iface.manager.portMapper.Map(nat.Frontend, net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}); err != nil {
|
||||||
return extPort, nil
|
iface.manager.portAllocator.Release(nat.Frontend)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
iface.extPorts = append(iface.extPorts, nat.Frontend)
|
||||||
|
return nat, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Nat struct {
|
||||||
|
Proto string
|
||||||
|
Frontend int
|
||||||
|
Backend int
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNat(spec string) (*Nat, error) {
|
||||||
|
var nat Nat
|
||||||
|
// If spec starts with ':', external and internal ports must be the same.
|
||||||
|
// This might fail if the requested external port is not available.
|
||||||
|
var sameFrontend bool
|
||||||
|
if spec[0] == ':' {
|
||||||
|
sameFrontend = true
|
||||||
|
spec = spec[1:]
|
||||||
|
}
|
||||||
|
port, err := strconv.ParseUint(spec, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nat.Backend = int(port)
|
||||||
|
if sameFrontend {
|
||||||
|
nat.Frontend = nat.Backend
|
||||||
|
}
|
||||||
|
nat.Proto = "tcp"
|
||||||
|
return &nat, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release: Network cleanup - release all resources
|
// Release: Network cleanup - release all resources
|
||||||
|
|
Loading…
Reference in a new issue