Ambiguous port publish parameters to "docker run" - docker

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.

Related

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

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.

How to run two instances of a Service without binding to specific port

I have two problem Statement for running the docker container.
Run two instances of a docker container.
I am running a container say test-service. When I execute the command Only one container named as test-service get created. I want to change the command and create one more instance of the container.
Dynamic Port number Allocation to the container.
I am binding the port say 8080:8080. I want to configure it in such a way that the port number will be dynamic.
The command which I am using to run the container is as below:
docker run -p ${EXTERNAL_PORT_NUMBER}:${INTERNAL_PORT_NUMBER} --network ${NETWORK} --name ${SERVICE_NAME} --restart always -m 1024M --memory-swap -1 -itd ${ORGANISATION}/${SERVICE_NAME}:${VERSION}
The test-service is a node service.
Please let me know what modifications are needed in the above command.
For 2nd question:
Use --publish-all flag instead of providing port mapping.
$ docker run --publish-all --network ${NETWORK} --name ${SERVICE_NAME} --restart always -m 1024M --memory-swap -1 -itd ${ORGANISATION}/${SERVICE_NAME}:${VERSION}
This will publish a container's port(s) to the host port. Host port will be dynamic. And all container ports will be exposed.
But if you want to expose specific port, use -p :<port>
$ docker run -p :${INTERNAL_PORT_NUMBER} --network ${NETWORK} --name ${SERVICE_NAME} --restart always -m 1024M --memory-swap -1 -itd ${ORGANISATION}/${SERVICE_NAME}:${VERSION}
Leave ${EXTERNAL_PORT_NUMBER} part empty, then a port will be selected dynamically.
For 1st question:
You can use docker-compose. Check this answer.
Or, you can run docker run multiple time. In this case, use different --name

docker port mapping syntax

I am new to docker, and I am a bit confused about what the following command options do specifically for the command I came across.
--name : appname is the name of the image?
-t : Run in terminal?
-d : run as daemon?
-p : for somebody outside the container to talk to port 9090 they have to connect on port 9000?
Same for port 15501 but it is a udp port?
appname2: name assigned to running image?
docker run -t --name=appname -p 9090:9000 -p 15501:15501/udp -d appname2
docker run -t --name=appname -p 9090:9000 -p 15501:15501/udp -d appname2
Q: --name : appname is the name of the image?
No. It's the name of the container that you are creating (optional).
--name string Assign a name to the container
Q: -t : Run in terminal?
-t, --tty Allocate a pseudo-TTY
Q: -d : run as daemon?
Sort of. It means that you want to run your container detached from your terminal.
-d, --detach Run container in background and print container ID
Q: -p : for somebody outside the container to talk to port 9090 they have to connect on port 9000?
9090:9000 means: port 9090 on the host machine binded to port 9000 on the container. To talk to the container port someone outside should talk to 9090.
-p, --publish list Publish a container's port(s) to the host (default [])
Q: Same for port 15501 but it is a udp port?
Right.
Q: appname2: name assigned to running image?
That is the image that you are running on. The container is based on top of it.
Bonus! You can find all of this info here: docker help run
Bonus 2! Try it yourself:
docker run -d -it --name my-container alpine sh
docker inspect my-container
# See all this funny output. It's all about the container that you've created
From https://docs.docker.com/engine/reference/run/
The -d flag means detached. When you run a docker container, you can either run a container in foreground, or you can run it in the background. The choice of how to run your container really depends on your use case. If, for example, you run an OS container with some functionality, you would probably want run the container in foreground in order to use this functionality. But if you run a DB server, you may want to run it in the background.
The -p flag, when used, publishes all exposed ports to the host interfaces. If for example you run a DB server inside a container which has some ports exposed, and you wish to communicate to the server from a distance, you may want to map the ports inside the container to a single or multiple ports of choice on your host system. That way when you connect to the port on your host, you connect to the docker server running inside of it (I hope this is clear). The mapping format is as follows:
ip:hostPort:contain`enter code here`erPort | ip::containerPort | hostPort:containerPort | containerPort
The --name flag gives the running container a nice name. If not used, it would generate a name. It can be used, for example, if you executed a container in detached mode, and then you wanted to get inside the container using the attach command.
The -t flag allocates a text console for the container.
appname2 is the name of the docker image.

Two docker's container see each others in the same machine

I create an Docker's image with name is sample, then I installed nginx on both of them that listen to port 80 and it shows simple index.html.
then I use below commands to run contianers:
docker run -it -p 80:80 --name sample1 sample
docker run -it -p 81:80 --name sample2 sample
and I successfully see the index.html from main OS from two containers, but when I go inside container sample1 I couldn't see the index.html of sample2 and It does not work conversely either.
The -p option is the shortform for ports. When you do -p you are binding the container's port 80 to its host's port 80.
So container sample1 and sample2 are just merely binding their respective port 80 to the host's port 80 and 81, hence there is no direct linkage between them.
To make the containers visible to each other, first you will have to use the --link option and then do an --expose to allow the containers to see each other through the exposed port.
Example:
docker run -it -p 80:80 --name sample1 sample
docker run -it -p 81:80 --link=sample1 --expose="80" --name sample2 sample
Essentially --link means to allow the container to see the link value's container
--expose means the linked containers are able to communicate through that expose port.
Note: linking the containers is not sufficient, you need to expose ports for them to communicate.
You might want refer to the docker-compose documentation for more details;
https://docs.docker.com/compose/compose-file/
While the documentation is for docker-compose but the options are pretty much the same as the raw docker binary, and everything is nicely put on 1 page. That's why I prefer looking at there.
In Docker you can bind container's port to docker machine (Machine installed with docker) port using
docker run -it -p 80:80 image
Then you can use docker machine Ip and port inside the another container.

How to forward all ports in docker container

Consider:
docker run -p 5000:5000 -v /host/:/host appimage
it forwards 5000 to 50000
even in multiple:
docker run -p 5000:5000 -p 5001:5001 -v /host/:/host appimage
What I want to know is:
docker run -p allports:allports
is there any command available that allows to forward all ports in container? Because in my case I am running flask app. For testing purpose I want to run multiple flask instances. So for each flask instance I want to run it in different ports. This auto multi-port forwarding would help.
You can expose a range of ports using the -p option, for example:
docker run -p 2000-5000:2000-5000 -v /host/:/host appimage
See the docker run reference documentation for more details.
You might have a working set-up by using docker run --net host ..., in which case host's network is directly exposed to the continer and all port bindings are "public". I haven't tested this with multiple containers simultaneously but it might work just fine.

Resources