Cannot access to dockerized net 6 api - c#

My api project (my-custom-api) is using rabbitmq instance. Since both are running in docker I created custom docker network and run both containers on that same network.
docker create my-network
docker run -d --hostname my-rabbitmq --network my-network --rm -it -p 15672:15672 -p 5672:5672 rabbitmq:3.11-management
docker run --network my-network --publish 8090:8080 -d my-custom-api
on docker ps -a both containers are up and running and inside docker log for my-custom-api there is no errors or warnings
However when I hit localhost:8090/swagger/index.html I'm getting This site can’t be reached. Using curl localhost:8090 I'm getting url: (52) Empty reply from server
Here's the content of Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /App
# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "My-Custom-Api.dll"]
Again, I'm not getting any errors in the docker log when trying to access localhost:8090 but still cannot access api from this address.
What I'm doing wrong here.
Update:
After I changed run command to include environment Development my container logs looks like this
2023-01-22 20:58:55 info: Microsoft.Hosting.Lifetime[14]
2023-01-22 20:58:55 Now listening on: http://[::]:80
2023-01-22 20:58:55 info: Microsoft.Hosting.Lifetime[0]
2023-01-22 20:58:55 Application started. Press Ctrl+C to shut down.
2023-01-22 20:58:55 info: Microsoft.Hosting.Lifetime[0]
2023-01-22 20:58:55 Hosting environment: Development
2023-01-22 20:58:55 info: Microsoft.Hosting.Lifetime[0]
2023-01-22 20:58:55 Content root path: /App/
2023-01-22 20:58:56 info: MassTransit[0]
2023-01-22 20:58:56 Bus started: rabbitmq://my-rabbitmq/
I still cannot open localhost:8090/ with or without swagger.

Swagger is not available by default when your program runs in a container.
In your Program.cs, you should see an if statement that makes it so Swagger is only available when your program runs in a development environment. A container is - by default - not considered development.
To run the program in development mode, you need to set the ASPNETCORE_ENVIRONMENT variable to 'Development'.
Another thing to be aware of is that the asp.net containers set the environment variable ASPNETCORE_URLS to http://+:80 making your app listen on port 80. So you need to map that, rather than port 8080.
You can see that your app is listening on port 80 in the log where it says Now listening on: http://[::]:80.
That means that you end up with a command like this:
docker run --network my-network --publish 8090:80 -d -e ASPNETCORE_ENVIRONMENT=Development my-custom-api
When you do that, Swagger will be available on port 8090.

Related

How to fix port error when dockerizing .Net API

I am trying to dockerize my .Net API and I cannot seem to get access to it after I create a container with it. I attempt to send a request using postman but I get a "Socket Hang Up" error. I believe this has to do with the ports I am using although I am not sure how to fix it. Below is all the information I could gather.
Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app
COPY WebAPI.csproj .
RUN dotnet restore "WebAPI.csproj"
COPY . ./
RUN dotnet publish "WebAPI.csproj" -c Release -o /publish
RUN dotnet build
FROM build AS final
WORKDIR /app
COPY --from=build /publish .
EXPOSE 5000
ENTRYPOINT ["dotnet", "WebAPI.dll"]
Commands:
docker build -t webapi:latest .
docker run -p 5000:5000 webapi:latest
Postman Proxy:
127.0.0.1:5000
P.S I have tried changing the ports in multiple ways, changing proxy settings for postman and nothing seems to work
Microsoft has set the environment variable ASPNETCORE_URLS to http://+:80/ in the aspnet image, which makes your application listen on port 80.
So your run command should map port 80 like this
docker run -p 5000:80 webapi:latest
Then your API will be available on http://localhost:5000/
Note that Swagger is only available when your application runs in Development mode and the Docker environment is not considered development. So by default, Swagger won't be available.
Update: Since I don't have your program source code, I've created the following Dockerfile that runs dotnet new to create a fresh template webapi project.
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
RUN dotnet new webapi -n WebAPI -o .
RUN dotnet publish -c Release -o /publish
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /publish .
CMD ["dotnet", "WebAPI.dll"]
I then run the following commands to build, run and test the container
docker build -t test .
docker run --rm -d -p 5000:80 test
curl http://localhost:5000/WeatherForecast
and I get the expected result from the API.

How to connect to app inside docker container inside wsl2 from Windows host?

On Windows:
I just created app via dotnet new mvc and created Dockerfile for that:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["src/App.csproj", "src/"]
RUN dotnet restore "src/App.csproj"
COPY . .
WORKDIR "/src/src"
RUN dotnet build "App.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "App.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "App.dll"]
I then opened wsl2, went into /mnt/d/myproject and built built that docker build -t app . and started it.
I see it running
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e17cbwe6e4c test1 "dotnet App.dll" 5 days ago Up About a minute 80/tcp, 443/tcp affectionate_goldstine
also there are correct logs:
[10:54:13 WRN] Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
[10:54:13 INF] User profile is available. Using '/root/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
[10:54:13 INF] Now listening on: http://[::]:80
[10:54:13 INF] Application started. Press Ctrl+C to shut down.
[10:54:13 INF] Hosting environment: Production
[10:54:13 INF] Content root path: /app/
but I'm not sure how can I connect to it?
you need to expose port using -p
docker run -itd --name myapp -p 80:80 <image>
then you can reach your app at host_ip:80

web api does not start up with NetCore 3 web api in linux container on azure

I am trying to "dockerize" this clean architecture template for .net Core 3. I use the docker pull request here as the base for my proff of concept app. This is a .net core 3 webapi project with an Angular front end as the client app.
WHAT I HAVE:
The base code from the pull request works locally.
An initial problem I had to overcome was setting the cert for identity server 4 in a local non development env, I had to mount a volume with the cert and reference it from the appsettings.json file like
"IdentityServer": {
"Key": {
"Type": "File",
"FilePath": "/security/mycert.pfx",
"Password": "MyPassword"
}
}
I set up a CI/CD pipeline in azure to build the project and deploy the image to an azure container registry
I set up a CI/CD release to deploy the docker image to a Web App for Containers (Linux) web app. Both these steps work properly
MY PROBLEM:
The web app loads and runs the container and the angular front end is shown. However, it appears that the web api is not running. Any attempt to hit an endpoint of the web api returns the following error in the browser console:
GET https://.....azurewebsites.net/_configuration/CleanArchitecture.WebUI 404 (Not Found)
Error: Uncaught (in promise): Error: Could not load settings for 'CleanArchitecture.WebUI' Error: Could not load settings for 'CleanArchitecture.WebUI'
CleanArchitecture.WebUI is the name of the assembly that is the entry point in the dockerfile:
ENTRYPOINT ["dotnet", "CleanArchitecture.WebUI.dll"]
All other aspects of the front end work properly, only calls to "backend" api fail.
Another issue is that if I get the docker logs from the azure container, there are no errors shown.
WHAT I TRIED
I tried to add "dotnet CleanArchitecture.WebUI.dll" to the startup command of the container in the container settings of the web app, but that just throws an error that it can't find CleanArchitecture.WebUI.dll
I have tried to increase the logging level ("LogLevel": "Default": "Debug") to get more details, but no additional error details are shown in the docker logs.
It might be an error loading the Identity Server 4 certificate, but there are no errors to confirm this problem.
Here is my docker compose file that is used by the azure pipeline:
version: '3.4'
services:
webui:
image: ${DOCKER_REGISTRY-}webui
build:
context: .
dockerfile: src/WebUI/Dockerfile
environment:
- "UseInMemoryDatabase=false"
- "ASPNETCORE_ENVIRONMENT=Production"
- "ConnectionStrings__DefaultConnection=myconnection"
- "ASPNETCORE_Kestrel__Certificates__Default__Password=mypass"
- "ASPNETCORE_Kestrel__Certificates__Default__Path=/security/mycert.pfx"
ports:
- "5000:5000"
- "5001:5001"
volumes:
- mcpdata:"/security:/"
restart: always
mcpdata is the name of the azure file share that gets mounted and contains the actual cert
here is my azure-pipeline.yml for the CI/CD:
trigger:
- staging
resources:
- repo: self
variables:
# Container registry service connection established during pipeline creation
dockerRegistryServiceConnection: '****'
imageRepository: 'cleanarchitecture'
containerRegistry: '****.azurecr.io'
dockerComposeFilePath: '$(Build.SourcesDirectory)docker-compose.Production.yml'
tag: '$(Build.BuildId)'
# Agent VM image name
vmImageName: 'ubuntu-latest'
stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: Docker#2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerComposeFile: $(dockerComposeFilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: staging
QUESTION?
Can someone help me figure out why it appears like my web api is not running but no errors are thrown. At a minimum I would be happy if someone could help me see the errors in the docker logs.
thanks in advance
I tried to repeat, with "clean architecture" using the following (note, I'm using zsh on MacOS, but the same should work on Windows/Linux too):
take clean_architecture
dotnet new --install Clean.Architecture.Solution.Template
dotnet new ca-sln
The documentation suggests, clicking F5 in Visual Studio will start the template, although I had to do:
cd src/WebUI/ClientApp
npm install
At this point the app starts locally by hitting F5. Note, what happens here is that ASP.Net Core forwards requests to the dev server, so effectively, this does ng serve --port 53543 AND starts Asp.Net Core (Kestrel in my case) on port 5001, browsing to http://127.0.0.1:53543 provides the angular page directly. Browsing to https://localhost:5001 brings up the same angular page, as forwarded by ASPNetCore to Angular. All very confusing... Detailed more here
Note in Startup.cs the following lines of code exist, these are usually set based on the environment variable ASPNETCORE_ENVIRONMENT
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
-- and within "app.UseSpa"
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
Anyway, it looks like you've got that environment variable set to Production, which should just serve the built files from the ClientApp\dist folder (rather than forwarding to the dev server) that suggests that if you see the Angular, then the .Net Core service is running... I'll try and rebuild the Dockerfiles first...
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
ENV ASPNETCORE_URLS=https://+:5001;http://+:5000
WORKDIR /app
EXPOSE 5000
EXPOSE 5001
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt install -y nodejs
WORKDIR /src
COPY ./src/WebUI/WebUI.csproj src/WebUI/
COPY ./src/Application/Application.csproj src/Application/
COPY ./src/Domain/Domain.csproj src/Domain/
COPY ./src/Infrastructure/Infrastructure.csproj src/Infrastructure/
RUN dotnet restore "src/WebUI/WebUI.csproj"
COPY . .
WORKDIR "/src/src/WebUI"
RUN dotnet build "WebUI.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebUI.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "CleanArchitecture.WebUI.dll"]
Then build and run as follows:
# build takes a while
docker build -f ./src/WebUI/Dockerfile -t clean-architecture .
# note, this fails first time, because I set up as clean_architecture so the entry point is incorrect
docker run --rm -it -p 5000:5000 -p 5001:5001 clean-architecture
# run the container and override the entrypoint
docker run --rm -it --entrypoint /bin/bash clean-architecture
# From within the container...
root#93afb0ad21c5:/app# dotnet clean_architecture.WebUI.dll
# note, in .Net 3.1, you can also do this directly, as follows:
root#93afb0ad21c5:/app# ./clean_architecture.WebUI
Now there is a problem with LocalDB: System.PlatformNotSupportedException: LocalDB is not supported on this platform.
Switch appsettings.Production.json to be "UseInMemoryDatabase": true
The problem then appears to be certificates...
I created a certificate using:
dotnet dev-certs https -ep ./https/clean-arch.pfx -p anything
For IdentityServer, I change appSettings.Production.json as follows:
"IdentityServer": {
"Key": {
"Type": "File",
"FilePath": "/app/https/https/clean-arch.pfx",
"Password": "anything"
}
}
and then running on Linux, probably means running Kestrel, which means we need to provide HTTPS certs there too, which I did by setting the following in Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel((context, options) =>
{
options.AllowSynchronousIO = true;
options.Listen(IPAddress.Loopback, 5000, listenOptions =>
{
listenOptions.UseConnectionLogging();
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2;
});
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.UseConnectionLogging();
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(new System.Security.Cryptography.X509Certificates.X509Certificate2("/app/https/https/clean-arch.pfx", "anything"));
});
});
webBuilder.UseStartup<Startup>();
});
At each stage I built the app in docker using...
\clean_architecture $ docker build -f ./src/WebUI/Dockerfile -t clean-architecture .
/clean_architecture $ docker run --rm -it -v /Users/monkey/src/csharp/clean_architecture/:/app/https/ -p 5000:5000 -p 5001:5001 --entrypoint /bin/bash clean-architecture
... and once running in bash (in docker), I used the following to start the application:
root#c5b4010d03be:/app# ./clean_architecture.WebUI
Good luck, hope that helps. Note, if it works in Docker, on your machine, it should work in Azure. I'll look at getting it going in Azure another day. Happy to upload my code to GitHub if it would help?
thanks to 0909EM for the huge effort in answering the question, but the solution was different.
I figured out what was going on. There are two issues.
The docer-compose.override.yml file looks like:
version: '3.4'
services:
webui:
environment:
- "ASPNETCORE_ENVIRONMENT=Development"
- "SpaBaseUrl=http://clientapp:4200"
clientapp:
image: ${DOCKER_REGISTRY-}clientapp
build:
context: src/WebUI/ClientApp
dockerfile: Dockerfile
depends_on:
- webui
restart: on-failure
db:
ports:
- "1433:1433"
notice the line dockerfile: Dockerfile in the src/webui/clientapp context. This dockerfile was overwriting the proper docker file in src/webui during the azure pipeline build. For some reason when I run the following command locally: docker-compose -f 'docker-compose.Production.yml' up --build it does not pull in the docker-compose.override settings, but the override settings do get used in the azure pipeline build.
Therefore, the angular dockerfile is the only one built and that image does not contain the .net core web api project. Which explains why I see the front end but cannot get to the api endpoints and also why the dockerfile has no .net core errors.
I was able to fix this in two ways.
First: rename the dockerfile in src/webui/clientapp to Dockerfile.clientapp and change the line in the docker.overrride file to dockerfile: Dockerfile.clientapp
SECOND: just remove the docker override file from the online repository that the azure pipeline pulls from.
As a result the proper dockerfile is used and the web api project is in the image.
The second issue: Now that the proper image is running, the .net core web api throws an error about loading the cert for identity server. This confirms my suspicion. Because this issue is not related to my original question about getting the web api running in the container, i have opened another question about it.

