Caching APT in Docker builds
Those poor servers hosting APT packages. APT is superbly optimized with clever caching, but that goes away when you’re doing Docker builds. And my poor slow internet access!
Yea we got Docker layer caching, but that doesn’t really account for when you have to make small changes all of the time to the APT packages when developing locally. And does your CI/CD pipeline have distributed Docker layer caching? No? Thought so.
Personally I’ve found a 60-80% build speedup for apt update && apt install
tasks thanks to just setting the http_proxy
environment variable. Here’s how!
Step 1. Run an APT cache server
We’re going to use the docker.io/konstruktoid/apt-cacher-ng Docker image that packages apt-cacher-ng (aka ACNG, APT-Cacher-Next-Generation).
docker run -d --restart=always --cap-drop=all --name apt-cacher-ng -p 3142:3142 konstruktoid/apt-cacher-ng VerboseLog=1 Debug=7 ForeGround=1 PassThroughPattern=.*
# Or via Podman:
podman run -d --restart=always --cap-drop=all --name apt-cacher-ng -p 3142:3142 konstruktoid/apt-cacher-ng VerboseLog=1 Debug=7 ForeGround=1 PassThroughPattern=.*
The above starts a “detached” container (i.e. runs in the background) of apt-cacher-ng
.
For CI/CD pipelines, you should consider hosting the APT cache server somewhere accessible in your company’s network. Like hosting the
apt-cacher-ng
in some internal Kubernetes cluster. Or, at our company we have a Nexus repository that supports APT cache as one of its repository types, which then also can be configured with automatic garbage collection.
Step 2. Set env var http_proxy
before any APT action
Here we’re just running a silly experiment to prove a point. Let’s run some apt
stuff!
$ podman run --rm -it ubuntu:22.04 bash -c 'time apt update'
...
real 0m2.113s
user 0m1.192s
sys 0m0.215s
$ podman run --rm -it -e http_proxy=http://localhost:3142 --network host ubuntu:22.04 bash -c 'time apt update'
...
real 0m1.239s
user 0m1.190s
sys 0m0.189s
Without cache: 2s With cache: 1.2s About 66% faster! :)
But let’s compare with some package installs.
$ podman run --rm -it ubuntu:22.04 bash -c 'time (apt update && apt install -y git)'
...
real 0m6.258s
user 0m2.848s
sys 0m1.016s
$ podman run --rm -it -e http_proxy=http://localhost:3142 --network host ubuntu:22.04 bash -c 'time (apt update && time apt install -y git)'
...
real 0m3.443s
user 0m2.759s
sys 0m0.960s
Without cache: 6s With cache: 3.5s Now 70-80% faster!
I’m adding
--network host
here because I want to have access to theapt-cacher-ng
container on the same host’s network. Ifapt-cacher-ng
was hosted elsewhere then I wouldn’t need the--network host
hack.
Step 3. Use in builds
You can use the ARG
Dockerfile command. Here’s an example Dockerfile:
FROM ubuntu:22.04
ARG http_proxy="http://localhost:3142"
# Just installing a bunch of stuff for testing purposes
RUN apt update && apt install -y curl wget git man python3 jq nodejs golang
podman build . -t my-image:latest --network host
And then just like that you get a major speed boost in your builds! Aaand the best part is that now you can rest easy that you computer isn’t DDOS’ing the APT servers.
I’m adding
--network host
here as well, same reason as above.Could also use the
ENV
Dockerfile command, but by usingARG
you allow the user to disable the proxy if they need to via--build-arg http_proxy=""
.
Have fun~
(Photo by Tiger Lily)