You can now build Docker images in werf using a regular Dockerfile

Better late than never. Or how we nearly made a serious mistake by not having support for regular Dockerfiles for building application images.

You can now build Docker images in werf using a regular Dockerfile

This is about werf — a GitOps utility that integrates with any CI/CD system and manages the entire application lifecycle, allowing for:

  • building and publishing images,
  • deploying applications to Kubernetes,
  • removing unused images using specific policies.


The project's philosophy is to gather low-level tools into a unified system that provides DevOps engineers with control over applications. Existing utilities (like Helm and Docker) should be utilized as much as possible. If a solution to a certain problem is lacking, we can create and maintain everything necessary for that.

Background: our image builder

This is exactly what happened with the image builder in werf: we were missing the familiar Dockerfile. If we take a quick dive into the project history, this issue emerged in the early versions of werf (then still known as dapp).

). Creating a tool for building applications into Docker images, we quickly realized that the Dockerfile was unsuitable for some quite specific tasks:

  1. The need to build typical small web applications following this standard scheme:
    • install the system-wide dependencies of the application,
    • install the bundle of application dependencies,
    • build assets,
    • and most importantly — update the code in the image quickly and efficiently.
  2. When files in the project are changed, the builder should quickly create a new layer by patching the modified files.
  3. If certain files have changed, it is necessary to rebuild the corresponding dependent stage.

To date, our builder has many other capabilities, but the original desires and impulses were as follows.

In general, without further ado, we armed ourselves with the chosen programming language (see below) and set out to implement our own DSL! Aligned with the set tasks, it was designed to describe the build process by stages and define the dependencies of these stages on files. It was complemented by our own compiler, which transformed the DSL into the final product — the built image. Initially, the DSL was in Ruby, and as we transitioned to Golang, our builder's configuration began to be described in a YAML file. — конфиг нашего сборщика стал описываться в YAML-файле.

You can now build Docker images in werf using a regular Dockerfile
Old config for a dapp on Ruby

You can now build Docker images in werf using a regular Dockerfile
Current config for werf on YAML

The mechanism for the builder has also changed over time. Initially, we simply generated a temporary Dockerfile from our configuration on the fly, and later we started executing build instructions in temporary containers and making commits.

NB: Currently, our builder, which works with its own config (in YAML) and is called the Stapel builder, has already evolved into a quite powerful tool. Its detailed description deserves separate articles, while basic details can be found in the documentation.

Recognition of the Problem

But we realized, although not immediately, that we made one mistake: we did not add the ability to build images using a standard Dockerfile and integrate them into the same comprehensive application management infrastructure (i.e., to build images, deploy them, and clean them up). How could we create a deployment tool for Kubernetes without implementing support for Dockerfile, that is, the standard way to describe images for most projects?..

Instead of answering such a question, we propose its solution. What to do if you already have a Dockerfile (or a set of Dockerfiles) and you want to use werf?

NB: By the way, why would you even want to use werf? The main features are as follows:

  • full application management lifecycle, including image cleanup;
  • the ability to manage the builds of several images from a single config;
  • enhanced chart deployment process compatible with Helm.

You can find a more complete list of these on the project page.

So, if earlier we would have suggested rewriting Dockerfile to our config, now we happily say: "Let werf build your Dockerfiles!"

How to use?

The full implementation of this feature appeared in the release werf v1.0.3-beta.1. The general principle is simple: the user specifies the path to the existing Dockerfile in the werf config, then runs the command werf build… and that's it — werf will build the image. Let's consider this with an abstract example.

Declare the following Dockerfile at the root of the project:

FROM ubuntu:18.04
RUN echo Building ...

And declare werf.yaml, which uses this Dockerfile:

configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: .\/Dockerfile

That's it! Now we just need to launch werf build:

You can now build Docker images in werf using a regular Dockerfile

Additionally, you can declare the following werf.yaml to build several images at once from different Dockerfiles:

configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: .\/dockerfiles\/Dockerfile-backend
---
image: frontend
dockerfile: .\/dockerfiles\/Dockerfile-frontend

Finally, the transmission of additional build parameters is supported — such as --build-arg and --add-host — through the werf config. A complete description of the Dockerfile image configuration is available on the documentation page.

Initially, a check is performed: does the client device support power via PoE? A voltage of 2.8 to 10 volts is supplied, and the input resistance is determined. If the results obtained are satisfactory for powering via PoE, the power device proceeds to the next stage.

During the build process, the standard cache of local layers in Docker operates. However, importantly, werf also integrates the Dockerfile configuration into its infrastructure. What does this mean?

  1. Each image built from a Dockerfile consists of a single stage called dockerfile (for more about what stages are in werf, you can read here).
  2. For the stage dockerfile werf calculates a signature that depends on the contents of the Dockerfile configuration. When the Dockerfile configuration changes, the signature of the stage is altered dockerfile and werf initiates a rebuild of that stage with the new Dockerfile config. If the signature remains unchanged, werf retrieves the image from the cache (more about using signatures in werf was discussed in this report).
  3. Afterwards, the built images can be published with the command werf publish (or werf build-and-publish) and used for deployment in Kubernetes. Published images in Docker Registry will be cleaned up by the standard werf cleanup tools, i.e., there will be automatic removal of old images (older than N days), images associated with non-existent Git branches, and according to other policies.

More about the points described here can be found in the documentation:

Notes and Precautions

1. External URLs in ADD are not supported

Currently, the use of external URLs in the ADDdirective is not supported. Werf will not initiate a rebuild when the resource at the specified URL changes. This feature is planned for the near future.

2. You cannot add .git to the image

In general, adding the directory .git to the image is considered a bad practice and here’s why:

  1. If .git it remains in the final image, violating the principles of 12 factor app: because the resulting image should be tied to a single commit, there should be no possibility of making a git checkout random commit.
  2. .git it increases the size of the image (the repository can be large due to having once added large files and then removed them). The size of the work-tree associated solely with a specific commit will not depend on the history of operations in Git. Meanwhile, adding and subsequently removing .git The final image won’t work: the image will still acquire an extra layer — that's how Docker operates.
  3. Docker can initiate unnecessary rebuilds even if it’s building the same commit from different work-trees. For instance, GitLab creates separate cloned directories in /home/gitlab-runner/builds/HASH/[0-N]/yourproject with parallel builds enabled. The extra rebuild will be related to the fact that the directory .git differs in different cloned versions of the same repository, even when building the same commit.

This last point also has implications when using werf. Werf requires that the built cache is present when executing certain commands (for example, werf deploy). When running such commands, werf calculates signature stages for the images specified in werf.yaml, and they must be in the build cache — otherwise, the command cannot continue. If the stage signature depends on the content .git, then we end up with an unstable cache against changes in irrelevant files, and werf won’t forgive such a mistake (more details in the documentation).

Overall adding only specific necessary files via the instruction ADD in any case improves the efficiency and reliability of what has been written Dockerfile, as well as enhances the cache resilience built from this Dockerfile, against irrelevant changes in Git.

Summary

Our initial path of writing our own builder for specific needs was difficult, honest, and straightforward: instead of using workarounds over the standard Dockerfile, we created our own solution with a custom syntax. And it brought its advantages: the Stapel builder performs excellently.

However, during the writing of our custom builder, we overlooked the support for existing Dockerfiles. This deficiency is now fixed, and in the future, we plan to develop support for Dockerfile along with our custom Stapel builder for distributed builds and builds using Kubernetes (i.e., builds on runners within Kubernetes, as done in kaniko).

So if you happen to have a couple of Dockerfiles laying around... please try werf!

P.S. Documentation list on the topic

Also read in our blog: 'werf is our tool for CI/CD in Kubernetes (overview and video report)».

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster