Creating a Docker image from a dockerfile is an easy task. Even some IDEs provide one-click template to sketch first steps. But it does not mean the end of the journey. To fully unleash Docker power, you must be aware of common pitfalls as well as how one could smartly leverage built-in facilities to craft better containers (smart to compile & tiny to deploy).
Context
Docker daemon uses context to operate from. Every docker command starts by sending this context to the daemon. The tiniest the context is, the fastest & smartest this step will be. Tweaking context is done via a .dockerignore file. And you should always have one. At an early stage.
Layer
Dockerfile is a sequence of instructions like FROM
, RUN
or ENTRYPOINT
. Every time you add a new instruction, Docker daemon creates a new layer.
In rock climbing, dockerfile is the route. Every instruction, a clipping point. The daemon the rock climber. As for clipping point, use instructions carefully. Too many leads to slow & rambling ascent. Too few to risky & complex one. Remember, dockerfile is part of the CI/CD and thus will be run again and again. It is not free climbing, but aid one. And daemon is for sure a powerful climber: it can teleport to any previous clipping point.
A docker file can be seen as a stack of instructions, every instruction leading to a new intermediate image.
Purpose split
Crafting a delivery can be split in many steps such as building, testing, or publishing. Every step comes with its own prerequisites or dependencies list. You need SDK version of a dependency to build against, but runtime version is enough to run along. Each step of the pipeline should be shaped accordingly, fulfilling its own duty & serving downstream ones. Leveraging built-in naming facility, it is easy to create bulkhead & efficient workflows.
Every context deserves its own lane, especially build & runtime pipelines do not need same prerequisites & do not achieve same goals. Be smart.
Start point
An important point to grasp when choosing Docker as unit of deployment is that you do not ship a plain old installer anymore, but a self-contained runnable environment. And you have full control to tailor it. As always, a good start does not mean you will win the race, but it helps 😉. Ensure you take some time to pick the best base image(s) from your application in terms of OS, size, built-in facilities, maintenance, …
Optimisation
There are 2 aspects you need to pay attention at to optimize your pipeline:
- How costly each step is.
- How resilient to change each step is.
Docker daemon comes with a powerful caching mechanism, but to make the best of it, you need to understand that:
- Stages are stacked. So, be very smart at tailing ones will not pay if you fail upstream. Cache will be invalidated, and all the downstream steps will be replayed. So, order & optimize every single step.
- Docker daemon monitor file changes to make decision regarding cache invalidation. Ensure you are smart with both .
dockerignore
andCOPY
instructions. They are literally game changers. - You are targeting a very specific stack, the one you build and publish on. No need to eagerly fetch dependencies/prerequisites, be specific.
- Clean stuff every time it makes sense. Remember final image size will mostly depend on the number of intermediate steps you have, and on what you cook in.
BuildKit
Because of the inherent nature of dockerfile, we were doomed for years to leverage anaemic builds. Imagine your favourite IDE with mono-threaded sequential capability. Rough journey… Luckily, Docker ecosystem tooling has evolved along needs and facilities. Defining bulkheads & swim lanes is a worthy move as we can now fully unleash BuildKit parallel build facility to process our dockerfile.
Leveraging both Docker & BuildKit allows you to only rebuild necessary stages and do it in parallel. At the very end, you compose your end user application.
And beyond
Once again, we only scratched the surface. Containers are there for years now, and broadly used in the world, both as delivery unit of deployments and as CI/CD staples. Reason is straightforward: they are smart, and they scale. Give them a try!