I've a .net / c# aspnet core application which connects to a MongoDb Atlas Cloud database.
When running localy every thing works fine.
Now i put the application inside a alpine docker image the application the connection fails.
I got some various exceptions pointing out that the authentication doesn't work.
Here my DockerFile which builds and runs the application
FROM microsoft/dotnet:2.1-sdk-alpine AS builder
WORKDIR /
COPY . .
RUN dotnet publish Api/Api.csproj -o /dockerout/ -c Release
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime-alpine
WORKDIR /app
EXPOSE 80 5000
RUN apk update
COPY --from=builder /dockerout .
ENTRYPOINT ["dotnet", "Api.dll"]
After a lot of research I found an Issue pointing me to the root cause:
https://github.com/dotnet/corefx/issues/9608#issuecomment-401370142
Because it took me a lot of time I'll answer my own question hoping someone is saving the time.
There two possible solutions are
a) don't use a alpine image
b) update the openssl package when building the image by adding open ssl like this apk add --no-cache openssl
Full DockerFile that solved it for me:
FROM microsoft/dotnet:2.1-sdk-alpine AS builder
WORKDIR /
COPY . .
RUN dotnet publish Api/Api.csproj -o /dockerout/ -c Release
FROM microsoft/dotnet:2.1.3-aspnetcore-runtime-alpine
WORKDIR /app
EXPOSE 80 5000
RUN apk update && apk add --no-cache openssl
COPY --from=builder /dockerout .
ENTRYPOINT ["dotnet", "Api.dll"]
Related
I'm running into an issue using Docker and couldn't find a proper solution.
I'm trying to build a Docker image using .NET SDK 2.1.
The thing is that when Docker tries to run the build statement, it fails and the error output is
CSC : error CS5001: Program does not contain a static 'Main' method
suitable for an entry point
The funny thing is that if I perform the build statement on command line locally, it works fine.
I have already checked my LanguageVersion tag on the project and it is 7.3.
Here is my Docker file
FROM microsoft/dotnet:2.1-sdk AS builder
WORKDIR /src
COPY ./nuget ./nuget
COPY ./NuGet.Config ./
COPY Services/AadTracking ./
# Copy all the referenced projects
COPY ./Services/AadTracking/Company/Company.Service.AadTracking/Company.Service.AadTracking.csproj ./AadTracking/Company/Company.Service.AadTracking/Company.Service.AadTracking.csproj
COPY ./Services/AadTracking/Office.Re.Service.AadTracking/Office.Re.Service.AadTracking.csproj ./AadTracking/Office.Re.Service.AadTracking/Office.Re.Service.AadTracking.csproj
COPY ./Services/AadTracking/Company/Office.Re.Service.AadTracking.Company/Office.Re.Service.AadTracking.Company.csproj ./AadTracking/Company/Office.Re.Service.AadTracking.Company/Office.Re.Service.AadTracking.Company.csproj
COPY ./Services/AadTracking/Office.Re.Service.AadTracking.EventStore/Office.Re.Service.AadTracking.EventStore.csproj ./AadTracking/Office.Re.Service.AadTracking.EventStore/Office.Re.Service.AadTracking.EventStore.csproj
# Restore packages
RUN dotnet restore "./AadTracking/Company/Company.Service.AadTracking/Company.Service.AadTracking.csproj"
RUN dotnet build -c Debug --no-restore "./AadTracking/Company/Company.Service.AadTracking/Company.Service.AadTracking.csproj"
# COPY source code
#aad tracking
COPY ./Services/AadTracking/Company/Company.Service.AadTracking ./AadTracking/Company/Company.Service.AadTracking/
COPY ./Services/AadTracking/Office.Re.Service.AadTracking ./AadTracking/Office.Re.Service.AadTracking/
COPY ./Services/AadTracking/Company/Office.Re.Service.AadTracking.Company ./AadTracking/Company/Office.Re.Service.AadTracking.Company/
COPY ./Services/AadTracking/Office.Re.Service.AadTracking.EventStore ./AadTracking/Office.Re.Service.AadTracking.EventStore/
# Publish
RUN dotnet publish "./AadTracking/Company/Company.Service.AadTracking/Company.Service.AadTracking.csproj" -c Debug -o "../../dist"
# #Build the app image
FROM microsoft/dotnet:2.1-aspnetcore-runtime
WORKDIR /app
ENV ASPNETCORE_ENVIRONMENT Switch
ENV REINSURANCE_INSTANCE Docker-dev
COPY --from=builder /dist .
ENTRYPOINT ["dotnet", "Company.Service.AadTracking.dll"]
Thanks for your help!
I know this is little bit late to answer. Still VS 2019 has the same issue with .NET Core 3.1. I took a peek at the examples provided by Microsoft. Turns out the Docker file resided in a different place in the solution and Docker copy command wasn't working properly.
You have to move your docker file one directory up, so that they are at the same level as the sln file. It will fix the issue.
OR else you can change the paths like below sample docker file WITHOUT changing the docker file location, IMHO it is better to keep the docker file with other files.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim-arm64v8 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["WhatzThat.Web.csproj", "WhatzThat.Web/"]
RUN dotnet restore "WhatzThat.Web/WhatzThat.Web.csproj" -r linux-arm64
WORKDIR "/src/WhatzThat.Web"
COPY . .
RUN dotnet build "WhatzThat.Web.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WhatzThat.Web.csproj" -c Release -o /app/publish -r linux-arm64 --self-contained false --no-restore
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WhatzThat.Web.dll"]
I had the same issue.
I've realized that I had my Docker file at the same level of my .csproj file. I've moved my Docker file one level up in my folder structure and it's building fine.
Compiling and publishing an application inside docker will need entire application to be copied inside docker.
which means you need to copy all class files(.cs) along with required supporting files(maybe resx or config files) inside docker.
please find below reference for same
https://github.com/aspnet/aspnet-docker/issues/401
Using a multi-project solution structure, I fixed by adding "src" again into the directory to build.
Something like this:
COPY ["src/Todo.Core/Todo.Core.csproj", "Todo.Core/"]
RUN dotnet restore "Todo.Api/Todo.Api.csproj"
COPY . .
WORKDIR "/src/Todo.Api/"
RUN dotnet build "Todo.Api.csproj" -c Release -o /app/build
Turned into this:
COPY ["src/Todo.Core/Todo.Core.csproj", "Todo.Core/"]
RUN dotnet restore "Todo.Api/Todo.Api.csproj"
COPY . .
WORKDIR "/src/src/Todo.Api/"
RUN dotnet build "Todo.Api.csproj" -c Release -o /app/build
2023 Update
Unfortunately, there is an inconsistency in what Microsoft includes in Dockerfile and in which directory you run it.
There are three solutions to get this work.
First Solution
Put your auto-generated Dockerfile one level up, alongside the .sln file.
From the root directory of the solution, run the below command
docker build -t imagename .
Second Solution
Leave the Dockerfile as it is, inside your project folder.
From the root directory of the solution, run the below command
docker build -t imagename -f .\SampleProject\Dockerfile .
Third Solution
Make small changes to the Dockerfile. Now you have to run docker commands not from the root directory of the solution, but from your project folder. (one level down from .sln file).
Change from below
to
Supplementary
My DockerFile is at root level not upper and I changed the DockerFile to:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
#For more information, please see https://aka.ms/containercompat
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["projectName.csproj", "projectName/"]
RUN dotnet restore "projectName/projectName.csproj"
WORKDIR "/src/projectName"
COPY . .
RUN dotnet build "projectName.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "projectName.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "projectName.dll"]
For me the COPY.. was after the workdir before the dotnet build command. I just put it after the workdir command. Then it was working.
WORKDIR "/src/WeatherAPI"
COPY . .
RUN dotnet build "WeatherAPI.csproj" -c Release -o /app/build
I have a faux pas reason.
My docker file.......I was correctly copying the directory structure and the .sln and .csproj files...........
But I had a syntax error copying the SOURCE files. (.cs files, etc, etc)
#doh!
If you look at the question above, basically I had a syntax-error/bug in the steps right below where the OP has this:
# COPY source code
More importantly, how did I figure this out ??? Here ya go:
docker images
and you do not want to drill into the last one (which is your failing image), but the NEXT TO LAST image. (remembering that docker keeps making new images for the steps of the docker file)
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mything1/mything2 latest aaaaaaaaaaaa 27 minutes ago 271MB
<none> <none> bbbbbbbbbbbb 27 minutes ago 1.18GB
and then drill into (the next to last one)
docker run --rm -it bbbbbbbbbbbb sh
when you get in there, start using "ls" and "cd" commands.
I found out I didn't have my .cs source files in the right place. A few fixes addressing relative-path issues (in my specific case) later......I had my source files in the right place(s). #yay
This is a great in-general tip for when trying to debug a failing non running image.
Answer by marvelTracker worked for me but busted using the built in Docker tools in Visual Studio 2022.
Using the command docker build -f Dockerfile .. while in the project folder builds the dockerfile from the perspective of the parent folder.
Microsoft Doc that explains building Docker in VS2022: https://learn.microsoft.com/en-us/visualstudio/containers/container-build?view=vs-2022
NOTE: I found this troubleshooting the same error for a .NET 6 Docker project.
Hopefully this helps someone else.
This error means that the file containing the Main method is NOT included so you either forgot to copy it over to the proper directory or docker is point to the incorrect directory.
From the folder having Dockerfile at present,
execute
mv Dockerfile ../
then invoke
docker build
I got same issue and manage to identify the root cause.
The issue occurred because I run the application on my windows machine before I build the docker Linux image.
Because I run it on my local windows it generate obj folder on the source code, the obj folder got copied to Docker container which contain windows specific assembly version IMHO.
To fix the issue I simply delete the obj folder from my project and rebuild the Docker.
Lesson learned, do build your Docker images on a freshly cloned repository.
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.
I normally use Rider for that but for reproduction purposes I will describe the process by using the terminal
I created a .Net 5 Web Api and want to add Docker support for it. I tried to get into it by playing around with a sample app. So with the terminal I create a new Web Api
mkdir project
cd project
dotnet new sln
dotnet new webapi -o Api
dotnet sln add ./Api
I check that everything is fine with
cd Api
dotnet run
call https://localhost:5001/weatherforecast in the browser
close with ctrl + c
Inside the Api project I create a Dockerfile with this content
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet
WORKDIR /app
EXPOSE 80
COPY --from=build /app/out .
ENTRYPOINT [ "dotnet", "Rest.dll" ]
I also create a .dockerignore file with this content
.git
Dockerfile
bin/
obj/
I'm building the image with
docker build -t api .
When I now run
docker images
this image has a size of 209MB. I would like to know if this is "the best/right way to go" or if there is something I can improve in the Dockerfile or .dockerignore file.
Thanks in advance
You can base your Dockerfile off a smaller image. Searching the catalogue of available images in the Microsoft container registry (MCR) here, the Linux alpine (5.0-alpine) is probably the most lightweight. Note that for the other distros, there may be a regular and slim variant, where the regular is the SDK environment and the slim is the production environment.
Then you can structure your Dockerfile as follows to move the artefacts from the build output in the SDK image to the final lightweight deployment image:
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base
WORKDIR /app
# Main build (SDK environment)
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
RUN dotnet restore "webapi.csproj"
COPY . .
WORKDIR "/src/webapi"
RUN dotnet build "webapi.csproj" -c Release -o /app/build
# Publish build outputs to /app dir
FROM build AS publish
RUN dotnet publish "webapi.csproj" -c Release -o /app/publish
# Final deployment image
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "api.dll"]
In my example, I've used the Debian buster SDK image for the build stage and the buster slim for deployment.
I have a dotnet project that work when i do dotnet run, i am trying to containerize that dotnet project.
For that i have create the Dockerfile as below:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
COPY bin/Release/netcoreapp3.1/publish/ App/
WORKDIR /App
EXPOSE 5000
CMD ["dotnet", "MediatorAgent.dll"]
Before creating the docker image i did run dotnet publish -c Release. Now when i try to run this docker image, i am getting the below error
Unhandled exception. System.DllNotFoundException: Unable to load shared library 'indy' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libindy: cannot open shared object file: No such file or directory
I am following the instruction for Containerize a .NET Core app for creating docker image.
How to create docker image for dotnet app?
Well, you did it.
What is likely to have gone wrong is that the DLL refered to as indy is not copied to the App folder.
Since you are copying the data, please verify it's included in the original build at bin/Release/netcoreapp3.1/publish
make sure bin/Release/ directory available in the same directory where your Dockerfile exist.
You can specify the project .csproj or .sln to build.
You can have a look on below dockerfile, hope that will help you.
FROM microsoft/aspnetcore-build AS builder
WORKDIR /source
COPY projectname.csproj .
RUN dotnet restore
RUN dotnet build projectname.csproj -c Release -o /app/build
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM microsoft/aspnetcore
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "projectname.dll"]
I just upgraded my Web API application to .NET core 3.0, all works fine when running in debug mode in IIS Express, but context does not respond when running in docker container either on server or in VS debug. No error thrown, just never responds.
I tried deploying an updated image to server which is where I first noticed the issue. I then tried running as docker in vs to debug.
I have updated all NuGet packages and set frameworks to .NET Core 3.0 or .NET Standard 2.1.
I have inspected the context connection string in debug and it appears to be correct. I rolled back to an earlier image using .NET core 2.2 and all worked as expected using the same startup parameters.
I created a test method that does not use context and it returns correct values on server and in VS docker debug.
I tried changing the method to use synchronous call to context, but no change in behavior.
The test database is very small, only 3 records in the table being queried.
public async Task<List<SendingSystemInfoResponse>> getSendingSystemInfoList()
{
try
{
return await _context.EmailSendingSystem.Where(m => !m.Deleted && m.Active == true).Select(m => new SendingSystemInfoResponse
{
SystemId = m.EmailSendingSystemId,
SystemName = m.Title,
SystemDescription = m.Description
}).ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, string.Format("EmailDataAccess: Exception retrieving EmailSendingSystem List"));
throw;
}
}
If there were an error connecting to the SQL Server, or if the SQL request timed out, I would expect to hit the catch block code, but this never happens.
Here is the content of the docker file, I'm not sure if my targets for base and build images are correct. They seem to work, but might be the cause of my issue.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY ["EmailAutomation.API/EmailAutomation.API.csproj", "EmailAutomation.API/"]
COPY ["EmailAutomation.API/NuGet.Config", "/src"]
RUN dotnet restore "EmailAutomation.API/EmailAutomation.API.csproj"
COPY . .
WORKDIR "/src/EmailAutomation.API"
RUN dotnet build "EmailAutomation.API.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "EmailAutomation.API.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "EmailAutomation.API.dll"]
------Update-----
So, I've been working on this off and on today, and have a little more info that might help someone point me in the right direction.
I created a simple test Web API project with an EF connection to SQL Server running on my local PC using .NET core 3.0 and the latest NuGet packages, and enabled TCP/IP connections to SQL Server running locally. I was able to get it to connect to the database and return values.
Next, I created a copy of the test database on my local SQL Server. This also worked, the Web API in the original question running in Docker connected and returned data.
I then changed the connection string to point back to the test SQL Server and the process hangs in the same spot with no error.
Next, I tested it with the connection still pointed to the test SQL Server but running in IIS Express rather than Docker. Again, everything worked as expected.
I then tried running the previous release docker image which uses .NET Core 2.2, and it also returned data from the test SQL Server.
What could be the reason that I can not connect via IP to the test SQL Server using .NET Core 3.0 in Docker when all other combinations work just fine.
------Update 2-----
I created the necessary database for my new simple test Web API project on the Test SQL Server, and changed the simple Web API project connection string. This new, clean, simple, .NET Core 3 project also did not connect to the Test SQL Server when running as Docker, but worked fine when running on IIS Express. It also worked fine when running in Docker but connecting to my local DB by IP.
Something has changed with .NET Core 3 in Docker that is stopping it from connecting to the external database server. Anybody have any ideas on what I need to do to resolve this?
--UPDATE 3 -----
Thanks to MATT! After reading Matt's response, I wasn't able to get the RUN commands to work within the docker file, but changing my base image to bionic did work. I have also been working with Microsoft support who also pointed me to the link that Matt provided.
Maybe I just didn't place the RUN commands in the right location, so if anyone can provide a sample docker file using the RUN commands to resolve this issue, I would be grateful.
Here is an updated docker file from a simple test project:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-bionic AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster 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"]
---Final Update -----
I tried the RUN commands in the docker file again, but got it right this time. Here is that version of the docker file.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app
RUN sed -i 's/DEFAULT#SECLEVEL=2/DEFAULT#SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT#SECLEVEL=2/DEFAULT#SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
EXPOSE 80
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster 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"]
I believe the issue you're running into is documented here: https://github.com/dotnet/SqlClient/issues/222. As you said, something did change with .NET Core 3 because those Docker images are based on Debian Buster by default. Buster is configured to use 1.2 as the minimum TLS protocol, a change from the previous version (see https://www.debian.org/releases/stable/amd64/release-notes/ch-information.en.html#openssl-defaults).
This can be temporarily fixed by adding the following to the Dockerfile:
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
This is not a great solution because it is essentially downgrading the version of TLS. The better long-term solution is to enable TLS 1.2 on the SQL Server (see https://support.microsoft.com/en-us/help/3135244/tls-1-2-support-for-microsoft-sql-server).