Skip to content

Repository files navigation

AxonOps Container Images

English | Français

License GitHub Issues Multi-Architecture

Container build definitions and CI/CD pipelines for AxonOps container images.

Table of Contents

Components

Databases

  • cassandra/ - Apache Cassandra with the AxonOps agent and no K8ssandra Management API, built from the k8ssandra Dockerfile with INCLUDE_MGMT_API=false (ghcr.io/axonops/cassandra/cassandra)

Kubernetes Distributions

  • k8ssandra/ - Apache Cassandra with AxonOps integration for K8ssandra Operator

AxonOps Self-Hosted

  • axonops/ - AxonOps self-hosted stack (complete platform components)

Integrations

Compose Stacks

  • docker-compose/ - Every Compose stack: the AxonOps platform on its own, the platform with a monitored Cassandra cluster, a cluster reporting to AxonOps SaaS, and a secured 3-rack cluster on a fixed subnet

Docker Compose

Docker Compose is a first-class deployment path in this repository. Every stack lives under docker-compose/, is built from the images published here, and is configured entirely through .env — no compose file needs editing to run one.

Quick start

A complete self-hosted AxonOps platform on one host:

git clone https://github.com/axonops/axonops-containers.git
cd axonops-containers/docker-compose/00-axonops-platform
cp env.example .env          # set AXONOPS_ORG_NAME
docker compose up -d
docker compose ps            # wait for all four services to report healthy

Then open http://localhost:3000. A cold start takes 2–3 minutes: the two data stores initialise first, then axon-server and the dashboard come up behind them.

The defaults in env.example are development values. Before running a stack you care about, set AXONOPS_ORG_NAME, AXONOPS_DB_PASSWORD and AXONOPS_SEARCH_PASSWORD — see docker-compose/README.md.

Which stack

Stack Use it to
00-axonops-platform run AxonOps for clusters you already have
01-cassandra-cluster see the whole thing working end to end — platform plus 3 monitored nodes
02-saas-cassandra-cluster monitor a cluster from AxonOps SaaS, with no platform to run locally
03-secure-3-rack-cluster model a production-shaped cluster — authentication, 3 racks, fixed addressing, remote JMX

Full comparison, including container counts and RAM at defaults: docker-compose/README.md.

Compose or Kubernetes?

Both paths deploy the same images; they differ in where the stack runs and what operates it.

Docker Compose Kubernetes
Where a single host a cluster
Use for evaluation, demos, development, small single-host deployments production, HA, anything that has to survive a host
AxonOps platform docker-compose/ stacks Helm charts oci://ghcr.io/axonops/charts/* — see VERSIONS.md and examples/AXONOPS_DEPLOYMENT.md
Cassandra cassandra/ image, run directly k8ssandra/ image via the K8ssandra operator — see examples/K8SSANDRA_DEPLOYMENT.md
Scaling and failover manual operator and scheduler

Agents report to axon-server the same way in both, so a cluster monitored by a Compose platform can be pointed at a Kubernetes one later without touching the monitored nodes.

Red Hat Universal Base Image (UBI)

All containers in this repository are built on Red Hat Universal Base Image (UBI) 9, providing enterprise-grade security, stability, and compliance.

Why Red Hat UBI?

  • Freely Redistributable - No subscription required to use or redistribute
  • Enterprise Security - Regular security updates and CVE patches from Red Hat
  • Production Hardened - Minimal attack surface with only essential packages
  • Compliance Ready - Meets requirements for regulated industries (finance, healthcare, government)
  • Long-Term Support - Stable base with predictable lifecycle (RHEL 9 supported until 2032)
  • Container Optimized - Purpose-built for containerized workloads with minimal footprint

Learn More:

Supported Versions

Which Apache Cassandra versions this repository builds is declared once, in the build_matrix section of versions.yaml. Workflow matrices, default versions, floating tag targets and release notes are all derived from it — no workflow file names a Cassandra version.

./scripts/build-matrix.sh versions   # every version built
./scripts/build-matrix.sh newest     # what the `latest` tag resolves to

