docker container ports confusion [duplicate] - docker

This question already has answers here:
What is the difference between "expose" and "publish" in Docker?
(8 answers)
Closed 3 years ago.
I have some confusion on Docker ports.As i am not aware of the IP of server i cannot check myself.
In Dockerfile i can see below
EXPOSE 8080:8080
But to run the container is ran using the same image below command is used
docker run -d --restart=unless-stopped --name image1 -p 3000:8080 image1:latest
My confusion is wile creating image host port was given as 8080 in Dockerfile but when running the container from same image host port given was 3000.So in which port of host this container will run and why ?

The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.
https://docs.docker.com/engine/reference/builder/
So 3000 port will exposed to your container.

Related

do not understand EXPOSE command Dockerfile [duplicate]

This question already has answers here:
What is the difference between "expose" and "publish" in Docker?
(8 answers)
Closed 5 days ago.
i really do not understand the following command in Dockerfile
EXPOSE 8080
I built a java application and dockerized it via this Dockerfile
FROM openjdk:10-jre-slim
WORKDIR /app
COPY ./target/display-console-1.0-SNAPSHOT.jar /app
CMD ["java", "-jar", "display-console-1.0-SNAPSHOT.jar"]
My java application got a controller which listen on port 8085.
So when i use it from my localhost, i just do something like
docker run -ti my-docker-hub-account/my-image -p 8085:8085
and all works perfectly !
So, what is the interest of command
EXPOSE XXXX
in Dockerfile ?
thanks by advance
The official documentation is pretty clear on the purpose
The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.
So if you use the -P (capital P) option it will expose the listed ports with EXPOSED (to random ports on the host).
And it also functions for documentation purposes to other people consuming and re-purposing those dockerfiles.
The EXPOSE command let the docker container be accessed over network on the specified port / port range.
When you run a web service from a docker container you must use this command so that you can access it from the outside of the container.

Can I see the IP address of the host in the Docker container? [duplicate]

This question already has answers here:
How to get the IP address of the docker host from inside a docker container [duplicate]
(28 answers)
Closed 2 months ago.
I used the Docker command to run a container.
docker run -itd -p 8001:801 --name centos7_01 centos:centos7 /bin/bash
Can I see the IP address of the host in the container?
Can I write the port of the host in the port map consistent with the port of the container?
The host is the host machine that you run docker on. There is no host in the container. The host runs the container(s), i.e. the containers run on the host.
The ports are HOST:CONTAINER.

How to Connect Docker Container to localhost [duplicate]

This question already has answers here:
Exposing a port on a live Docker container
(16 answers)
Closed yesterday.
I've created a docker container with ubuntu image. In that I've created a react app and when I try to run the app I could not see the app is running on localhost but in the terminal of container it says its running on the port. How can we connect a docker container with our localhost.
If You have a docker file just pass the port to docker run with -p
3001:3000
If you have a docker compose set the port with:
ports:
- 3001:3000
and run docker-compose up -d
Finally navigate to localhost:{Port}
From official documentation : docker run -p 127.0.0.1:80:8080/tcp ubuntu bash
This binds port 8080 of the container to TCP port 80 on 127.0.0.1 of the host machine. You can also specify udp and sctp ports. The Docker User Guide explains in detail how to manipulate ports in Docker.
Then docker ps and verify its running and ports are exposed.
Also check about your firewall, it may block ports.

What is the use of Expose in docker file for ASP.NET Core application [duplicate]

