werf uses the Build process to build images defined in the werf configuration.

Dockerfile image

werf uses Dockerfile as the principal way to describe how to build an image. Images built with Dockerfile will be referred to as dockerfile images (learn more about a dockerfile image).

How a dockerfile image is being built

werf creates a single stage called dockerfile to build a dockerfile image.

How the dockerfile stage is being built:

  1. Stage signature is calculated based on specified Dockerfile and its contents. This signature represents the resulting image state.
  2. werf does not perform a new docker build if an image with this signature already exists in the stages storage.
  3. werf performs a regular docker build if there is no image with the specified signature in the stage storage. werf uses the standard build command of the built-in docker client (which is analogous to the docker build command). The local docker cache will be created and used as in the case of a regular docker client.
  4. When the docker image is complete, werf places the resulting dockerfile stage into the stages storage (while tagging the resulting docker image with the calculated signature) if the :local stages storage parameter is set.

See the configuration article for the werf.yaml configuration details.

Stapel image and artifact

Also, werf has an alternative tool for building images. The so-called stapel builder:

  • provides an integration with the git and incremental rebuilds based on the git repo history;
  • allows using ansible tasks to describe instructions needed to build an image;
  • allows sharing a common cache between builds with mounts;
  • reduces image size by detaching source data and build tools.

The image built with a stapel builder will be referred to as a stapel image.

See stapel image and stapel artifact articles for more details.

How stapel images and artifacts are built

Each stapel image or an artifact consists of several stages. The same mechanics is used to build every stage.

werf generates a specific list of instructions needed to build a stage. Instructions depend on the particular stage type and may contain internal service commands generated by werf along with user-specified shell commands. For example, werf may generate instructions to apply a prepared patch from a mounted text file using git cli util.

All generated instructions to build the current stage are supposed to be run in a container that is based on the previous stage. This container will be referred to as a build container.

werf runs instructions from the list in the build container (as you know, it is based on the previous stage). The resulting container state is then committed as a new stage and saved into the stages storage.

werf has a special service image called flant/werf-stapel. It contains a chroot /.werf/stapel with all the necessary tools and libraries to build images with a stapel builder. You may find more info about the stapel image in the article.

flant/werf-stapel is mounted into every build container so that all precompiled tools are available in every stage being built and may be used in the instructions list.

How stapel builder processes CMD and ENTRYPOINT

To build a stage image, werf launches a container with the CMD and ENTRYPOINT service parameters and then substitutes them with the base image values. If the base image does not have corresponding values, werf resets service to the special empty values:

  • [] for CMD;
  • [""] for ENTRYPOINT.

Also, werf uses the special empty value in place of a base image’s ENTRYPOINT if a user specifies CMD (docker.CMD).

Otherwise, werf behavior is similar to docker’s.

Multiple builds on the same host

Multiple build commands can be executed concurrently on the same host. While building a stage, werf acquires a lock using the stage signature as ID so that only one building process is active for a stage with a particular signature at a time.

When another build process is holding a lock for a stage, werf waits until this process releases a lock. Then werf proceeds to the next stage.

We intentionally implemented such logic since it doesn’t make any sense to build the same stage multiple times. The werf building process can wait until another process completes its work and puts a stage into the stages storage.