5 minute read Published: Author: Derek Laventure
Cloud , Infrastructure , Ansible , Vault


You are reading our blog series: Pure Ansible Infrastructure


Playbooks

Ansible Playbooks are the heart of any project driven by this tool, and in our example project we are now ready to look at this core piece of the puzzle.

Essentially, when we think about the infrastructure resources needed to host a site or application like Aegir, there are 3 main categories to think about:

  • Support infrastructure: VPCs and Firewalls, etc.
  • Hosts: usually VMs, sometimes clusters or “bare metal” servers
  • Applications: the software stack from operating system up through the hosted software (eg. Drupal)

Our project’s playbooks/ folder mirrors this structure:

This setup allows us to separate concerns between plays that are “global” (in the sense they set up the VPC, Firewall, and Project for everything else), those that create a host (on which to run a particular application), and those that configure the software applications themselves.

Ansible’s variables system allows us to share important data across these sets of plays as needed. For example, when we create the Firewall we give it a name (web), which is defined in the inventory/group_vars/all/vars.yml in the variable aegir_droplet_firewall. This variable is used when creating the Firewall, but also when creating the Droplet in order to associate the two.

To tie things together, we use Drumkit make targets to encode the specific way to call these make targets, and chain them together. We typically break these targets out into smaller pieces in the drumkit/mk.d/*.mk structure that Drumkit provides for exactly this purpose.

Support infrastructure

The early plays in the sequence of spinning up this Ansible-driven infrastructure use localhost as the target host for the playbook (see playbooks/infra/00-up.yml for example). This is because we are making API calls to DigitalOcean from our local workstation, with the aim of creating cloud resources: a Project, VPC, and Firewall, then finally a Droplet. From there, our Aegir playbooks can target the droplet to run on, but in the bootstrapping moment we use localhost

Below we’ll break down each of the pieces of the support infrastructure playbooks, but I’ll first note the 2 “wrapper” playbooks to bring all the other pieces up or down:

You’ll note that these two playbooks are nearly identical, but the “down” variation simply sets the “state” related variable (see inventory/host_vars/localhost/vars.yml. Finally, we wrap these up in the Drumkit targets make infra and make infra-down to call these playbooks.

Project and Tags

DigitalOcean Projects are logical containers within which to house (some kinds of) cloud resources. In our case, it keeps Droplets and Volumes logically separated from others in our DigitalOcean account. Tags are similarly used to group resources with similar attributes. As discussed in Dynamic inventory we use this mechanism to create Ansible host groups.

These items are created in the playbooks/infra/project.yml playbook, using the variables we’ve set up to provision the configured project and tags.

VPC

In our example project, the VPC is a bit of complexity that’s not strictly necessary. As we’ll see, our Droplet will join our Tailscale VPN, which provides an effective means for private networking between Droplets if needed. Obviously we only have a single Droplet in our example, but we could easily scale up to more.

That said, VPCs are a typical component of many cloud architectures, and require little extra overhead to provision up-front. In our example project, if we were to add a DigitalOcean managed service into the mix to meet some requirement, we can easily imagine a need for those services (not on our tailnet) to communicate privately with our Droplets.

The VPC is created in the playbooks/infra/vpc.yml using a straightforward play that follows the documentation examples, substituting variables for most values.

Firewall

The firewall is the last piece of the support infrastructure puzzle in our example, but of course you can imagine any number of other components and resources coming into play here. By now you should see the pattern and be able to extend it as needed if you have a requirement for a Load Balancer, for example. Add a playbook under playbooks/infra/, following the documentation for the Ansible module related to the resource in question (eg. digital_ocean_load_balancer, and then add it to the list of things in 00-up.yml and 01-down.yml. Introduce variables in appropriate places to make the playbook configurable via your inventory/variables system, and you’re all set.

Our firewall setup follows this pattern:

One note about the Firewall rules: there is (currently) no Ansible module for modifying firewalls after creation. The DigitalOcean API supports adding/removing rules from a Firewall after creating it, but there’s no access to this feature via Ansible as it stands. Our example project creates the Firewall at the beginning of the process, then our Droplet gets attached to it as we’re creating it.

However, what if we needed to add other rules after the Droplet is created, if they needed to encode IP addresses we don’t know beforehand, for example? It would be a straightforward matter to shift firewall creation to happen later in the process. We could simply take the firewall playbook out of the 00-up.yml list, and introduce a new Drumkit target to run later on.

Next steps

In the next post we’ll explore the Ansible Collections we’ve published in the process of building out this infrastructure. In particular, we created a role that will provision a DigitalOcean Droplet in the (opinionated) way we generally want. In future, we may incorporate some of the support infrastructure playbooks discussed above into roles/collections as well.


The article Playbooks and support infrastructure first appeared on the Consensus Enterprises blog.

We've disabled blog comments to prevent spam, but if you have questions or comments about this post, get in touch!