Skip to content
This repository has been archived by the owner on Aug 1, 2023. It is now read-only.

teamniteo/nix-docker-base

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DEPRECATED!

This project relied on https://channels.nix.gsc.io/ to get commits to nixos channels. This website is no longer updated so no new Docker images are built and uploaded to Docker Hub. If you want to built one image manually, see #23.

We are no longer maintaining this project. Reach out if you want to take over.

nix-docker-base: Nix Docker base images for fast and minimal builds

This project automatically generates Docker images for nixpkgs channels. The images come with a prefetched nixpkgs, corresponding to the image tag, which is the nixpkgs commit hash. All basic Nix utilities are preinstalled, including Cachix. Also included is the export-profile script, allowing super minimal images via multi-stage builds.

See the Usage section for how to use it in your project.

Features

Prefetched nixpkgs tarballs

All images come prefetched with the nixpkgs version corresponding to the image tag. So the image niteo/nixpkgs-nixos-20.03:14006b724f3d1f25ecf38238ee723d38b0c2f4ce contains a prefetched tarball of 14006b724f3d. This allows Nix builds that pin nixpkgs to that version to start quickly, without having to first fetch and unpack a tarball.

Preinstalled dependencies

All images come preinstalled with a basic set of dependencies needed for working with Nix. This currently includes Cachix and all dependencies of Nix, but may be expanded in the future as the need arises. Since the intent is to use these images as the first stage in a multi-stage build, they won't influence the final image size, allowing the addition of more tools without a significant cost.

These dependencies notably come from the very nixpkgs version that is prefetched. If you need these tools or their dependencies in a Nix build, this saves you the cost of having to download them.

Automatic channel updates

Every hour, a GitHub Action runs to detect any nixpkgs channel updates, in which case a new Docker image is built and pushed to DockerHub with the corresponding tag.

Additionally, if this repository changes how images are built, the image tags corresponding to the latest channel versions are updated to incorporate these changes. This is the only way in which tagged images are updated, meaning once a nixpkgs channel commit is outdated, its image won't get updated anymore. So if this repository receives an update, you need to update nixpkgs to the latest version of the channel.

Minimal multi-stage builds

All images contain the export-profile utility, which allows easy creation of a final stage in Docker multi-stage builds. The resulting image then contains only exactly the dependencies needed to run the programs you specify, nothing else.

Usage

Pinning nixpkgs

To use this for your project, you should ensure that the prefetched nixpkgs tarball can be used, such that builds can start as fast as possible. This requires that you pin nixpkgs to the nixpkgs commit of the channel that you wish to use. Specifically, the Nix expression that evaluates to the prefetched version is

fetchTarball {
  name = "nixpkgs-src";
  url = "https://github.com/NixOS/nixpkgs/archive/<commit>.tar.gz";
  sha256 = "<sha256>";
}

Note that choosing the name as nixpkgs-src is very important, because Nix can only reuse a prefetched version if the name matches.

Only Nix channels specified in channel matrix in the push workflow are available, but new ones may be added over time.

Using Niv

If you use Niv to manage your nixpkgs source, you need to ensure the following:

  • The nix/sources.nix file was generated by a Niv version after this change
  • The nixpkgs Niv package is named nixpkgs. These two points are necessary for Niv to name the tarball nixpkgs-src
  • The branch of the nixpkgs Niv package points to the nixpkgs channel you wish to use. This ensures that you don't update to unavailable commits

For a new project wanting to use the nixos-20.03 channel, this can be done with:

niv init
niv modify nixpkgs -b nixos-20.03
niv update nixpkgs

For regenerating the nix/sources.nix in an existing project, you can run

rm nix/sources.nix
niv init

Finally, use the following command to check the tarballs name. It needs to end with nixpkgs-src for the prefetched nixpkgs to apply:

nix-instantiate --eval -E '(import nix/sources.nix).nixpkgs.outPath
=> "/nix/store/r07cldfsnr8kvkr1kpsc6jf6bibfc1mg-nixpkgs-src"

If it ends with -source, make sure to use a more recent Niv version.

Nix expression

To use this project, you need a Nix expression in your project that ideally exposes a single derivation as an attribute for installation. A convenient helper for this is pkgs.buildEnv, which allows you to build a derivation that combines multiple other derivations into one. Here is an example default.nix, showing how pkgs.buildEnv can be used to create an environment with both pkgs.curl and pkgs.cacert in it:

