Crafting container images without Dockerfiles

This page summarizes the projects mentioned and recommended in the original post on news.ycombinator.com

Our great sponsors
  • InfluxDB - Power Real-Time Data Analytics at Scale
  • WorkOS - The modern identity platform for B2B SaaS
  • SaaSHub - Software Alternatives and Reviews
  • rules_docker

    Discontinued Rules for building and handling Docker images with Bazel

  • My company uses Bazel's rules docker to build our images: https://github.com/bazelbuild/rules_docker

    They're pretty great and have a lot of the caching and parallelism benefits mentioned in the post for free out of the box, along with determinism (which Docker files don't have because you can run arbitrary shell commands). Our backend stack is also built with Bazel so we get a nice tight integration to build our images that is pretty straightforward.

    We've also built some nice tooling around this to automatically put our maven dependencies into different layers using Bazel query and buildozer. Since maven deps don't change often we get a lot of nice caching advantages.

  • buildah

    A tool that facilitates building OCI images.

  • InfluxDB

    Power Real-Time Data Analytics at Scale. Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.

    InfluxDB logo
  • tiles

  • Sure. Putting a simple binary in a container: https://gitlab.com/kevincox/tiles/-/blob/a2b907eab7a84989c94.... This is the trivial case where you just stick the main executable in the command string. Nix will automatically include the dependencies.

    The GitLab CI example is a bit more complex. It requires some commands that are unused by the image and some config files: https://gitlab.com/kevincox/nix-ci/-/blob/efe6f4deedc50c2474...

  • nix-ci

  • Sure. Putting a simple binary in a container: https://gitlab.com/kevincox/tiles/-/blob/a2b907eab7a84989c94.... This is the trivial case where you just stick the main executable in the command string. Nix will automatically include the dependencies.

    The GitLab CI example is a bit more complex. It requires some commands that are unused by the image and some config files: https://gitlab.com/kevincox/nix-ci/-/blob/efe6f4deedc50c2474...

  • rules_nixpkgs

    Rules for importing Nixpkgs packages into Bazel.

  • apko

    Build OCI images from APK packages directly without Dockerfile

  • This is one of my absolute favorite topics. Pardon me while I rant and self-promote :D

    Dockerfiles are great for flexibility, and have been a critical contributor to the adoption of Docker containers. It's very easy to take a base image, add a thing to it, and publish your version.

    Unfortunately Dockerfiles are also full of gotchas and opaque cargo-culted best practices to avoid them. Being an open-ended execution environment, it's basically impossible to tell even during the build what's being added to the image, which has downstream implications for anybody trying to get an SBOM from the image for example.

    Instead, I contribute to a number of tools to build and manage images without Dockerfiles. Each of them are less featureful than Dockerfiles, but being more constrained in what they can do, you can get a lot more visibility into what they're doing, since they're not able to do "whatever the user wants".

    1. https://github.com/google/go-containerregistry is a Go module to interact with images in the registry and in tarballs and layouts, in the local docker daemon. You can append layers, squash layers, modify metadata, etc.

    2. crane is a CLI that uses the above (in the same repo) to make many of the same modifications from the commandline. `crane append` for instance adds a layer containing some contents to an image, entirely in the registry, without even pulling the base image.

    3. ko (https://ko.build) is a tool to build Go applications into images without Dockerfiles or Docker at all. It runs `go build`, appends that binary on top of a base image, and pushes it directly to the registry. It generates an SBOM declaring what Go modules went into the app it put into the image, since that's all it can do.

    4. apko (https://apko.dev) is a tool to assemble an image from pre-built apks, without Docker. It's capable of producing "distroless" images easily with config in YAML. It generates an SBOM declaring exactly what apks it put in the image, since that's all it can do.

    Bazel's rules_docker is another contender in the space, and GCP's distroless images use it to place Debian .debs into an image. Apko is its spiritual successor, and uses YAML instead of Bazel's own config language, which makes it a lot easier to adopt and use (IMO), with all of the same benefits.

    I'm excited to see more folks realizing that Dockerfiles aren't always necessary, and can sometimes make your life harder. I'm extra excited to see more tools and tutorials digging into the details of how container images work, and preaching the gospel that they can be built and modified using existing tooling and relatively simple libraries. Excellent article!

  • go-containerregistry

    Go library and CLIs for working with container registries

  • This is one of my absolute favorite topics. Pardon me while I rant and self-promote :D

    Dockerfiles are great for flexibility, and have been a critical contributor to the adoption of Docker containers. It's very easy to take a base image, add a thing to it, and publish your version.

    Unfortunately Dockerfiles are also full of gotchas and opaque cargo-culted best practices to avoid them. Being an open-ended execution environment, it's basically impossible to tell even during the build what's being added to the image, which has downstream implications for anybody trying to get an SBOM from the image for example.

    Instead, I contribute to a number of tools to build and manage images without Dockerfiles. Each of them are less featureful than Dockerfiles, but being more constrained in what they can do, you can get a lot more visibility into what they're doing, since they're not able to do "whatever the user wants".

    1. https://github.com/google/go-containerregistry is a Go module to interact with images in the registry and in tarballs and layouts, in the local docker daemon. You can append layers, squash layers, modify metadata, etc.

    2. crane is a CLI that uses the above (in the same repo) to make many of the same modifications from the commandline. `crane append` for instance adds a layer containing some contents to an image, entirely in the registry, without even pulling the base image.

    3. ko (https://ko.build) is a tool to build Go applications into images without Dockerfiles or Docker at all. It runs `go build`, appends that binary on top of a base image, and pushes it directly to the registry. It generates an SBOM declaring what Go modules went into the app it put into the image, since that's all it can do.

    4. apko (https://apko.dev) is a tool to assemble an image from pre-built apks, without Docker. It's capable of producing "distroless" images easily with config in YAML. It generates an SBOM declaring exactly what apks it put in the image, since that's all it can do.

    Bazel's rules_docker is another contender in the space, and GCP's distroless images use it to place Debian .debs into an image. Apko is its spiritual successor, and uses YAML instead of Bazel's own config language, which makes it a lot easier to adopt and use (IMO), with all of the same benefits.

    I'm excited to see more folks realizing that Dockerfiles aren't always necessary, and can sometimes make your life harder. I'm extra excited to see more tools and tutorials digging into the details of how container images work, and preaching the gospel that they can be built and modified using existing tooling and relatively simple libraries. Excellent article!

  • WorkOS

    The modern identity platform for B2B SaaS. The APIs are flexible and easy-to-use, supporting authentication, user identity, and complex enterprise features like SSO and SCIM provisioning.

    WorkOS logo
  • pack

    CLI for building apps using Cloud Native Buildpacks

  • Although Dockerfiles have the benefit of migrating existing workloads to containers without having to update your toolchain, I definitely prefer the container-first workflow. Cloud Native [Buildpacks](https://buildpacks.io/) are a CNCF incubating project but were proven at Heroku. Buildpacks support common languages, but working on a Go project I've also had a great experience with [ko](https://ko.build/). Free yourself from Dockerfile!

  • conda-docker

    Create minimal docker images from conda environments

  • For creating images without docker from conda/mamba environments, there's also the existing `conda-docker` tool https://github.com/conda-incubator/conda-docker.

  • nixery

    Container registry which transparently builds images using the Nix package manager. Canonical repository is https://cs.tvl.fyi/depot/-/tree/tools/nixery

  • I built a service for doing this ad-hoc via image names a few years ago and it enjoys some popularity with CI & debugging use-cases: https://nixery.dev/

  • manifest-tool

    Command line tool to create and query container image manifest list/indexes

  • dinker

    Dinker, dinky Docker images

  • (Self plug) I had the same thoughts as the author, and made this: https://github.com/andrewbaxter/dinker . Like stated in the article, if you're doing rust or go all you want is to dump the binary in the image. There's no reason to do the build inside the docker vm in that case, and it's super fast, and only uses dumb filesystem access - no daemons like docker, weird wip container managers like buildah, etc.

  • mkosi

    💽 Build Bespoke OS Images

  • System's mkosi is worth checking out too: https://github.com/systemd/mkosi I don't think it generates docker/OCI images directly, but it definitely can generate a tarball of the final image contents and then crane of a similar tool could package it up into an appropriate image. For just docker usage it's probably overkill, the main advantage would be it can build other image types like adding a kernel and init to be a fully bootable iso of VM image.

  • kubevirt

    Kubernetes Virtualization API and runtime in order to define and manage virtual machines.

  • It can, kubevirt is a project for running VMs https://kubevirt.io/ and there have been more esoteric things like WASM (https://github.com/krustlet/krustlet).

  • krustlet

    Kubernetes Rust Kubelet

  • It can, kubevirt is a project for running VMs https://kubevirt.io/ and there have been more esoteric things like WASM (https://github.com/krustlet/krustlet).

  • bazel-nix-example

  • I put together an example that mixes Nix and Bazel a couple of years ago: https://github.com/jvolkman/bazel-nix-example

    Nix is used to build a base Docker image, and Bazel builds layers on top.

  • cargo-chef

    A cargo-subcommand to speed up Rust Docker builds using Docker layer caching.

  • If this ends up being a cleaner/easier way to having to workaround super expensive rebuilds for Rust given cache + deps compared to this https://github.com/LukeMathWalker/cargo-chef , reading this thread will have been a huge win for me (and hopefully others).

    Whether introducing Bazel is easier/worth it, subjective I guess.

  • sdk-container-builds

    Libraries and build tooling to create container images from .NET projects using MSBuild

  • We've been baking this functionality directly into the .NET SDK for a couple releases now: https://github.com/dotnet/sdk-container-builds

    It's really nice to derive mostly-complete container images from information your build system already has available, and the speed/UX benefits are great too!

  • crane

    A Nix library for building cargo projects. Never build twice thanks to incremental artifact caching.

  • To get Rust incremental builds, did you consider using something such as crane https://github.com/ipetkov/crane ?

    And regarding OCI images, i built nix2container (https://github.com/nlewo/nix2container) to speed up image build and push times.

  • nix2container

    An archive-less dockerTools.buildImage implementation

  • To get Rust incremental builds, did you consider using something such as crane https://github.com/ipetkov/crane ?

    And regarding OCI images, i built nix2container (https://github.com/nlewo/nix2container) to speed up image build and push times.

  • SaaSHub

    SaaSHub - Software Alternatives and Reviews. SaaSHub helps you find the best software and product alternatives

    SaaSHub logo
NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts