diff --git a/docker-build-nix/README.md b/docker-build-nix/README.md new file mode 100644 index 0000000..a0f14b0 --- /dev/null +++ b/docker-build-nix/README.md @@ -0,0 +1,143 @@ +# docker-build-nix + +Build and push Docker/OCI images generated by Nix flakes, with Attic cache integration. + +## Features + +- **Reproducible builds**: Uses Nix flakes for bit-for-bit identical images +- **Attic caching**: Pushes build artifacts to your Attic cache for faster subsequent builds +- **Nix store optimization**: Leverages Nix's existing binary caches (nixos.org + your Attic) +- **Smaller images**: Nix `dockerTools.buildLayeredImage` creates optimized layers + +## Usage + +### Basic example + +```yaml +name: Build Docker Image +on: + push: + branches: [main] + +jobs: + build: + runs-on: nix # Requires runner with Nix + steps: + - uses: actions/checkout@v4 + + - uses: https://git.toph.so/toph/ci-actions/docker-build-nix@main + with: + flake-output: .#dojo-image + image-name: toph/dojo + registry-password: ${{ secrets.GITEA_TOKEN }} + env: + ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }} +``` + +### Multiple images + +```yaml +jobs: + build-web: + runs-on: nix + steps: + - uses: actions/checkout@v4 + - uses: https://git.toph.so/toph/ci-actions/docker-build-nix@main + with: + flake-output: .#dojo-image + image-name: toph/dojo + image-tag: main + registry-password: ${{ secrets.GITEA_TOKEN }} + env: + ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }} + + build-agent: + runs-on: nix + steps: + - uses: actions/checkout@v4 + - uses: https://git.toph.so/toph/ci-actions/docker-build-nix@main + with: + flake-output: .#agent-image + image-name: toph/dojo/agent + image-tag: main + registry-password: ${{ secrets.GITEA_TOKEN }} + env: + ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }} +``` + +## Inputs + +| Input | Required | Default | Description | +|-------|----------|---------|-------------| +| `flake-output` | ✅ | - | Nix flake output (e.g., `.#dojo-image`) | +| `image-name` | ✅ | - | Target image name (e.g., `user/repo`) | +| `registry-password` | ✅ | - | Registry password/token | +| `image-tag` | ❌ | `main` | Image tag | +| `registry` | ❌ | `git.toph.so` | Docker registry | +| `registry-username` | ❌ | `${{ gitea.actor }}` | Registry username | +| `cache-name` | ❌ | `ci` | Attic cache name | +| `attic-endpoint` | ❌ | `https://cache.toph.so` | Attic endpoint | + +## Environment Variables + +| Variable | Required | Description | +|----------|----------|-------------| +| `ATTIC_TOKEN` | Optional | Attic token for pushing to cache. If not set, skips cache push. | + +## How It Works + +1. **Build with Nix**: Runs `nix build ` which uses Nix caching +2. **Push to Attic**: Uploads the entire build closure to your Attic cache +3. **Load to Docker**: Loads the OCI tarball into local Docker daemon +4. **Tag & Push**: Tags and pushes to your Docker registry + +## Example Flake + +Your `flake.nix` should export image outputs: + +```nix +{ + outputs = { self, nixpkgs }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + in + { + packages.x86_64-linux = { + # Your app + default = pkgs.callPackage ./package.nix { }; + + # OCI image + dojo-image = pkgs.dockerTools.buildLayeredImage { + name = "dojo"; + tag = "latest"; + contents = [ self.packages.x86_64-linux.default ]; + config = { + Cmd = [ "${self.packages.x86_64-linux.default}/bin/dojo" ]; + }; + }; + }; + }; +} +``` + +## Prerequisites + +- **Nix runner**: Runner with `nix` label using `docker://registry.toph.so/nix-runner:latest` +- **Attic cache**: Optional but recommended for caching (`cache.toph.so`) +- **ATTIC_TOKEN**: Set in Forgejo secrets if you want cache push +- **GITEA_TOKEN**: Auto-available in Forgejo Actions + +## Comparison with docker-build + +| Feature | docker-build | docker-build-nix | +|---------|-------------|------------------| +| Build method | Docker | Nix | +| Reproducibility | Layer-dependent | Byte-for-byte | +| Caching | S3 layers | Attic derivations | +| Image size | Larger | Optimized | +| Runner | Any | Requires Nix | + +## See Also + +- [docker-build](../docker-build/) - Traditional Docker builds with S3 cache +- [push-nix-cache](../push-nix-cache/) - Push arbitrary Nix paths to Attic diff --git a/docker-build-nix/action.yaml b/docker-build-nix/action.yaml new file mode 100644 index 0000000..d03a32d --- /dev/null +++ b/docker-build-nix/action.yaml @@ -0,0 +1,88 @@ +name: Build and Push Docker Image from Nix +description: Build OCI image with Nix flake, push to registry with Attic caching + +inputs: + flake-output: + description: 'Nix flake output for the OCI image (e.g., .#dojo-image)' + required: true + + image-name: + description: 'Target image name in registry (e.g., git.toph.so/user/repo)' + required: true + + image-tag: + description: 'Image tag' + required: false + default: 'main' + + registry: + description: 'Docker registry' + required: false + default: 'git.toph.so' + + registry-username: + description: 'Registry username' + required: false + default: ${{ gitea.actor }} + + registry-password: + description: 'Registry password/token' + required: true + + cache-name: + description: 'Attic cache name to push build artifacts' + required: false + default: 'ci' + + attic-endpoint: + description: 'Attic cache endpoint' + required: false + default: 'https://cache.toph.so' + +runs: + using: composite + steps: + - name: Build OCI image with Nix + shell: bash + run: | + echo "Building ${{ inputs.flake-output }}..." + nix build "${{ inputs.flake-output }}" --print-build-logs + + - name: Push build artifacts to Attic cache + shell: bash + if: env.ATTIC_TOKEN != '' + env: + ATTIC_TOKEN: ${{ env.ATTIC_TOKEN }} + run: | + # Configure attic client + mkdir -p ~/.config/attic + cat > ~/.config/attic/config.toml <