freundcloud

NixOS Containers

NixOS containers are lightweight virtualization solutions that leverage the Nix package manager’s declarative approach. They provide system-level isolation without the overhead of traditional virtual machines.

Overview

NixOS containers (not to be confused with Docker or OCI containers) are a built-in feature of NixOS that:

  • Utilize Linux namespaces for isolation
  • Share the kernel with the host system
  • Can be defined and managed declaratively through NixOS configuration
  • Provide an efficient way to run isolated NixOS systems

Key Features

  • Declarative Configuration: Define containers in your NixOS configuration files
  • System-Level Isolation: Full system isolation similar to VMs, but lighter weight
  • Nix Store Sharing: Efficient resource usage by sharing the Nix store with the host
  • Seamless Integration: Direct integration with NixOS tooling and ecosystem
  • Reproducible Environments: Guaranteed consistency through Nix’s deterministic builds

Setting Up NixOS Containers

Basic Container Definition

Add to your /etc/nixos/configuration.nix:

{ config, pkgs, ... }:

{
  # Other system configuration...
  
  containers.mycontainer = {
    config = { config, pkgs, ... }: {
      system.stateVersion = "23.11";
      
      # Container configuration
      services.openssh.enable = true;
      networking.firewall.allowedTCPPorts = [ 22 ];
      
      # Container packages
      environment.systemPackages = with pkgs; [
        vim
        curl
        htop
      ];
    };
    
    # Container properties
    privateNetwork = true;
    hostAddress = "10.100.0.1";
    localAddress = "10.100.0.2";
    autoStart = true;
  };
}

Container Management Commands

# Start a container
nixos-container start mycontainer

# Stop a container
nixos-container stop mycontainer

# Execute commands in a container
nixos-container run mycontainer -- command-to-run

# Get a shell in a container
nixos-container root-login mycontainer

# List all containers
nixos-container list

# Create an imperative container (without config file)
nixos-container create newcontainer

# Destroy a container
nixos-container destroy mycontainer

Container Configuration Options

Networking

containers.mycontainer = {
  # Private virtual Ethernet connection
  privateNetwork = true;
  
  # Host side of the Ethernet pair
  hostAddress = "10.0.0.1";
  
  # Container side of the Ethernet pair
  localAddress = "10.0.0.2";
  
  # Forward specific host ports to container
  forwardPorts = [
    { hostPort = 8080; containerPort = 80; protocol = "tcp"; }
  ];
  
  # Use the host's network namespace
  # privateNetwork = false;
};

Resource Limits

containers.mycontainer = {
  # Set CPU limits
  config = { config, pkgs, ... }: {
    systemd.slices.container.sliceConfig = {
      CPUQuota = "50%";  # Limit to 50% CPU
    };
  };
  
  # Memory limits can be set via the host's systemd configuration
  extraFlags = [ "--memory-limit=1G" ];
};

Bindmounts and Storage

containers.mycontainer = {
  # Bind mount host directories to container
  bindMounts = {
    "/host/data" = {
      hostPath = "/path/on/host";
      isReadOnly = false;
    };
  };
  
  # You can also use ephemeralRootfs for temporary containers
  ephemeralRootfs = true;
};

Differences from OCI Containers

NixOS containers differ from Docker/OCI containers in several ways:

Feature NixOS Containers OCI (Docker) Containers
Isolation System-level, full NixOS environment Process-level isolation
Configuration Declarative Nix expressions Dockerfile or docker-compose
Init System systemd (full init) Usually simple PID 1 processes
Packaging Nix packages Container images with layers
Network Various networking options Docker bridge, host, overlay networks
Portability NixOS specific Run on any system with OCI runtime

Best Practices

  • Use ephemeralRootfs for short-lived, immutable containers
  • Define clear resource limits to avoid host resource contention
  • Use bindMounts for persistent data
  • Leverage Nix expressions for container reusability

Advanced Features

Accessing the Container

# Get an interactive shell
nixos-container root-login mycontainer

# Attach to container console
machinectl shell mycontainer  # Containers integrate with systemd-machined

Container Updates

# Update the container after configuration changes
nixos-rebuild switch

# Rebuild a specific container
nixos-container update mycontainer
  • nixos2container: Convert NixOS configurations to OCI containers
  • nix2container: Build OCI images from Nix expressions
  • nixery: On-demand container generation service for Nix

Resources