The policy:

  • Added when Apache has released the patch and k8ssandra has published a matching cass-management-api base image. Both Cassandra images here are built FROM that base, so the second condition is not negotiable: a version added before its base exists fails every build job for it.
  • Kept once added. A newer patch does not retire an older one: every version in the matrix keeps being rebuilt and CVE-scanned, so a deployment pinned to an older patch still receives fixes.
  • Retired only when the line is end-of-life upstream, or when a dependency makes it unbuildable. Either way the line stays in versions.yaml marked published: false with the reason, rather than being deleted.
  • Retained but unpublished where the Dockerfiles are maintained and the images are not shipped. No line is in this state today.

Currently published: Cassandra 4.0.0 – 4.0.21, 4.1.0 – 4.1.12 and 5.0.1 – 5.0.9, with 4.0-latest, 4.1-latest and 5.0-latest resolving to the newest patch of each line and latest resolving to 5.0.9. See k8ssandra/README.md for the per-line detail and VERSIONS.md for the current tag and digest of every published image.

Repository Conventions

  • Multi-architecture support: linux/amd64, linux/arm64
  • Published to: GitHub Container Registry ghcr.io/axonops/<image-name>:<tag>
  • Automated CI/CD: GitHub Actions with comprehensive testing
  • Security scanning: Trivy vulnerability scanning on all images
  • Base images: Red Hat UBI 9 (digest-pinned for supply chain security)
  • Current versions: VERSIONS.md lists the current tag and digest of every published image and chart. It is generated from versions.yaml by ./scripts/update-versions.sh — edit the YAML, never the Markdown.
  • Build matrix: the Cassandra versions built are declared once, in the build_matrix section of versions.yaml, and read by workflows through ./scripts/build-matrix.sh. Never write a version list into a workflow file — see Supported Versions.

Security

CVE Policy

Immutable Tagging: All container images use immutable versioning. When CVEs are discovered and patched, we release NEW versions rather than overwriting existing tags.

Version Increments:

  • Critical CVEs (CRITICAL, HIGH severity): Immediate patch release (e.g., 1.0.31.0.4)
  • Non-critical CVEs (MEDIUM, LOW): Batched into monthly releases
  • Patch version increments may include: CVE fixes, component updates (e.g., AxonOps agent), bug fixes, or feature additions

Latest Tag Behavior:

  • latest tag always points to the most recent secure version
  • Provides automatic security updates when using latest tag
  • NOT recommended for production - use specific versions instead

Production Deployment:

  • Always pin to specific immutable versions (e.g., 5.0.6-v0.1.110-1.0.5)
  • Never use latest, 5.0-latest, or {version}-latest tags in production
  • Review release notes before upgrading
  • Test upgrades in non-production environments first

CVE Notifications:

  • Automated nightly security scans with Trivy
  • Email notifications for new CRITICAL/HIGH CVEs
  • Transparent disclosure in release notes

For highest security environments, see Gold Standard Security Deployment.


Gold Standard Security Deployment

Digest-Based Deployment provides the highest level of security and immutability for container deployments.

What is Digest-Based Deployment?

Instead of using tags (which can be mutable), deploy using the image's SHA256 digest:

# Tag-based (good)
image: ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# Digest-based (best)
image: ghcr.io/axonops/k8ssandra/cassandra@sha256:412c85225...

Benefits

100% Immutable - Guaranteed exact same image every time, forever

Survives Tag Manipulation - Unaffected if tags are accidentally or maliciously changed

Compliance Ready - Meets requirements for regulated environments (finance, healthcare, government)

Audit Trail - Digest in deployment manifest provides cryptographic proof of exact image

Supply Chain Security - Combined with signature verification, provides complete provenance

Finding Image Digests

Method 1: From GHCR UI

  1. Navigate to package: https://github.com/axonops/axonops-containers/pkgs/container/k8ssandra%2Fcassandra
  2. Click on specific version
  3. Copy SHA256 digest shown

Method 2: Using Docker/Podman

# Pull the image first
docker pull ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# Get digest
docker inspect ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5 \
  --format='{{index .RepoDigests 0}}'

# Output: ghcr.io/axonops/k8ssandra/cassandra@sha256:412c85225...

Method 3: During Workflow

  • Check GitHub Actions workflow logs after publishing
  • Digest printed in build output

Kubernetes Deployment Example

