Kubernetes Installation
Deploy Arc on Kubernetes with the Helm chart: configure storage backends and credentials, size persistent volumes, set resource limits, and expose the service.
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
LATEST=$(curl -s https://api.github.com/repos/basekick-labs/arc/releases/latest | grep tag_name | cut -d '"' -f 4 | sed 's/v//')
helm install arc https://github.com/basekick-labs/arc/releases/download/v${LATEST}/arc-${LATEST}.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.kubernetes.io/name=arc
# View logs to find admin token
kubectl logs -l app.kubernetes.io/name=arc | grep -i "admin"You should see:
======================================================================
FIRST RUN - INITIAL ADMIN TOKEN GENERATED
======================================================================
Admin API token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
======================================================================Save This Token
Copy this token immediately - you won't see it again!
Set the admin token yourself
To skip the log lookup, give the chart the token to create on first run. Either let the chart create the Secret from a value:
# values.yaml
auth:
bootstrapToken:
value: "<at least 32 characters>"or point it at a Secret you created, which must hold the key bootstrap-token:
kubectl create secret generic arc-admin-token \
--from-literal=bootstrap-token="$(openssl rand -base64 32)"# values.yaml
auth:
bootstrapToken:
existingSecret: arc-admin-tokenThe chart passes the token to Arc as ARC_AUTH_BOOTSTRAP_TOKEN. Arc uses it only
on first run, when no token exists yet; after that it is ignored, so changing it
on a later upgrade does not change the admin token. The chart refuses a value
shorter than 32 characters. Arc would reject it and start with no admin token.
Prefer existingSecret in production: a value is stored in the Helm release
along with the rest of your values.
Arc Enterprise cluster mode (v26.06.1+)
In a multi-pod Arc Enterprise cluster, only one pod prints the banner — the Raft leader that wins the bootstrap election. Other pods log INFO Deferring initial token bootstrap until cluster Raft proposer is wired during startup and then INFO Cluster auth state replication enabled — token writes now propagate via Raft once the leader is elected. The non-leader pods silently no-op the bootstrap (they get an "already exists" response from the leader's FSM) and converge on the leader's token via Raft. The same command with -l app.kubernetes.io/name=arc-enterprise still works — it just returns the single banner from whichever pod won the election. See Cluster auth replication for the full semantics, including token-propagation behaviour and the divergence-detection error log.
Installation methods
LATEST=$(curl -s https://api.github.com/repos/basekick-labs/arc/releases/latest | grep tag_name | cut -d '"' -f 4 | sed 's/v//')
helm install arc https://github.com/basekick-labs/arc/releases/download/v${LATEST}/arc-${LATEST}.tgzStorage backends
The OSS chart selects the backend with arc.storageBackend (local, s3, or
minio). The chart auto-sets ARC_STORAGE_BACKEND and ARC_STORAGE_LOCAL_PATH;
everything else (bucket, region, keys, endpoint) is passed through as
ARC_STORAGE_* environment variables via the free-form arc.env[] list.
Local disk on a Persistent Volume - the default. The chart provisions a PVC
mounted at /app/data/arc.
# values.yaml
arc:
storageBackend: local
persistence:
enabled: true
size: 100Gi
accessMode: ReadWriteOnce
storageClass: "" # default storage classhelm install arc ./arc -f values.yamlConfiguration profiles
The OSS chart is a single Deployment. Arc's own settings (auth, WAL, log level,
ingest buffers, etc.) are passed as environment variables through arc.env[],
or as a whole arc.toml through arc.config (below).
Minimal resources for development/testing:
# values-dev.yaml
replicaCount: 1
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "1"
arc:
storageBackend: local
env:
- name: ARC_AUTH_ENABLED
value: "false"
- name: ARC_LOG_LEVEL
value: "debug"
persistence:
enabled: true
size: 10Gihelm install arc ./arc -f values-dev.yamlSupplying a whole arc.toml
arc.config mounts an arc.toml from a ConfigMap at /app/arc.toml, in place
of the one in the image:
# values.yaml
arc:
config:
enabled: true
contents: |
[log]
level = "info"
format = "json"Or keep the file next to your values and load it with
--set-file arc.config.contents=arc.toml.
Environment variables override the file. The chart always sets
ARC_STORAGE_BACKEND, ARC_STORAGE_LOCAL_PATH, ARC_WAL_ENABLED and
ARC_WAL_DIRECTORY, so set those through arc.storageBackend and arc.wal, not
in the file. Anything in arc.env[] also wins over the file.
Changing arc.config.contents on helm upgrade restarts the pod, because a
running pod never sees a change to a file mounted this way.
Chart from Arc 27.01.1
Earlier OSS charts did not include the ConfigMap template: with
arc.config.enabled: true the pod stayed in ContainerCreating with
MountVolume.SetUp failed for volume "config". Upgrade the chart, or use
arc.env[] instead. auth.bootstrapToken is also new in this chart.
Sizing the data volume when the WAL is on
With an object-storage backend (storageBackend: s3), the pod's PersistentVolume
holds only the WAL and local cache — but that does not make it small. The
WAL absorbs everything between ingest and flush, so size it against your peak
ingest rate × worst-case flush lag, with generous headroom. The default
persistence.size: 10Gi is a development default: at a bulk-load rate of
100 MB/s it fills in under two minutes.
Before v27.01.1 a full WAL volume was a bad failure. Writes kept being
accepted while their WAL entries could not be written, and the writer could not
boot again on a full disk. Since v27.01.1 Arc refuses writes with a retryable
503 once the volume runs low (arc.wal.diskMinFreeMB), and starts on a full
volume by releasing a reserve file. See
When the WAL volume runs low.
Size the volume for your ingest rate anyway: while writes are refused, clients
must retry.
With persistence.enabled: false the data lives in an emptyDir, which
reports the node's free space rather than its size limit. The chart then caps
the WAL directory at 80% of persistence.emptyDirSizeLimitMB, or at 1024 MB
when no limit is set. Local Parquet files, arc.db and temp files share that
emptyDir, so leave room for them too.
Helm values reference
Core settings
# Number of pod replicas (single Deployment).
replicaCount: 1
# Container image (tag defaults to the chart appVersion).
image:
repository: ghcr.io/basekick-labs/arc
tag: "" # set "26.06.2" for full IRSA query-read support
pullPolicy: IfNotPresent
imagePullSecrets: []
# Service configuration
service:
type: ClusterIP
port: 8000Resources
resources: {} # empty by default; set requests/limits as needed
# requests:
# memory: "2Gi"
# cpu: "1"
# limits:
# memory: "8Gi"
# cpu: "4"Storage
arc:
# local | s3 | minio. The chart sets ARC_STORAGE_BACKEND from this and
# ARC_STORAGE_LOCAL_PATH automatically.
storageBackend: local
# Write-ahead log. On by default in the chart; the Arc binary itself
# defaults wal.enabled to false for backwards compatibility, so the chart
# overrides it. Without a WAL a crash loses every record buffered since the
# last flush.
wal:
enabled: true
directory: /app/data/wal
# Refuse writes with 503 + Retry-After when the volume runs low (v27.01.1+).
diskPressureEnabled: true
diskMinFreeMB: 0 # 0 = max(512, 2 x wal.max_size_mb), at most a fifth of the volume
maxDirectoryMB: 0 # WAL directory cap; 0 = none (set automatically with persistence disabled)
# Free-form env vars passed straight to the Arc container. Use ARC_STORAGE_*
# for bucket/region/keys/endpoint, plus any other ARC_* settings.
env: []
# - name: ARC_STORAGE_S3_BUCKET
# value: arc-production
# - name: ARC_STORAGE_S3_REGION
# value: us-east-1
# - name: ARC_STORAGE_S3_ENDPOINT
# value: https://s3.us-east-1.amazonaws.com
# - name: ARC_STORAGE_S3_ACCESS_KEY # omit for IRSA
# value: ""
# - name: ARC_STORAGE_S3_SECRET_KEY # omit for IRSA
# value: ""
# - name: ARC_STORAGE_S3_USE_SSL
# value: "true"
# - name: ARC_STORAGE_S3_PATH_STYLE
# value: "false"
# Whole arc.toml, mounted at /app/arc.toml. Environment variables win
# over it. A change rolls the pod.
config:
enabled: false
contents: ""
# Initial admin token, used on first run only. value: at least 32 characters.
# existingSecret: a Secret with the key "bootstrap-token".
auth:
bootstrapToken:
existingSecret: ""
value: ""
# PVC used when storageBackend is local (mounted at /app/data/arc).
persistence:
enabled: true
accessMode: ReadWriteOnce
size: 10Gi
storageClass: ""
# existingClaim: ""Ingress
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: arc.local
paths:
- path: /
pathType: Prefix
tls: []Service account
serviceAccount:
create: true
automount: true
name: ""
annotations: {} # eks.amazonaws.com/role-arn for IRSA on EKSClustering & HA are Enterprise features
The OSS chart runs Arc as a single Deployment with no writer/reader/compactor roles, Raft clustering, or multi-writer failover. For high availability, multi-writer ingest, and peer replication see the Arc Enterprise Kubernetes guide.
Operations
View logs
# Follow logs
kubectl logs -l app.kubernetes.io/name=arc -f
# Last 100 lines
kubectl logs -l app.kubernetes.io/name=arc --tail=100
# Logs from last hour
kubectl logs -l app.kubernetes.io/name=arc --since=1hCheck status
# Pod status
kubectl get pods -l app.kubernetes.io/name=arc
# Describe pod
kubectl describe pod -l app.kubernetes.io/name=arc
# Check events
kubectl get events --field-selector involvedObject.name=arc-0Scale (restart)
# Restart pod
kubectl rollout restart deployment arc
# Or delete pod (will be recreated)
kubectl delete pod -l app.kubernetes.io/name=arcPort forward
kubectl port-forward svc/arc 8000:8000Access shell
kubectl exec -it $(kubectl get pod -l app.kubernetes.io/name=arc -o jsonpath='{.items[0].metadata.name}') -- /bin/shUpgrade
# Upgrade to new version
LATEST=$(curl -s https://api.github.com/repos/basekick-labs/arc/releases/latest | grep tag_name | cut -d '"' -f 4 | sed 's/v//')
helm upgrade arc https://github.com/basekick-labs/arc/releases/download/v${LATEST}/arc-${LATEST}.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.kubernetes.io/name=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: 10As of 26.09.1, /health includes a storage field with per-tier credential
state (ok / degraded / expired / fallback / unknown), computed from
Arc's credential refresher — no S3/Azure probing from the probe path. Alert on
storage.*.state != "ok" or on expires_at approaching. For reader pools,
setting server.storage_credentials_fail_ready = true makes /ready return
503 while any tier's credentials are expired, so Kubernetes recycles the pod
(a restart re-resolves credentials). Leave it off for writers — ingest keeps
working through credential expiry, and Arc warns at startup if it is enabled on
a cluster writer.
Troubleshooting
Pod won't start
# Check pod status
kubectl describe pod -l app.kubernetes.io/name=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.kubernetes.io/name=arc
# Check PV
kubectl get pv
# Describe PVC for errors
kubectl describe pvc -l app.kubernetes.io/name=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.kubernetes.io/name=arc
# Increase limits in values.yaml
resources:
limits:
memory: "16Gi"Next steps
- Write your first data
- Configure storage backends
- Monitoring & ops playbook — what to scrape and alert on
- Telemetry — what Arc reports back, and how to opt out
- Enable WAL for durability
Native Installation
Install Arc on Linux from .deb, .rpm, or Arch packages, or build it from source: set up the systemd service, configure a storage backend, and upgrade an existing install in place.
AWS Marketplace
Launch Arc from the AWS Marketplace AMI: pick an instance type, configure the VPC and security groups, attach S3 storage, and retrieve the admin token.