Exposing Docker Container Ports - network-programming

I understand that to expose ports in a docker container, you can use the -p flag (e.g. -p 1-100:1-100). But is there a nice way to expose a large percentage of possible ports from the container to the host machine? For instance if I am running a router of sorts in a container that lives in a VM, and I would like to expose all ports in the container from 32768 upwards to 65535, is there a nice way to do this? As it stands I've tried using the -p flag and it complains about memory allocation errors.

Nvm. I figured out my misunderstanding. -P is what I want, and I want to expose and not explicitly map ports.

tl;dr
docker run --net=host ...
Docker offers different networking modes for containers. By default the networking mode is bridge which implies the need to expose ports.
If you run a container with networking mode host then you won't need to expose/forward ports as both the docker host and the container will share the very same network interface.
In the container, localhost will refer to the docker host. Any port opened in the container is in fact opened on the docker host network interface.

Related

communicate with a service inside a docker from the host without using it's IP

I have a process running on a host that needs to communicate with a docker and I want it to be done by some parameter that can't change (like docker name or host name) unlike IP (prefer not to make the IP of the docker static or install external dockers for this).
I'm aware that dockers can resolve addressees by name in a private network and that's what I want but not between dockers but between process running on the host and docker.
couldn't find a solution, can it be done ?
Edit:
I'm not allowed to use host network and open additional ports on the host for security reasons.
You're welcome to choose the way which fits your needs better.
Option 1. Use host's networking. In this case Docker does not create separate net for container and you connect to container's services as if they would run on your host:
docker run --network=host <image_name>
Drawback of this approach - low isolation and thus security. You dont need to expose any ports here - if service listens on 8080, just open localhost:8080 and enjoy.
Second approach is more correct - you expose (somehow forward) internal ports in container and map them onto ports in the host.
docker run -p 8080:80 <image_name>
This will map port 80 from container to port 8080 on the host. As in previous example, you still connect using localhost, e.g. localhost:8080.

Does docker EXPOSE refer to the container port or the host port?

The Dockerfile command EXPOSE and the docker run argument --expose tells docker that the port must be exposed.
When publishing ports with -p, you can map an outer host port to a different inner container port, e.g. docker run -p 8080:80, where 8080 is the host port and 80 is the container port.
My question is, does EXPOSE refer to the inner container port or the outer host port?
The EXPOSE instruction in a Dockerfile refers to the container port.
The EXPOSE instruction documents the port on which an application inside the container is expected to be listening. The important word there is "documents". It does not change the behavior of docker running your container, it does not publish the port, and does not impact the ability to connect between containers.
Whether or not you expose the port, you need to separately publish the port to access it from outside the container network. And whether or not you expose the port, you can connect between containers on the same docker network.
There are various tools that can use this image metadata to automatically discover your application. This includes the -P flag to publish all container ports on random high numbered host ports. You will also see reverse proxies (like traefik) use this when querying the docker engine to determine the default port to use for your container.
EXPOSE just means those exposed ports of this current container are available/exposed to all containers that are in the same network.
According to the documentation, the EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime. So it refers to the inner container.
EXPOSE allow communication between the container and other containers in the same network. But it does not allow communication with the host machine, or containers in another network! In order to permit that, you need to publish the port, with -p option.

Expose all ports for a Docker image

I am troubleshooting a solution in which I am setting up a HA cluster. Although I know the ports needed for the application to perform failover and failback, somehow the dockerized solution is not working. I suspect that there are some ports that I do not know about yet.
Currently, my EXPOSE statement says:
EXPOSE 8080 61616 5672 61613 5445 1883
I also start my docker containers with
docker run --network host -p 8080:8080 -p 61616:61616 -p 5672:5672 -p 61613:61613 -p 5445:5445 -p 1883:1883
But for the sake of troubleshooting, I want to expose ALL ports.
I tried something like:
EXPOSE 1-65535
But this gives an ERROR.
What is the best way I can expose ALL ports of the docker container?
When running using --network host there is no need to map the ports. All the docker container ports will be available since the network host mode makes the container use the host's network stack.
Also the EXPOSE 8080 61616 5672 61613 5445 1883 is not needed. This instruction doesn't do anything. It is just a way to document which ports need to be mapped.
In short, running docker run --network host ... will expose all the container ports.
The host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server.
More information on the Docker documentation portal.
Using host networking will expose almost all the ports just like you're running the application in the host machine. If port flags are used when running in host networking mode, those flags are ignored with a warning
Note: Given that the container does not have its own IP-address when using host mode networking, port-mapping does not take effect, and the -p, --publish, -P, and --publish-all option are ignored, producing a warning instead:
WARNING: Published ports are discarded when using host network mode
Make sure your host is a Linux host because host networking is only supported by Linux hosts.
The host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server.
This is mentioned in Docker documentation it self. View particular Documentation

What does --net=host option in Docker command really do?