K8ssandraCluster manifest:

apiVersion: k8ssandra.io/v1alpha1
kind: K8ssandraCluster
metadata:
  name: production-cluster
spec:
  cassandra:
    serverVersion: "5.0.6"
    # Use digest instead of tag
    serverImage: "ghcr.io/axonops/k8ssandra/cassandra@sha256:412c852252ec4ebcb8d377a505881828a7f6a5f9dc725cc4f20fda2a1bcb3494"
    datacenters:
      - metadata:
          name: dc1
        size: 3
        # ... rest of configuration

Verifying Signatures

All images published to GHCR are signed with Sigstore Cosign using keyless signing.

Standard Verification:

# Install cosign
brew install sigstore/tap/cosign  # macOS
# or: https://docs.sigstore.dev/cosign/installation/

# Verify signature
cosign verify \
  --certificate-identity-regexp='https://github.com/axonops/axonops-containers' \
  --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
  ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# Check signature exists
cosign tree ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

Troubleshooting (macOS Issues):

If you encounter issues with local cosign on macOS, use the official Cosign container image:

# Using Docker
docker run --rm gcr.io/projectsigstore/cosign:v2.4.1 verify \
  --certificate-identity-regexp='https://github.com/axonops/axonops-containers' \
  --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
  ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# Using Podman
podman run --rm gcr.io/projectsigstore/cosign:v2.4.1 verify \
  --certificate-identity-regexp='https://github.com/axonops/axonops-containers' \
  --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
  ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

This uses the official Cosign container and works reliably across all platforms.

Successful verification proves:

  • ✅ Image was built by official GitHub Actions workflow
  • ✅ Image has not been tampered with
  • ✅ Build provenance is traceable to specific commit and workflow run

Enforcing Signed Images in Kubernetes

For production environments requiring signature verification before deployment:

Policy Enforcement Tools:

  • Kyverno - Kubernetes native policy engine
  • OPA Gatekeeper - Open Policy Agent for Kubernetes
  • Sigstore Policy Controller - Official Sigstore admission controller

Example: Kyverno Policy

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-axonops-images
spec:
  validationFailureAction: Enforce
  rules:
    # RULE 1: Deny any image NOT from ghcr.io/axonops/
    - name: check-registry
      match:
        any:
        - resources:
            kinds: [Pod]
            namespaces: [kafka,k8ssandra-operator,strimzi]
      validate:
        message: "Only images from ghcr.io/axonops/ are allowed in this namespace."
        foreach:
        - list: "request.object.spec.containers"
          deny:
            conditions:
              all:
              - key: "{{ element.image }}"
                operator: NotEquals # Use NotEquals with wildcards
                value: "ghcr.io/axonops/*"

    # RULE 2: Verify the signatures of those images
    - name: verify-signature
      match:
        any:
        - resources:
            kinds: [Pod]
            namespaces: [kafka,k8ssandra-operator,strimzi]
      verifyImages:
        - imageReferences:
            - "ghcr.io/axonops/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/axonops/axonops-containers/*"
                    issuer: "https://token.actions.githubusercontent.com"
                    rekor:
                      url: https://rekor.sigstore.dev

Cloud Provider Support:

  • AWS EKS - Use Kyverno or OPA Gatekeeper via Helm
  • Google GKE - Binary Authorization with Cosign attestations
  • Azure AKS - Azure Policy with Ratify + Cosign
  • Rancher/RKE - Kyverno or OPA Gatekeeper via Rancher Apps

For detailed setup, see your Kubernetes distribution's documentation on admission controllers and image policy enforcement.

Best Practices

For Production Clusters:

  1. ✅ Use digest-based deployment
  2. ✅ Verify signatures before deployment (signed images)
  3. ✅ Pin digest in version control (GitOps)
  4. ✅ Document digest → version mapping in release notes
  5. ✅ Update digests only after testing in non-production

For Development/Testing:

  • Tag-based deployment is acceptable for faster iteration
  • Use development image registry for testing

Updating Digests:

# 1. Pull new version
docker pull ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# 2. Get new digest
NEW_DIGEST=$(docker inspect ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5 \
  --format='{{index .RepoDigests 0}}' | cut -d@ -f2)

