What is the interaction between docker run "--publish" and "--publish-all"? - docker

I couldn't find this documented. Suppose I wanted to publish one port to a known place, but sometime publish all the other "exposed" ports for debugging or testing.
A simple Dockerfile
FROM alpine
CMD /bin/sleep 600
--publish/-p allows me to bind a specific host port to a container port. --publish-all/-P binds all container ports to random ports, which can be found using, for example docker ps.
$ docker build -t foo .
<build prints>
$ docker run -d -p 8000:8000 -P -p 9000:9000 foo
<some id prints>
$ docker ps --format '{{.Command}} {{.Ports}}'
"/bin/sh -c '/bin/sl…" 0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp
But suppose I have a Dockerfile like this, and publish one port to a known port but the rest to randomly assigned ports.
FROM alpine
EXPOSE 8000
# Various management ports or something
EXPOSE 8005
EXPOSE 8443
EXPOSE 8009
CMD /bin/sleep 600
What is the defined behavior for
$ docker run -d -P -p 8000:8000 foo

Doing exactly this the behavior seems to be "as expected". The explicit port bindings take precedence over the --publish-all, independent of where the flags occur. In the example above, the results are
$ docker ps --format '{{.Command}} {{.Ports}}'
"/bin/sh -c '/bin/sl…" 0.0.0.0:8000->8000/tcp, 0.0.0.0:32792->8005/tcp, 0.0.0.0:32791->8009/tcp, 0.0.0.0:32790->8443/tcp
The explicit requested port binding occurs, and the other ports are bound to os-assigned unused ports.
It also clarified something to me I did not understand. I've always mostly ignored "EXPOSE" since the documentation basically said that it doesn't actually do anything but serve as documentation, and to actually "expose" a port you should publish it explicitly. But --publish-all does use the exposed ports. I had been naively thinking that by doing --publish-all it would publish ALL the ports that the process I had started was listening on, but those ports are opened after the container is already initialized.

Related

Close Docker expose port from parent file

I have made my own Dockerfile for a apache server that starts with an standard parent file. See first line in my Dockerfile below:
FROM php:7.0-apache
EXPOSE 8080
This parent exposes port 80. Now have I exposed port 8080 in my Dockerfile. Only when I run it both ports are exposed.
It it posible to close the parent port 80 in my Dockerfile? As I cannot edit that file.
Unfortunately, this is currently impossible.
But you can follow this issue on Docker's GitHub. It's from 2014, but it is still Open. Never know...
As an alternative, rather than editing the configuration in the docker image you can also use port mapping to achieve the same result.
For example mapping port 8080 on the host to port 80 within the docker image, like so:
docker run -d -p 8080:80 image_name
Apart from telling docker to expose the port, you must configure apache to listen 8080, doing these two editions:
/etc/apache2/ports.conf
/etc/apache2/sites-enabled/000-default.conf
Dockerfile:
FROM php:7.0-apache
RUN sed -si 's/Listen 80/Listen 8080/' /etc/apache2/ports.conf
RUN sed -si 's/VirtualHost .:80/VirtualHost *:8080/' /etc/apache2/sites-enabled/000-default.conf
EXPOSE 8080
Then:
docker run -d -p 8080:8080 image_name
Edit:
About port 80. The port is not opened and it's not exposed if you use the previous command. If you don't see the ->80 symbol in docker ps, the port is not exposed:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
100fbb367226 php7 "docker-php-entryp..." 2 minutes ago Up 46 seconds 80/tcp, 0.0.0.0:8080->8080/tcp musing_snyder
And:
▶ docker inspect 100fbb367226 -f "{{json .NetworkSettings.Ports}}"
{"80/tcp":null,"8080/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"}]}

Docker and Neo4J

