Documentation / memcached
Memcached Helm Chart
An enterprise-grade Helm chart for deploying Memcached on Kubernetes. Provides a production-ready, highly-configurable distributed memory caching system with built-in observability, security hardening, and high-availability features.
Prerequisites
- Kubernetes 1.23+
- Helm 3.x
- (Optional) Netdata or any OpenMetrics-compatible collector for metrics scraping
Installation
helm install my-cache ./charts/memcached
With custom values:
helm install my-cache ./charts/memcached -f my-values.yaml
Uninstallation
helm uninstall my-cache
Architecture
The chart supports two workload types:
- Deployment (default) – Best for stateless caching where pod identity is not important.
- StatefulSet – Enable with
useStatefulSet: truefor stable network identities and headless service DNS. Useful when clients need to address individual memcached nodes (e.g., consistent hashing).
Parameters
Global
| Parameter | Description | Default |
|---|---|---|
replicaCount |
Number of memcached replicas | 1 |
image.repository |
Memcached image repository | memcached |
image.tag |
Image tag (defaults to appVersion) |
Set in each release |
image.pullPolicy |
Image pull policy | IfNotPresent |
imagePullSecrets |
Image pull secrets | [] |
nameOverride |
Override chart name | "" |
fullnameOverride |
Override full release name | "" |
useStatefulSet |
Deploy as StatefulSet instead of Deployment | false |
Memcached Configuration
All core memcached tuning parameters are exposed as values:
| Parameter | Description | Default |
|---|---|---|
memcached.maxMemory |
Max memory for items in MB (-m) |
64 |
memcached.maxConnections |
Max simultaneous connections (-c) |
1024 |
memcached.threads |
Number of worker threads (-t) |
4 |
memcached.defaultExpiry |
Default item TTL in seconds (0 = no expiry) | 0 |
memcached.maxItemSize |
Max item size, supports k/m units (-I) |
"1m" |
memcached.growthFactor |
Chunk size growth factor (-f) |
1.25 |
memcached.minItemSize |
Min allocated space per key in bytes (-n) |
48 |
memcached.listenBacklog |
Listen backlog queue limit (-b) |
1024 |
memcached.enableCas |
Enable CAS (Check And Set) operations | true |
memcached.disableFlushAll |
Disable the flush_all command |
false |
memcached.disableWatch |
Disable the watch / live logging command |
false |
memcached.largepages |
Enable large memory pages (requires OS support) | false |
memcached.protocol |
Protocol mode: "auto", "ascii", or "binary" |
"auto" |
memcached.verbosity |
Log verbosity: 0=none, 1=verbose, 2=very verbose | 0 |
memcached.extraFlags |
Additional CLI flags passed to memcached | [] |
SASL Authentication
| Parameter | Description | Default |
|---|---|---|
memcached.sasl.enabled |
Enable SASL authentication | false |
memcached.sasl.existingSecret |
Name of existing secret with SASL credentials | "" |
memcached.sasl.username |
SASL username (if not using existing secret) | "" |
memcached.sasl.password |
SASL password (if not using existing secret) | "" |
Service
| Parameter | Description | Default |
|---|---|---|
service.type |
Kubernetes service type | ClusterIP |
service.port |
Service port | 11211 |
service.nodePort |
Node port (when type is NodePort) | "" |
service.annotations |
Service annotations | {} |
headlessService.enabled |
Create headless service (for StatefulSet) | false |
headlessService.annotations |
Headless service annotations | {} |
Service Account
| Parameter | Description | Default |
|---|---|---|
serviceAccount.create |
Create a service account | false |
serviceAccount.automount |
Automount service account token | true |
serviceAccount.annotations |
Service account annotations | {} |
serviceAccount.name |
Service account name override | "" |
Security
| Parameter | Description | Default |
|---|---|---|
podSecurityContext.fsGroup |
Pod filesystem group | 11211 |
securityContext.runAsUser |
Container user ID | 11211 |
securityContext.runAsGroup |
Container group ID | 11211 |
securityContext.runAsNonRoot |
Require non-root execution | true |
securityContext.readOnlyRootFilesystem |
Read-only root filesystem | true |
securityContext.allowPrivilegeEscalation |
Disallow privilege escalation | false |
securityContext.capabilities.drop |
Linux capabilities to drop | ["ALL"] |
Resources and Probes
| Parameter | Description | Default |
|---|---|---|
resources.limits.cpu |
CPU limit | 500m |
resources.limits.memory |
Memory limit | 256Mi |
resources.requests.cpu |
CPU request | 100m |
resources.requests.memory |
Memory request | 128Mi |
startupProbe.enabled |
Enable startup probe | true |
livenessProbe.enabled |
Enable liveness probe | true |
readinessProbe.enabled |
Enable readiness probe | true |
Pod Disruption Budget
| Parameter | Description | Default |
|---|---|---|
podDisruptionBudget.enabled |
Enable PDB | false |
podDisruptionBudget.minAvailable |
Minimum available pods | 1 |
podDisruptionBudget.maxUnavailable |
Max unavailable pods (alternative) | - |
Network Policy
| Parameter | Description | Default |
|---|---|---|
networkPolicy.enabled |
Enable NetworkPolicy | false |
networkPolicy.allowFrom |
Allowed ingress sources (podSelector/namespaceSelector) | [] |
Metrics and Monitoring
The chart deploys a memcached-exporter sidecar that exposes a /metrics endpoint in OpenMetrics/Prometheus format. When enabled, pod annotations are added so that Netdata (or any annotation-based collector) auto-discovers and scrapes the pods directly.
| Parameter | Description | Default |
|---|---|---|
metrics.enabled |
Enable Prometheus exporter sidecar | false |
metrics.image.repository |
Exporter image | prom/memcached-exporter |
metrics.image.tag |
Exporter image tag | Set in each release |
metrics.port |
Exporter listen port | 9150 |
metrics.resources |
Exporter resource limits/requests | See values.yaml |
metrics.podAnnotations |
Pod annotations for metrics discovery | prometheus.io/scrape: "true", etc. |
Default pod annotations when metrics are enabled:
prometheus.io/scrape: "true"
prometheus.io/port: "9150"
prometheus.io/path: "/metrics"
Scheduling
| Parameter | Description | Default |
|---|---|---|
nodeSelector |
Node selector labels | {} |
tolerations |
Pod tolerations | [] |
affinity |
Pod affinity rules | {} |
topologySpreadConstraints |
Topology spread constraints | [] |
priorityClassName |
Pod priority class | "" |
terminationGracePeriodSeconds |
Graceful shutdown timeout | 30 |
Extensions
| Parameter | Description | Default |
|---|---|---|
podAnnotations |
Additional pod annotations | {} |
podLabels |
Additional pod labels | {} |
extraEnv |
Extra environment variables | [] |
extraInitContainers |
Extra init containers | [] |
extraVolumes |
Extra volumes | [] |
extraVolumeMounts |
Extra volume mounts | [] |
Examples
Minimal production setup
replicaCount: 3
memcached:
maxMemory: 256
maxConnections: 2048
threads: 4
disableFlushAll: true
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: 250m
memory: 384Mi
podDisruptionBudget:
enabled: true
minAvailable: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels: {}
With metrics for Netdata scraping
metrics:
enabled: true
That’s it – Netdata auto-discovers pods via the prometheus.io/* annotations that are added automatically. The exporter sidecar exposes memcached stats on port 9150 at /metrics.
StatefulSet with headless service
useStatefulSet: true
replicaCount: 3
headlessService:
enabled: true
This creates stable DNS names like my-cache-memcached-0.my-cache-memcached-headless.namespace.svc.cluster.local for client-side consistent hashing.
With SASL authentication
memcached:
sasl:
enabled: true
existingSecret: my-memcached-credentials
High-throughput tuning
memcached:
maxMemory: 1024
maxConnections: 4096
threads: 8
maxItemSize: "5m"
growthFactor: 1.05
listenBacklog: 2048
extraFlags:
- "-o modern"
- "-o slab_reassign"
- "-o slab_automove=1"
- "-o hashpower=20"
resources:
limits:
cpu: "4"
memory: 2Gi
requests:
cpu: "2"
memory: 1536Mi
With NetworkPolicy (restrict access)
networkPolicy:
enabled: true
allowFrom:
- podSelector:
matchLabels:
app: my-app
- namespaceSelector:
matchLabels:
name: my-namespace
Testing
Run the built-in Helm test:
helm test my-cache
This verifies the memcached service is reachable and responding to stats commands.
Upgrading
To 1.x
This is the initial release. No migration steps required.