Skip to content

Drupal

Deploy Drupal on Kubernetes using the Docker Official drupal image with a persistence model tailored for the installer-managed sites/ directory, plus native backup automation and safe scaling guardrails.

Why This Chart Matters

  • Reference CMS chart — built to be HelmForge’s production baseline for installer-driven PHP CMS workloads
  • Seeded sites/ persistence — preserves uploads and installer-generated state without masking Drupal core files from the image
  • Built-in backup automation — archives Drupal sites/ plus either MySQL or SQLite to S3-compatible storage
  • Safe horizontal scaling — HPA is supported only when the storage and database combination is actually safe
  • Installer-first workflow — the chart prepares runtime, storage, ingress, and database connectivity, then guides setup through NOTES.txt

Image Decision

This chart uses docker.io/library/drupal because Drupal does not currently publish its own upstream-maintained runtime container image.

HelmForge pins:

  • docker.io/library/drupal:11.4.1-php8.5-apache-bookworm

That choice is intentional:

  • the Apache variant already includes PHP
  • the image includes the Drupal-relevant extensions such as pdo_mysql, pdo_sqlite, sqlite3, gd, mbstring, curl, dom, openssl, and zip
  • Drupal 11.4 supports PHP 8.5, so the explicit PHP 8.5 tag is a better production pin than the older generic apache-bookworm form
  • bookworm keeps the Debian base explicit and conservative for production environments

Official Product

Release Notes

This chart tracks Drupal 11.4.1, a production-ready patch release that fixes three regressions found in 11.4.0. The Drupal 11.4 line changes the Composer dependency policy for drupal/core-recommended: Guzzle, Twig, and Symfony polyfills are no longer pinned there, so security and patch updates can be applied without waiting for a new Drupal core release.

The bundled HelmForge MySQL dependency is aligned to the current 2.0.2 chart while preserving the same Drupal installer values for the default bundled database path. Before upgrading production workloads, test the site in staging with the same PHP extensions, Composer dependency set, storage class, and database mode used in production. Review Drupal’s 11.4.1 known issues, especially the documented search-module update path, before running database updates.

Installation

HTTPS Repository

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install drupal helmforge/drupal

OCI Registry

helm install drupal oci://ghcr.io/helmforgedev/helm/drupal

Install Example

resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: '1'
    memory: 1Gi

mysql:
  enabled: true
  auth:
    database: drupal
    username: drupal

persistence:
  enabled: true
  size: 8Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: drupal.example.com
      paths:
        - path: /
          pathType: Prefix

After installation:

  1. Wait for Drupal and MySQL to become ready.
  2. Open the configured URL or port-forwarded service.
  3. Run the Drupal web installer.
  4. Use the database details printed by helm get notes <release>.

Database Modes

Bundled MySQL

database:
  mode: auto

mysql:
  enabled: true

External Database

database:
  mode: external
  external:
    host: db.example.com
    port: 3306
    name: drupal
    username: drupal

mysql:
  enabled: false

SQLite

database:
  mode: sqlite

mysql:
  enabled: false

For SQLite installs, use sites/default/files/.ht.sqlite in the Drupal installer unless you intentionally choose another writable path.

SQLite is supported and backed up by the chart, but it remains a single-replica path and is not the preferred default for most production Drupal sites.

Persistence

This chart persists only /var/www/html/sites.

That layout is intentional:

  • settings.php, uploaded files, and installer output live under sites/
  • Drupal core remains in the container image instead of being shadowed by a PVC
  • an init container seeds the initial sites/ directory into the mounted volume before Drupal starts

Single-replica deployments are the default recommendation. If you scale above one replica, use shared writable storage for sites/.

Backup Strategy

When backup.enabled=true, the chart creates a CronJob that always captures two things:

  • the Drupal sites/ tree
  • the active database

Database backup behavior depends on the selected mode:

  • MySQL or external MySQL-compatible databasemysqldump
  • SQLite — a consistent SQLite snapshot created through Python’s SQLite backup API before compression

Backup Example

backup:
  enabled: true
  schedule: '0 2 * * *'
  s3:
    endpoint: https://minio.example.com
    bucket: drupal-backups
    existingSecret: drupal-backup-s3

If database.mode=external, also provide backup credentials for the dump job:

backup:
  database:
    existingSecret: drupal-backup-db

Autoscaling And HPA

HPA is supported, but only when the chart can guarantee safe shared state.

Required for multi-replica or HPA Drupal:

  • persistence.enabled=true
  • persistence.accessMode=ReadWriteMany
  • a MySQL-compatible database mode

If those requirements are not met, the chart fails during render instead of letting an unsafe deployment reach the cluster.

HPA Example

persistence:
  accessMode: ReadWriteMany

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 5

pdb:
  enabled: true
  minAvailable: 1

Values

The chart still has an installer-oriented surface, but it now covers production runtime, storage, backups, scaling, networking, probes, and escape hatches.

Runtime And Installer Values

Key Default Description
replicaCount 1 Number of Drupal replicas
image.repository docker.io/library/drupal Docker Official Drupal image repository
image.tag 11.4.1-php8.5-apache-bookworm Pinned Drupal image tag
image.pullPolicy IfNotPresent Container pull policy
imagePullSecrets [] Optional image pull secrets
drupal.siteName Drupal Suggested site name shown in install guidance
drupal.installProfile standard Suggested Drupal install profile
drupal.locale en Suggested locale for the installer
drupal.sqlitePath sites/default/files/.ht.sqlite Suggested SQLite path for the web installer
drupal.extraEnv [] Extra container environment variables
php.ini "" Extra PHP configuration mounted as custom.ini

