BlueBuild CLI

repository·main·Indexed 41 days ago

https://github.com/blue-build/cli

A command-line tool for building custom container images (Containerfiles) based on a simplified recipe.yml configuration, specifically designed for Fedora/Silverblue-style immutable distributions. It automates templating and building using tools like podman, docker, or buildah, and supports image signing with cosign and CI/CD integration for GitHub Actions and GitLab CI.

Tokens
18.6K
Snippets
83
Records
98
Agent score
52%

What's inside BlueBuild

  1. How platform selection works in BlueBuild

    main

    When building images, the final set of target platforms is determined by a hierarchy between CLI flags and recipe definitions:

    1. CLI Flags: If the --platform flag is provided in the command line, it overrides any platform settings defined in the recipe files.
    2. Recipe Settings: If no --platform flag is provided, the CLI uses the platforms specified within the recipe(s).
    3. Default: If neither the CLI nor the recipe specifies a platform, the CLI defaults to the host's default platform.

    Note: Building for an architecture different from your hardware (e.g., building arm64 on amd64) requires qemu to be installed and will result in significantly longer build times.

  2. Use the `copy` module to add COPY instructions

    main

    The copy module is a shorthand for adding a Docker COPY instruction to your image. It is a built-in module available only during compiler-based builds using the BlueBuild CLI.

    Properties:

    • src: The source path (file or directory).
    • dest: The destination path in the image.
    • from (optional): The source image or stage to copy from. If omitted, files are copied from the local build context.
    modules:
    - type: copy
      from: docker.io/mikefarah/yq
      src: /usr/bin/yq
      dest: /usr/bin/
  3. Control the order of operations in the `containerfile` module

    main

    The order in which instructions are added to the main Containerfile follows these rules for each module definition:

    1. All containerfiles: are added first, in the order they are defined.
    2. All snippets: are added second, in the order they are defined.

    To run snippets before your external containerfiles, you must define them in a separate module block appearing earlier in the modules list.

    modules:
      # Snippets here will appear BEFORE containerfiles
      - type: containerfile
        snippets:
          - RUN --mount=type=tmpfs,target=/tmp /some/script.sh
    
      # Containerfiles here will appear AFTER the snippets above
      - type: containerfile
        containerfiles:
          - example
          - subroutine
  4. Optimize images with rechunking methods

    main

    Rechunking allows for smaller images and more efficient updates by restructuring how layers are stored. The build command supports three primary rechunking strategies:

    1. Chunkah

    Uses Chunkah to rechunk the image.

    • Flag: --chunkah
    • Version: Use --chunkah-version to specify a tag or a SHA-256 digest.
    • Layers: Control the number of layers with --max-layers.

    2. Build-Chunked-OCI

    Uses rpm-ostree compose build-chunked-oci.

    • Flag: --build-chunked-oci
    • Warning: This increases build time and disk space usage during the build process.
    • Layers: Control the number of layers with --max-layers.
    • Plan: Use --rechunk-clear-plan to ignore previous rechunk plans.

    3. hhd-dev/rechunk

    Uses hhd-dev/rechunk.

    • Flag: --rechunk
    • Warning: This must be run as root and is marked for future deprecation.
    • Warning: Increases build time and disk space usage.
    • Plan: Use --rechunk-clear-plan to ignore previous rechunk plans.

    Note: When using any rechunker, you can use --remove-base-image to free up disk space by removing the base image from local storage after the build but before rechunking.

  5. Configure BlueBuild CI builds

    main

    BlueBuild supports CI/CD workflows for both GitHub Actions and GitLab CI.

    GitHub Actions

    Use the blue-build/github-action@v1. You must provide a recipe, cosign_private_key (for signing), and a registry_token.

    GitLab CI

    Use the ghcr.io/blue-build/cli image with a docker:dind service. Ensure you use GitLab's Secure Files to handle your cosign.key.

    bluebuild build --push ./recipes/$RECIPE
  6. Rebase an existing Fedora Atomic installation to a blue-build image

    main

    To rebase an existing Fedora Atomic installation to a blue-build image, you must perform the rebase in two stages: first to the unsigned image to install the necessary signing keys and policies, and then to the signed image.

    Warning: This uses an experimental feature (OstreeNativeContainerStable).

    1. Rebase to the unsigned image:
      rpm-ostree rebase ostree-unverified-registry:cli/blue-build/test-empty-files:latest
    2. Reboot to complete the rebase.
    3. Rebase to the signed image:
      rpm-ostree rebase ostree-image-signed:docker://cli/blue-build/test-empty-files:latest
    4. Reboot again to complete the installation.

    Note: The latest tag points to the most recent build, but the Fedora version is controlled by the recipe.yml file in the repository, preventing accidental major version upgrades.

    # Step 1: Rebase to unsigned
    rpm-ostree rebase ostree-unverified-registry:cli/blue-build/test-empty-files:latest
    
    # Step 2: Reboot
    systemctl reboot
    
    # Step 3: Rebase to signed
    rpm-ostree rebase ostree-image-signed:docker://cli/blue-build/test-empty-files:latest
    
    # Step 4: Reboot again
    systemctl reboot
  7. Install the BlueBuild CLI

    main

    BlueBuild can be installed using several methods depending on your environment. Note that every image created with bluebuild comes with the CLI pre-installed.

    Best for building specifically for your environment.

    cargo install --locked blue-build

    Podman or Docker

    Installs the binary to /usr/local/bin.

    # Using Podman
    podman run --pull always --rm ghcr.io/blue-build/cli:latest-installer | bash
    
    # Using Docker
    docker run --pull always --rm ghcr.io/blue-build/cli:latest-installer | bash

    GitHub Install Script

    bash <(curl -s https://raw.githubusercontent.com/blue-build/cli/main/install.sh)

    Distrobox

    Run bluebuild in a rootless alpine container without installing it on your host. Clone the repository and run:

    distrobox assemble create

    Note: Rootless Distrobox builds cannot be used to locally rebase images. For rebasing, install the CLI directly.

    Nix / NixOS

    Install via Flakehub.

    Non-NixOS:

    nix profile install https://flakehub.com/f/blue-build/cli/*.tar.gz#bluebuild

    NixOS (via fh input):

    {pkgs,inputs,...}: {
        ...
        environment.SystemPackages = [
            inputs.bluebuild.packages.${pkgs.system}.bluebuild
        ];
        ...
    }
    cargo install --locked blue-build
  8. Represent OCI references with OciRef

    main

    The OciRef enum is used to represent different ways an OCI image can be referenced, such as local storage, OCI archives, OCI directories, or remote registries. When converted to a string (via Display), it uses specific URI schemes:

    • LocalStorage: containers-storage:<reference>
    • OciArchive: oci-archive:<path>
    • OciDir: oci:<path>
    • Remote: docker://<reference>
    // Example of how OciRef variants are represented as strings
    // LocalStorage -> "containers-storage:image:tag"
    // OciArchive   -> "oci-archive:/path/to/archive.tar"
    // OciDir       -> "oci:/path/to/directory"
    // Remote       -> "docker://registry.com/image:tag"
  9. Define Modules using `from-file`

    main

    A Module can be defined in two ways:

    1. Inline: By providing required_fields directly in the current file.
    2. External: By using the from-file key, which points to a path relative to the base recipe path. This allows for modularizing recipes and reusing definitions across different files.

    Note: You cannot use both required_fields and from-file in the same module definition.

    # Example of an external module reference
    from-file: my_custom_module.yml
  10. Configure secrets for container builds

    main

    The Secret enum defines how sensitive information (like API keys or SSH keys) is provided to the container build process. Secrets are identified by a unique hash and can be provided via several methods. When used in a build context, they are passed to the builder (e.g., Podman or Docker) using --secret flags and then made available inside the container via mounts or environment variables.

    Supported secret types:

    • env: Uses an existing environment variable from the host.
    • file: Uses a file from the host filesystem.
    • exec: Runs a command on the host and uses its standard output as the secret value.
    • ssh: Enables SSH agent forwarding for the build process.
    // Example JSON representation of different secret types
    {
      "secrets": [
        { "type": "env", "name": "MY_API_KEY", "mount": { "type": "env", "name": "API_KEY_IN_CONTAINER" } },
        { "type": "file", "source": "/path/to/cert", "mount": { "type": "file", "destination": "/etc/ssl/cert" } },
        { "type": "exec", "command": "pass", "args": ["service/api_key"], "mount": { "type": "env", "name": "API_KEY" } },
        { "type": "ssh" }
      ]
    }