{"id":28480467,"url":"https://github.com/backupscale/terraform-kubernetes-drupal","last_synced_at":"2026-05-08T01:33:06.441Z","repository":{"id":297331901,"uuid":"994366779","full_name":"BackUpScale/terraform-kubernetes-drupal","owner":"BackUpScale","description":"Drubernetes: The Terraform module for provisioning Drupal within a Kubernetes cluster. Published in the Terraform registry at https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes .  See https://gitlab.com/backupscale/drubernetes for the authoritative project; this is a mirror.","archived":false,"fork":false,"pushed_at":"2025-06-19T02:50:13.000Z","size":92,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-19T03:35:15.595Z","etag":null,"topics":["drupal","kubernetes","terraform"],"latest_commit_sha":null,"homepage":"https://gitlab.com/backupscale/drubernetes","language":"HCL","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BackUpScale.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-01T19:34:27.000Z","updated_at":"2025-06-19T02:48:16.000Z","dependencies_parsed_at":"2025-06-05T04:55:09.997Z","dependency_job_id":"5c71d7f9-7c0c-4cec-99da-cbd3d1d500ad","html_url":"https://github.com/BackUpScale/terraform-kubernetes-drupal","commit_stats":null,"previous_names":["backupscale/terraform-kubernetes-drupal"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/BackUpScale/terraform-kubernetes-drupal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackUpScale%2Fterraform-kubernetes-drupal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackUpScale%2Fterraform-kubernetes-drupal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackUpScale%2Fterraform-kubernetes-drupal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackUpScale%2Fterraform-kubernetes-drupal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BackUpScale","download_url":"https://codeload.github.com/BackUpScale/terraform-kubernetes-drupal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackUpScale%2Fterraform-kubernetes-drupal/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263388626,"owners_count":23459240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drupal","kubernetes","terraform"],"created_at":"2025-06-07T19:06:32.170Z","updated_at":"2026-05-08T01:33:06.425Z","avatar_url":"https://github.com/BackUpScale.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"[[_TOC_]]\n\n## Introduction\n\n**Drubernetes** is a Terraform module for provisioning Drupal within a generic Kubernetes cluster.\n\nIt tries to not make any assumptions about your cluster or cloud provider so you should be able to run this in any modern Kubernetes cluster at an cloud provider.  If you can't, please open an issue to add support for your use case.\n\n## Background\n\nThis project was created because we couldn't find any generic infrastructure as code (IaC) to do this kind of thing.\n\nIt shouldn't be that hard to run Drupal in Kubernetes, but all we could find were no-longer supported projects, projects that didn't do everything you'd typically want to do when running Drupal, or very opinionated projects that weren't generally usable.\n\n## What it does\n\nThis module does a lot.  Here's what it can do for you at a high level:\n\n* Sets up a namespace for the installation\n* Sets up a MariaDB database\n* Sets up a Drupal deployment\n* Creates a persistent volume claim (PVC) for Drupal's file system\n* Uses Envoy Gateway for setting up the load balancer\n* Automatically manages Let's Encrypt TLS certificates for HTTPS\n* Provides VPN-only access to Drupal's administration pages\n* Sets up a Kubernetes cron job to run Drupal's cron tasks\n* Stores sensitive passed-in data as Kubernetes secrets\n* Sets your [trusted host patterns](https://www.drupal.org/docs/getting-started/installing-drupal/trusted-host-settings)\n* Sets your [reverse proxy addresses](https://www.drupal.org/docs/getting-started/installing-drupal/using-a-load-balancer-or-reverse-proxy)\n* Provides a mechanism to inject [configuration overrides](https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-override-system) into Drupal settings (e.g. secrets that you don't want in the DB)\n* Makes just about everything configurable via variables\n\n## Non-Terraform components\n\n### Dockerfile\n\nYou'll need a Drupal image that the deployment can use, which can be built from a Dockerfile.  As we couldn't find a good one, we [made one ourselves](examples/Dockerfile).  Feel free to modify the example to your liking, and then use that.\n\nYou can have your continuous integration (CI) system (e.g. GitLab CI) build it from your Drupal code repository, and then push it to your container registry.\n\n### Drupal settings\n\nOur example [settings.kubernetes.php](examples/settings.kubernetes.php) shouldn't require any modification.  You can add it to your Drupal code repository, and the Dockerfile will use it.\n\n### Configuration overrides\n\nIt's possible to pass a list of [configuration overrides](https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-override-system) (e.g. secrets that you don't want in the Drupal DB) into the module.  We use [Platform.sh's methodology](https://docs.platform.sh/development/variables.html#implementation-example).  Here's an example of how to pass a single entry, but you can add more, one per line:\n\n\n```terraform\n  drupal_config_overrides = {\n    \"drupalconfig:symfony_mailer.mailer_transport.proton_mail:configuration:pass\" = var.public_address_smtp_password\n  }\n```\n\n## Module metadata\n\nThese can be found at the Terraform Registry:\n\n* [Inputs](https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes/latest?tab=inputs)\n* [Outputs](https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes/latest?tab=outputs)\n* [Dependencies](https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes/latest?tab=dependencies)\n* [Resources](https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes/latest?tab=resources)\n\nThe [Provisioning Instructions](https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes/latest) are on that page too.\n\n## Example implementation\n\nHere's an example of a minimal implementation.  There is more information on some of these below the module inclusion.\n\nFor sensitive values (i.e. secrets), don't set these directly in your root variables file because you don't want them in your Git repository.  Instead, get them from [environment variables](https://developer.hashicorp.com/terraform/language/values/variables#environment-variables) (e.g. `TF_VAR_drupal_site_root_password`).  You can set all of these by exporting your vault (e.g. [SOPS](https://getsops.io/) or [Ansible Vault](https://docs.ansible.com/ansible/latest/vault_guide/index.html)) to your environment beforehand.\n\n### Module inclusion\n\n```hcl\nmodule \"drupal\" {\n  # This can also be a relative path if you've installed it as a Git submodule.\n  # If you're doing that, leave out the \"version\".\n  source  = \"BackUpScale/drupal/kubernetes\"\n  version = \"1.0.0\"\n  # Assuming you have `alias = \"main\"` in your `kubernetes` provider definition.\n  providers = {\n    kubernetes = kubernetes.main\n  }\n  cluster_terraform_id = civo_kubernetes_cluster.my_cluster.id\n  namespace = var.drupal_namespace\n  container_registry_credentials = module.gitlab.rendered_container_registry_credentials\n  cron_key = var.drupal_cron_key\n  db_admin_password = var.drupal_site_root_password\n  db_password = var.drupal_site_db_password\n  drupal_container_image_url = \"registry.gitlab.com/myorg/infrastructure/drupal-${var.cloud_environment}:latest\"\n  firewall_id_annotation_value = civo_firewall.myfirewall.id\n  hash_salt = var.drupal_hash_salt\n  public_hostname = cloudflare_record.drupal_public_hostname.name\n  private_hostname = cloudflare_record.drupal_private_hostname.name\n  technical_contact_email = var.technical_contact_email\n}\n```\n\n### Container registry credentials\n\nYou container registry credentials should probably come from another module (e.g. `gitlab`, if you're using the GitLab container registry) like this:\n\n```hcl\noutput \"rendered_container_registry_credentials\" {\n  value = data.template_file.container_registry_credentials.rendered\n}\n```\n\n...where the data is defined like so:\n\n```hcl\ndata \"template_file\" \"container_registry_credentials\" {\n  template = file(\"${path.module}/container_registry_credentials_template.json\")\n  vars = {\n    docker-username = var.registry_pull_token_user\n    docker-password = var.registry_pull_token_pass\n    docker-server = \"https://registry.gitlab.com\"\n    docker-email = \"placeholder@example.com\"\n    auth = base64encode(\"${var.registry_pull_token_user}:${var.registry_pull_token_pass}\")\n  }\n}\n```\n\n...and `container_registry_credentials.json` has the contents:\n\n```json\n{\"auths\":{\"${docker-server}\":{\"username\":\"${docker-username}\",\"password\":\"${docker-password}\",\"email\":\"${docker-email}\",\"auth\":\"${auth}\"}}}\n```\n\n## Drupal operations\n\n### Importing a database\n\nFor small dumps, you can stream the SQL straight into `drush sql:cli` over `kubectl exec`'s stdin:\n\n* `gunzip --stdout /tmp/drupal.sql.gz | kubectl --namespace=drupal exec -i service/drupal-service -- drush sql-cli`\n\nThis is quick to type, but Drush warns against it for anything non-trivial because the same SPDY stream truncation issues that affect dumps (see [Dumping a database](#dumping-a-database)) also affect imports piped over stdin.  For larger dumps, copy the file into the pod first and then run the import locally to it:\n\n```bash\n# kubectl cp needs a pod name (not a service), so resolve one first.\nPOD=$(kubectl --namespace=drupal get pod -l app=drupal -o name | head -n 1 | cut -d/ -f2)\n\nkubectl --namespace=drupal cp /tmp/drupal.sql.gz \"$POD:/tmp/drupal.sql.gz\"\nkubectl --namespace=drupal exec -i \"$POD\" -- sh -c \\\n  'gunzip /tmp/drupal.sql.gz \u0026\u0026 drush sql:query --file=/tmp/drupal.sql \u0026\u0026 rm /tmp/drupal.sql'\n```\n\nAdjust the `-l app=drupal` label selector to match your deployment.\n\n### Dumping a database\n\nNormally, one would expect to be able to do something like this:\n\n* `kubectl --namespace=drupal exec -i service/drupal-service -- drush sql:dump --gzip \u003e /tmp/drupal.dump.sql.gz`\n\nIt will create a valid dump inside the pod, but all of the bytes probably won't make it back to your workstation, which will produce a dump file that can't be imported. The culprit is almost always the way `kubectl exec` streams large amounts to `stdout`: the SPDY stream can be interrupted, silently truncated, or timed-out long before the database dump is finished, so the file you redirect locally stops in the middle without any error message. This is [a known issue in Kubernetes](https://github.com/kubernetes/kubernetes/issues/124571).  It should work better with Kubernetes clusters ≥ v1.31, which defaults to WebSocket streaming (which has fewer truncation bugs﻿).\n\nIn any case, a better option is to download one of your backups, and use that instead.  Besides avoiding the above issue, this process also forces you to test your backups, which is always a good idea.  For more information on backups, see [the section here](#backups).\n\n### Running non-interactive Drush commands\n\nClear caches:\n* `kubectl --namespace=drupal exec -i service/drupal-service -- drush cache:rebuild`\n\n### Running interactive Drush commands\n\nGet a MariaDB database shell:\n* `kubectl --namespace=drupal exec -it service/drupal-service -- drush sql:cli`\n\nGet a shell on one of the Drupal containers:\n* `kubectl --namespace=drupal exec -it service/drupal-service -- /bin/bash`\n\n## What's missing\n\nWhile we try to as much as we can here, this project can't do everything.  Notably...\n\n### Backups\n\nIt would be hard to find a generic way to automate backups for all Drupal site running in Kubernetes.  As such, this module does not support this feature, even though it's something you need.\n\n**So make sure to get your own backups rolling!**\n\nOne option is to set up a GitLab CI pipeline schedule that runs a job to dump the database, compresses it, and then pushes it to a bucket at your object storage provider.  Here's an example of such a job that pushes a DB dump to BackBlaze:\n\n```yaml\nbackup_drupal_db:\n  image: $KUBECTL_IMAGE\n  stage: backup\n  rules:\n    - if: '$CI_PIPELINE_SOURCE == \"schedule\"'\n  script:\n    - \u003e\n      apk add --no-cache\n      --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main\n      --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community\n      --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing\n      b2-tools\n    - kubectl config use-context mygroup/myproject:prod  # group/project:agent\n    - kubectl --namespace=$DRUPAL_NAMESPACE exec deploy/drupal -- sh -c 'drush sql-dump' | gzip \u003e \"$DRUPAL_DB_DUMP_SOURCE_PATH\"\n    - b2 account authorize \"$B2_ID\" \"$B2_KEY\"\n    - b2 file upload --no-progress \"$DRUPAL_DB_BACKUP_BUCKET\" \"$DRUPAL_DB_DUMP_SOURCE_PATH\" \"$DRUPAL_DB_DUMP_UPLOAD_FOLDER/db-$(date +%FT%T%Z).sql.gz\"\n```\n\n## Upgrades\n\nSee the [release notes](https://gitlab.com/backupscale/drubernetes/-/releases) for details.\n\n## References\n\n* [Introductory article: Want to Run Drupal in Kubernetes? Try Our New Terraform Module](https://backupscale.com/posts/drubernetes-terraform-module-for-kubernetes-clusters/)\n* [Drubernetes on the Terraform Registry](https://registry.terraform.io/modules/BackUpScale/drupal/kubernetes)\n* [Drubernetes project tracker for issues, MRs, etc.](https://gitlab.com/backupscale/drubernetes)\n\n## Feedback and contributions\n\nFeedback and contributions are welcome!  To contribute, please:\n\n1. [Create an issue on the board](https://gitlab.com/backupscale/drubernetes/-/boards), and then\n2. a merge request (MR) from within the issue (if you can).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackupscale%2Fterraform-kubernetes-drupal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbackupscale%2Fterraform-kubernetes-drupal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackupscale%2Fterraform-kubernetes-drupal/lists"}