Build a Nix docker image in Gitlab CI

Frustrated with fetching, checksum checking, and extracting of the packages in a Dockerfile that I need for a project, this week finally found a way to build docker images with Nix. Embedded in nixpkgs there are the functions buildImage and buildLayeredImage. With these functions you can build docker images that are assembled from Nix packages. How wonderful is that?

Here is the Nix derivation that I have used:

with import <nixpkgs> {};

pkgs.dockerTools.buildLayeredImage {
  name = "k8s-deployer";
  tag = "latest";
  created = "now";

  contents = with pkgs; [
    kubectl
    kubernetes-helm
    terraform
    yq
    jq
    bash
    coreutils # mkdir and such
    python3
    moreutils # for sponge
    git
    cacert
    curl
  ];

  extraCommands = ''
    mkdir -p usr/bin
    ln -sf ${pkgs.coreutils}/bin/env usr/bin/env
    mkdir tmp
    chmod 1777 tmp
  '';

  config = {
    Cmd = [ "/bin/bash" ];
    WorkingDir = "/";
    Env = [
      "SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"
    ];
  };
}

Test it by building it locally and loading it into Docker:

nix-build -o image.tar.gz
docker load -i ./image.tar.gz
docker run -it --rm k8s-deployer:latest

… and here is how to build it in Gitlab CI, and push it to the Gitlab Container Registry:

stages:
  - build

build:
  stage: build
  image: nixos/nix:latest
  script:
    # For pinning:
    # - export NIX_PATH="nixpkgs=https://github.com/NixOS/nixpkgs/archive/ab593d46dc38b9f0f23964120912138c77fa9af4.tar.gz"
    - nix-channel --update
    - nix-build -o image.tar.gz
    - |
      nix run nixpkgs.skopeo -c skopeo \
        --insecure-policy \
        copy \
        --dest-creds $CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD \
        docker-archive:image.tar.gz \
        docker://$CI_REGISTRY_IMAGE:latest

This currently always builds from unstable, but by uncommenting the line with export NIX_PATH=... you can pin to a specific Nixpkgs version.

For more examples on how to use buildImage and buildLayeredImage see this link.