Skip to content

Build container images

Having created a collection of packages in an environment, flox can render that environment as an OCI container runtime suitable for use with Docker, K8S, Nomad, etc.

If you haven't already, please install flox before continuing.

flox containerize is currently only supported on Linux

1. Edit an environment

Prior to creating a container let's create an environment and install the hello package in it:

$ flox install hello
...
Installed 'hello' package(s) into 'default' environment.

2. flox containerize - containerize any environment

To render your environment to a container run flox containerize. This command will pipe the container image to stdout for usage with docker load:

$ flox containerize | docker load # (1)!
...
Building container...
Done.
No 'fromImage' provided
Creating layer 1 from paths: [...]
...
Creating layer ... with customisation...
Adding manifests...
Done...Loaded image: default:latest
  1. flox containerize will stream generated docker image to docker load command.

Why so many layers?

By default flox splits every dependency into a different layers, which allows better dependency sharing and faster iteration. The number of layers is configurable with container.maxLayers

3. Run container

$ docker run --rm -it default hello
Hello, world!

4. Configure the container image

To add container configuration, use flox edit:

flox edit

Set the environment config to the following:

flox.nix
{
  packages.nixpkgs-flox.hello = {};
  packages.nixpkgs-flox.cowsay = {}; # (1)!
  container.name = "hello-flox"; # (2)!
  container.config.Cmd = "hello"; # (3)!
  environmentVariables.message = "Supercharged by flox!";
  shell.hook = ''
    echo "$message" | cowsay
  ''; # (4)!
}
  1. Add another package to the environment and resulting container image.
  2. Changes the name of the container image.
  3. Command to run on container startup (after flox activation). Any option from the Docker Image Specification is supported in container.config.
  4. The shell hook is run as part of the container entrypoint.

Load and run the new container image:

$ flox containerize | docker load
Building container...
Done.
No 'fromImage' provided
Creating layer 1 from paths: ['/nix/store/sam6f5k16n40d5x1a7dnby0air32z8lj-libunistring-1.0']
Creating layer 2 from paths: ['/nix/store/wx906mwfnhyp6fd0bqjn0hzx13g0zjw9-libidn2-2.3.2']
Creating layer 3 from paths: ['/nix/store/hc3db8k7svnz6zyhhqx8srjabkb6ij1q-glibc-2.35-224']
...
Creating layer 25 from paths: ['/nix/store/l1mcmpdgvdw0nvpxv7a9f4b6sn4x1xl6-bash-interactive-5.1-p16-man']
Creating layer 26 with customisation...
Adding manifests...
Done.
495ce63ccba8: Loading layer [==================================================>]  1.874MB/1.874MB
5403d8a5ea74: Loading layer [==================================================>]    297kB/297kB
3b34e999008b: Loading layer [==================================================>]   42.1MB/42.1MB
...
35b6f6f2314e: Loading layer [==================================================>]  184.3kB/184.3kB
Loaded image: hello-flox:latest

$ docker run --rm -it hello-flox
 _______________________ 
< Supercharged by flox! >
 ----------------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
Hello, world!

Where to next?