I am trying to expose a port on a Docker container without having to map it to a port on the host; this works fine for the likes of sql databases or web systems such as redmine where I can access Redmine on port 3000 of the containers IP address from the host system without mapping the port.
My Dockerfile looks something like this (volumes, envs, etc removed for "clarity")
FROM python:2.7
RUN pip install gunicorn
EXPOSE 8000
CMD ["gunicorn", "-b", "0.0.0.0:8000", "myapp.wsgi" ]
This should tell gunicorn to bind (-b) to port 8000 or all addresses; so I expected port 8000 to be open on the container when I run it with say
docker run myappthing
But no - even tho gunicorn is running happily. Yet if I do
docker run -p 127.0.0.1:8028:8000 myappthing
Then not only is port 8028 open on the host but 8000 is open on the container too.
Whats going on here; what have I missed?
Thanks
docker ps report ports differently as below: redmine and mysql show they are not mapped to a port on the host where my attempt is mapped
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b68765d57f0b 52adec2834c2 "gunicorn -b 172.18.…" 45 minutes ago Up 45 minutes 127.0.0.1:8028->8000/tcp afc-timerec-manual
aaecd3cd319d 9671544d5284 "/docker-entrypoint.…" 7 months ago Up 7 weeks 3000/tcp afc-redmine
fb4e55d352b2 1571059e8458 "docker-entrypoint.s…" 13 months ago Up 4 days 3306/tcp afc-glpi-data
More illustrations: if I open a shell on the container, I can do this:
lynx http://127.0.0.1:8000
lynx http://172.18.0.28:8000
(where 172.18.0.28 is the container IP address) and both commands allow me to access the webapp.
Meanwhile, back on the host - port 8000 is not open on the container so lynx http://172.18.0.28:8000 fails
The port is not published using the EXPOSE instruction, you need to use -p.
See https://docs.docker.com/engine/reference/builder/#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. 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.
Related
I am new to Docker and trying to run an open-source Django application with Docker Desktop for Windows.
Command docker container ls shows the application is running, and the service is listening on port 0.0.0.0:8000.
What IP address should I use on the Windows host to access this service? I appreciate your help.
docker container ls
...
1f2c70d56d48 saleor-platform_api "python manage.py ru…" 23 minutes ago Up 23 minutes 0.0.0.0:8000->8000/tcp
saleor-platform-api-1
...
As you can see here:
0.0.0.0:8000->8000
Docker is mapping the port 8000 of your container to the port 8000 of the host. Therefore, to send a request to the container, you need to make a request to localhost:8000 from the host (Windows in your case).
You would use port 8000 and host as either localhost or 127.0.0.1 or 0.0.0.0.
I have a problem with expose my .Net Core App on Docker.
My Dockerfile starts like that
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-bionic AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic AS build
WORKDIR /src
I build it and run:
docker run -d -p 8080:80 --name test testapp
Container starts but I can not access the app on port 8080
In the container logs I can see that
warn: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'.
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://localhost:5000
but I was expecting:
Now listening on: http://[::]:80
Why can not understand why this is not 80 and I can not reach my app from outside, even if run it with 8080:5000
CURL to loclalhost:5000 from inside the container returns proper HTML
You can use the ASPNETCORE_URLS environment variable to tell Kestrel to listen on a host/port different from localhost:5000.
I.e.
docker run -d -p 8080:80 -e ASPNETCORE_URLS=http://+:80 --name test testapp
More info on that in the docs.
Now, in my experience, I need to set this environment variable if I have my entrypoint/cmd to do dotnet run. On the other hand, if I set it to use the DLL, i.e. CMD ["dotnet", "testapp.dll"], it listens on
0.0.0.0:80 by default, meaning I do not have to set the ASPNETCORE_URLS variable.
So you could also play a bit with your entrypoint/cmd. I couldn't find this part documented, so unsure exactly how it works...
We had this same issue and could not find a resolution to this problem. This occurred for us in a .net 6 application and took us days to troubleshoot.
The environment for us was: a c# REST API docker composed up in a debian container launched on a windows operating system.
The ports are opening correctly most likely on your container and you look to be mapping your local port to the container port correctly. So most likely all of that is correct.
However it is likely the application itself is not running on port 80 inside the container. Kestrel runs on port 5000 by default which is why you are seeing the 5000 error.
If you are running .net 5 or 6 you can add this to program.cs
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(80);
}
);
To tell kestrel to listen on port 80 on both the ipv4 and ipv6 interfaces.
For us this instantly forced the app to run on port 80 inside the container.
To confirm this is the issue you can always use docker desktop and go inside your linux container (command line interface) and see what is running on the ports in the linux container. To do this you can use netstat - a but you need to install net-tools first (most likely).
In the linux container
apt update
apt install net-tools
netstat -a
If kestrel is running on port 80 you will see port 80 exposed. if it is running on port 5000 you will see it running on port 5000.
For us we were running on port 5000 before we made the adjustment. After the adjustment we were running on 80 appropriately and were instantly fixed.
port 5000 in linux container
port 80 in linux container
The application runs on port 5000 and you are trying expose 80. So change your Dockerfile and expose 5000
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-bionic AS base
WORKDIR /app
EXPOSE 5000
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic AS build
WORKDIR /src
Now run the image by exposing 5000 port
docker run -d -p 8080:5000 --name test testapp
Which operating system are you using? I had the exact same issue using Fedora. If you are using Fedora or RHEL, Docker networking requires additional configuration to work.
See https://fedoramagazine.org/docker-and-fedora-32/
(I do not have sufficient reputation to comment so I am answering).
I have a running Docker container which shows PORTS 9191/tcp. So on my browser, I tried accessing server using localhost:9191/api/.... However, browser throws an error This site can’t be reached
Here is a log to docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c214aefed15e shah "youtube-dl-server -…" 6 seconds ago Up 5 seconds 9191/tcp boring_swirles
This is what my docker file looks like
FROM mariozig/youtube-dl_server
RUN pip install --pre youtube_dl_server
EXPOSE 9191
ENTRYPOINT ["youtube-dl-server", "--host=0.0.0.0"]
You have not mapped the docker container port to host port.
The docker container runs on a host. And The host doesn't know which requests to be directed to the docker container. For that you have to to map the host port to docker container port using -p flag in docker run command as shown below:
docker run -d -p HOST_PORT:CONTAINER_PORT IMAGE_NAME
-p in this command will specify that you are forwarding your host port to the container port. In your local host in the port HOST_PORT will call the port CONTAINER_PORT of your container.
Now when you will access the HOST_IP:HOST_PORT then the host will redirect the request to corresponding container with which this HOST_PORT has been mapped.
For example I started a tomcat docker container and mapped the tomcat container's 8080 port to host's 9092 port by using the above command. When I do docker ps I can see the mapping under PORTS as 0.0.0.0:9092->8080/tcp
I need to run a Java app into several Docker containers in order to isolate their execution.
This app listens on port 12345 and I run my docker container with "-p 12345:5000" to redirect the port 12345 (from Docker container) to the port 5000 of my host. It works fine.
But when I run another Docker container with "-p 12345:50001", I have an error "Bind for 0.0.0.0:12345 failed: port is already allocated."
I don't understand why .. Thank you :)
You've mixed up your host and container ports!
The host port comes first and must be unique. The container port comes second. You probably want something like this, if your java apps both run on the same port in the container:
"-p 12345:50000"
"-p 12346:50000"
Or this if they really expose different ports in the container:
"-p 12345:50000"
"-p 12346:50001"
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"}]}