1

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?

Richard Collette
  • 5,462
  • 4
  • 53
  • 79
Arzu Suleymanov
  • 671
  • 2
  • 11
  • 33
  • That's what happens if you try to use Microsoft software in a container. The go application, if it's on alpine, will produce a container that's a couple of hundred kilobytes in size. The MS app must be upwards of 2GB. That's going to take a long time just to move around the network, let alone build. MS is slow and bloated and should be avoided at all cost :) Having said that, 7 minutes isn't bad -- is this a real operational concern? – Software Engineer Apr 06 '20 at 15:39
  • @SoftwareEngineer I don't know maybe possible to reduce time using some small images from docker.hub maybe I am not using correct ones. – Arzu Suleymanov Apr 06 '20 at 15:49

1 Answers1

4

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
Richard Collette
  • 5,462
  • 4
  • 53
  • 79