Kubernetes Installation
Deploy an Arc Enterprise cluster with Helm: separate writer, reader, and compactor StatefulSets, IRSA or MinIO storage, peer replication, and an L7 load balancer for writers.
Deploy Arc on Kubernetes using Helm for production-grade analytical data management.
Prerequisites
- Kubernetes 1.24+
- Helm 3.0+
kubectlconfigured to access your cluster- Persistent storage (for local storage backend)
Quick start
# Install Arc
helm install arc https://github.com/basekick-labs/arc/releases/latest/download/arc-26.09.1.tgz
# Port forward to access locally
kubectl port-forward svc/arc 8000:8000
# Verify installation
curl http://localhost:8000/healthGet your admin token
# Get the pod name
kubectl get pods -l app=arc
# View logs to find admin token
kubectl logs -l app=arc | grep -i "admin"You should see:
======================================================================
FIRST RUN - INITIAL ADMIN TOKEN GENERATED
======================================================================
Initial admin API token: arc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
======================================================================Save This Token
Copy this token immediately - you won't see it again!
Installation methods
helm install arc https://github.com/basekick-labs/arc/releases/latest/download/arc-26.09.1.tgzStorage backends
Local storage - each Arc node keeps its own PersistentVolume and the cluster
stays in sync via peer-to-peer replication (Pattern 1). No object storage is
required. Set storage.mode: local and size each role's PVC.
# values.yaml
storage:
mode: local
local:
storageClass: "" # default storage class
minio:
enabled: false # no object storage in local mode
writer:
replicas: 1
persistence:
size: 50Gi # local Parquet + WAL
reader:
replicas: 2
persistence:
size: 50Gi # reader needs a full data replica
compactor:
enabled: true
replicas: 1
persistence:
size: 50Gihelm install arc-ent helm/arc-enterprise -f values.yaml \
--set license.key=ARC-ENT-... \
--set cluster.sharedSecret.value=$(openssl rand -hex 32)The chart emits S3 config only (ARC_STORAGE_BACKEND=s3); point endpoint at
any S3-compatible service. For local-disk + peer replication instead of shared
object storage, use storage.mode: local (see
Deployment Patterns).
Configuration profiles
The Enterprise chart ships two ready-to-deploy presets in the chart root:
values-shared-storage.yaml (shared object storage via bundled MinIO) and
values-local-storage.yaml (per-node PVCs + peer replication). Both require a
license key and a cluster shared secret.
Shared object storage with the bundled MinIO — the recommended cloud-native layout. All writer pods accept writes concurrently (Pattern 2 multi-writer) and read/write the same bucket; the bucket is the durability layer, so the writer and compactor PVCs hold only WAL/scratch.
# values-shared-storage.yaml (excerpt)
storage:
mode: shared
shared:
external: false # bundled MinIO
bucket: arc-data
usePathStyle: true
useSSL: false
minio:
enabled: true
replicas: 1
persistence:
size: 100Gi
writer:
replicas: 1 # 1 = single writer; 3 = HA (2 is refused)
persistence:
size: 20Gi # WAL only; bucket holds Parquet
reader:
replicas: 2 # emptyDir in shared mode (no PVC)
compactor:
enabled: true
replicas: 1
persistence:
size: 20Gi # scratch only; bucket holds Parquethelm install arc-ent helm/arc-enterprise \
-f helm/arc-enterprise/values-shared-storage.yaml \
--set license.key=ARC-ENT-... \
--set cluster.sharedSecret.value=$(openssl rand -hex 32) \
--set minio.credentials.rootUser=arcminio \
--set minio.credentials.rootPassword=$(openssl rand -hex 32)Required overrides
license.key, cluster.sharedSecret.value, and (for bundled MinIO)
minio.credentials.rootUser / minio.credentials.rootPassword are mandatory —
the chart refuses to install if any of them is empty.
Helm values reference
Image & service account
# Container image (tag defaults to the chart appVersion)
image:
repository: ghcr.io/basekick-labs/arc
tag: "" # set "26.09.1" (or >=26.06.2) for full IRSA query-read support
pullPolicy: IfNotPresent
imagePullSecrets: []
# ServiceAccount shared by all Arc pods (writer/reader/compactor).
# Attach an AWS IAM role via the role-arn annotation for IRSA.
serviceAccount:
create: false # true = chart creates the ServiceAccount
name: ""
annotations: {} # eks.amazonaws.com/role-arn: arn:aws:iam::...:role/arc-s3License & authentication
license:
existingSecret: "" # Secret with key "license-key"
key: "" # your ARC-ENT-... license key (REQUIRED)
auth:
bootstrapToken:
existingSecret: "" # Secret with key "bootstrap-token"
value: "" # leave empty to let the Raft leader generate oneCluster
cluster:
name: arc-prod
# HMAC peer authentication — REQUIRED (chart refuses to install if empty).
sharedSecret:
existingSecret: "" # Secret with key "shared-secret"
value: "" # REQUIRED — e.g. $(openssl rand -hex 32)
# TLS between cluster nodes (recommended for multi-writer / production).
tls:
enabled: false
existingSecret: "" # tls.crt, tls.key (and optionally ca.crt)
# Single switch governing writer + compactor failover.
failover:
enabled: true
# Peer replication tuning — consulted ONLY when storage.mode=local.
replication:
pullWorkers: 4
fetchTimeoutMs: 60000
serveTimeoutMs: 120000
catchup:
enabled: true
barrierTimeoutMs: 10000Storage
The chart supports two modes via storage.mode. It emits S3 config only
(ARC_STORAGE_BACKEND=s3); there is no Azure path.
storage:
mode: shared # "shared" or "local"
# Shared mode — S3-compatible object storage (bundled MinIO or external S3).
shared:
external: false # false = bundled MinIO; true = your own S3
bucket: arc-data
region: us-east-1
endpoint: "" # auto-set for bundled MinIO; set for external S3
prefix: "" # optional key prefix (multi-tenant bucket sharing)
usePathStyle: true # true for MinIO and many S3-compatible services
useSSL: false # true for production S3
credentials:
useIRSA: false # true = AWS credential chain (external S3 only)
existingSecret: "" # keys: access-key, secret-key (ignored if useIRSA)
accessKey: ""
secretKey: ""
# Local mode — per-node PVCs + peer replication.
local:
storageClass: "" # fallback for roles that don't set their ownBundled MinIO
Rendered only when storage.mode=shared and storage.shared.external=false.
minio:
enabled: true
replicas: 1
persistence:
size: 100Gi
storageClass: ""
credentials:
existingSecret: "" # keys: root-user, root-password
rootUser: "" # REQUIRED (no weak defaults)
rootPassword: "" # REQUIREDRoles (writer / reader / compactor)
Each role is a StatefulSet with its own replica count, resources, persistence, and scheduling.
writer:
replicas: 1 # 3 = HA; 2 is REFUSED (no failure tolerance)
resources:
requests: { cpu: 500m, memory: 1Gi }
limits: { cpu: 4000m, memory: 8Gi }
persistence:
size: 20Gi # shared mode: WAL only; local mode: WAL + Parquet
storageClass: ""
wal:
enabled: true
syncMode: fdatasync # fdatasync | fsync | async
nodeSelector: {}
tolerations: []
affinity: {}
extraEnv: [] # extra env vars passed through to Arc
reader:
replicas: 2 # scale horizontally for query throughput
resources:
requests: { cpu: 500m, memory: 1Gi }
limits: { cpu: 4000m, memory: 8Gi }
persistence:
size: 50Gi # shared mode: emptyDir (no PVC); local mode: PVC
storageClass: ""
nodeSelector: {}
tolerations: []
affinity: {}
extraEnv: []
compactor:
enabled: true
replicas: 1 # exactly one active compactor — failover replaces it
resources:
requests: { cpu: 1000m, memory: 4Gi }
limits: { cpu: 4000m, memory: 16Gi }
persistence:
size: 50Gi # scratch space for compaction jobs
storageClass: ""
nodeSelector: {}
tolerations: []
affinity: {}
extraEnv: []Services & telemetry
service:
writer:
type: ClusterIP # backend for the L7 layer below — not a client-facing endpoint
port: 8000
annotations: {}
reader:
type: ClusterIP # expose via Ingress / annotated LoadBalancer
port: 8000
annotations: {}
# Disable for air-gapped / defense deployments.
telemetry:
enabled: trueMulti-writer needs an L7 load balancer in front of the writer Service
A ClusterIP Service balances per TCP connection, and keep-alive clients pin to whichever writer pod they first dialed — one writer takes nearly all traffic while the rest idle. Front the writer Service with an ingress controller, Envoy/HAProxy, or a cloud ALB so each request is balanced independently. See Clustering — multi-writer.
Operations
View logs
# Follow logs
kubectl logs -l app=arc -f
# Last 100 lines
kubectl logs -l app=arc --tail=100
# Logs from last hour
kubectl logs -l app=arc --since=1hCheck status
# Pod status
kubectl get pods -l app=arc
# Describe pod
kubectl describe pod -l app=arc
# Check events
kubectl get events --field-selector involvedObject.name=arc-0Scale (restart)
The Enterprise chart deploys each role as a StatefulSet (writer, reader,
compactor).
# Restart a role
kubectl rollout restart statefulset arc-ent-writer
# Or delete a pod (will be recreated)
kubectl delete pod -l app.kubernetes.io/component=writerPort forward
kubectl port-forward svc/arc 8000:8000Access shell
kubectl exec -it $(kubectl get pod -l app=arc -o jsonpath='{.items[0].metadata.name}') -- /bin/shUpgrade
# Upgrade to new version
helm upgrade arc https://github.com/basekick-labs/arc/releases/latest/download/arc-26.09.1.tgz
# With custom values
helm upgrade arc ./arc -f values-prod.yamlUninstall
# Uninstall Arc
helm uninstall arc
# Delete PVCs (optional - removes all data!)
kubectl delete pvc -l app=arc
# Delete namespace (if dedicated)
kubectl delete namespace arcMonitoring
Prometheus metrics
Arc exposes Prometheus metrics at /metrics:
# ServiceMonitor for Prometheus Operator
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: arc
spec:
selector:
matchLabels:
app: arc
endpoints:
- port: http
path: /metrics
interval: 30sReadiness/liveness probes
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 10Troubleshooting
Pod won't start
# Check pod status
kubectl describe pod -l app=arc
# Check events
kubectl get events --sort-by='.lastTimestamp'
# Common issues:
# - ImagePullBackOff: Check image name/tag
# - Pending: Check PVC status, node resources
# - CrashLoopBackOff: Check logsStorage issues
# Check PVC status
kubectl get pvc -l app=arc
# Check PV
kubectl get pv
# Describe PVC for errors
kubectl describe pvc -l app=arcConnection issues
# Check service
kubectl get svc arc
# Test from within cluster
kubectl run curl --image=curlimages/curl -it --rm -- curl http://arc:8000/healthMemory issues
# Check resource usage
kubectl top pod -l app=arc
# Increase limits in values.yaml
resources:
limits:
memory: "16Gi"High availability (EKS)
In shared mode the Enterprise chart runs Arc as a Pattern 2 multi-writer cluster: every writer pod accepts writes concurrently behind a Kubernetes Service, and each writer PUTs to the same S3 bucket independently. Singleton background tasks (retention, continuous queries, deletes) run on whichever pod is the cluster Raft leader, so they execute exactly once.
Failover is Service-based: clients always talk to the writer Service, which load-balances across healthy pods. If a writer pod dies, the Service stops routing to it and Raft re-elects a leader for the singleton tasks — no client URL changes.
Set writer.replicas to control the topology:
writer.replicas | Behaviour |
|---|---|
1 | Single writer (lowest cost). The Service still fronts it, so client URLs are identical to the multi-writer case. No failure tolerance. |
3 | HA + horizontal scale. Raft quorum tolerates one pod failure; writes round-robin across all healthy pods. |
2 | Refused by chart validation — a quorum of 2 stalls Raft writes on any single-pod loss, so it offers no failure tolerance over 1. |
In shared mode the reader uses emptyDir (no PVC — the bucket holds Parquet),
and writer/compactor PVCs are WAL/scratch only (~20Gi). In local mode
(Pattern 1), HA instead relies on per-node PVCs and peer replication, and the
reader needs a full data replica (~50Gi); cluster.replication.* tuning applies
only in this mode.
For the full topology comparison see Deployment Patterns, and for the cluster shared secret and inter-node TLS see Cluster Security.
Next steps
Native Installation
Install Arc Enterprise from the .deb, .rpm or Arch package, or build from source, then run it under systemd with a license key, storage backend, and cluster role in arc.toml.
AWS Marketplace
Launch the Arc Enterprise AMI from AWS Marketplace: pick an instance type, size the EBS and S3 storage, set security groups, and reach the console without a separate license key.