Using Ansible with Terraform
Terraform is a great tool for building infrastructure in the cloud. Ansible is a beautifully simple agentless (and serverless) configuration management tool. A common use case is to build servers with Terraform, and have Ansible configure them. Unfortunately Terraform lacks a provisioning plugin for Ansible - but fear not, they can be used together fairly trivially by using the local-exec
provisioner of Terraform.
Let’s take an example of creating a Jenkins master server in AWS EC2. Here is the Terraform specification for the instance:
resource "aws_instance" "jenkins_master" {
# Use an Ubuntu image in eu-west-1
ami = "ami-f95ef58a"
instance_type = "t2.small"
tags {
Name = "jenkins-master"
}
# We're assuming the subnet and security group have been defined earlier on
subnet_id = "${aws_subnet.jenkins.id}"
security_group_ids = ["${aws_security_group.jenkins_master.id}"]
associate_public_ip_address = true
# We're assuming there's a key with this name already
key_name = "deployer-key"
# This is where we configure the instance with ansible-playbook
provisioner "local-exec" {
command = "sleep 120; ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u ubuntu --private-key ./deployer.pem -i '${aws_instance.jenkins_master.public_ip},' master.yml"
}
}
To break down the local-exec
command, we’re first sleeping 120 seconds just to give the instance some time to boot up before having Ansible knock on the door. After that we’re setting the ANSIBLE_HOST_KEY_CHECKING
environment variable to False, to make Ansible trust the newly-launched server. Then we are running the ansible-playbook
command, with the user ubuntu, a specified private key, and most importantly: a specified Ansible inventory that only contains the public IP of the server we’ve just launched.
Here is an accompanying Ansible playbook (master.yml
) for installing Jenkins:
- hosts: all
become: true
tasks:
- name: ensure the jenkins apt repository key is installed
apt_key: url=https://pkg.jenkins.io/debian-stable/jenkins.io.key state=present
- name: ensure the repository is configured
apt_repository: repo='deb https://pkg.jenkins.io/debian-stable binary/' state=present
- name: ensure jenkins is installed
apt: name=jenkins update_cache=yes
- name: ensure jenkins is running
service: name=jenkins state=started
With both of these in a directory, you will be able to provision a server with Terraform and have Ansible configure it automatically.
While we use Jenkins as an example here, one thing to consider would be persistent storage for the Jenkins installation. One approach is to create an EFS volume with Terraform, and store the Jenkins home directory on that volume. You can pass the EFS volume id to the Ansible playbook with -e 'efs_id=${aws_efs_file_system.volumename.id}'
.
To mount an EFS volume with Ansible, see https://github.com/dmitrybelyakov/ansible-localcloud-efs
Releaseworks Academy has a free online training course on Docker & Jenkins best practices: https://www.releaseworksacademy.com/courses/best-practices-docker-jenkins