Zum Inhalt

NixOS Docker Build (Optional)

Übersicht

Solar-Log kann mit NixOS Flakes gebaut werden für:

Reproduzierbare Builds - Exakt gleiche Ergebnisse
Dependency Management - Automatische Dependencies
Multi-Platform - Linux x86_64, ARM64
Development Shells - Isolierte Entwicklungsumgebungen

⚠️ macOS Limitation: Nix buildLayeredImage funktioniert nicht auf macOS Sequoia (fakeroot Issue). Verwende Dockerfiles stattdessen.

Installation

Nix Package Manager installieren

# Multi-User Installation (empfohlen)
sh <(curl -L https://nixos.org/nix/install) --daemon

# Flakes aktivieren
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf

Setup Script (Automatisch)

# Automated Setup
./deployment/nix/setup-nix.sh

# Was wird gemacht:
# 1. Nix installieren (falls nicht vorhanden)
# 2. Flakes aktivieren
# 3. Git Repository initialisieren
# 4. Docker Images bauen

Flake Structure

Datei: flake.nix

{
  description = "Solar-Log Enterprise - NixOS Docker Build";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system: {
      packages = {
        # Backend Docker Image
        backend = /* ... */;

        # Frontend Docker Image
        frontend = /* ... */;

        # PostgreSQL Image
        postgres = /* ... */;

        # Nginx Proxy
        nginx = /* ... */;

        # Alle Images bauen
        dockerAll = /* ... */;
      };

      devShells = {
        # Python Development Shell
        python = /* ... */;

        # Node.js Development Shell
        nodejs = /* ... */;

        # Full Stack Shell
        default = /* ... */;
      };
    });
}

Docker Images bauen

Einzelne Images

# Backend Image
nix build .#backend
docker load < result

# Frontend Image
nix build .#frontend
docker load < result

# PostgreSQL
nix build .#postgres
docker load < result

# Nginx Proxy
nix build .#nginx
docker load < result

Alle Images gleichzeitig

# Alle Images bauen
nix build .#dockerAll

# Images laden
docker load < result-backend
docker load < result-frontend
docker load < result-postgres
docker load < result-nginx

Makefile Commands

# NixOS Builds
make nix-build-backend
make nix-build-frontend
make nix-build-all

# Images laden
make nix-load-images

# Cleanup
make nix-clean

Development Shells

Python Shell

# Python Dev Shell aktivieren
nix develop .#python

# Verfügbare Tools:
python --version    # Python 3.11
pip --version
black --version     # Code Formatter
flake8 --version    # Linter
pytest --version    # Test Runner

Node.js Shell

# Node.js Dev Shell aktivieren
nix develop .#nodejs

# Verfügbare Tools:
node --version      # Node 20.x
npm --version
eslint --version    # Linter
prettier --version  # Code Formatter

Full Stack Shell (Default)

# Default Dev Shell
nix develop

# Alle Tools verfügbar:
python --version
node --version
docker --version
docker compose version

flake.nix Details

Backend Image Definition

backend = pkgs.dockerTools.buildLayeredImage {
  name = "solarlog-backend";
  tag = "latest";

  contents = with pkgs; [
    python311
    python311Packages.pip
    postgresql
    nmap
    curl
  ];

  config = {
    Cmd = [ "sh" "-c" "uvicorn app.main:app --host 0.0.0.0 --port 8000" ];
    ExposedPorts = { "8000/tcp" = {}; };
    Env = [
      "PYTHONUNBUFFERED=1"
      "DATABASE_URL=postgresql://solarlog:solarlog_secret@postgres:5432/solarlog"
    ];
    WorkingDir = "/app";
    User = "1000:1000";
  };

  extraCommands = ''
    mkdir -p app data logs tmp
    chmod 755 app data logs tmp
  '';
};

Frontend Image Definition