I'm experimenting with Dockerfiles, and I think I understand most of the logic. However, I don't see the difference between "exposing" and "publishing" a port in this context.
All the tutorials I have seen first include the EXPOSE command in the Dockerfile:
...
EXPOSE 8080
...
They then build an image from this Dockerfile:
$ docker build -t an_image - < Dockerfile
And then publish the same port as above when running the image:
$ docker run -d -p 8080 an_image
or publish all ports using
$ docker run -d -P an_image
What is the point of exposing a port in the Dockerfile, if it will be published anyway? Would there ever be a need to expose a port first, and not publish it later? Effectively, I would like to specify all the ports that I will use in the Dockerfile when creating the image, and then not bother with them again, running them simply with:
$ docker run -d an_image
Is this possible?
Basically, you have three (four) options:
Neither specify EXPOSE nor -p
Only specify EXPOSE
Specify EXPOSE and -p
Only specify -p which implicitly does EXPOSE
If you specify neither EXPOSE nor -p, the service in the container will only be accessible 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.
If you do -p, but do not EXPOSE, Docker does an implicit EXPOSE. This is because if a port is open to the public, it is automatically also open to other Docker containers. Hence -p includes EXPOSE. This is effectively same as 3).
The reason why both are separated is IMHO because:
choosing a host port depends on the host and hence does not belong to the Dockerfile (otherwise it would be depending on the host),
and often it's enough if a service in a container is accessible from other containers.
The documentation explicitly states:
The EXPOSE instruction exposes ports for use within links.
It also points you to how to link containers, which basically is the inter-container communication I talked about.
Short answer:
EXPOSE is a way of documenting
--publish (or -p) is a way of mapping a host port to a running container port
Notice below that:
EXPOSE is related to Dockerfiles ( documenting )
--publish is related to docker run ... ( execution / run-time )
Exposing and publishing ports
In Docker networking, there are two different mechanisms that directly involve network ports: exposing and publishing ports. This applies to the default bridge network and user-defined bridge networks.
You expose ports using the EXPOSE keyword in the Dockerfile or the --expose flag to docker run. Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports. Exposing ports is optional.
You publish ports using the --publish or --publish-all flag to docker run. This tells Docker which ports to open on the container’s network interface. When a port is published, it is mapped to an available high-order port (higher than 30000) on the host machine, unless you specify the port to map to on the host machine at runtime. You cannot specify the port to map to on the host machine when you build the image (in the Dockerfile), because there is no way to guarantee that the port will be available on the host machine where you run the image.
from: Docker container networking
Update October 2019: the above piece of text is no longer in the docs but an archived version is here: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports
Maybe the current documentation is the below:
Published ports
By default, when you create a container, it does not publish any of its ports to the outside world. To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag. This creates a firewall rule which maps a container port to a port on the Docker host.
and can be found here: docs.docker.com/config/containers/container-networking/#published-ports
Also,
EXPOSE
...The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published.
from: Dockerfile reference
Service access when EXPOSE / --publish are not defined:
At #Golo Roden's answer it is stated that::
"If you do not specify any of those, the service in the container will not be accessible from anywhere except from inside the container itself."
Maybe that was the case at the time the answer was being written, but now it seems that even if you do not use EXPOSE or --publish, the host and other containers of the same network will be able to access a service you may start inside that container.
How to test this:
I've used the following Dockerfile. Basically, I start with ubuntu and install a tiny web-server:
FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd
I build the image as "testexpose" and run a new container with:
docker run --rm -it testexpose bash
Inside the container, I launch a few instances of mini-httpd:
root#fb8f7dd1322d:/# mini_httpd -p 80
root#fb8f7dd1322d:/# mini_httpd -p 8080
root#fb8f7dd1322d:/# mini_httpd -p 8090
I am then able to use curl from the host or other containers to fetch the home page of mini-httpd.
Further reading
Very detailed articles on the subject by Ivan Pepelnjak:
Exposed ports
Published ports
See the official documentation reference: https://docs.docker.com/engine/reference/builder/#expose
The EXPOSE allows you to define private (container) and public (host) ports to expose at image build time for when the container is running if you run the container with -P.
$ docker help run
...
-P, --publish-all Publish all exposed ports to random ports
...
The public port and protocol are optional, if not a public port is specified, a random port will be selected on host by docker to expose the specified container port on Dockerfile.
A good pratice is do not specify public port, because it limits only one container per host ( a second container will throw a port already in use ).
You can use -p in docker run to control what public port the exposed container ports will be connectable.
Anyway, If you do not use EXPOSE (with -P on docker run) nor -p, no ports will be exposed.
If you always use -p at docker run you do not need EXPOSE but if you use EXPOSE your docker run command may be more simple, EXPOSE can be useful if you don't care what port will be exposed on host, or if you are sure of only one container will be loaded.
You expose ports using the EXPOSE keyword in the Dockerfile or the
--expose flag to docker run. Exposing ports is a way of documenting which
ports are used, but does not actually map or open any ports. Exposing ports
is optional.
Source: github commit
Most people use docker compose with networks. The documentation states:
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).
Which means that if you use networks for communication between containers you don't need to worry about exposing ports.
EXPOSE keyword lets owner to inform others that which ports are going to be used by the container mainly.
You can publish any port even if you don't specify the port in EXPOSE.
For example we create a Dockerfile with nginx image that exposes port 1234
FROM nginx:latest
EXPOSE 1234
and build it
docker build -t porttest .
And run it with publishing 80 port to localhost:80
docker run -p 80:80 porttest
When you go localhost:80, you will see nginx default page.
Nginx default page
expose - will only allow that specific port to connect with container and it will use as "inter container communication " only
-p ( publish ) will map the host port with container port ( which you have already exposed in step 1 or in docker file ) and once you expose it , you will need to map it so we use publish , it will then access container outside world/internet.
EXPOSE is used to map local port container port
ie : if you specify expose in docker file like
EXPOSE 8090
What will does it will map localhost port 8090 to container port 8090

