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
).
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.
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'
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
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
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
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.
Most helpful comment
OK, looks like there was a spurious semi-colon like...
...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.