frontend = pkgs.dockerTools.buildLayeredImage {
  name = "solarlog-frontend";
  tag = "latest";

  contents = with pkgs; [
    nodejs_20
    nginx
    wget
  ];

  config = {
    Cmd = [ "nginx" "-g" "daemon off;" ];
    ExposedPorts = { "80/tcp" = {}; };
    WorkingDir = "/usr/share/nginx/html";
  };

  extraCommands = ''
    # Build React App
    cd /tmp
    npm ci --only=production
    npm run build

    # Copy to Nginx
    cp -r build/* usr/share/nginx/html/
  '';
};

Build-Cache

Nix Store

# Store Size prüfen
du -sh /nix/store

# Alte Generationen entfernen
nix-collect-garbage -d

# Store optimieren
nix-store --optimise

Build Cache

# Cache Statistiken
nix path-info -rS .#backend

# Cache löschen
rm -rf result result-*

Cross-Compilation

ARM64 Builds (z.B. Raspberry Pi)

# ARM64 Backend
nix build .#backend --system aarch64-linux

# Alle ARM64 Images
nix build .#dockerAll --system aarch64-linux

Multi-Platform

# In flake.nix
outputs = { self, nixpkgs, flake-utils }:
  flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system: {
    packages = {
      backend = /* ... */;
      frontend = /* ... */;
    };
  });

CI/CD Integration

GitHub Actions

name: Build with Nix

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: cachix/install-nix-action@v24
        with:
          nix_path: nixpkgs=channel:nixos-24.05

      - uses: cachix/cachix-action@v12
        with:
          name: solarlog
          authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

      - name: Build Docker Images
        run: |
          nix build .#dockerAll
          docker load < result-backend
          docker load < result-frontend

      - name: Push to Registry
        run: |
          docker tag solarlog-backend:latest ghcr.io/user/solarlog-backend:latest
          docker push ghcr.io/user/solarlog-backend:latest

GitLab CI

build:
  image: nixos/nix:latest
  script:
    - nix build .#dockerAll
    - docker load < result-backend
    - docker load < result-frontend
  artifacts:
    paths:
      - result-*

Troubleshooting

macOS fakeroot Issue

Problem: fakeroot: symbol not found '_fstat$INODE64'

Lösung: Verwende Dockerfiles statt Nix auf macOS:

# docker-compose.yml
services:
  backend:
    build: ./backend  # Statt Nix Image

Permission Errors

Problem: chown: Operation not permitted

Lösung: Entferne chown aus extraCommands:

extraCommands = ''
  mkdir -p app data
  # chown -R 1000:1000 .  # ← Entfernen für macOS
'';

Build Errors

# Verbose Build
nix build .#backend --print-build-logs

# Debug Mode
nix build .#backend --show-trace

Cache Issues

# Cache zurücksetzen
nix-collect-garbage -d
rm -rf result*

# Neu bauen
nix build .#backend --rebuild

Performance

Layer Caching

buildLayeredImage erstellt automatisch Layers: - Base Layer: OS + System Packages - Dependencies Layer: Python/Node Packages
- App Layer: Application Code

Vorteile: - Schnellere Rebuilds - Kleinere Image Sizes - Besseres Caching

Parallel Builds

# Max 8 parallel Jobs
nix build .#dockerAll --max-jobs 8

# Auto-detect CPU Cores
nix build .#dockerAll --max-jobs auto

Migration zu Nix

Von Docker zu Nix

  1. Dockerfile analysieren:

    # Extrahiere Dependencies aus Dockerfile
    grep "RUN apt-get install" backend/Dockerfile
    grep "RUN pip install" backend/Dockerfile
    

  2. In flake.nix übersetzen:

    contents = with pkgs; [
      # apt-get install → pkgs.packageName
      postgresql      # postgresql-client
      curl            # curl
      nmap            # nmap
    ];
    

  3. Build Commands migrieren:

    extraCommands = ''
      # Dockerfile RUN → extraCommands
      pip install -r requirements.txt
      npm ci --only=production
    '';
    

Best Practices

  1. Pin Nixpkgs Version: Verwende spezifische Nixpkgs Revision
  2. Separate Layers: Dependencies und App Code trennen
  3. Minimal Contents: Nur benötigte Packages einbinden
  4. Health Checks: In Docker Compose statt Nix
  5. Secrets: Über Environment Variables, nicht in Nix Store

Comparison: Nix vs Dockerfile

Feature Nix Dockerfile
Reproduzierbarkeit ✅ 100% ⚠️ ~80%
Build Cache ✅ Granular ⚠️ Layer-basiert
Cross-Platform ✅ Native ⚠️ QEMU
macOS Support ❌ Limitiert ✅ Voll
Learning Curve ⚠️ Steil ✅ Flach
Ecosystem ⚠️ Nix-only ✅ Standard

Empfehlung: - Entwicklung: Dockerfiles (macOS kompatibel) - Produktion: Nix auf Linux (reproduzierbar) - CI/CD: Nix (konsistente Builds)

Weitere Ressourcen

Nächste Schritte