The back-end consumes Operations from the queue, and run various commands. The initial engine is ansible-playbook
, but Kubernetes is also likely to follow.
Fundamentally, a Backend needs to be able to:
Over the last couple years, we’ve had the opportunity to work on deploying complex, stateful web applications (Django, Drupal) in a Kubernetes environment. We’ve defined a general framework to support our development and production hosting workflows, and recognized this as a solid basis for an alternate backend to plug in to the existing Aegir5 front-end.
As shown in the diagram below, traffic enters the system via the router that directs traffic to the cluster. The router exposes a public IP address, to which we point our DNS entries. From there the K8S ingress service directs traffic within the cluster.
In addition, the ingress controller automatically generates Let’s Encrypt HTTPS certificates, and acts as the HTTPS endpoint, handling the TLS handshake, etc.
Traffic gets directed to the Drupal deployment, which in turn, connects to the database deployment. These are running Docker containers. In addition, temporary job containers can be launched to perform specific tasks, such as installing the site, or running cron.
In the case of the Drupal containers, we’re running a custom Drupal image that bakes our code base in. The database deployment, for its part, is using a stock mariadb image.
Our custom Drupal image, by including the project code base, provides us with reproducible builds. We can deploy this same image to multiple environments with confidence that it will be consistent across all of them.
Both the database, and the Drupal site are connected to storage via Persistent Volume Claims (PVCs). More on this later.
Currently we write small Ansible roles to represent each task we want to implement, rather than the usual model of handling all tasks related to a given application. A small set of variables will need to be mapped to the equivalent front-end fields.
This is somewhat tedious, and we’re likely to refactor this so that frontend Task maps to a task within an Ansible role, so a Role roughly maps to an Operation.
- hosts: web0
vars:
( populated from task )
roles:
( populated from task )
“Task” roles are small re-usable pieces of config.
aegir.GenerateDrupalSiteBackup/
├── meta/main.yml (equiv. to .info)
├── defaults/main.yml (variable defaults)
└── tasks/main.yml (steps to execute)
├── drush archive-dump
├── move to storage location (path)
└── post path back to front-end
aegir.WriteNginxVhost/
├── meta/main.yml
├── files/default-nginx-vhost.conf.j2
├── defaults/main.yml
└── tasks/main.yml
├── write vhost from template (possibly looking for overrides in various places)
└── restart nginx (but only if the vhost changed; i.e. idempotence)