/stacker

An OCI / Docker image rebasing tool, best paired with GitOps

Primary LanguageGoMIT LicenseMIT

Stacker

A tool to rebase container (Docker) images instead of rebuilding them.

It is based around the idea of adding OCI annotations for base images to just replace the layers of the base image if a newer version is available. Have a look at crane rebase for more information.

This enables updates of app images without needing a complete build and is useful e.g. when running many different apps based on the same base image(s).

Usage

Requirements

  • You need to build your app images with OCI base image annotations (e.g. with crane append --set-base-image-annotations)
  • The FROM image in your app Dockerfile should point to a base image tag that is updated as an alias (e.g. :1 or :latest)
  • You need to include {"$rebase": "[identifier]:name"} and {"$rebase": "[identifier]:tag"} annotations as comments in a YAML file, where identifier needs to be unique per file

Example

Take this example of rebasing images inside a Flux HelmRelease:

config/my-app.yaml

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: integration
spec:
  chart:
    spec:
      chart: my-app
      reconcileStrategy: ChartVersion
      sourceRef:
        kind: HelmRepository
        name: my-app
        namespace: my-namespace
      version: '1.1.0'
  interval: 5m0s
  releaseName: integration
  values:
    app:
      image:
        repository: registry.example.com/my-group/my-project # {"$rebase": "app:name"}
        tag: 2.3.0 # {"$rebase": "app:tag"}

By using the $rebase annotation, Stacker will rebase the given image onto the latest base image and update the YAML tag to include the new digest.

stacker ./config
  ◦ Rebasing                  file=config/my-app.yaml image=registry.example.com/my-group/my-project tag=2.3.0
  ◦ Pushing rebased image as  file=config/my-app.yaml image=registry.example.com/my-group/my-project tag=2.3.0 rebased=registry.example.com/my-group/my-project:2.3.0
  • Rebased image             file=config/my-app.yaml image=registry.example.com/my-group/my-project tag=2.3.0 newDigest=sha256:b8a1c2638173eb55dc30489cc0a1beb60680b5838d9eddb34bf9213ec73d3d1e
  • Wrote back updated YAML to file file=config/my-app.yaml

After running the command, the rebased image will be pushed and the YAML file will be updated to:

# ...
spec:
  # ...
  values:
    app:
      image:
        repository: registry.example.com/my-group/my-project # {"$rebase": "app:name"}
        tag: 2.3.0@sha256:b8a1c2638173eb55dc30489cc0a1beb60680b5838d9eddb34bf9213ec73d3d1e # {"$rebase": "app:tag"}

The next step is to push the changes back to your Git repository, so a GitOps operator like Flux can apply the changes.

Ideally this is done in a scheduled CI pipeline to keep the images up-to-date.

CLI

NAME:
   stacker - Automatic rebasing of images using OCI base image annotations

USAGE:
   cmd [global options] command [command options] [directory]

DESCRIPTION:
   Recurses through the given directory to find YAML files with a rebase annotation and rebases the image onto the newest base image.

COMMANDS:
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h             show help (default: false)
   --super-verbose, --vv  Enable super verbose logging (default: false)
   --verbose, -v          Enable verbose logging (default: false)

Acknowledgements

This tool is based on the code from https://github.com/google/go-containerregistry/tree/main/cmd/crane for the image manipulation.

License

MIT