From 3f15ab0551220e95991e752e7ea9a3edea4b571c Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 21 Jun 2026 14:54:13 +0200 Subject: [PATCH] switch to nix2container for image building --- .forgejo/workflows/docker.yaml | 3 +- flake.lock | 67 +++++---- flake.nix | 59 +++++--- nix/image/haze.nix | 243 +++++++++++++++++++-------------- 4 files changed, 230 insertions(+), 142 deletions(-) diff --git a/.forgejo/workflows/docker.yaml b/.forgejo/workflows/docker.yaml index a8c493d..244919b 100644 --- a/.forgejo/workflows/docker.yaml +++ b/.forgejo/workflows/docker.yaml @@ -37,5 +37,4 @@ jobs: - name: Push image if: github.ref == 'refs/heads/main' run: | - skopeo copy --insecure-policy --dest-creds="${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" \ - "docker-archive:$(nix build .#'"haze-image-php-${{ matrix.php-version }}"' --print-out-paths)" "docker://icewind1991/haze:${{ matrix.php-version }}" + nix run .#'"haze-image-php-${{ matrix.php-version }}"'.copyToRegistry -- --dest-creds="${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" diff --git a/flake.lock b/flake.lock index a7766b8..3b2be4f 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "crane": { "locked": { - "lastModified": 1763938834, - "narHash": "sha256-j8iB0Yr4zAvQLueCZ5abxfk6fnG/SJ5JnGUziETjwfg=", + "lastModified": 1780099841, + "narHash": "sha256-EVZd2RsbpreRUDSi9rBwPY+ZxoyMaiEBbZxxhljbaS4=", "owner": "ipetkov", "repo": "crane", - "rev": "d9e753122e51cee64eb8d2dddfe11148f339f5a2", + "rev": "0532eb17955225173906d671fb36306bdeb1e2dc", "type": "github" }, "original": { @@ -38,11 +38,11 @@ ] }, "locked": { - "lastModified": 1773062095, - "narHash": "sha256-u+cK9IoJokO4YzQwMc2s8Vti0RL/LVSrROOEn2opc5U=", + "lastModified": 1781543995, + "narHash": "sha256-wsSyxNWOSMofu4F5xGYGMrB1d8cepvBNhxhm9bGGmXg=", "owner": "nix-community", "repo": "flakelight", - "rev": "c99e4d5f40e578cb2d8f460ea2bbd5dc26316d24", + "rev": "fd1d557721e07b5a9d319442e4bcb5d286600011", "type": "github" }, "original": { @@ -60,11 +60,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1772297202, - "narHash": "sha256-UEzHO/tCmhPhr8RpWtbm1MTa7ABobwt3nCjrcuDAPm0=", + "lastModified": 1780231986, + "narHash": "sha256-OyafczPtzE0Xa2zl3j/KvV2+ZVYGhYQHt0MOVWtDXlY=", "ref": "refs/heads/main", - "rev": "8690e1514863b934de12f2a503c9431d186ce30b", - "revCount": 68, + "rev": "f5cbda29b945df03256bf63c22fa4cd5fa429e67", + "revCount": 72, "type": "git", "url": "https://codeberg.org/icewind/mill-scale.git" }, @@ -73,28 +73,48 @@ "url": "https://codeberg.org/icewind/mill-scale.git" } }, + "nix2container": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775487831, + "narHash": "sha256-2lguQpLPQaxpQCJjXhmEEAfabwsAhkP29Z7fgLzHARA=", + "owner": "nlewo", + "repo": "nix2container", + "rev": "76be9608a7f4d6c985d28b0e7be903ae2547df3e", + "type": "github" + }, + "original": { + "owner": "nlewo", + "repo": "nix2container", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1772822230, - "narHash": "sha256-yf3iYLGbGVlIthlQIk5/4/EQDZNNEmuqKZkQssMljuw=", + "lastModified": 1781216227, + "narHash": "sha256-9mUW6gNwoN2SWc/l0fW4svPNOulXLl8ijqKyeSOGgJE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "71caefce12ba78d84fe618cf61644dce01cf3a96", + "rev": "a0374025a863d007d98e3297f6aa46cc3141c2f0", "type": "github" }, "original": { "id": "nixpkgs", - "ref": "nixos-25.11", + "ref": "nixos-26.05", "type": "indirect" } }, "nixpkgs_2": { "locked": { - "lastModified": 1772173633, - "narHash": "sha256-MOH58F4AIbCkh6qlQcwMycyk5SWvsqnS/TCfnqDlpj4=", + "lastModified": 1781268102, + "narHash": "sha256-Zn5KTggEmUB3lXn/ccERNcBdddE6IaOFber9dWViWDg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c0f3d81a7ddbc2b1332be0d8481a672b4f6004d6", + "rev": "49a4bd0573c376468dd7996ddb6f9fa31d8c4d97", "type": "github" }, "original": { @@ -111,11 +131,11 @@ "utils": "utils" }, "locked": { - "lastModified": 1772365008, - "narHash": "sha256-/ynkWKeZ1dyRIUkQas0AB35semWAwCbTKXu+/q+8MGg=", + "lastModified": 1781456983, + "narHash": "sha256-z3SNuQpkSeIRTS6Y/Q5FgGAuGSY5+YJBXtqWPXw0f0k=", "owner": "fossar", "repo": "nix-phps", - "rev": "f47eb877bf1c219809e4357eec2fdab8e3263b7b", + "rev": "6458735dece7e48f27d52ac68eee2d2cfe55b79a", "type": "github" }, "original": { @@ -128,6 +148,7 @@ "inputs": { "flakelight": "flakelight", "mill-scale": "mill-scale", + "nix2container": "nix2container", "nixpkgs": "nixpkgs", "phps": "phps" } @@ -141,11 +162,11 @@ ] }, "locked": { - "lastModified": 1764557621, - "narHash": "sha256-kX5PoY8hQZ80+amMQgOO9t8Tc1JZ70gYRnzaVD4AA+o=", + "lastModified": 1780197589, + "narHash": "sha256-FVCr2Ij/jKf59a4LW481eeOF6rJRreOBrVgW/aUBTrw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "93316876c2229460a5d6f5f052766cc4cef538ce", + "rev": "21632e942d89bf1cce4e5a63d7e58a215a0cbfcc", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 9934eb7..a85bdd6 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { inputs = { - nixpkgs.url = "nixpkgs/nixos-25.11"; + nixpkgs.url = "nixpkgs/nixos-26.05"; flakelight = { url = "github:nix-community/flakelight"; inputs.nixpkgs.follows = "nixpkgs"; @@ -12,12 +12,18 @@ phps = { url = "github:fossar/nix-phps"; }; + nix2container = { + url = "github:nlewo/nix2container"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { - mill-scale, - phps, - ... - }: + outputs = + { + nix2container, + mill-scale, + phps, + ... + }: mill-scale ./. { crossTargets = [ "x86_64-unknown-linux-gnu" @@ -36,8 +42,17 @@ withOverlays = [ (import ./nix/overlay.nix) - (prev: final: { + (final: prev: { inherit (phps.packages.${prev.system}) php81 php80; + inherit (nix2container.packages.x86_64-linux) nix2container; + blackfire = prev.blackfire.overrideAttrs ( + oldAttrs: finalAttrs: { + src = final.fetchurl { + url = "https://packages.blackfire.io/debian/pool/any/main/b/blackfire/blackfire_${finalAttrs.version}_amd64.deb"; + sha256 = "sha256-1fswfZEElLyXWqvNW76BpKTpBomK9cglJtitZgcpxhM="; + }; + } + ); }) ]; @@ -50,20 +65,28 @@ "haze-image-php-8.0" = pkgs: pkgs.haze-image-php-80; }; - tools = pkgs: with pkgs; [cargo-edit bacon skopeo]; + tools = + pkgs: with pkgs; [ + cargo-edit + bacon + skopeo + dive + ]; homeModules = { - default = { - pkgs, - config, - lib, - ... - }: { - imports = [./nix/hm-module.nix]; - config = lib.mkIf config.programs.haze.enable { - programs.haze.package = lib.mkDefault pkgs.haze; + default = + { + pkgs, + config, + lib, + ... + }: + { + imports = [ ./nix/hm-module.nix ]; + config = lib.mkIf config.programs.haze.enable { + programs.haze.package = lib.mkDefault pkgs.haze; + }; }; - }; }; }; } diff --git a/nix/image/haze.nix b/nix/image/haze.nix index 5ce1051..10190ee 100644 --- a/nix/image/haze.nix +++ b/nix/image/haze.nix @@ -36,14 +36,24 @@ dnsmasq, frankenphp, nushell, -}: let + nix2container, + buildEnv, +}: +let inherit (builtins) toString compareVersions; - inherit (lib) readFile getExe concatStringsSep splitString take optionals; + inherit (lib) + readFile + getExe + concatStringsSep + splitString + take + optionals + ; version = (fromTOML (readFile ../../Cargo.toml)).package.version; phpVersion = concatStringsSep "." (take 2 (splitString "." php.version)); - phpEnv = callPackage ./php.nix {inherit debug php;}; + phpEnv = callPackage ./php.nix { inherit debug php; }; bootstrap = writers.writeNuBin "bootstrap" (readFile ./bootstrap); shadowSetupScript = writeShellApplication { @@ -51,7 +61,7 @@ text = dockerTools.shadowSetup; }; - tmpDir = runCommand "tmp-dir" {} '' + baseDirs = runCommand "tmp-dir" { } '' mkdir -p $out/tmp mkdir -p $out/var/cache/nginx mkdir -p $out/var/log/nginx @@ -63,9 +73,10 @@ mkdir -p $out/conf mkdir -p $out/var/spool ''; - configs = callPackage ./configs.nix {}; - scripts = callPackage ./scripts.nix {}; - phpunitUnwrapped = majorVersion: + configs = callPackage ./configs.nix { }; + scripts = callPackage ./scripts.nix { }; + phpunitUnwrapped = + majorVersion: callPackage ./phpunit.nix { inherit majorVersion; php = phpEnv; @@ -73,7 +84,7 @@ phpunit = writeShellApplication { name = "phpunit"; - runtimeInputs = [jq]; + runtimeInputs = [ jq ]; text = '' MAJOR=$(jq -r 'first(.require."phpunit/phpunit" | scan("[[:digit:]]+"))' vendor-bin/phpunit/composer.json) case "$MAJOR" in @@ -97,108 +108,142 @@ ''; }; - certificates = runCommand "scripts" {} '' + certificates = runCommand "scripts" { } '' mkdir -p $out cp -r ${../../certificates} $out/certificates ''; - clamav-data = runCommand "scripts" {} '' + clamav-data = runCommand "scripts" { } '' mkdir -p $out/etc mkdir -p $out/var/lib/clamav cp ${data/clamav/daily.cvd} $out/var/lib/clamav/daily.cvd cp -r ${configs/clamav} $out/etc/clamav ''; - baseImage = dockerTools.buildImage { - name = "icewind1991/haze-base"; - tag = phpVersion; + basePackages = [ + dockerTools.caCertificates + dockerTools.usrBinEnv + bash + blackfire + nginx + coreutils + shadow + cronie + redis + gnused + procps + gnugrep + minio-client + sudo + su + which + git + sqlite-interactive + clamav + samba + wget + curl + oracle-instantclient + vim + helix + python3Packages.supervisor + dnsmasq + nushell + getent + clamav-data + ]; - copyToRoot = [ - dockerTools.caCertificates - dockerTools.usrBinEnv - bash - blackfire - nginx - coreutils - shadow - cronie - redis - gnused - procps - gnugrep - minio-client - sudo - su - which - git - sqlite-interactive - clamav - samba - wget - curl - oracle-instantclient - vim - helix - python3Packages.supervisor - dnsmasq - nushell - getent - ]; - }; + phpPackages = [ + phpEnv + phpEnv.packages.composer + phpunit + ] + ++ optionals ((compareVersions phpVersion "8.2") == 1) [ + (frankenphp.override { + php = php.withExtensions ( + import ./php-ext.nix { + inherit lib php; + enableBlackfire = false; + } + ); + }) + ]; - phpImage = dockerTools.buildImage { - name = "icewind1991/haze-php"; - tag = phpVersion; - fromImage = baseImage; - - copyToRoot = - [ - phpEnv - phpEnv.packages.composer - phpunit - ] - ++ optionals ((compareVersions phpVersion "8.2") == 1) [ - (frankenphp.override { - php = php.withExtensions (import ./php-ext.nix { - inherit lib php; - enableBlackfire = false; - }); - }) - ]; - }; + # https://blog.eigenvalue.net/2023-nix2container-everything-once/ + foldImageLayers = + let + mergeToLayer = + priorLayers: component: + assert builtins.isList priorLayers; + assert builtins.isAttrs component; + let + layer = nix2container.buildLayer ( + component + // { + layers = priorLayers; + } + ); + in + priorLayers ++ [ layer ]; + in + layers: lib.foldl mergeToLayer [ ] layers; in - dockerTools.buildLayeredImage { - name = "icewind1991/haze"; - tag = phpVersion; - maxLayers = 5; - fromImage = phpImage; - contents = [ - tmpDir - bootstrap - configs - scripts - certificates - clamav-data - shadowSetupScript - ]; - fakeRootCommands = '' - chmod 1777 tmp - chmod 1777 var/tmp - chmod 1777 var/run - chmod 1777 var/log/nginx - chmod 1777 var/cache/nginx - chmod 1777 var/spool - chmod -R 0755 etc/nc - ''; - config = { - Cmd = [(getExe bootstrap)]; - Env = [ - "EDITOR=hx" - "WEBROOT=/var/www/html" - "HAZE_IMAGE_VERSION=${toString version}" - ]; - WorkingDir = "/var/www/html"; - Labels = { - "nl.icewind.haze.version" = toString version; +nix2container.buildImage { + name = "icewind1991/haze"; + tag = phpVersion; + layers = foldImageLayers [ + { + copyToRoot = buildEnv { + name = "base"; + paths = basePackages; + pathsToLink = [ + "/bin" + "/sbin" + "/etc" + "/usr" + "/conf" + ]; }; + } + { + copyToRoot = buildEnv { + name = "php"; + paths = phpPackages; + pathsToLink = [ "/bin" ]; + }; + } + { + copyToRoot = [ + baseDirs + bootstrap + configs + scripts + certificates + shadowSetupScript + ]; + perms = [ + { + path = baseDirs; + regex = "/tmp|var/(tmp|run|log/nginx|cache/nginx|spool)"; + mode = "0777"; + } + { + path = baseDirs; + regex = "/etc/nc"; + mode = "0755"; + } + ]; + } + ]; + config = { + Cmd = [ (getExe bootstrap) ]; + Env = [ + "EDITOR=hx" + "WEBROOT=/var/www/html" + "HAZE_IMAGE_VERSION=${toString version}" + ]; + WorkingDir = "/var/www/html"; + Labels = { + "nl.icewind.haze.version" = toString version; }; - } + }; +}