/flake-containers

A proof of concept project for defining NixOS containers (systemd-nspawn) in a flake.nix file.

Primary LanguageNixMIT LicenseMIT

flake-containers

Introduction

A proof of concept project for defining NixOS containers (systemd-nspawn) in a flake.nix file.

Description

"flake-containers" is a small project demonstrating the usage of Nix for managing systemd containers. It utilizes the Nix language and the Nix flake system to define and launch containers with systemd-nspawn.

Features

  • Define systemd containers in Nix.
  • Generate commands to manage the containers (mostly wrappers around machinectl, instead of the ups commands).

Why?

As stated, this is a proof of concept. I created it for experimenting with systemd-nspawn, NixOS, and flake-parts.

That being said, in my development workflow, I almost always define my development dependencies into a flake for Rust, Python, Go, etc. When I need to use different services, such as a database, I would typically rely on Docker. However, with flake-containers, I can directly benefit from NixOS services and enable and configure the services that I need, in a reproducible and shareable way.

It's worth mentioning that while there already exists a way to manage NixOS containers using nixos-container, it integrates within a NixOS configuration. This project has been largely inspired by nixos-containers (in fact, most of the code comes from there). However, flake-containers enables the definition and management of NixOS containers without the need to update your system configuration. Furthermore, it should work on any Linux distribution with Nix installed.

Limitations

  • It requires root privileges to start the containers.
  • nixpkgs can be configured with a config and overlays, even changing the nixpkgs source. However, it cannot be set on a per container basis, and it is effective for each containers.
  • There is a dependency on flake-roots to retrieve the path for the project, where I store the states for the containers.
  • I dont think that the container can be updated while alive (with with nixos-rebuild switch for instance).

Future Works

  • It is not a compose-style project (at least for now); there is one command per container. No "flake-containers up" command.
  • No support for volumes (temporary or permanent).
    • Volumes can be configured now in nix, but why not adding the possibility to specify volumes in the command line ?
  • The network configuration is currently simple and not configurable (no support for bridges for instance).
  • Compatibility with other distributions is untested; it has only been tested on NixOS.
  • The project lacks testing. It appears to work on my computer; that's the only guarantee I can offer at the moment.
  • There is an ugly sleep at the start time. I need a better way to detect when a container is alive to start the network configuration.
  • Better nix code (add comments and types)
  • Create a script to clean container states directory: NixOS/nixpkgs#63028 (comment)
  • Add an ephemeral mode
    • see --ephemeral on systemd-npsawn ?
    • manually setting up tmpfs ?
  • Add comparison with devenv, nix2containers, nixos-compose
  • Create a better way to specify run commands
  • Create a way to easily define testscripts (same as in nixos)
  • Find a way to transfer ownership inside the container (so for instance, when running commands from inside the container, we don't end up with a lot of root files in the host system)

Usage

  1. Start by creating a flake with the following content:
    {
        inputs = {
            nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
            # This project is based on flake-parts, so you need to import it
            flake-parts.url = "github:hercules-ci/flake-parts";
            # flake-root is a dependency that enable to find the root project for the flake
            # repositorty to create the states for the containers
            flake-root.url = "github:srid/flake-root";
            # Import flake-containers
            flake-containers.url = "github:adfaure/flake-containers";
        };
        outputs =
            inputs@{ self, nixpkgs, flake-parts, flake-containers, flake-root, ... }:
            flake-parts.lib.mkFlake { inherit inputs; } {
            imports =
                [ inputs.flake-containers.flakeModule inputs.flake-root.flakeModule ];
    
            systems = [ "x86_64-linux" ];
    
            flake-containers = {
                # Enable the containers
                enable = true;
                # Define the containers as nixos modules
                containers = {
                    # One container named httpsserver
                    httpserver = {
                        # Define volumes to be bind inside the conaiter
                        volumes = [ "/tmp" "src:/tmp/src" ];
                        volumes-ro = [ "/data" ];
                        
                        # The configuration is a regular nixos module
                        configuration = { pkgs, lib, ... }: {
                            # Network configuration.
                            networking.useDHCP = false;
                            networking.firewall.allowedTCPPorts = [ 80 ];
    
                            # Enable a web server.
                            services.httpd = {
                                enable = true;
                                adminAddr = "morty@example.org";
                            };
                        };
                    };
                };
            };
        };
    }
  2. Use nix flake show to see what is available. For each container, the flake defines the command to manage.
    > nix flake show
    git+file:///home/adfaure/code/flake-containers?dir=examples/httpserver
    ├───devShells
    │   └───x86_64-linux
    │       └───flake-containers: development environment 'nix-shell'
    └───packages
        └───x86_64-linux
            ├───httpserver-down: package 'httpserver-down'
            ├───httpserver-shell: package 'httpserver-shell'
            └───httpserver-up: package 'httpserver-up'
    
  3. Use nix develop .#flake-containers to dive into a shell containing commands to manage your containers.
  4. Start the container with sudo httpserver-up to start the container.
  5. The container should appear with the machinectl list command.

Similar Projects

Similar (or related) projects Description
nixos-containers Declare and manage NixOs systemd containers.
extra-container Generates systemd service files for starting containers directly from systemctl. Maintains compatibility with nixos-container.
nixos-compose The goal of NixOS-Compose is to reduce the burden of setting up ephemeral distributed systems thanks to Nix functional package manager and Nixos
devenv Use a simple unified configuration to configure packages, processes, services, scripts, git hooks, integrations. Devenv has its own way to create containers.
nix2Container An archive-less dockerTools.buildImage implementation
Arion Run docker-compose with help from Nix/NixOS.

Contributing

Contributions are welcome! Feel free to open issues for bugs or feature requests, and submit pull requests with improvements.

License

This project is licensed under the MIT License.

References