Cannot access asp .net core app when run with docker on local machine, or to kubernetes

I have a very simple asp.net core app (C# Web Application with Docker Support for Linux) and when i build the docker image and try to run it on my local PC the following happens;
In docker with my image called test, i type docker run test, at which point it states "Content root path: /app Now listening on: http://[::]:80"
And even though when i type docker ps i can see the process running, when i try to navigate to localhost:80 all i get is a long wait and then "This site can’t be reached, localhost refused to connect."
I typed
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ec158cc3b344
which gave me the containers IP address, but even navigating directly to the container i either get "This site can’t be reached
" if i navigate on port 80, or "Your connection was interrupted" if i try to access the IP directly.
I also tried to step over docker completely and deploy the image to Kubernetes to see if this would give me any luck, but instead when i try to access the services External-IP (In this case localhost), i get the following
"This page isn’t working, localhost didn’t send any data."
I also tried to use
kubectl get pods -o wide
and access the IP's of the pods directly, but this just gives me "This 10.1.0.32 page can’t be found", for example.
And incase you're wondering, this is my dockerfile and kubernetes deployment .yml
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["Test/Test.csproj", "Test/"]
RUN dotnet restore "Test/Test.csproj"
COPY . .
WORKDIR "/src/Test"
RUN dotnet build "Test.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "Test.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Test.dll"]
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
replicas: 3
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: test
image: <DockerEndpoint>.io/test:v5 #Sorry, can't include the real endpoint!
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: test
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: test
I also understand that .net core work in weird way that don't allow it to expose its ports to the outside world unless you tell it to, but that combined with my relative newness to the docker/kubernetes stack and leaving me bewildered.
Does anybody have any idea how i can make a .net core app, any app, work with docker?
P.S. I am really using such a simple app that even if i create a brand new .net core app with docker support, and try to immediately build and run the basic .net core app, it doesnt work. i cannot make it work with literally any .net core app!
When it says listening on http://[::]:80, it's talking about localhost in the container. When you try to access it via http://localhost in your web browser running on your computer, localhost is your computer, not the container. You need to use the container's IP.
From your description, it sounds like you tried that as well, but there's no reason you should have any issues with that. You either didn't get the right IP or you did something else incorrect not detailed here.
You have 8080 as your target port for port forwarding, but your application is listening on port 80. Change the targetport setting to 80 and you should be able to connect to your containerized application as expected.
You may need to adjust the containerPort setting as well.

My docker-compose asp.net core project is not properly running, I get ERR_CONNECTION_REFUSED

I have a small web service that I wrote in asp.net core 2.2, Im using docker-compose for this project but I cant get it to work properly, everytime I try to run it I get the ERR_CONNECTION_REFUSED and it doesnt show my Swagger documentation. For now Im just using the self generated docker file from Visual Studio because I want to get at least my Swagger documentation so It doesnt show the ERR_CONNECTION_REFUSED error.
When I do docker ps it shows the following:
So I know the container is up and running.
My docker file:
FROM microsoft/dotnet:2.2-aspnetcore-runtime-stretch-slim AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.2-sdk-stretch AS build
WORKDIR /src
COPY AppointmentsAPI/AppointmentsAPI.csproj AppointmentsAPI/
RUN dotnet restore AppointmentsAPI/AppointmentsAPI.csproj
COPY . .
WORKDIR /src/AppointmentsAPI
RUN dotnet build AppointmentsAPI.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish AppointmentsAPI.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "AppointmentsAPI.dll"]
Docker-Compose file:
version: '3.4'
services:
appointmentsapi:
image: ${DOCKER_REGISTRY-}appointmentsapi
build:
context: .
dockerfile: AppointmentsAPI/Dockerfile
As you guys can see everything is self generated by visual studio, so it should work, I only want to be able to see my documentation or at least have it working and after that I will add the other things.
Try adding port 80 to Compose file. You are exposing port in dockerfile which will work with docker run -p 80:80 .... Using compose you need to map the port.
version: '3.4'
services:
appointmentsapi:
image: ${DOCKER_REGISTRY-appointmentsapi
build:
context: .
dockerfile: AppointmentsAPI/Dockerfile
ports:
- 80:80
you can Map 80 to whatever you want or let docker map it for you.
Let Docker map external port:
ports:
- 80
Map port 80 to external 3000
ports:
- 80:3000
UPDATE:
running VirtualBox and needed to use the VirtualBox IP rather than localhost.
Using the virtual box IP and adding port mapping to the compose file should resolve the issue.
the ports and the firewall, check it, because docker make a owns network

Categories