I run an ASP.NET Core service in a Docker container on MacOS.
Visual Studio for Mac v18.1.2 (build 2)
.NET Core SDK: 2.2.300
Here is the Dockerfile:
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /
COPY src/Services/Service.API/Service.API.csproj src/Services/Service.API/
RUN dotnet restore src/Services/Service.API/Service.API.csproj
COPY . .
WORKDIR /src/Services/Service.API
RUN dotnet build Service.API.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish Service.API.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Service.API.dll"]
Here is how the docker-compose file for the service looks like:
service.api:
build:
context: .
dockerfile: src/Services/Service.API/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:80;https://+:443
- ASPNETCORE_HTTPS_PORT=5254
- ASPNETCORE_Kestrel__Certificates__Default__Password=crypticpassword
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
ports:
- "5204:80"
- "5254:443"
volumes:
- ${HOME}/.aspnet/https:/https/
The ports of the running Docker container looks good too:
0.0.0.0:5204->80/tcp, 0.0.0.0:5254->443/tcp
But when I try to call https://localhost:5254 it says site cannot be reached.
Also in the output I see following warning:
warn: Microsoft.AspNetCore.Server.Kestrel[0]
Unable to bind to https://localhost:5001 on the IPv6 loopback interface: 'Cannot assign requested address'.
Microsoft.AspNetCore.Server.Kestrel:Warning: Unable to bind to
https://localhost:5001 on the IPv6 loopback interface: 'Cannot assign
requested address'. Hosting environment: Development Content root
path: /app Now listening on: https://localhost:5001
Why doesn't it take the urls set by the ASPNETCORE_URLS enivronment variable?
What else could I do for troubleshooting to find the problem?
I had your problem a while ago, this is how I fixed it. You need to specify --server.urls as a running argument like below:
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Service.API.dll", "--server.urls", "http://+:80;https://+:443"]
And where that 5000 and 5001 come from?
Kestrel Endpoint configuration
By default, ASP.NET Core binds to:
http://localhost:5000
https://localhost:5001 (when a local development
certificate is present)
Update 1:
According to your docker-compose configuration, you have set ASPNETCORE_ENVIRONMENT to Development. I think you should change it to Production because when you enable Development the ASP.NET Core will read settings from launchSettings.json.
The development environment can enable features that shouldn't be exposed in production. For example, the ASP.NET Core templates enable the Developer Exception Page in the development environment.
The environment for local machine development can be set in the
Properties\launchSettings.json file of the project. Environment values
set in launchSettings.json override values set in the system
environment.
As far as I remember the default ports for Kestrel are 80 and 443 in every default launchSettings.json.
If you need to run your project in development mode on Docker you should change configuration inside launchSettings.json but I think it's not recommended and it's better to change the mode to Production.
service.api:
build:
context: .
dockerfile: src/Services/Service.API/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:80;https://+:443
- ASPNETCORE_HTTPS_PORT=5254
- ASPNETCORE_Kestrel__Certificates__Default__Password=crypticpassword
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
ports:
- "5204:80"
- "5254:443"
volumes:
- ${HOME}/.aspnet/https:/https/
First, check if your container is up and running with:
docker ps
If it is running, Kestrel inside the container may not be started. You may need to check your entrypoint, Linux in the container is case sensitive. In this case, try to run your app manually. First, get into the container by:
docker exec -it your_container /bin/bash
cd /app
dotnet yourprojectfile.dll
and then navigate:
https://localhost:5254
Basically, in the asp.net core code, it only listens to localhost which is in Container, but not your local pc. You can solve the issue by updating your setting to listen "http://*:5000" instead of "http://localhost:5000".
Here is a detailed explaination of the cause and solution.
https://stackoverflow.com/a/65953771/8918445
For your current docker-compose.yml, you are referring the existing image service.api:${TAG:-latest} directly instead of using the generated image from the dockerfile.
Remove this line image: service.api:${TAG:-latest}
version: '3'
services:
service.api:
build:
context: .
dockerfile: src/Services/Service.API/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:80;https://+:443
- ASPNETCORE_HTTPS_PORT=5254
- ASPNETCORE_Kestrel__Certificates__Default__Password=crypticpassword
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
ports:
- "5204:80"
- "5254:443"
volumes:
- ${HOME}/.aspnet/https:/https/
Turns out this is a bug in Visual Studio for Mac v18.1.2 (docker-compose up works)
Related
I am encountering an interesting difference in startup behaviour when running a simple net6.0 web api built with docker-compose in comparison to being built with docker. The application itself runs in a kubernetes cluster.
Environment
Minikube v1.26.1
Docker Desktop v4.12
Docker Compose v2.10.2
Building with docker-compose
docker-compose.yml
version: "3.8"
services:
web.api:
build:
context: ./../
dockerfile: ./web.API/Dockerfile
The context is set to the parent directory due to some files needed there.
Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build
WORKDIR /src
ENV ASPNETCORE_URLS=http://+:80
COPY Directory.Build.props ./Directory.Build.props
COPY .editorconfig ./.editorconfig
COPY ["webapi/web.API", "web.API/"]
RUN dotnet build "web.API/web.API.csproj" -c Release --self-contained true --runtime alpine-x64
RUN dotnet publish "webapi/web.API.csproj" -c Release -o /app/publish \
--no-restore \
--runtime alpine-x64 \
--self-contained true \
/p:PublishSingleFile=true
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-alpine
WORKDIR /app
EXPOSE 80
EXPOSE 443
COPY --from=build /app/publish .
ENTRYPOINT ["./web.API"]
This results in the app starting up within the kubernetes cluster with the following logs:
Now listening on: http://[::]:80
Building with docker build
Using the same Dockerfile mentioned earlier with the same build context you can see in the docker-compose.yml, a deployment to k8s results in the following log:
Now listening on: http://localhost:5000
Running the image locally
Running the exact same image from the k8s cluster locally however results in
Now listening on: http://[::]:80
Already tried
As suggested in many posts, I tried setting the environment variable ASPNETCORE_URLS via Dockerfile or k8s deployment.yml- neither of which had an impact on the startup url.
I can't seem to figure out why there is a difference between those 2 ways of building an image.
Update
The only thing that seems to work is to add
builder.WebHost.ConfigureKestrel(option =>{
option.ListenAnyIP(80);
});
to the Program.cs.
Still not sure about the reason behind the behaviour though.
A few things:
I assume that the container already running and working on port 80 (docker run) is stopped before attempting to run docker-compose?
Environment variables can be used in docker-compose.yml file
Ports most likely need to be exposed correctly, which from the Dockerfile and docker-compose.yml seems like it is not?
Environment Variables
First off, before the environmental ENV ASPNETCORE_URLS=http://+:80 is going to be of any use, your docker-compose instance does not define which ports to use, your docker-compose (if trimmed) does not show any ports.
Perhaps because the ports aren't exposed, this means the environmental tries to connect to 80, which fails (already in use/not exposed) and then fails, and somehow connects on 5000.
Alternatively, more likely: it does not really not _see your ENV ASPNETCORE_URLS
You can try environment variables directly in your docker-compose file:
my-service:
image: ${IMAGE_NAME}
environment:
MY_SECRET_KEY: ${MY_SECRET_KEY}
Publishing ports
In docker-compose file you need this, to publish ports:
ports:
- "80"
- "443"
... or
ports:
- "80:80" // "host-port:container-port"
- "443:1234"
Additional information
The keyword EXPOSE\expose in Dockerfile/docker-compose.yml is just informative (comments in a sense), functionally it does not process anything. A port need to be exposed (published) to be used.
So, those EXPOSE 443 & 80 is not telling Docker to use it, perhaps you are running your container for example like this:
This exposes port 80 for it to be available.
docker run -p 127.0.0.1:80:80/tcp image command
In short, use ports keyword in docker-compose.yml.
EDIT:
I read your comment above:
But the app is not accessible in k8s when listening to localhost:5000 even with correct service and container configuration
This indicates what I am trying to say regarding the ports being published or not. Your port 5000 is also not exposed because nothing in your configuration shows that is the case.
I've created a default ASP.NET Core 5 Web API through Visual Studio 2019 and have it running inside a Docker container (no https to make this example simple). I am using Windows, but the image is running as a Linux Docker Container. When I run the application from Visual Studio, it is started with Docker Compose. When the application runs I'm able to access it from my browser on the Docker host machine, but I'm not able to access it from another device on the same network.
Below are the files I'm using. You can see that I am exposing port 61234 from docker-compose.yml. Assuming my Host IP address is 192.168.1.12, if I were to navigate to http://192.168.1.12:61234/weatherforecast from a web browser on the host machine, I get a REST response from the controller. If I access that same endpoint from a different laptop on the same Wi-Fi network, the endpoint is unreachable.
I have validated that the laptop can reach the REST endpoint if the application is not running within a Docker container. For this reason, I don't believe the Windows Firewall is getting in the way.
I've looked at everything I can think of. So my question is: Is there anything else I should look at? I assume I'm missing something simple, but just can't seem to find what that might be.
The only change I made to the C# code generated by Visual Studio is making a UseUrls() call when creating the web host builder: webBuilder.UseUrls("http://*:80").UseStartup<Startup>();
Here is my docker-compose.yml file. Note the exposed TCP port and the bridge network:
version: '3.4'
services:
webapplication1:
image: ${DOCKER_REGISTRY-}webapplication1
build:
context: .
dockerfile: WebApplication1/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "61234:80"
networks:
- practice-webapi-network
networks:
practice-webapi-network:
driver: bridge
And here is the auto-generated Dockerfile that Visual Studio created:
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]
One thing I want to point out. I believe I would be able to work around this by changing the network driver to Host instead of Bridge, but I need to use a Bridge network for my application. This is just a proof of concept.
Edit 1: Added missing port to example endpoint
I'm struggling to move my web api to the docker containers. However, it doesnt want to run.
Running docker-compose build and then docker-compose up console shows me that app is start listening on: http://localhost:5000 and https://localhost:5001, but before those line i'm receiving: " Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'."
Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["ShoppingCart.API/ShoppingCart.API.csproj", "ShoppingCart.API/"]
#COPY ["ShoppingCart.Domain.Entities/ShoppingCart.Domain.Entities.csproj", "ShoppingCart.Domain.Entities/"]
#COPY ["ShoppingCart.Domain.Interfaces/ShoppingCart.Domain.Interfaces.csproj", "ShoppingCart.Domain.Interfaces/"]
#COPY ["ShoppingCart.Infrastructure.Data/ShoppingCart.Infrastructure.Data.csproj", "ShoppingCart.Infrastructure.Data/"]
#COPY ["ShoppingCart.Infrastructure.Business/ShoppingCart.Infrastructure.Business.csproj", "ShoppingCart.Infrastructure.Businesss/"]
#COPY ["ShoppingCart.Services.Interfaces/ShoppingCart.Services.Interfaces.csproj", "ShoppingCart.Services.Interfaces/"]
RUN dotnet restore "ShoppingCart.API/ShoppingCart.API.csproj"
COPY . .
WORKDIR "/src/ShoppingCart.API"
RUN dotnet build "ShoppingCart.API.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "ShoppingCart.API.csproj" -c Release -o /app/publish
WORKDIR /app
COPY --from=build /app/build .
ENTRYPOINT ["dotnet", "ShoppingCart.API.dll"]
Docker-compose:
version: '3.9'
networks:
localdev:
name: localdev
services:
main-api:
build: .
restart: always
ports:
- "5000:80"
- "5001:443"
networks:
- localdev
So, on http://localhost:5000 and https://localhost:5001 i dont see anything...
I even tried to add some arguments to Dockerfile:
ENTRYPOINT ["dotnet", "ShoppingCart.API.dll", "--urls", "https://0.0.0.0:5000"]
And after this, i dont receive the error of not assignning requested address. And also, cant reach any content on those ports...
Problem
You are binding port 5000 on your localhost to 80 on your docker container (and same with 5001:443). Is that really what you want to do? Since this is an aspnet-core project you are most likely running your webapp on port 5000 or 5001 (in the container), not 80 or 443. It also seems that you may already be running something on port 5000 on your localhost so docker is failing to bind it (I assume you're running your app probably).
Solution
You most likely need to:
Bind to ports 5000/5001 in your container, not 80/443.
Shut down what's running on port 5000 in your localhost environment, or pick another port to bind that isn't in use.
For example, lets pick a random higher port that isn't being used:
version: '3.9'
services:
main-api:
build: .
ports:
- "6000:5000"
- "6001:5001"
Bring this up with docker-compose up and then see what you get from http://localhost:6000 or https://localhost:6001.
Notes
It looks like you're attempting to create a multi-stage docker build where your app is built inside the sdk image and then run inside the aspnet image. But you are not introducing the aspnet image, so your container's runtime environment is still sdk which includes a lot of stuff we don't need in the runtime. You should add this line after your publish to change to the aspnet image. Example.
FROM mcr.microsoft.com/dotnet/aspnet:3.1
I created a basic Rest API using ASP.NET Core 5 i want to make run with docker. The application works fine on IIS Express.
https://learn.microsoft.com/fr-fr/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio
I also want to create a docker container in order to launch the application.
In the project folder i created a Docker folder with several files.
Here is my App.dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:5.0
ARG WEBAPP_VERSION=0.0.1
LABEL maintainer=anymail#email_server.com \
Name=webapp \
Version=${WEBAPP_VERSION}
ARG URL_PORT
WORKDIR /app
ENV NUGET_XMLDOC_MODE skip
ENV ASPNETCORE_URLS http://*:${URL_PORT}
ENTRYPOINT [ "dotnet", "WebApplication.dll" ]
I also have a Build.docker file:
FROM mcr.microsoft.com/dotnet/aspnet:5.0
## Can be Debug or Release.
ARG BUILD_CONFIG=Debug
ARG BUILDER_VERSION=0.0.1
LABEL maintainer=some_email#email_server.com \
Name=webapp-build-${BUILD_CONFIG} \
Version=${BUILDER_VERSION}
## Will be the path mapped to the external volume.
ARG BUILD_LOCATION=/app/out
ENV NUGET_XMLDOC_MODE skip
WORKDIR /app
COPY *.csproj .
RUN dotnet restore
COPY . /app
RUN dotnet publish --output ${BUILD_LOCATION} --configuration ${BUILD_CONFIG}
Finally I have a docker-compose.yml
version: '3'
services:
webapp:
container_name: webapp.test
image: webapp:${WEBAPP_VERSION}
build:
context: ../
dockerfile: ./Docker/App.dockerfile
args:
WEBAPP_VERSION: ${WEBAPP_VERSION}
URL_PORT: ${URL_PORT}
ports:
- "5000:${URL_PORT}"
volumes:
- appbuild:/app
links:
- mysql
environment:
MYSQL_SERVER_NAME: ${MYSQL_SERVER_NAME}
env_file:
- secrets.env
depends_on:
- builder
builder:
container_name: builder
image: webapp:${BUILDER_VERSION}.${BUILD_CONFIG}
build:
context: ../
dockerfile: ./Docker/Build.dockerfile
args:
BUILDER_VERSION: ${BUILDER_VERSION}
BUILD_CONFIG: ${BUILD_CONFIG}
BUILD_LOCATION: ${BUILD_LOCATION}
volumes:
- appbuild:${BUILD_LOCATION}
mysql:
container_name: ${MYSQL_SERVER_NAME}
image: mysql/mysql-server:8.0.23
restart: always
volumes:
- dbvol:/var/lib/mysql
environment:
MYSQL_RANDOM_ROOT_PASSWORD: root
env_file:
- secrets.env
volumes:
appbuild:
dbvol:
Finally, I launch the following command line :
docker build -f Docker/App.dockerfile -t webapp:Debug --build-arg URL_PORT=7909 .
the process is rather quick.
I also launch this command line :
docker run --name webapp.test -p 5000:7909 -it webapp:Debug
I unfortunatelly obtain an error message.
Could not execute because the application was not found or a compatible .NET SDK is not installed.
Possible reasons for this include:
* You intended to execute a .NET program:
The application 'WebApplication.dll' does not exist.
* You intended to execute a .NET SDK command:
It was not possible to find any installed .NET SDKs.
Install a .NET SDK from:
https://aka.ms/dotnet-download
Your build Dockerfile uses the ASP.NET Core runtime container image:
FROM mcr.microsoft.com/dotnet/aspnet:5.0
This container doesn't have an SDK, just the runtime. When you build it, it fails:
RUN dotnet restore
Could not execute because the application was not found or a compatible .NET SDK is not installed. and The application 'restore' does not exist
Because the dotnet restore command is an SDK command. It's not available if you are just using the runtime.
You should use the SDK container for your build Dockerfile (not your runtime Dockerfile, that's fine):
FROM mcr.microsoft.com/dotnet/sdk:5.0
If you already installed the SDK and you have x64 machine;
Delete the following item from System Variables > Path
C:\Program Files (x86)\dotnet
In my case dot net SDKs were installed in different locations. A simple
where.exe dotnet on powershell returned the following
There were 2 entries in system environment variables i.e. The one with x86 was above so it was taking precedence, so I swapped both of them and hurray it started working.
Special thanks to
https://www.hanselman.com/blog/dotnet-could-not-execute-because-the-application-was-not-found-or-a-compatible-net-sdk-is-not-installed
Had the same message while trying to configure Docker Container Debugging in VS Code for .NET 6. Couple of issues:
In tasks.json of VS Code the default "target": "base" was not working for me, because I used stage build in Dockerfile. So I commented it out... But Docker extension needs it to inject the Debugging metadata.
Changing to "target": "build" fixed the error.
I skipped the EXPOSE and ENV part because it worked via docker compose or while manually forwarding ports in cmd. Should be at the beginning of base/build stage:
FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine as build
WORKDIR /source
EXPOSE 80 #was missing
ENV ASPNETCORE_URLS=http://+:80 #was missing
Works for me when i changed
FROM mcr.microsoft.com/dotnet/core/aspnet:5.0
to:
FROM mcr.microsoft.com/dotnet/sdk:5.0
In my case volume mounting is created this kind of problem.
volumes:
- ./docker/caadminservice/certificate:/**CAAdminService**
CAAdminService is the root folder in container. We should not mount that directly with host machine. It created me this kind of problem
I am working on setting up two Docker containers using Docker for Windows. A simple node based web app, and a dotnet core API application. I am starting both these containers using "docker-compose up". The node app starts up perfectly and I can hit the exposed URL, however the dotnet app isn't seeming to work.
The output of the docker-compose up command is below:
application.client_1 | INFO: Accepting connections at http://localhost:8080
application.api_1 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
application.api_1 | No XML encryptor configured. Key {cc83a8ac-e1de-4eb3-95ab-8c69a5961bf9} may be persisted to storage in unencrypted form.
application.api_1 | Hosting environment: Development
application.api_1 | Content root path: /app/application.Api
application.api_1 | Now listening on: http://[::]:80
application.api_1 | Application started. Press Ctrl+C to shut down.
The Docker file looks like the following:
FROM microsoft/dotnet AS build
WORKDIR /app
ENV PORT=8081
COPY application.Api/application.Api.csproj application.Api/
COPY application.Business/application.Business.csproj application.Business/
COPY application.DataAccess/application.DataAccess.csproj application.DataAccess/
COPY application.DataModel/application.DataModel.csproj application.DataModel/
WORKDIR /app/application.Api
RUN dotnet restore
WORKDIR /app/
COPY application.Api/. ./application.Api/
COPY application.Business/. ./application.Business/
COPY application.DataAccess/. ./application.DataAccess/
COPY application.DataModel/. ./application.DataModel/
WORKDIR /app/application.Api
RUN dotnet publish -c Release -o out
FROM microsoft/dotnet AS runtime
WORKDIR /app/application.Api
COPY --from=build /app/application.Api/out .
ENTRYPOINT ["dotnet", "application.Api.dll" ]
EXPOSE $PORT
I am unable to get an IP and thus hit the API url. Any thoughts would be much appreciated as I am pretty new to Docker.
UPDATE 1: Compose YML
version: '3.4'
services:
tonquin.api:
image: application.api
ports:
- 8081:5000
build:
context: .
dockerfile: Dockerfile
tonquin.client:
image: application.client
ports:
- 8080:8080
build:
context: .
dockerfile: ../application.Client/Dockerfile
As they've mentioned it seems your container is running on port 80. So for whatever reason that's the port being exposed.
Maybe the EXPOSE $PORT is not returning 8081 as you expect?
When you run the container, unless you specify where to map it, it will only be available at the container's IP at the exposed port (80 in your case). Find out this container Ip easily by running docker inspect <container_id>
Test your image by doing something like docker run -p 8080:80 yourimage. You'll see that in addition to the port 80 that the image exposes, it is being mapped to your local port 8080 so that http://localhost:8080 should be reachable.
See this in case it helps you
See this answer.
The base dotnet image overrides the default kestrel port. Why, I don't know. Adding the environment declaration to my docker file fixed the problem for me.
It's trying to use the IPv6 protocol on the network interface. Disable IPv6 and restart docker. It also looks like you might have both apps trying to use port 80. You can only serve one item on a given port with a given interface/IP. Try setting the API to use a different port number, like 8080.