I'm a little bit beginner to Docker. I couldn't find any clear description of what this option does in docker run command in deep and bit confused about it.
Can we use it to access the applications running on docker containers without specifying a port? As an example if I run a webapp deployed via a docker image in port 8080 by using option -p 8080:8080 in docker run command, I know I will have to access it on 8080 port on Docker containers ip /theWebAppName. But I cannot really think of a way how --net=host option works.
After the docker installation you have 3 networks by default:
docker network ls
NETWORK ID NAME DRIVER SCOPE
f3be8b1ef7ce bridge bridge local
fbff927877c1 host host local
023bb5940080 none null local
I'm trying to keep this simple. So if you start a container by default it will be created inside the bridge (docker0) network.
$ docker run -d jenkins
1498e581cdba jenkins "/bin/tini -- /usr..." 3 minutes ago Up 3 minutes 8080/tcp, 50000/tcp friendly_bell
In the dockerfile of jenkins the ports 8080 and 50000 are exposed. Those ports are opened for the container on its bridge network. So everything inside that bridge network can access the container on port 8080 and 50000. Everything in the bridge network is in the private range of "Subnet": "172.17.0.0/16", If you want to access them from the outside you have to map the ports with -p 8080:8080. This will map the port of your container to the port of your real server (the host network). So accessing your server on 8080 will route to your bridgenetwork on port 8080.
Now you also have your host network. Which does not containerize the containers networking. So if you start a container in the host network it will look like this (it's the first one):
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1efd834949b2 jenkins "/bin/tini -- /usr..." 6 minutes ago Up 6 minutes eloquent_panini
1498e581cdba jenkins "/bin/tini -- /usr..." 10 minutes ago Up 10 minutes 8080/tcp, 50000/tcp friendly_bell
The difference is with the ports. Your container is now inside your host network. So if you open port 8080 on your host you will acces the container immediately.
$ sudo iptables -I INPUT 5 -p tcp -m tcp --dport 8080 -j ACCEPT
I've opened port 8080 in my firewall and when I'm now accesing my server on port 8080 I'm accessing my jenkins. I think this blog is also useful to understand it better.
The --net=host option is used to make the programs inside the Docker container look like they are running on the host itself, from the perspective of the network. It allows the container greater network access than it can normally get.
Normally you have to forward ports from the host machine into a container, but when the containers share the host's network, any network activity happens directly on the host machine - just as it would if the program was running locally on the host instead of inside a container.
While this does mean you no longer have to expose ports and map them to container ports, it means you have to edit your Dockerfiles to adjust the ports each container listens on, to avoid conflicts as you can't have two containers operating on the same host port. However, the real reason for this option is for running apps that need network access that is difficult to forward through to a container at the port level.
For example, if you want to run a DHCP server then you need to be able to listen to broadcast traffic on the network, and extract the MAC address from the packet. This information is lost during the port forwarding process, so the only way to run a DHCP server inside Docker is to run the container as --net=host.
Generally speaking, --net=host is only needed when you are running programs with very specific, unusual network needs.
Lastly, from a security perspective, Docker containers can listen on many ports, even though they only advertise (expose) a single port. Normally this is fine as you only forward the single expected port, however if you use --net=host then you'll get all the container's ports listening on the host, even those that aren't listed in the Dockerfile. This means you will need to check the container closely (especially if it's not yours, e.g. an official one provided by a software project) to make sure you don't inadvertently expose extra services on the machine.
Remember one point that the host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server
you can create your own new network like --net="anyname"
this is done to isolate the services from different container.
suppose the same service are running in different containers, but the port mapping
remains same, the first container starts well , but the same service from second container will fail.
so to avoid this, either change the port mappings or create a network.

is there a way to do bind particular port on host to container port using docker file

is there a way to do bind particular port on host to container port using docker file
I have following item in docker file
Step 1 : EXPOSE 8090:8080
but when i run docker run, container binds to port 8080 instead of 8090 as described in docker file.
any idea how i can achieve this using docker file or is there any better way to achieve this.
Can't see that docker implements the EXPOSE feature as You described it.
From the documentation:
EXPOSE
EXPOSE <port> [<port>...]
The EXPOSE instructions informs Docker that the container will listen on the specified network ports at runtime. Docker uses this information to interconnect containers using links (see the Docker User Guide).
EXPOSE isn't an equivalent for the vagrant forwarded_port functionality.
It's useful when You need to link containers.
If You need to forward a port from the container to the host use the -p flag.
Example:
docker run -it -p 80:80 5959f94a4d10 /bin/bash
is there a way to do bind particular port on host to container port using docker file
No. The Dockerfile is designed to include only portable configuration. Binding to a host port is not portable because the host port may not be available on every system. These configuration flags may be available at runtime, but are not included in the Dockerfile syntax (and resulting Docker images).
Under the hood, host ports and other non-portable configuration (e.g. volume mounts) are part of the HostConfig structure of the container. These are only available at container runtime.

Resources