Beginner’s Guide to Docker – Part 3 - Debugging a Docker Build (Continued)

October 24, 2021

In this post I starting a series on getting started with Docker; here, I’m going to expand to give some tips on how to debug a docker build when even the build itself is failing.

Imagine that you’re trying to debug a docker build script, and you keep getting build errors. The script never completes, and so you can’t attach to the running container (as shown here).

In this case, there are still a few options available. Let’s consider the following build script:




FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["pcm-test.csproj", "pcm-test/"]
RUN dotnet restore "pcm-test/pcm-test.csproj"
COPY . .
WORKDIR "/src/pcm-test"

RUN dotnet build "pcm-test.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "pcm-test.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "pcm-test.dll"]


When I run this (it’s a console app, btw), I get the following build error:



 => ERROR [build 10/10] RUN dotnet build "pcm-test.csproj" -c Release -o /app/build

#18 0.790 Microsoft (R) Build Engine version 17.0.0-preview-21501-01+bbcce1dff for .NET
#18 0.790 Copyright (C) Microsoft Corporation. All rights reserved.
#18 0.790
#18 1.351   Determining projects to restore...
#18 1.623   All projects are up-to-date for restore.
#18 1.703   You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
#18 2.897 CSC : error CS5001: Program does not contain a static 'Main' method suitable for an entry point


I can absolutely assure you that the program does have a main method.

Debugging

When a build goes wrong, I’ve determined two ways to debug - the first is by simply executing debug commands inside the build, and the second is to reduce the build until it works, and then inspect the image.

Executing Debug Commands

Since you can run any command inside a build file, you can simply do something like this:



RUN ls -lrt

Remember that if you do this, you’ll need to change a couple of settings:

—progress

This can be set to auto (default), plain, and tty.

tty (or interactive terminal) and auto will compress the output; whereas plain will show all the container output (including these kind of debug messages.

—no-cache

Docker tries to be clever, and cache the commands that have already executed; however, for debug statements, this is going to mean that they’ll only ever fire the first time. It tells you when it’s executing these from the cache:

docker



docker build -t pcm-test --no-cache --progress=plain .

Sometimes, executing these statements is enough; however, sometimes, it helps to build a partial image.

Removing the breaking parts of the build

When I first started writing software, on a ZX Spectrum - I’d frequently copy (BASIC) code out from a magazine. I didn’t really know what I was writing, so if it didn’t work it would give me an error that I didn’t understand; however, it would tell me the offending line number, and so I’d simply remove that line. Obviously, subsequent lines would then start to fail, and typically, I’d end up with a program that ended at the first typing (or printing) error. This didn’t make for a very good game.

This isn’t true in docker - if you remove the offending code, you can still create an environment, explore it, and even manually execute the rest of the build inside the environment, to see what’s going wrong!




FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["pcm-test.csproj", "pcm-test/"]
RUN dotnet restore "pcm-test/pcm-test.csproj"
COPY . .
WORKDIR "/src/pcm-test"

#RUN dotnet build "pcm-test.csproj" -c Release -o /app/build
#
#FROM build AS publish
#RUN dotnet publish "pcm-test.csproj" -c Release -o /app/publish
#
#FROM base AS final
#WORKDIR /app
#COPY --from=publish /app/publish .
#ENTRYPOINT ["dotnet", "pcm-test.dll"]

This will now create an image, and so we can run and attach to that image:



 docker run -it pcm-test sh

I can now have a look around the image:

docker

As you can see, this looks a bit strange - there’s no code there.

Summary

In this post, I’ve covered two techniques to work out why your docker build may be failing.



Profile picture

A blog about one man's journey through code… and some pictures of the Peak District
Twitter

© Paul Michaels 2024