Base Docker Image
Docker is fantastic and has given developers more power and control over their application’s OS. Sometimes building Docker images can be slow, though. Docker layer caching technology helps speed up the process by only rebuilding required layers. But sometimes, one minor change results in having to rebuild many layers.
The slowness is exacerbated when using CI Build systems like AWS CodeBuild, GitHub Actions, CircleCI, etc to build Docker images. This is because managed build services usually create a fresh build machine to ensure consistency. It’s difficult for these services to leverage Docker layer caching effectively.
For example, even though AWS CodeBuild has a LOCAL_DOCKER_LAYER_CACHE option, the cache is a best effort and won’t be used if your builds don’t run often enough. IE: Within 15 mins or so. See: GitHub Issue 194 Local docker layer cache lifespan is too short. Similarly, CircleCI has a setup_remote_docker feature that tries to speed up the build process. It also has its own limitations with cache misses.
Base Image Approach
UFO supports building a Docker base image to help speed up the build process. The
ufo docker base commands builds a Docker image from
Dockerfile.base. It can then be used as a guaranteed cache in the FROM instruction for the main
Dockerfile. This base Docker cache image technique can substantially speeds up the build process.
Pros and Cons
There are pros and cons to using this approach. As the adage goes, there are 2 hard problems in computer science:
The main con about this approach is if you forget to update the base Docker image, you will have cached artifacts that will not disappear unless you rebuild the base Docker image. While some folks are not keen on this cache layer, some have loved how much it speeds up their Docker workflow. If you use this technique, you should probably set up automation that rebuilds the base Docker image on a scheduled basis.
For the case of building a new base Docker image, UFO supports dynamically creating a Dockerfile from a
You may want a different
FROM statement in your Dockerfile on a per-environment basis. For example, you’ve segregated your environments like dev and prod on separate AWS accounts for security. The Docker
FROM statements could have different ECR repos from different AWS accounts.
You could also allow different AWS accounts like prod to read ECR images from the dev AWS accounts. While some are okay with this, many prefer strict security boundary permissions between the AWS accounts.
How It Works
Dockerfile.erb exists, UFO uses it to generate a
Dockerfile as a part of the build process. Here’s what the
FROM statement in a
Dockerfile.erb looks like:
FROM <%= @base_image %>
@base_image variable is read from state stored by UFO. This state can be stored on s3. See: Config State Docs
The ufo docker base command automates the process, including updating the state data and updating the existing Dockerfile FROM statement.
UFO_ENV=dev, it’ll produce the following.
UFO_ENV=prod, it’ll produce the following.
The general steps are:
- Create both
<%= @base_image %>. Remove
Dockerfileand add it to
ufo docker baseto update the state with the built Docker base image. Probably should be automated on a scheduled basis.
ufo shipto build a Docker image using
Important: Remember when using
Dockerfile.erb, you should update the source
Dockerfile.erb instead of
Dockerfile is auto-generated. You should
Why not use build args?
UFO automates this process, so users will not have to remember to provide the build arg. Found that it is too easy to forget to specify the build args, and there are still a lot of manual steps aside from the use of build args.