Database And Persistence Values

Key Default Description
database.mode auto Database mode: auto, external, mysql, or sqlite
database.external.host "" External database hostname
database.external.port 3306 External database port
database.external.name drupal External database name
database.external.username drupal External database username
mysql.enabled true Enable the bundled MySQL subchart
mysql.architecture standalone MySQL deployment architecture
mysql.auth.database drupal Database name created by the MySQL subchart
mysql.auth.username drupal Database username created by the MySQL subchart
mysql.auth.password "" Optional application password override
mysql.auth.rootPassword "" Optional root password override
mysql.auth.existingSecret "" Existing secret for MySQL passwords
mysql.auth.existingSecretUserPasswordKey mysql-user-password Secret key used for the app user password
mysql.standalone.persistence.enabled true Enable bundled standalone MySQL persistence
mysql.standalone.persistence.size 8Gi Bundled standalone MySQL PVC size
persistence.enabled true Enable persistence for /var/www/html/sites
persistence.storageClass "" Explicit storage class for the sites PVC
persistence.accessMode ReadWriteOnce Access mode for the sites PVC
persistence.size 8Gi Sites PVC size
persistence.existingClaim "" Reuse an existing sites PVC
persistence.annotations {} Annotations applied to the sites PVC

Backup, Scaling, And Availability Values

Key Default Description
backup.enabled false Enable scheduled backups
backup.schedule 0 3 * * * Cron schedule for backups
backup.s3.endpoint "" S3-compatible endpoint
backup.s3.bucket "" S3 target bucket
backup.s3.prefix drupal Key prefix in the bucket
backup.s3.existingSecret "" Existing secret for S3 credentials
backup.database.host "" Optional database host override for backup
backup.database.password "" Inline database password override for backup
backup.database.existingSecret "" Existing secret for backup database password
autoscaling.enabled false Enable HPA
autoscaling.minReplicas 2 HPA minimum replicas
autoscaling.maxReplicas 5 HPA maximum replicas
autoscaling.targetCPUUtilizationPercentage 75 CPU utilization target
autoscaling.targetMemoryUtilizationPercentage 80 Memory utilization target
pdb.enabled false Create a PodDisruptionBudget
pdb.minAvailable 1 Minimum healthy pods during voluntary disruption

Service, Ingress, Probes, And Platform Values

Key Default Description
service.type ClusterIP Drupal service type
service.port 80 Drupal service port
service.annotations {} Annotations applied to the service
service.ipFamilyPolicy omitted Service IP family policy: SingleStack, PreferDualStack, or RequireDualStack. Omit for cluster default.
service.ipFamilies omitted Ordered list of IP families (IPv4, IPv6). Omit for cluster default.
ingress.enabled false Enable ingress resources
ingress.ingressClassName "" Ingress class name
ingress.annotations {} Ingress annotations
ingress.hosts [] Ingress host and path definitions
ingress.tls [] TLS secret mappings for ingress
startupProbe.enabled true Enable the startup probe
startupProbe.path / Startup probe HTTP path
livenessProbe.enabled true Enable the liveness probe
livenessProbe.path / Liveness probe HTTP path
readinessProbe.enabled true Enable the readiness probe
readinessProbe.path / Readiness probe HTTP path
resources.requests.cpu 250m Default CPU request for the Drupal container
resources.requests.memory 512Mi Default memory request for the Drupal container
resources.limits.cpu 1 Default CPU limit for the Drupal container
resources.limits.memory 1Gi Default memory limit for the Drupal container
podSecurityContext.fsGroup 33 Group ownership applied to the mounted Drupal files volume
securityContext {} Container-level security context
serviceAccount.create false Create a dedicated service account
serviceAccount.name "" Existing or custom service account name
serviceAccount.annotations {} Service account annotations
nodeSelector {} Node selector rules
tolerations [] Pod tolerations
affinity {} Pod affinity and anti-affinity
topologySpreadConstraints [] Topology spread constraints
priorityClassName "" Priority class for the pod
terminationGracePeriodSeconds 30 Pod termination grace period
podLabels {} Extra pod labels
podAnnotations {} Extra pod annotations
extraVolumes [] Additional volumes injected into the pod
extraVolumeMounts [] Additional volume mounts injected into the Drupal container
extraManifests [] Extra Kubernetes manifests rendered by the chart

Dual-stack Networking

The Drupal Service accepts Kubernetes dual-stack configuration. By default, both service.ipFamilyPolicy and service.ipFamilies are unset and the chart inherits whatever the cluster advertises (matching prior behavior).

service:
  ipFamilyPolicy: PreferDualStack
  ipFamilies:
    - IPv4
    - IPv6

PreferDualStack is the safer choice for clusters that may be single- or dual-stack: omit ipFamilies and the cluster auto-populates whatever it supports. Set ipFamilies explicitly only when the cluster is configured for both families — the Kubernetes API rejects an explicit family the cluster does not advertise. RequireDualStack enforces both.

More Information