This guide covers various techniques to debug Docker image builds, from basic to advanced approaches.
BuildKit (the default builder in modern Docker) offers several powerful debugging options:
# Enable detailed debugging output
BUILDKIT_STEP_LOG_MAX_SIZE=-1 docker build .
# Continue build after error (buildx feature)
docker buildx build --progress=plain --on-error=continue .
# Print verbose output
docker buildx build --progress=plain .If you have a failing command like:
FROM busybox
RUN echo 'hello world' > /tmp/test
RUN exit 1 # problematic command
RUN echo 'ready'Simply remove the failing command and subsequent commands:
FROM busybox
RUN echo 'hello world' > /tmp/testTurn off BuildKit to see layer SHA:
DOCKER_BUILDKIT=0 docker build -t test .
# Use the SHA of the last successful layer
docker run --rm -it <sha> shFROM busybox
RUN echo 'hello world'
RUN sleep infinite # Add this for debugging
RUN exit 1# In terminal 1: Start the build
docker build -t test .
# In terminal 2: Enter the container's namespace
docker run -it --rm --privileged --pid=host justincormack/nsenter1
ps -ef | grep sleep
nsenter -p -m -u -i -n -t <PID> shdocker run --privileged --pid=host -it alpine \
nsenter -t 1 -m -u -n -i shFROM busybox as working
RUN echo 'hello world'
FROM working as error
RUN exit 1# Build specific target
docker build -t test --target working .
# Debug the working stage
docker run --rm -it test sh# Development stage with debugging tools
FROM ruby:3.2 as development
RUN apt-get update && \
apt-get install -y vim curl htop
# Production stage
FROM ruby:3.2-slim as production
COPY --from=development /app /app# Cache apt packages
RUN --mount=type=cache,target=/var/cache/apt \
apt-get update && apt-get install -y build-essential# Mount secrets during build
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecretHere's an improved version of the Rails Dockerfile with debugging considerations:
FROM ruby:3.2
# Install essential libraries
RUN --mount=type=cache,target=/var/cache/apt \
apt-get update && \
apt-get install -y \
libssl-dev \
postgresql-client \
nodejs \
npm
# Set working directory
WORKDIR /app
# Install debugging tools in development
ARG RAILS_ENV=development
RUN if [ "$RAILS_ENV" = "development" ]; then \
gem install debase ruby-debug-ide; \
fi
# Copy Gemfile and install dependencies
COPY Gemfile Gemfile.lock ./
RUN bundle install
# Install JavaScript dependencies
COPY package.json yarn.lock ./
RUN npm install -g yarn && yarn install
# Copy application code
COPY . .
# Start Rails server
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]-
Layer Caching
- Use multi-stage builds to separate build dependencies
- Order Dockerfile commands from least to most frequently changing
- Use .dockerignore to exclude unnecessary files
-
Debugging Tools
- Include debugging tools only in development stages
- Use BuildKit's cache mounts for package managers
- Leverage BuildKit's --progress=plain for detailed build output
-
Security
- Never leave debugging tools in production images
- Use secrets mounting for sensitive data
- Regular security scanning of base images
-
Bundle Install Failures
# Debug bundle install docker run --rm -it <image-id> bundle install --verbose
-
Permission Issues
# Fix permission problems RUN chown -R user:user /app USER user -
Network Issues
# Test network connectivity docker run --rm -it <image-id> ping -c 3 google.com
-
Docker Dive
# Analyze image layers dive <image-name>
-
Docker History
# View layer history docker history --no-trunc <image-name>
Remember to always clean up debugging artifacts before pushing to production:
# Remove debugging layers
docker image prune -f