Tech Stuff Tales from the trenches

Bootstrapping Ec2 Instances

I love AWS, even if for nothing more than the fact that as one commentator put it, it works at all. When provisioning instances with Ansible I like to always start from vanilla distro AMIs (usually CentOS). But this leaves the problem of bootstrapping so I can get the barebones authentication and DNS stuff set up (ie. I can ssh as a non-default sudo user via a DNS name, which I can add to my playbook).

(One way around the DNS issue that I'd like to explore is via dynamic inventories, but I'm not quite ready for that yet...)

So to bootstrapping. While looking into how I might do this I found a handy piece of information buried deep down in a Stackoverflow comment (that I can no longer find) - you can pass a list of host names as the -i argument to ansible-playbook. For example...

ansible-playbook -i "hostname," ec2-bootstrap.yml

Note the comma at the end, that's actually required to let Ansible know this is a list of hostnames. My playbook then looks like...

1 # ec2-bootstrap.yml
2 - hosts: all
3   user: root
4   roles:
5     - sudo-access
6     - setup-dns

This playbook will target all the hosts that I've specified by -i and run the list of roles against them. When its done I'm left with an instance I can add to my inventory for full provisioning, and ssh in to via my standard ops user.

Maybe I could even specify the role via a command line extra-vars option... so I could do the whole provisioning at once... I will have to try that! No wait, I need the parameters from the inventory, natch...

How do other people handle this, with "gold" AMIs to clone maybe? I don't fancy that option as it's something to maintain. And things like this that need maintenance usually don't get it. Please let me know if I'm doing it wrong!

Mounting Folders With Mock

I use Mock to build RPMs in a clean chroot'd environment - and it works great! The only problem is the documentation is abysmal. Now, I'm not trying to be one of the people who complains and slags off someone else's project - I'm actually trying to not be that person... but in this case I'm afraid the criticism is absolutely true.

If you need to use Mock then it seems the only place that has any kind of information is the official website. And if you're not already an expert, then like me I expect you'll find yourself pretty lost (though you won't be lost for long as it's only one page, so you'll move on quite quickly from being lost to being completely stuck).

I was quite happily building RPMs with Mock for a PHP application, but build times were slow as the environment was clean each time Composer was having to download every single one of the dependencies. Not ideal. Luckily there's a plugin for Mock (which is enabled by default) called bind_mount which allows mounting host folders inside the chroot which can then act as the durable cache folder for Composer.

Brilliant! Indeed, if you can figure out how to use it... Sorry... I'm trying hard and failing to not be bitchy here, but the only documentation I could find that this feature even existed (after resorting to IRC channels) were two lines of example configuration that comes installed with Mock. I used these...

configopts['pluginconf']['bind_mount_enable'] = True
configopts['pluginconf']['bind_mount_opts']['dirs'].append(('/var/cache/composer/', '/var/cache/composer/' ))

But alas... watching the builds crawl by it was clear nothing was actually being cached. But no errors, no clues as to why. I suspected it was something to do with the permissions of the folder on the host I was mounting into the chroot. After a lot of trial and error I finally hit upon the solution, here it is...

chmod 2755 /var/cache/composer

Or in my Ansible role...

1 - name: Composer Cache Directory
2   file: path=/var/cache/composer state=directory
3         owner=jenkins group=mock mode=2775

Then the next time I ran a build I could see the dependencies getting written, and after that the build time was cut by about 70%