Docker container on raspberry with linux/arm64 - c#

I have the next docker file
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Pitman.csproj", ""]
RUN dotnet restore "./Pitman.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "Pitman.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Pitman.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Pitman.dll"]
and I'm running the build command:
docker buildx build --platform linux/arm64 -t latest .
tagging and pushing the image to docker hub
docker tag 8986ff79cb02 myid/pitman:latest
docker push myid/pitman
downloading the image on raspberry pi:
sudo docker pull myid/pitman:latest
and when I run the image
sudo docker run 8986ff79cb02
I get the next error:
standard_init_linux.go:211: exec user process caused "exec format error"
after building the image on my rpi I get this
Step 6/15 : RUN dotnet restore "./Pitman.csproj"
---> Running in 8562957be5d6
standard_init_linux.go:211: exec user process caused "exec format error"
The command '/bin/sh -c dotnet restore "./Pitman.csproj"' returned a non-zero code: 1
what am I missing?

This is the base image you're using for the final docker image:
mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim
That image only supports amd64 (not ARM). You need to choose another base image that either supports ARM-only or multi-arch (amd64 + arm64). For example, "latest" and "3.1.8" at time of writing are multi-arch.
I know for a fact that if you build an image on ARM (with an ARM base image) it will be able to run on any ARM system. I've never done multi-arch builds before, so I don't know if choosing a multi-arch base image, building on amd64, then trying to run on arm64, will work (but based on your comment it sounds like it did).

Related

How can I run a Docker container made for use in Heroku, in a localhost in my computer?

I have a docker image with a simple .net core API built in it, it works fine when I push it to heroku, but I am having troubles setting it to run in my localhost to test it locally.
I have this line in my Dockerfile
CMD ASPNETCORE_URLS=http://*:$PORT dotnet test-api.dll
But I can't make it run in "localhost:7050"
I am running the image with the following command
docker run -e PORT=7050 --rm --name api-container test-api
The problem is, it runs fine, but in a strange location, it says Now listening on: http://[::]:80
And I can't access that URL.
Of course, I can just do a simple dotnet run, and test it in the port configured, but I would like to test running a container in my computer, if that makes any sense.
The full Dockerfile is bellow, if it helps
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY . .
RUN dotnet restore
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish
RUN dotnet publish --no-restore -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
# Padrão de container ASP.NET
# ENTRYPOINT ["dotnet", "CarterAPI.dll"]
# Opção utilizada pelo Heroku
CMD ASPNETCORE_URLS=http://*:$PORT dotnet testeApi.dll

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.

docker ASP.net web API 6.0 build - the type or namespace name could not be found

Im trying to make an ASP.NET API (.NET 6.0) that runs in docker.
I made the project with build in docker support from visual studio and set it to linux.
Also I included an custom assembly with functions i want to use abroad multiple applications.
Whenever I build the project in debug mode it works fine and starts up my project.
The build command:
docker build -f "C:\Users\USER\source\repos\PROJECT\PROJECT\Dockerfile" --force-rm -t PROJECT:dev --target base --label "com.microsoft.created-by=visual-studio" --label "com.microsoft.visual-studio.project-name=PROJECT" "C:\Users\USER\source\repos\PROJECT"
But whenever i start it in release mode it gets rid of the "--target base" flag in the docker build command and gives me the error "The type or namespace name could not be found" of that assembly i try to include.
Also when i try a simple:
docker build -t /Dockerfile .
Gives me the same error.
My Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS base
WORKDIR /app
EXPOSE 443
ENV ASPNETCORE_URLS=http://+:443
FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
WORKDIR /src
COPY Project* .
RUN dotnet restore "Project.csproj"
COPY . .
RUN dotnet build "Project.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Project.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Project.dll"]

How to lower down the size of dockerized .Net Core apps?

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.

How can I reduce the build time for a .NET Core application using Docker and Kaniko?