I'm trying to get a Neo4J database up and running in a docker container.
Currently i have it running by using the command:
docker run -d -p 7474:7474 -p 7687:7687 neo4j
.. and it's working fine.
I want to put it in a Dockerfile so i can do some server configuration, but when i use the Dockerfile, it does not expose the ports that i have set it to expose unless i explicitly expose them when i do "docker run":
FROM neo4j
ENV NEO4J_AUTH neo4j/password
EXPOSE 7474:7474
EXPOSE 7687:7687
Did i misunderstand something, or shouldn't the ports be exposed automatically with this configuration?
The EXPOSE instruction informs Docker that the container listens on
the specified network ports at runtime. EXPOSE does not make the ports
of the container accessible to the host. To do that, you must use
either the -p flag to publish a range of ports or the -P flag to
publish all of the exposed ports. You can expose one port number and
publish it externally under another number.
To set up port redirection on the host system, see using the -P flag.
The Docker network feature supports creating networks without the need
to expose ports within the network, for detailed information see the
overview of this feature).
https://docs.docker.com/engine/reference/builder/

How to expose ports defined in EXPOSE without explicitly setting ports via CLI options?

Difference between "expose" and "publish" in docker this post describes 3 different options to expose ports:
If you do not specify [EXPOSE or -p], the service in the container
will not be accessible from anywhere except from inside the container
itself.
If you EXPOSE a port, the service in the container is not accessible
from outside Docker, but from inside other Docker containers. So this
is good for inter-container communication.
If you EXPOSE and -p a port, the service in the container is
accessible from anywhere, even outside Docker.
What if I have defined EXPOSE in Dockerfile and I want container to expose these ports to the host?
Example:
If I have the following Dockerfile.
FROM node:6
# ...
CMD node ./dist/bin/server.js
EXPOSE 8001
EXPOSE 8002
and I run docker run, I want mapping to be setup 8001:8001, 8002:8002.
However, I need to do this without hardcoding the port values using -p option.
The use case:
Migrating from VM based deployment system to Docker based deployment system. Each docker container is running in its own VM. Therefore, there will not be conflicts with other services.
To map to specific ports like you've asked you have to use the -p PORT:PORT option.
The other option is to use -P to publish all ports and then docker will randomly assign ports starting typically in the 32700 range to the various ports are that are defined by the image.
Solved my problem with a little bash:
docker run $(cat Dockerfile | grep EXPOSE | sed -n 's/EXPOSE \([0-9]*\)/-p \1:\1/p' | tr '\n' ' ') app

docker run with -p and a single port (instead of mapping)

What is the different between the following commands when creating a container in docker?
docker run -d -p 8080 sample/image
and
docker run -d -p 8080:8080 sample/image
I have seen majority of them use the second command, but I am not sure if they mean different things, or if the first is shorthand.
I couldn't find any material on this.
docker run -d -p 8080 sample/image
Exposes port 8080 of the container as an arbitrary port on the host. Which port that is is up to Docker.
Whereas,
docker run -d -p 8080:8080 sample/image
Exposes port 8080 of the container as port 8080 on the host.
In both cases, you can see the mapping using docker inspect, or even docker ps:
380af8c2bcc6 ubuntu "bash" 15 seconds ago Up 13 seconds 0.0.0.0:32768->1234/tcp elegant_meitner
In this case, port 1234 of the container is exposed as port 32768 on the host.

Ambiguous port publish parameters to "docker run"

Docker's shipyard project has a prebuilt container to simplify running its components. It's simply just a run script that launches and links several other containers.
However, I find their usage of the port-publish parameter (-p) confusing in two of the run commands:
sudo docker run -i -t -d -p 80 --link shipyard_redis:redis --name shipyard_router shipyard/router
sudo docker run -i -t -d -p 80:80 --link shipyard_redis:redis --link shipyard_router:app_router --name shipyard_lb shipyard/lb
The first command passes a single parameter to "-p", which doesn't seem legal, since every official usage is suppose to have at least two, colon-separated parts:
-p, --publish=[] Publish a container's port to the host
format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
(use 'docker port' to see the actual mapping)
The second command is confusing because it seems like this would cause a port collision with the container started in the first command.
Can someone clarify?
When you specify -p with only 1/single port number. Docker automatically assigns a random port mapping (usually starting from port 49150) to the single port exposed in the container ie. 80
what this means is, lets say you run Apache 2 on port 80 inside your container. Then you will have to point your browser to localhost:49150 to access your Apache web server.

Resources