How to Create an Ansible Test Environment using LXD

LXD/LXC is great for setting up test / development environments as it allows us to quickly create Linux based containers that behave like full virtual machines.

I recently had the requirement to develop an Ansible Playbook to configure a bunch of machines as a web farm. I decided to use LXD/LXC to create an environment where I could test the playbook quickly and easily. This meant I wouldn’t have to worry about needing to build any VMs, or anything external to the system I was working on.

In the following sections I will show the commands I ran to create the environment, explaining what each part does, before showing the completed script at the end of the page, so please read through to the end! Before continuing, you will need to have installed LXC. Checkout this article on how to install LXC/LXD if you haven’t already.

Let’s get started!

Create an LXC Container

The first step is to create an LXC container, which will form the basis of the Ansible test environment. I will be using Ubuntu as my container OS. To create an Ubuntu LXD container, we can run:

lxc launch ubuntu ansible01

This command will create an container using the Ubuntu image. If you don’t already have an Ubuntu image on your system it will be downloaded from the online repo.

That was easy, next we need to set up a couple of scripts to help us configure the containers.

Configure SSH

Ansible uses SSH to communicate with nodes in order to be able to configure them. For my test environment I will generate a new SSH key in my new container and add it to the authorized_keys file. Later on, when we copy the container it will mean that every container we launch will have the key already allowed. Note that this approach isn’t advised in a production scenario. The following commands are used to create the new key and add it to authorized_keys:

ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

We don’t yet want to run these commands manually however. We will have them run from a script, which we can send to the container. To do so, I’ve used the following in my script:

cat >> sshsetup.sh << EOF
#!/bin/bash
ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
EOF

The code above will create a new script called sshsetup.sh which we will later copy to the new container.

Install Ansible in the LXC/LXD Container

We want to use a similar approach to install Ansible within the container. Rather than running the commands interactively, we can set up a script to later run inside the container. I have done this using the following code:

cat >> ansibleinstall.sh << EOF
#!/bin/bash
apt update
apt install software-properties-common -y
apt-add-repository --yes --update ppa:ansible/ansible
apt install ansible -y
export ANSIBLE_HOST_KEY_CHECKING=False
echo "[test]" >> /etc/ansible/hosts
echo "ansible02" >> /etc/ansible/hosts
echo "[defaults]" >> /root/.ansible.cfg
echo "host_key_checking = False" >> /root/.ansible.cfg

EOF

This will output a file called ansibleinstall.sh which can be used to install Ansible.

At this point we should have a running Ubuntu container and two scripts, one to configure the SSH key and the other to install Ansible. We can now use these scripts to help configure the Ansible test environment.

Configure the Container

We’re now ready to use the scripts to configure the container. First of all we want to run the SSH script to get the SSH key set up. We can do so by copying the script to the container, and then running it. This is done by using the following commands:

lxc file push sshsetup.sh ansible01/tmp/
lxc exec ansible01 -- sh /tmp/sshsetup.sh

Once the script has ran sucessfully we want to take a snapshot of the container:

lxc snapshot ansible01 1.0

The reason for this is that we now have a snapshot of a container that has that SSH key already trusted. This means that we can use this snapshot to launch new containers that we will be able to SSH to without any additional configuration.

Create another LXD container from snapshot

Lets create and start a new container from the snapshot:

lxc copy ansible01/1.0 ansible02
lxc start ansible02

Now, we will be able to SSH from our ansible01 container to ansible02 without needing to provide any credentials. This will also work from ansible02 to ansible01.

Installing Ansible

So, we now have two identical containers called ansible01 and ansible02. The first container will be my Ansible system so we want to go ahead and install Ansible on it using the script created earlier.

lxc file push ansibleinstall.sh ansible01/tmp/
lxc exec ansible01 -- sh /tmp/ansibleinstall.sh

With that done we can test the install by attempting to ‘ping’ ansible02 from ansible01:

lxc exec ansible01 -- ansible test -m ping

This should return a successful response. If so, we can go ahead and start creating some Ansible playbooks to deploy onto ansible02.

By creating more containers from the snapshot we can easily scale this out to create many many more Ansible targets. This is great for quickly testing Ansible playbooks.

Automating the whole thing!

Speaking of quickly, we can wrap up all the commands used in this article into a single bash script:

#!/bin/bash
echo "+++ \e[44mLaunch first container \e[0m"
lxc launch ubuntu ansible01

echo "+++ \e[44mCreating script to configure SSH \e[0m"
cat >> sshsetup.sh << EOF
#!/bin/bash
ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
EOF

echo "+++ \e[44mCreating script to install ansible \e[0m"
cat >> ansibleinstall.sh << EOF
#!/bin/bash
apt update
apt install software-properties-common -y
apt-add-repository --yes --update ppa:ansible/ansible
apt install ansible -y
export ANSIBLE_HOST_KEY_CHECKING=False
echo "[test]" >> /etc/ansible/hosts
echo "ansible02" >> /etc/ansible/hosts
echo "[defaults]" >> /root/.ansible.cfg
echo "host_key_checking = False" >> /root/.ansible.cfg

EOF

echo "+++ \e[44mCopy and Run SSH script \e[0m"
lxc file push sshsetup.sh ansible01/tmp/
lxc exec ansible01 -- sh /tmp/sshsetup.sh

echo "+++ \e[44mSnapshot ansible01 \e[0m"
lxc snapshot ansible01 1.0

lxc copy ansible01/1.0 ansible02
lxc start ansible02

echo "+++ \e[44mInstall Ansible on ansible01 \e[0m"
lxc file push ansibleinstall.sh ansible01/tmp/
lxc exec ansible01 -- sh /tmp/ansibleinstall.sh

echo "+++ \e[44mClean Up Files \e[0m"
rm ansibleinstall.sh
rm sshsetup.sh

echo "+++ \e[44mInstall Finished! \e[0m"
lxc list

echo "+++ \e[44mTest Ansible using Ping \e[0m"
lxc exec ansible01 -- ansible test -m ping

echo "+++ \e[44mComplete! \e[0m"

This script takes a few moments to run, the outcome from which is the two running containers, one with Ansible installed and with SSH configured so that the 2nd container can be easily used as an Ansible target.

As a bonus, you can delete the whole environment by running the following script:

#!/bin/bash
lxc stop ansible02
lxc stop ansible01
sleep 15
lxc delete ansible01
lxc delete ansible02

Conclusion

In this article I have shown how you can use LXC/LXD to create a test environment for developing and testing Ansible playbooks quickly and easily. I have also included an example of a bash script which automates the creation of the Ansible test environment using LXD containers.

Related posts

Mastering the Linux ifconfig Command

Docker Exec Command With Practical Examples

Debugging with Git Bisect

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Read More