I have following Dockerfile in my .NET Core 2.2 console application.
FROM mcr.microsoft.com/dotnet/core/runtime:2.2-stretch-slim AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["TaikunBillerPoller.csproj", ""]
RUN dotnet restore "TaikunBillerPoller.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "TaikunBillerPoller.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "TaikunBillerPoller.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "TaikunBillerPoller.dll"]
My .dockerignore file looks like
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.vs
**/.vscode
**/*.*proj.user
**/azds.yaml
**/charts
**/bin
**/obj
**/Dockerfile
**/Dockerfile.develop
**/docker-compose.yml
**/docker-compose.*.yml
**/*.dbmdl
**/*.jfm
**/secrets.dev.yaml
**/values.dev.yaml
**/.toolstarget
We are using GitLab and Kaniko for building gitlab-ci.yml file.
This console application takes 7 minutes to build, but another application written in the Go language takes 40 seconds.
How might I reduce the build time for this application?
Your first FROM line is completely unused. Instead change your FROM base line to FROM mcr.microsoft.com/dotnet/core/runtime:2.2-stretch-slim
This issue may be due to the fact that Kaniko **/someDir .dockerignore patterns are not properly observed. I'm noticing that /obj, /bin, .idea (rider) and .git folders are all being copied.
https://github.com/GoogleContainerTools/kaniko/issues/1396
You are also not using the alpine based sdk and runtime images.
In the dotnet restore command you can use the --no-cache flag because docker layer cacheing will take care of that.
dotnet publish does a build so you can skip calling dotnet build. If you want to perform testing you can call dotnet test then
You are explicitly calling dotnet restore so in all subsequent dotnet commands you can use the --no-restore option.
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS base
#Add whatever tools you need to the base image
RUN apk add --update --no-cache git bash curl zip; \
export PATH="$PATH:/root/.dotnet/tools"; \
dotnet tool install --global dotnet-xunit-to-junit --version 1.0.2
FROM base AS restore
WORKDIR /src
COPY ["TaikunBillerPoller.csproj", ""]
RUN dotnet restore --no-cache "TaikunBillerPoller.csproj"
COPY . .
FROM restore as publish
ARG VERSION="0.0.0"
RUN dotnet test "TaikunBillerPoller.csproj" --configuration Release --no-restore
RUN dotnet publish "TaikunBillerPoller.csproj" --output /app --configuration Release --no-restore /p:Version=$VERSION
FROM mcr.microsoft.com/dotnet/core/runtime:2.2-alpine AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "TaikunBillerPoller.dll"]
On a 2015 Mac I have an asp.net microservice that builds, tests, publishes and creates a beanstalk_bundle zip using a normal docker build with the following times:
51s No cache
22s Code change
<1s No code change (pipeline yml change)
Kaniko adds overhead because layer caching is done remotely to some repository (typically).
This time is going to depend a lot on how you have your Kaniko cache and mounted volumes configured. Here is something I use on my local machine for debugging.
#!/bin/bash
# Assuming this is either not an ephemeral machine, or the ephemeral machine
# maps the cache directory to permanent volume.
# We cache images into the local machine
# so that the Kaniko container, which is ephemeral, does not have to pull them each time.
docker run -v $(pwd):/workspace gcr.io/kaniko-project/warmer:latest \
--cache-dir=/workspace/cache \
--image=mcr.microsoft.com/dotnet/core/sdk:2.2-alpine \
--image=mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine
docker run -it --rm \
-v `pwd`:/workspace \
-v `pwd`/kaniko-config.json:/kaniko/.docker/config.json:ro \
-v `pwd`/reports:/reports \
-v `pwd`/beanstalk_bundle:/beanstalk_bundle \
gcr.io/kaniko-project/executor:latest \
--dockerfile "buildTestPublish.Dockerfile" \
--destination "registry.gitlab.com/somePath/theImageName:theVersion" \
--skip-unused-stages \
--cache \
--cache-dir=/workspace/cache \
--verbosity=trace

Categories