Deploying AxonOps on Kubernetes¶
This guide explains how to deploy AxonOps components and a Strimzi Kafka cluster on Kubernetes with local (hostPath) storage or shared storage and AxonOps monitoring agent integration.
Quick Start Alternative
For a streamlined deployment experience, you can use our automated installation script that handles the complete setup process. This script automates many of the manual steps described in this guide.
Components Required¶
- AxonOps Server - Core management server
- AxonOps Dashboard - Web UI
- AxonOps Timeseries DB - Metrics storage (Cassandra-based)
- AxonOps Search DB - Log and event storage (OpenSearch-based)
- cert-manager (Recommended) - Automatic TLS certificate management
AxonOps Infrastructure Setup¶
Cert Manager¶
Install cert-manager for automatic TLS certificate management:
helm upgrade --install \
cert-manager oci://quay.io/jetstack/charts/cert-manager \
--version v1.19.1 \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true
Create a self-signed cluster issuer if you do not have another issuer to use:
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-cluster-issuer
spec:
selfSigned: {}
EOF
AxonOps Timeseries DB¶
Create the data directories on the host (user ID 999):
mkdir -p /data/axon-timeseries
chown -R 999:999 /data/axon-timeseries
Create timeseries-values.yaml:
# Optional: Increase heap size for better performance
heapSize: 8192M
# TLS/SSL Configuration
tls:
# Enable TLS/SSL for Cassandra
enabled: true
# cert-manager configuration for automatic certificate management
certManager:
# Enable cert-manager for certificate provisioning
enabled: true
issuer:
name: selfsigned-cluster-issuer
persistence:
enabled: false # Disable PVC-based persistence
# Define hostPath volumes using extraVolumes
extraVolumes:
- name: timeseries-data
hostPath:
path: /data/axon-timeseries # Host directory path
type: DirectoryOrCreate # Creates directory if it doesn't exist
# Mount the hostPath volumes (do not change the paths)
extraVolumeMounts:
- name: timeseries-data
mountPath: /var/lib/cassandra
# Optional: Set resource limits
resources:
requests:
cpu: 1001m
memory: 2Gi
limits:
cpu: 2000m
memory: 4Gi
Install:
helm install axondb-timeseries oci://ghcr.io/axonops/charts/axondb-timeseries \
--namespace axonops \
--create-namespace \
-f timeseries-values.yaml
AxonOps Search DB¶
Create the data directory on the host:
mkdir -p /data/axon-search
chown -R 999:999 /data/axon-search
Create search-values.yaml:
# Large set up may need higher Heap Size
opensearchHeapSize: "8g"
persistence:
enabled: false
# Define hostPath volumes using extraVolumes
extraVolumes:
- name: data
hostPath:
path: /data/axon-search
type: DirectoryOrCreate # Creates directory if it doesn't exist
# Mount the hostPath volumes (do not change the paths)
extraVolumeMounts:
- name: data
mountPath: /var/lib/opensearch
# TLS/SSL Configuration
tls:
# Enable TLS/SSL
enabled: true
# cert-manager configuration for automatic certificate management
certManager:
# Enable cert-manager for certificate provisioning
enabled: true
issuer:
name: selfsigned-cluster-issuer
Install:
helm install axondb-search oci://ghcr.io/axonops/charts/axondb-search \
--namespace axonops \
--create-namespace \
-f search-values.yaml
AxonOps Server¶
Create axonops-server-secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: axon-server-config
namespace: axonops
type: Opaque
stringData:
axon-server.yml: |
agents_port: 1888
api_port: 8080
host: 0.0.0.0
search_db:
hosts:
- https://axondb-search-cluster-master.axonops.svc.cluster.local:9200
username: admin
password: MyS3cur3P@ss2025
skip_verify: true
org_name: example
axon_dash_url: https://axonops.example.com
# Log to stdout for Kubernetes
log_file: /dev/stdout
tls:
mode: disabled
auth:
enabled: false
cql_autocreate_tables: true
cql_hosts:
- axondb-timeseries-headless.axonops.svc.cluster.local
cql_skip_verify: true
cql_ssl: true
cql_username: cassandra
cql_password: cassandra
Note
The default installation assumes your clients will be all in Kubernetes. If you will have AxonOps clients outside of Kubernetes (external Cassandra or Kafka clusters) you will also need to add an ingress or NodePort configuration.
If you need external access, create axon-server-values.yaml using the following example:
# If you do not have an ingress (Preferred) you can use nodePort by setting
# it up here
agentService:
type: ClusterIP
listenPort: 1888
annotations: {}
labels: {}
externalIPs: []
# Optional, only used for "type: ClusterIP"
clusterIP: ""
# Optional, only used for "type: LoadBalancer"
loadBalancerIP: ""
loadBalancerSourceRanges: []
# Optional, only used for "type: NodePort"
nodePort: 0
# For ingress, you can chose between nginx, traefik, etc or the new
# HTTPRoute Gateway API: https://gateway-api.sigs.k8s.io/api-types/httproute/
apiIngress:
enabled: false
className: traefik
annotations: {}
# cert-manager.io/cluster-issuer: "letsencrypt"
hosts:
- host: api.example.com
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: api-tls
# hosts:
# - api.example.com
# HTTPRoute configuration for Gateway API (alternative to Ingress)
httpRoute:
enabled: false
annotations: {}
parentRefs:
- name: gateway
sectionName: http
# namespace: default
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
Install:
kubectl apply -n axonops -f axonops-server-secret.yaml
helm install axon-server oci://ghcr.io/axonops/charts/axon-server \
--namespace axonops \
--create-namespace \
-f axon-server-values.yaml \ ## IF used
--set configurationSecret=axon-server-config
AxonOps Dashboard¶
Create axonops-dash-values.yaml:
# Configuration for axon-dash application
config:
# Axon server URL endpoint
axonServerUrl: "http://axon-server-api.axonops.svc.cluster.local:8080"
service:
type: ClusterIP
port: 3000
# Alternative: NodePort configuration
# service:
# type: NodePort
# ports:
# - port: 3000
# targetPort: 3000
# nodePort: 32000 # The ACTUAL "Host Port" (must be 30000-32767)
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# cert-manager.io/cluster-issuer: selfsigned-cluster-issuer
hosts:
- host: axonops.mycompany.com
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: axon-dash-tls
# hosts:
# - axonops.mycompany.com
Note
You will need to choose between Ingress (preferred option) or NodePort for external access.
Install:
helm install axon-dash oci://ghcr.io/axonops/charts/axon-dash \
--namespace axonops \
--create-namespace \
-f axonops-dash-values.yaml
Validation¶
Verify all pods are running:
k get po -n axonops
Expected output:
NAME READY STATUS RESTARTS AGE
axon-dash-847d57885-bmnnl 1/1 Running 0 62s
axon-server-0 1/1 Running 0 63s
axondb-search-cluster-master-0 1/1 Running 0 3m9s
axondb-timeseries-0 1/1 Running 0 4m43s
Verify all services are created:
k get svc -n axonops
Expected output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
axon-dash-svc ClusterIP 10.43.72.64 <none> 3000/TCP 89s
axon-server-agent ClusterIP 10.43.8.100 <none> 1888/TCP 90s
axon-server-api ClusterIP 10.43.237.168 <none> 8080/TCP 90s
axondb-search-cluster-master ClusterIP 10.43.120.95 <none> 9200/TCP,9300/TCP,9600/TCP 3m36s
axondb-search-cluster-master-headless ClusterIP None <none> 9200/TCP,9300/TCP,9600/TCP 3m36s
axondb-timeseries ClusterIP 10.43.16.42 <none> 9042/TCP,7199/TCP 5m10s
axondb-timeseries-headless ClusterIP None <none> 9042/TCP 5m10s