Moby: Cannot Bind Ports via Remote API

Created on 10 Jun 2016  ·  3Comments  ·  Source: moby/moby

I am able to launch containers and map their ports from the CLI. However, the same thing seems impossible through the Remote API. In both cases I'm running with docker-machine on Mac OS El Capitan.

I have now simplified the test case to the absolute bare minimum, which is based on a standard ubuntu image with just a single package netcat-openbsd, apt-get installed (and run as nc).

Resetting the system

Before each test, I run

eval $(docker-machine env default); docker stop $(docker ps -a -q); docker rm $(docker ps -a -q) 

...to stop and remove all previous containers.

CLI Version (addressable)

The following CLI successfully brings up an addressable service...

docker run -it --rm -p 3000:3000 ubuntu-nc /bin/bash -c 'echo "Working" | nc -l 3000'

Proving Addressable Service

I can prove the service is accessible with properly-mapped ports from outside the docker container (at the IP allocated to the VM by docker-machine) by running the following...

$ nc 192.168.99.100 3000
Working

NodeJS Version (not addressable)

Attempting to bring up the same service via Dockerode on Node creates a service which is not addressable, even though Dockerode apparently passes on all the arguments to Docker, and I am apparently conforming to the conventions of https://godoc.org/github.com/docker/engine-api/types/container#Config and https://godoc.org/github.com/docker/engine-api/types/container#HostConfig hence raising this issue.

This is the code I'm attempting to use...

var fs = require("fs"),
    dockermachine = require("dockermachine"),
    dockerode = require("dockerode");

var createOptions = {
    Image:"ubuntu-nc",
    Tty:true,
    ExposedPorts: {
        "3000/tcp:": {},
    },
    Cmd:[
        "/bin/bash", "-c", "echo Working | nc -l 3000"
    ],
    HostConfig:{
        PortBindings: {
            "3000/tcp": [{
                "HostIP":"0.0.0.0",
                "HostPort": "3000"
            }],
        },
    },
};

dockermachine.inspect("default").then(function(info){

    var docker = new dockerode({
        host:info.Driver.IPAddress,
        port:2376,
        ca:fs.readFileSync(info.HostOptions.AuthOptions.CaCertPath),
        cert:fs.readFileSync(info.HostOptions.AuthOptions.ClientCertPath),
        key:fs.readFileSync(info.HostOptions.AuthOptions.ClientKeyPath),
    });

    docker.createContainer(createOptions, function(err, result){
        var container = docker.getContainer(result.id);

        container.attach({stream: true, stdout: true, stderr: true}, function (err, stream) {
            stream.pipe(process.stdout);
        });

        container.start(function(err, data){
            if(err) console.log(err);
        });

    });
});

The NodeJS version definitely runs the service in the container

For example I can access the service from within its own container...

$ docker exec -it 3dd7 /bin/bash -c "nc localhost 3000"
Working

However, it does not apparently respect the external port mapping which has been requested, so if I restart the working test above from scratch, then attempt to access the service from outside the container in the same way as 'Proving Addressable Service' earlier, it reports a failed connection.

$ nc -v 192.168.99.100 3000
nc: connectx to 192.168.99.100 port 3000 (tcp) failed: Connection refused

Extra Debugging Information

Output of docker version:

bash-3.2$ docker version
Client:
 Version:      1.10.1
 API version:  1.22
 Go version:   go1.5.3
 Git commit:   9e83765
 Built:        Fri Feb 12 22:11:40 UTC 2016
 OS/Arch:      darwin/amd64

Server:
 Version:      1.11.2
 API version:  1.23
 Go version:   go1.5.4
 Git commit:   b9f10c9
 Built:        Wed Jun  1 21:20:08 2016
 OS/Arch:      linux/amd64

Output of docker info:

bash-3.2$ docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 3
Server Version: 1.11.2
Storage Driver: aufs
 Root Dir: /mnt/sda1/var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 7
 Dirperm1 Supported: true
Logging Driver: json-file
Plugins: 
 Volume: local
 Network: null host bridge
Kernel Version: 4.4.12-boot2docker
Operating System: Boot2Docker 1.11.2 (TCL 7.1); HEAD : a6645c3 - Wed Jun  1 22:59:51 UTC 2016
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 995.9 MiB
Name: default
ID: FWTM:2N6I:VM5L:OL4U:RD3K:HFKH:6VYP:QSV5:VHG5:ZTSW:GFOP:CDNT
Debug mode (server): true
 File Descriptors: 14
 Goroutines: 35
 System Time: 2016-06-10T13:58:19.242425997Z
 EventsListeners: 0
 Init SHA1: 
 Init Path: 
 Docker Root Dir: /mnt/sda1/var/lib/docker
Labels:
 provider=virtualbox
versio1.11

Most helpful comment

OK, looks like there was a spurious semi-colon like...

ExposedPorts: {
        "3000/tcp:": {},
 },

...which caused ExposedPorts to be silently ignored.

It is very unfortunate not to have any apparent error reporting, apparently thanks to the 'open schema model' behaviour of the Remote API.

I can't see how this swallowing of errors when properties are clearly intended to control Docker could ever be a feature.

All 3 comments

OK, looks like there was a spurious semi-colon like...

ExposedPorts: {
        "3000/tcp:": {},
 },

...which caused ExposedPorts to be silently ignored.

It is very unfortunate not to have any apparent error reporting, apparently thanks to the 'open schema model' behaviour of the Remote API.

I can't see how this swallowing of errors when properties are clearly intended to control Docker could ever be a feature.

wait, what? was that it?...a typo?
I have been reading this because I have the same problem -- cannot get any port-mapping to work, no Network IP address.
( but I don't have your typo )
Is there nothing else to be learned here?

never mind...I have learned something : after creating a container you then have to "start()" the container before you get an IP Address or port mappings.

Was this page helpful?
0 / 5 - 0 ratings