let

  # Without niv
  pkgs = fetchTarball {
    name = "nixpkgs-src";
    url = "https://github.com/NixOS/nixpkgs/archive/<commit>.tar.gz";
    sha256 = "<sha256>";
  };

  # With niv
  pkgs = (import nix/sources.nix).nixpkgs;

in {
  myEnv = pkgs.buildEnv {
    name = "env";
    paths = with pkgs; [
      curl
      cacert
    ];
  };
}

Dockerfile

The base images are made available under Niteo on DockerHub as niteo/nixpkgs-<channel>:<commit>. With the Dockerfile being in the same directory as the projects default.nix file, you can install any exposed attribute of that file with the following basic Dockerfile structure

FROM niteo/nixpkgs-<channel>:<commit> AS build
# Import the project source
COPY . src
RUN \
  # Install the program to propagate to the final image
  nix-env -f src -iA myEnv \
  # Exports a root directory structure containing all dependencies
  # installed with nix-env under /run/profile
  && export-profile /dist

# Second Docker stage, we start with a completely empty image
FROM scratch
# Copy the /dist root folder from the previous stage into this one
COPY --from=build /dist /
# Set PATH so Nix binaries can be found
ENV PATH=/run/profile/bin

What export-profile does

The main idea of export-profile <root> is to export the default nix-env profile with all its dependencies into <root>, such that the next build stage only needs to initialize its root directory with <root> from the previous stage. In more details, the script currently does:

  • Symlink to the default nix-env profile from <root>/run/profile
  • If the profile contains an etc directory, it symlinks to it from <root>/etc. This behavior mirrors NixOS, and allows for files like /etc/bashrc to take effect
  • If the profile contains a bin/env (usually from pkgs.coreutils) or bin/sh (usually from pkgs.bashInteractive), it symlinks to those from <root>/usr/bin/env and <root>/bin/sh respectively. These are standard POSIX executable paths.
  • All Nix store paths the profile depends on are copied to <root>/nix/store. This ensures that any previously established symlinks actually work.

SSL root certificates

If you require binaries like curl in the final image, you need to make sure that they can find SSL root certificates. To do this:

  • Install pkgs.cacert in the build stage, either by adding it to the environment of the attribute you install, or with an additional nix-env command like
      nix-env -f '<nixpkgs>' -iA cacert
    
  • Set the NIX_SSL_CERT_FILE environment variable as follows in the final stage
    ENV NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt

Updating the Dockerfile

Since the nixpkgs commit is embedded into the Dockerfile, it should be kept in sync with the nixpkgs of your Nix files to ensure it being as efficient as possible. So if you update your nixpkgs source to a newer channel commit, be sure to update it in the Dockerfile as well.

If you manage your nixpkgs source with niv, this can be achieved automatically with the following commands:

niv update nixpkgs
channel=$(jq -r .nixpkgs.branch nix/sources.json)
rev=$(jq -r .nixpkgs.rev nix/sources.json)
sed -i "s#FROM.*AS build#FROM niteo/nixpkgs-$channel:$rev AS build#g" Dockerfile

Connecting with SSH during CI

This image has built-in helpers for setting up a tmate connection to the image, useful for debugging when running in CI:

  • start-tmate [maxIdle]: Starts a tmate session, which is persisted until maxIdle (by default 60) seconds pass without any connection. The command only exits once this has occured.
  • bash-tmate: A drop-in replacement for bash that runs start-tmate when the bash command fails. Useful as a shell for CI scripts, allowing debugging in case of failures.

Development and Contributing

This section is only intended for developers/contributors of this project. Feel free to contribute by opening a PR or open issues for enquiries.

Adding new nixpkgs channels

A new channel can be added by editing the channel matrix in push.yml workflow to contain the one you want.

Adding new tools to the base image

New tools for the base image can be added under Extra tools in image.nix.

Out-of-tree requirements for forks

  • A DockerHub account. Insert your username for REGISTRY_USER in the push.yml workflow, and set up the password as a REGISTRY_PASSWORD secret for the repository. This is of course needed to update images on DockerHub. Other container registries could work too, but the code needs to be adjusted for that.
  • A Cachix cache for speeding up CI. Set the Cachix name under the cachix-actions in the push.yml workflow, and add the signing key as the CACHIX_SIGNING_KEY secret in the repository.

Related projects

About

Nix Docker base images for fast and minimal builds.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published