How to Fix "Docker build slow on step RUN apt-get update"
Quick answer
The issue where a "Docker build is slow on step RUN apt-get update" occurs during image compilation when the Debian or Ubuntu package manager spends excessive...
The issue where a "Docker build is slow on step RUN apt-get update" occurs during image compilation when the Debian or Ubuntu package manager spends excessive time fetching package indexes from default remote mirrors. This delay stems from slow geographical mirror routing, un-cached package list downloads across builds, IPv6 timeout retries, or redundant layer invalidation. Optimizing repository mirrors, enabling BuildKit cache mounts, and structuring layer caching cuts build times drastically.
The Problem
When running docker build, the build process hangs or progresses at extremely low download speeds (e.g., bytes per second) during the apt-get update step:
#7 [2/5] RUN apt-get update && apt-get install -y curl
#7 0.512 Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
#7 15.23 Get:2 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
#7 45.89 Get:3 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
#7 120.4 Ign:1 http://deb.debian.org/debian bookworm InRelease...
#7 210.8 Fetching package indexes takes over 5 minutes...
In automated CI/CD environments, slow mirror responses can trigger runner timeouts, failing builds with connection errors:
Err:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Could not connect to archive.ubuntu.com:80 (91.189.91.38), connection timed out
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dests/jammy/InRelease Could not connect to archive.ubuntu.com:80
Why It Happens
The apt-get update command downloads package repositories from remote HTTP mirrors every time Docker invalidates the layer cache. Common bottlenecks include:
- S3 / Mirror Geographic Latency: Default distribution mirrors (like
deb.debian.orgorarchive.ubuntu.com) route traffic to distant, overloaded geographical mirrors. - IPv6 Network Timeouts: APT attempts to connect via IPv6 by default. If your network or Docker daemon lacks full IPv6 routing, APT hangs for 30-60 seconds waiting for connections to time out before falling back to IPv4.
- No APT Package Caching: Docker builds execute in clean ephemeral layers, forcing APT to re-download package lists from scratch on every cache invalidation.
- Layer Cache Invalidation: Ordering
COPY . .beforeRUN apt-get updateinvalidates the layer cache on every local file edit.
The Fix
Implement these optimizations to drastically reduce build times during the package update phase.
Step 1: Force APT to use IPv4
Prevent long network timeouts by forcing APT to resolve repositories over IPv4 only. Add an APT configuration option inside your Dockerfile before running apt-get update:
RUN echo 'Acquire::ForceIPv4 "true";' > /etc/apt/apt.conf.d/99force-ipv4 && apt-get update && apt-get install -y --no-install-recommends curl git && rm -rf /var/lib/apt/lists/*
Step 2: Use fast local or regional mirrors
Replace slow default Ubuntu/Debian archive mirrors with faster, geographically closer mirrors (like Cloudflare or official fast mirrors) using sed:
# For Debian base images
RUN sed -i 's/deb.debian.org/debian.map.fastly.net/g' /etc/apt/sources.list.d/debian.sources && apt-get update && apt-get install -y --no-install-recommends curl
# For Ubuntu base images
RUN sed -i 's/archive.ubuntu.com/ports.ubuntu.com/g' /etc/apt/sources.list && apt-get update && apt-get install -y --no-install-recommends curl
Step 3: Enable BuildKit APT Caching (Recommended)
Docker BuildKit supports persistent package cache mounts across builds using --mount=type=cache. This retains downloaded APT packages across build runs without baking package lists into the final image size:
# syntax=docker/dockerfile:1
FROM ubuntu:22.04
# Enable persistent caching for apt archives and lists
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=cache,target=/var/lib/apt,sharing=locked apt-get update && apt-get install -y --no-install-recommends build-essential curl git
Step 4: Optimize Dockerfile layer order
Ensure system dependency installations are placed at the very top of your Dockerfile, before copying application source code. This ensures apt-get update is cached indefinitely until you alter the actual dependency list:
FROM node:20-slim
WORKDIR /app
# Install system dependencies FIRST (cached layer)
RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
# Copy application files LAST to prevent invalidating the apt layer cache
COPY package*.json ./
RUN npm ci
COPY . .
Still Not Working?
If apt-get update continues to hang indefinitely during Docker builds on corporate networks or local developer machines, your Docker engine network MTU (Maximum Transmission Unit) setting may be mismatched with host interface limits.
Set the network MTU to 1460 or 1400 in /etc/docker/daemon.json to fix packet fragmentation issue on network interfaces:
{
"mtu": 1400
}
Restart Docker and rebuild your image:
sudo systemctl restart docker
docker build --no-cache -t my-app .