Ansible continuously integrated with Drone

Last time when we got our little Ansible setup to spin up Docker containers as systemd services, I suggested that we should perhaps have Drone running the syntax checks and playbook runs for us. Let's give it a try now, shall we?

The plan

Let's just agree to keep it simple. For the start we just want to:
  • Run ansible-playbook --check-syntax on the code we've just pushed to repository
  • Actually run the playbook (deploy it) if the code has been pushed to master

This doesn't sound terribly complicated to get it running, right? So let's begin with..

.drone.yml

build:
    image: rics3n/drone-ansible
    commands:
        - ansible-playbook -vvv playbook.yml -i inventory --syntax-check

deploy:
    ansible:
        image: rics3n/drone-ansible
        inventory: inventory
        playbook: playbook.yml
        when:
            branch: master

The build step is really just our test step in this case. We're using rics3n/drone-ansible image for this as it comes with ansible-playbook inside and we're going to use it as a deployment plugin anyway. In theory any docker image with Ansibe installed would be just as good for the build phase. What Drone does in the background for this step is following..

It will:
  • Spin up plugins/drone-git and checkout the code you just pushed somewhere into /drone/src/repo.server/repo/name. This happens before the build phase and while you can customize the behavior, this is what it does by default.
  • During the build phase, it will spin up rics3n/drone-ansible container
  • Attach the /drone/src
  • Owerride its entrypoint with /bin/sh (this as a sideffect won't start the usual plugin binary)
  • cd into the /drone/src/repo.server/repo/name and run command(s) specified for the build phase. In our case this will just run the desired --syntax-check.

Obviously you can add more commands here - even multiple build steps with different Docker images if you want. If you have any unit tests to run or some checks to do, this phase is exactly for that.

Once all build steps pass, Drone will execute the deploy step. The when condition makes sure, that it will do that only for code pushed to master. This is the most basic scenario - you can add deployment to dev environment from its own, dedicated, branch like this:

deploy:
    ansible:
        image: rics3n/drone-ansible
        inventory: dev_inventory
        playbook: playbook.yml
        when:
            branch: dev

Add more deploy steps for each of your environments and you can "promote" your Ansible configuration from Dev to Test to QA,.. just by merging the changes to appropriate branch. (Obviously you can do the same on repository level or some other combination) This way you can have your basic CI pipeline in couple lines of yaml.

Before we execute the whole configuration, there's couple outstanding steps we need to do.

Credentials for Ansible

Ansible running in the deployment plugin needs some way to log into the appropriate hosts to execute tasks. Fortunately Drone makes this quite easy for us. For every repository Drone generates its own private key. This key is then available in running container (during all steps) under $HOME/.ssh/id_rsa. All we need to do is to copy the public portion of the key to appropriate authorized_keys files on our destination servers. You can find the public part of the key in the Drone web interface on the settings tab for this repository.

Obviously this is somewhat limited, but very quick approach. Another option would be to use Drone's secrets functionality and provide our custom key or username/password combination to Ansible that way. There's some work in Drone's v0.5 pipeline, that will bring us more options, but even now there are ways to give Ansible access in automated and secure manner.

Enable the Drone plugin

Due to security reasons, custom plugins (meaning all other than official plugins) whave to be whitelisted. This just means, that you need to set the PLUGIN_FILTER environment variable for the Drone container appropriately. You can just add rics3n/drone-ansible to it, if you wan to be strict, or you can add your internal registry plugins like this if you want: my_registry:5000/plugins/* and then tag and push this Ansible plugin there. You can also build your own plugin if you require special features or extra control - it's almost as easy as building your own Docker image.

And we're done

All is set now, just activate your Ansible repository in Drone if you didn't do so already and commit and push the .drone.yml file. You can then follow the build in Drone web interface as it progresses through the steps. From now on you can change your infrastructure by simple git push.

Enjoy