# 3. Update manifest
sed -i "s|@sha256:.*|@${NEW_DIGEST}\"|" k8ssandra-cluster.yaml

# 4. Review, test, and commit
git diff k8ssandra-cluster.yaml

Development

Branch Structure:

  • development - Default branch, commit directly here
  • main - Production releases only (PR required)
  • feature/* - Optional, for complex features

See DEVELOPMENT.md for complete guidelines.

Developer Workflow:

# Work directly on development
git checkout development && git pull origin development
git add . && git commit -S -m "Add feature" && git push origin development

# For production: create PR development → main (approval required)

Container Security Standards (ALL Components)

Every container we build MUST follow these security practices:

  1. Digest Pinning (Supply Chain Security)

    • ALWAYS pin base images by SHA256 digest, NEVER by tag
    • Tags are mutable - can be replaced maliciously
    • Digests are immutable - cryptographically guaranteed
    • Example:
      # CORRECT
      FROM upstream/image@sha256:abc123...
      
      # WRONG - Supply chain vulnerability!
      FROM upstream/image:latest
      FROM upstream/image:v1.0.0
  2. Container Signing (Authenticity)

    • ALL published images MUST be signed with Cosign
    • Use keyless signing with GitHub OIDC (no secret management)
    • Sign by digest immediately after build
    • Publish to ghcr.io/axonops/<component>/<image-name>:tag
  3. Verification & Testing

    • Verify checksums for downloaded artifacts (RPMs, tarballs, etc.)
    • Verify base image digest matches expected version
    • Automated startup error detection
    • Security scanning with Trivy before publishing

Why these standards matter:

  • Prevents supply chain attacks (malicious base images)
  • Ensures image authenticity (Cosign signatures)
  • Provides full audit trail (digests + signatures)
  • Meets compliance requirements for regulated environments

Releasing

Development Publishing

Purpose: Publish signed images to development registry for testing before production release.

Registry: ghcr.io/axonops/development/<component>/<image-name>

Example: ghcr.io/axonops/development/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.0

Characteristics:

  • All images are Cosign signed (same as production)
  • Uses same security standards as production (digest pinning, checksums, verification)
  • Allows testing with specific versions
  • No GitHub Releases created
  • Tagged from development branch

Process:

# 1. Tag development branch (any name, e.g., dev-feature-x, dev-1.0.0)
git checkout development && git pull origin development
git tag dev-1.0.0 && git push origin dev-1.0.0

# 2. Trigger development publish workflow
gh workflow run development-<component>-publish.yml \
  -f dev_git_tag=dev-1.0.0 \
  -f container_version=dev-1.0.0

# 3. Test development image
docker pull ghcr.io/axonops/development-<image>:5.0.6-dev-1.0.0
# Run tests, validate functionality

# 4. Promote to main (auto-creates PR)
git tag merge-1.0.0 && git push origin merge-1.0.0
# PR auto-created, review and merge to main

Use for: Feature testing, integration testing, QA validation before production.


Production Publishing

Purpose: Publish stable, tested images to production registry.

Registry: ghcr.io/axonops/<image-name>

Characteristics:

  • Immutable (version validation prevents overwrites)
  • Creates GitHub Releases
  • Tagged from main branch only
  • Only after testing in development

Prerequisites:

  • Changes merged to development and tested
  • Development images validated (if published)
  • PR from developmentmain approved and merged

Process:

Step 1: Create Git Tag on Main Branch

IMPORTANT: Tags must be created on the main branch. The publish workflow will validate this.

# Ensure you're on main and up to date
git checkout main
git pull origin main

# Tag the commit
git tag 1.0.0

# Push tag to remote
git push origin 1.0.0

The tag can be any name (e.g., 1.0.0, v1.0.0, release-2024-12). It marks the exact code snapshot to build from.

Note: If you tag a commit not on main, the publish workflow will fail with an error.

Step 2: Trigger Publish Workflow

You can trigger the publish workflow via GitHub CLI or GitHub UI.

Option A: GitHub CLI

Install and authenticate (first time only):

# macOS
brew install gh

# Linux
# See: https://github.com/cli/cli#installation

# Authenticate
gh auth login

Trigger the signed publish workflow:

gh workflow run <component>-publish-signed.yml \
  -f main_git_tag=1.0.0 \
  -f container_version=1.0.0

Arguments explained:

  • -f main_git_tag=1.0.0 - The git tag on main branch to checkout and build (the tag you created in Step 1)
  • -f container_version=1.0.0 - The container version for GHCR images (e.g., creates 5.0.6-v0.1.110-1.0.5)

Note: Use the -signed workflows (k8ssandra-publish-signed.yml) for new releases. These publish to the new image paths with cryptographic signatures. Old workflows remain for backward compatibility but are deprecated.

Monitor progress:

gh run watch

Option B: GitHub UI

  1. Navigate to Actions tab in GitHub repository
  2. Select the publish workflow (e.g., K8ssandra Publish to GHCR)
  3. Click Run workflow button (top right)
  4. A form appears with inputs:
    • main_git_tag: Enter the git tag on main branch created in Step 1 (e.g., 1.0.0)
      • This determines which code to build
    • container_version: Enter the container version (e.g., 1.0.0)
      • This becomes the container version on published images
      • Example: 5.0.6-v0.1.110-1.0.5 where 1.0.0 is the container version
  5. Click Run workflow to start

Step 3: Workflow Execution

The signed publish workflow will:

  • Validate tag is on main branch (fails if not)
  • Validate container_version doesn't exist in GHCR (fails if duplicate)
  • Checkout the main_git_tag commit (exact code snapshot)
  • Run full test suite
  • Build multi-arch images (amd64, arm64)
  • Push to GHCR with multi-dimensional tags
  • Sign images with Sigstore Cosign (keyless, GitHub OIDC)
  • Re-push tags to ensure proper GHCR UI display
  • Create GitHub Release named <component>-signed-<container_version>

Images are signed using keyless signing with transparency log entries. Signatures can be verified with cosign verify (see Verifying Signatures).

Step 4: Verify Release

# View GitHub Release
gh release view k8ssandra-signed-1.0.0

# Pull and test image
docker pull ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# Verify signature
cosign verify \
  --certificate-identity-regexp='https://github.com/axonops/axonops-containers' \
  --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
  ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

# Or check signature exists
cosign tree ghcr.io/axonops/k8ssandra/cassandra:5.0.6-v0.1.110-1.0.5

All production images are cryptographically signed. Signature verification proves the image was built by official workflows and has not been tampered with. See Gold Standard Security Deployment for more details.

Component Release Documentation

Each component has detailed release documentation:

Acknowledgements

Apache Cassandra

We extend our appreciation to the Apache Cassandra community for their outstanding work and contributions to the distributed database field. Apache Cassandra is a free and open-source, distributed, wide-column store, NoSQL database management system designed to handle large amounts of data across many commodity servers, providing high availability with no single point of failure.

For more information:

K8ssandra

We acknowledge K8ssandra for providing excellent Kubernetes operator and management tools for Apache Cassandra. K8ssandra is a production-ready platform for running Apache Cassandra on Kubernetes, including backup/restore, repairs, and monitoring capabilities.

For more information:

AxonOps Schema Registry

We acknowledge AxonOps Schema Registry for providing a Confluent-compatible Schema Registry with support for multiple storage backends including PostgreSQL, MySQL, and Apache Cassandra.

For more information:

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Legal Notices

This project may contain trademarks or logos for projects, products, or services. Any use of third-party trademarks or logos are subject to those third-party's policies.

Trademarks

  • AxonOps is a registered trademark of AxonOps Limited
  • Apache, Apache Cassandra, and Cassandra are trademarks of the Apache Software Foundation or its subsidiaries in Canada, the United States and/or other countries
  • Apache Kafka and Kafka are trademarks of the Apache Software Foundation
  • K8ssandra is a trademark of the Apache Software Foundation
  • Docker is a trademark or registered trademark of Docker, Inc. in the United States and/or other countries
  • Podman is a trademark of Red Hat, Inc.
  • OpenSearch is a trademark of Amazon.com, Inc. or its affiliates
  • Kubernetes is a registered trademark of The Linux Foundation

Made with ❤️ by AxonOps

About

Add the AxonOps components to Cassandra UBI containers used by K8ssandra and others

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages