Docker - can not expose on port 80 - docker

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).

Related

From inside of a Docker container, how do I connect to another process listening inside the same container?

I have spent a couple of hours researching this and the consensus seems to be that using host.docker.internal instead of localhost should allow one process within a container to connect to another process within the same container.
However, host.docker.internal does not work for me.
Environment:
Docker Desktop 4.6.1 running on Windows 10
docker run command running on WSL2 Ubuntu
Command:
docker run -p 80:80
Error
Connection timeout
Dockerfile contents
FROM openjdk:17-alpine
COPY xxx/target/AAA.jar AAA.jar
COPY xxx/target/BBB.jar BBB.jar
COPY xxx/target/CCC.jar CCC.jar
COPY ./dockerboot.sh dockerboot.sh
ENTRYPOINT ["sh", "-c", "./dockerboot.sh"]
EXPOSE 80
dockerboot.sh contents
java -jar AAA.jar &
java -jar BBB.jar &
java -jar CCC.jar &
wait
The AAA, BBB, CCC jars contain java Springboot applications listening on ports 80, 8081, and 8082 respectively.
The answer is to just use localhost or 127.0.0.1.
It turns out the root cause of my issue was unrelated to Docker networking:
One of the microservice jars was malformed (no main manifest attribute) and was not starting up correctly, hence, failing to listen on port 8081 and causing Connection refused.

Docker expose port internals

In Docker we all know how to expose ports, EXPOSE instruction publishes and -p or -P option to expose during runtime. When we use "docker inspect" or "docker port" to see the port mappings and these configs output are pulled /var/lib/docker/containers/container-id/config.v2.json.
The question I got is when we expose port how does Docker actually changes the port in container, say the Apache or Nginx, say we can have the installation anywhere in the OS or file path, how does Docker finds the correct conf file(Apache /etc/httpd/conf/httpd.conf) to change if I suppose Docker does this on the line "Listen 80" or Listen "443" in the httpd.conf file. Or my whole understanding of Docker is in stake:)
Any help is appreciated.
"docker" does not change anything in the internal configuation of the container (or the services it provides).
There are three different points where you can configure ports
the service itself (for instance nginx) inside the image/container
EXPOSE xxxx in the Dockerfile (ie at build time of the image)
docker run -p 80:80 (or the respective equivalent for docker compose) (ie at the runtime of the container)
All three are (in principle) independent of each other. Ie, you can have completely different values in each of them. But in practice, you will have to adjust them to each other to get a working system.
We know, EXPOSE xxxx in the dockerfile doesn't actually publish any port at runtime, but just tells the docker service, that that specific container will listen to port xxxx at runtime. You can see this as sort of documentation for that image. So it's your responsibility as creator of the Dockerfile to provide the correct value here. Because anyone using that image, will probaby rely on that value.
But regardless, of what port you have EXPOSEd (or not, EXPOSE is completely optional) you still have to publish that port when you run the container (for instance when using docker run via -p aaaa:xxxx).
Now let us assume you have an nginx image which has the nginx service configured to listen to port 8000. Regardless of what you define with EXPOSE or -p aaaa:xxxx, that nginx service will always listen to port 8000 only and nothing else.
So if you now run your container with docker run -p 80:80, the runtime will bind port 80 of the host to port 80 of the container. But as there is no service listening on port 80 within the container, you simply won't be able to contact your nginx service on port 80. And you also won't be able to connect to nginx on port 8000, because it hasn't been published.
So in a typical setup, if your service in the container is configured to listen to port 8000, you should also EXPOSE 8000 in your dockerfile and use docker run -p aaaa:8000 to bind port aaaa of your host machine to port 8000 of your container, so that you will be able to connect to the nginx service via http://hostmachine:aaaa

Docker: exposing port on container IP

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.

Unable to run application on Docker if used any other port except default port 80

I have a demo app which is hosted on docker. The exposed port for Docker is 80 and the app is running fine on local machine and I am able to see landing page for my app on localhost:8888.
Docker file is as given below
FROM microsoft/aspnetcore:2.0
COPY dist /app
WORKDIR /app
EXPOSE 80/tcp
ENTRYPOINT ["dotnet", "demoapp.dll"]
Whenever I change line "EXPOSE 80/tcp" to for ex- "EXPOSE 8080/tcp" , "EXPOSE 5000/tcp" etc to expose any other port except 80 of Docker container as given in many online available sample codes, I am unable to run my app on browser. Any port except 80 is not working.
I am able to create image and create container for application too. Everything goes well but when I try to run app on browser (localhost:8080/5000/9000 etc.) The app landing page doesn't load.
Any suggestions? Do I need to do some port related configuration or contact my network team? or any code which I am missing here?
You should be able to expose any port inside the container.
However you publish the exposed port on the host during the start of the container.
This is done with the -p flag of the docker run command.
When you say you are able to access the application using localhost:8888 it means you have run the docker run command with -p 8888:80. This publishes the container port 80 onto the host as port 8888.
To use any other port just change the docker run command to -p 8888:<new exposed port> and that should do it.
See the docker run command help for more info:
https://docs.docker.com/v17.12/edge/engine/reference/commandline/run/#publish-or-expose-port--p-expose
Publish or expose port (-p, –expose)
$ docker run -p 127.0.0.1:80:8080 ubuntu bash
This binds port 8080 of the container to port 80 on
127.0.0.1 of the host machine. The Docker User Guide explains in detail how to manipulate ports in Docker.
If your application runs at port suppose 8080 then make sure to do port mapping while running the container.
docker run -itd -p 8080:8080 <image>
This will map port 8080 of host on port 8080 inside the container. (-p hostport:containerport)
If you don't want port mapping then run docker container in host mode.
docker run -itd --net=host <image>
In this case your container use host network, so whatever port your application is running inside it should get exposed.
For microsoft/aspnetcore, it sets the ASPNETCORE_URLS environment variable to http://+:80 which means that if you have not explicity set a URL in your application, via app.UseUrl in your Program.cs for example, then your application will be listening on port 80 inside the container.
Reference: microsoft/aspnetcore
If you want to change the default port 80, you need to use UseUrls in Program.cs with like below, and use EXPOSE 8080/tcp in dockerfile.
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://+:8080")
.UseStartup<Startup>();
Or, you need to change ASPNETCORE_URLS environment like
FROM microsoft/aspnetcore:2.0
COPY dist /app
WORKDIR /app
EXPOSE 8080/tcp
ENV ASPNETCORE_URLS=http://+:8080
ENTRYPOINT ["dotnet", "demoapp.dll"]
Command to run
docker run -it -p 8080:8080 mytest

dotnet core docker container - Unable to bind to https://localhost:5001 on the IPv6 loopback interface

I created an image for .NET core:
FROM microsoft/dotnet:2.1-sdk AS build-env
WORKDIR /app
EXPOSE 80 443 5000 5001 5010 5011 7000 22676
#ENTRYPOINT [ "bash"]
CMD ["bash"]
I run a container from it
docker container run -it --publish 5000:8018 --name versie3001 -v //c/tijd/mount:/app michel03
What goes well is that I see the mounted files.
When I create a new website with dotnet new razor and I run it with dotnet run it tries to run on port 5000/5001 (default ports) but I get this error:
warn: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to bind to https://localhost:5001 on the IPv6 loopback interface: 'Cannot assign requested address'.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'.
Actually it says warn, but the result is the same, when I go to localhost:8018 I get no result (ERR_CONNECTION_REFUSED)
What am I doing wrong here?
I saw an answer saying I should do this in my containerfile:
ENTRYPOINT [ "dotnet", "watch", "run", "--no-restore", "--urls", "https://0.0.0.0:5000"]. It does not give me the error (output is Now listening on: https://0.0.0.0:5000), which is good, but it also does not connect from https://localhost:8018 on my local machine.
Your --publish option is backwards: it's -p <hostPort>:<containerPort>, so for your setup you'd want --publish 8018:5000.
Startup issues aside, you do need the option to cause the container to listen on 0.0.0.0 (or ::0, if IPv6 works). If it binds to localhost it will be unreachable from outside its container, including from other containers and from the host.

Resources