I am new to Docker and going through documentation and Pluralsight videos. I have a really simple API I am practising/learning to run as a docker container. Everything builds and runs but it doesn't respond to postman request.
However when I run the project in VS 2019 it responds to Postman.
Docker desktop 4.X Linux containers
VS 2019
API:
[HttpGet("basic")]
[AllowAnonymous]
public IActionResult Basic()
{
return Ok("Alive");
}
Postman:
GET
http://localhost:5150/HealthCheck/basic
Docker Compose:
version: "3"
services:
api:
#snipped container name etc for brevity
ports:
- "5150:5150"
networks:
- backend
networks:
backend:
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base
WORKDIR /app
EXPOSE 5150
#snipped brevity
ENTRYPOINT ["dotnet", "TestingDocker.API.dll"]
Launch settings
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5150/",
"sslPort": 0
}
},
Compose output:
[12:49:29 INF] Now listening on: http://[::]:80
I don't understand where it gets the port 80 from.
Docker Desktop
Running Port:5150
Docker Inspect on the image
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"ASPNETCORE_URLS=http://+:80",
"DOTNET_RUNNING_IN_CONTAINER=true",
"DOTNET_VERSION=5.0.10",
"ASPNET_VERSION=5.0.10"
],
I read something in troubleshooting this about how Windows Docker Desktop hyper-v's have their own IP address so I tried to find that and see if that would respond but all I could find was the entire subnet defined in docker desktop settings. 192.168.65.0/24
When I look at the hyper v virtual nic configs they have an ip of a totally different subnet. 172.19.240.1
So then I pulled a Mongo image and it DOES respond. When I run inspect on it the only network related difference I can see it that Mongo has a hostname.
So I'm sure it is something with my network settings but I can't figure it out.
Edit
Per Camilo's comment I added back the Entrypoint I had tried earlier.
ENTRYPOINT ["dotnet", "DockerTest.API.dll", "--server.urls", "http://0.0.0.0:5150"]
I thought 0.0.0.0 was a wildcard ip binding but that didn't work so I switched to suggested
ENTRYPOINT ["dotnet", "DockerTest.API.dll", "--urls", "http://+:5150"]
And that worked!!
One thing to note. All these tiny little changes didn't seem to be getting picked us as supposedly a new image was building in like .03 seconds. So to be sure my changes throughout this process were being picked up I used
docker-compose build --no-cache
docker-compose up -d --force-recreate
You have an environment variable like:
"ASPNETCORE_URLS=http://+:80"
That one is created automatically by ASP.NET Core when it's not given any specific URL to use, which is the case in this question.
Your confusion probably comes from the launch.settings.json file, which appears to be configuring the app to run on port 5150, but that is not correct for 2 reasons:
The file is only for Visual Studio debugging, and it's not published with the application, and
Even if the file was used, you're configuring the iisExpress settings, and IIS Express doesn't exist on Linux.
You have a few ways to solve this issue:
Add a Docker map for the port, as mentioned by #OneCricketeer, by using 5150:80.
Specify the URL to use as part of the ENTRYPOINT:
ENTRYPOINT ["dotnet", "DockerTest.API.dll", "--urls", "http://+:5150"]
As well as others, as specifying the URLs directly in your Program, when building the WebHost.
Those logs are internal to the container. It's not clear how you've told your server to run on 5150, but EXPOSE doesn't change the code behavior, and there appears to be this ASPNETCORE_URLS environment variable which controls the server binding, and you've not overridden this anywhere
If you simply want to use localhost:5150, with no other changes, you would need to use 5150:80 as your compose ports definition
Related
I got stuck on this for quite some time and i don't know why it doesn't work.
I looked into posts similair to mine but i can't fix it, (tried checking the firewall settings, using different ports).
I have a Dockerfile that looks like this:
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
COPY bin/Release/net6.0/publish/ App/
WORKDIR /App
ENTRYPOINT ["dotnet", "MonitorApplication1.dll"]
The application is a simple REST API with C# .NET Core 6. The database is a MS SQL Server Database.
The image and container seem fine but when i try to view it in the browser (using Chrome as standard, but also tried Edge) i get the ERR_EMPTY_RESPONSE error.
The log of the container (using Docker Desktop) only shows this:
{"EventId":14,"LogLevel":"Information","Category":"Microsoft.Hosting.Lifetime","Message":"Now listening on: http://[::]:80","State":{"Message":"Now listening on: http://[::]:80","address":"http://[::]:80","{OriginalFormat}":"Now listening on: {address}"}}
Update
I tried to create a new .NET 6 API with Docker Enabled but when i tried to run the container i still get the Error Empty Response.
I solved a similar problem by adding the ASPNETCORE_URLS environment variable, like this:
ENV ASPNETCORE_URLS=http://*:5000
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.
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.
In my .net core 2 application, I have files
appsettings.Development.json
appsettings.Staging.json
Application is dockerized and I have a docker-compose.yml with corresponding docker-compose.override.yml.
Inside docker-compose.override.yml I have ports and Staging related things using ENV variables
serviceone:
environment:
- ASPNETCORE_ENVIRONMENT=Staging
- ASPNETCORE_URLS=http://0.0.0.0:5500
ports:
- "5500:5500"
This works perfectly so far, cause I had only one dockerize env (Staging), Development one I use only for debugging locally. Now I want to introduce support for QA by having another docker image for QA.
I'll put appsettings.QA.json in the solution and my question is:
Should I create another docker-compose.overrideSTAGING.yml (or what's the naming convention here) and how will docker-compose know about it's existence?
Currently, I'm using docker-compose up --build from cli
Should I create another docker-compose.overrideSTAGING.yml (or what's the naming convention here) and how will docker-compose know about it's existence?
Compose only includes docker-compose.yml and docker-compose.override.yml files, by default.
You should use the -f option to include files with different names.
See explanation here.
I'm trying to get a service on-boarded to Docker containers.
Target Framework - .NET Framework 4.6.1
Output type - Console Application
When I initially tried to right click -> Add -> Docker Support on the project in the Visual Studio 2017 sln I got a prompt "You cannot add Docker support to this project type"
I went ahead and created a Dockerfile by hand and placed it in the root. This is what it looks like:
FROM microsoft/windowsservercore
SHELL ["powershell", "-command"]
RUN Add-WindowsFeature NET-Framework-45-ASPNET, Web-Asp-Net45
EXPOSE 80
EXPOSE 5000
EXPOSE 13134
ADD ./bin/Debug/net461/win7-x64 .
COPY ./bin/cert-that-needs-to-be-installed.pfx /cert-that-needs-to-be-installed.pfx
RUN $Secure_String_Pwd = ConvertTo-SecureString "thePasswordToTheCert!" -AsPlainText -Force; \
Import-PfxCertificate -FilePath .\cert-that-needs-to-be-installed.pfx -CertStoreLocation Cert:\LocalMachine\My -Exportable -Password $Secure_String_Pwd;
ENV ASPNETCORE_ENVIRONMENT="Development"
ENTRYPOINT ["./ServiceName.exe"]
Upon doing the following, I was able to successfully create an image and also a container with the service running on it: (the prod version listens on port 5000 while the test one listens on 13134 and those ports are also open in my localhost Firewall)
docker build -t ServiceName .; docker run -p 5000:5000 -p 13134:13134 -it ServiceName
I am able to get the ip of the container by doing this:
docker inspect <containerId>
Now when I try to test the service by doing a HttpGet call to an API using Postman I don't get a response. I have the docker container open in my cmd prompt and I don't see my request coming in either.
My service works fine on a Windows VM.
Since my GET calls don't even seem to reach the container I fear I am doing the port mapping wrong/or is it something else?
From what I know you don't need the ip of the container, the ports have been projected on your localhost, you should get a response when you make REST calls to localhost:5000/localhost:13134