What is the difference between "expose" and "publish" in Docker?

I'm experimenting with Dockerfiles, and I think I understand most of the logic. However, I don't see the difference between "exposing" and "publishing" a port in this context.
All the tutorials I have seen first include the EXPOSE command in the Dockerfile:
...
EXPOSE 8080
...
They then build an image from this Dockerfile:
$ docker build -t an_image - < Dockerfile
And then publish the same port as above when running the image:
$ docker run -d -p 8080 an_image
or publish all ports using
$ docker run -d -P an_image
What is the point of exposing a port in the Dockerfile, if it will be published anyway? Would there ever be a need to expose a port first, and not publish it later? Effectively, I would like to specify all the ports that I will use in the Dockerfile when creating the image, and then not bother with them again, running them simply with:
$ docker run -d an_image
Is this possible?
Basically, you have three (four) options:
Neither specify EXPOSE nor -p
Only specify EXPOSE
Specify EXPOSE and -p
Only specify -p which implicitly does EXPOSE
If you specify neither EXPOSE nor -p, the service in the container will only be accessible 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.
If you do -p, but do not EXPOSE, Docker does an implicit EXPOSE. This is because if a port is open to the public, it is automatically also open to other Docker containers. Hence -p includes EXPOSE. This is effectively same as 3).
The reason why both are separated is IMHO because:
choosing a host port depends on the host and hence does not belong to the Dockerfile (otherwise it would be depending on the host),
and often it's enough if a service in a container is accessible from other containers.
The documentation explicitly states:
The EXPOSE instruction exposes ports for use within links.
It also points you to how to link containers, which basically is the inter-container communication I talked about.
Short answer:
EXPOSE is a way of documenting
--publish (or -p) is a way of mapping a host port to a running container port
Notice below that:
EXPOSE is related to Dockerfiles ( documenting )
--publish is related to docker run ... ( execution / run-time )
Exposing and publishing ports
In Docker networking, there are two different mechanisms that directly involve network ports: exposing and publishing ports. This applies to the default bridge network and user-defined bridge networks.
You expose ports using the EXPOSE keyword in the Dockerfile or the --expose flag to docker run. Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports. Exposing ports is optional.
You publish ports using the --publish or --publish-all flag to docker run. This tells Docker which ports to open on the container’s network interface. When a port is published, it is mapped to an available high-order port (higher than 30000) on the host machine, unless you specify the port to map to on the host machine at runtime. You cannot specify the port to map to on the host machine when you build the image (in the Dockerfile), because there is no way to guarantee that the port will be available on the host machine where you run the image.
from: Docker container networking
Update October 2019: the above piece of text is no longer in the docs but an archived version is here: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports
Maybe the current documentation is the below:
Published ports
By default, when you create a container, it does not publish any of its ports to the outside world. To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag. This creates a firewall rule which maps a container port to a port on the Docker host.
and can be found here: docs.docker.com/config/containers/container-networking/#published-ports
Also,
EXPOSE
...The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published.
from: Dockerfile reference
Service access when EXPOSE / --publish are not defined:
At #Golo Roden's answer it is stated that::
"If you do not specify any of those, the service in the container will not be accessible from anywhere except from inside the container itself."
Maybe that was the case at the time the answer was being written, but now it seems that even if you do not use EXPOSE or --publish, the host and other containers of the same network will be able to access a service you may start inside that container.
How to test this:
I've used the following Dockerfile. Basically, I start with ubuntu and install a tiny web-server:
FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd
I build the image as "testexpose" and run a new container with:
docker run --rm -it testexpose bash
Inside the container, I launch a few instances of mini-httpd:
root#fb8f7dd1322d:/# mini_httpd -p 80
root#fb8f7dd1322d:/# mini_httpd -p 8080
root#fb8f7dd1322d:/# mini_httpd -p 8090
I am then able to use curl from the host or other containers to fetch the home page of mini-httpd.
Further reading
Very detailed articles on the subject by Ivan Pepelnjak:
Exposed ports
Published ports
See the official documentation reference: https://docs.docker.com/engine/reference/builder/#expose
The EXPOSE allows you to define private (container) and public (host) ports to expose at image build time for when the container is running if you run the container with -P.
$ docker help run
...
-P, --publish-all Publish all exposed ports to random ports
...
The public port and protocol are optional, if not a public port is specified, a random port will be selected on host by docker to expose the specified container port on Dockerfile.
A good pratice is do not specify public port, because it limits only one container per host ( a second container will throw a port already in use ).
You can use -p in docker run to control what public port the exposed container ports will be connectable.
Anyway, If you do not use EXPOSE (with -P on docker run) nor -p, no ports will be exposed.
If you always use -p at docker run you do not need EXPOSE but if you use EXPOSE your docker run command may be more simple, EXPOSE can be useful if you don't care what port will be exposed on host, or if you are sure of only one container will be loaded.
You expose ports using the EXPOSE keyword in the Dockerfile or the
--expose flag to docker run. Exposing ports is a way of documenting which
ports are used, but does not actually map or open any ports. Exposing ports
is optional.
Source: github commit
Most people use docker compose with networks. The documentation states:
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).
Which means that if you use networks for communication between containers you don't need to worry about exposing ports.
EXPOSE keyword lets owner to inform others that which ports are going to be used by the container mainly.
You can publish any port even if you don't specify the port in EXPOSE.
For example we create a Dockerfile with nginx image that exposes port 1234
FROM nginx:latest
EXPOSE 1234
and build it
docker build -t porttest .
And run it with publishing 80 port to localhost:80
docker run -p 80:80 porttest
When you go localhost:80, you will see nginx default page.
Nginx default page
expose - will only allow that specific port to connect with container and it will use as "inter container communication " only
-p ( publish ) will map the host port with container port ( which you have already exposed in step 1 or in docker file ) and once you expose it , you will need to map it so we use publish , it will then access container outside world/internet.
EXPOSE is used to map local port container port
ie : if you specify expose in docker file like
EXPOSE 8090
What will does it will map localhost port 8090 to container port 8090

Resources