Ansible and CloudFormation

🎵… sitting in a tree…🎵 For both my personal projects, and projects at Unbounce, I use Ansible to create CloudFormation stacks. This brings some amazing user experience improvements for people not used to working with CloudFormation and its asynchronous behaviour. Before I show some of the benefits, I will explain what each piece of the technology is doing. What is Ansible? Ansible is a configuration and orchestration tool for servers and services. People primarily use Ansible to configure packages, libraries, and services on Linux machines (though other operating systems are supported). It is focused on idempotency, which is to ensure that running the Ansible playbook once will change the system, but subsequent runs will not effect any change. ...

June 24, 2016 · 7 min · 1468 words · Scott Brown

Be Nice to Sysadmins, Add a version.txt to Your App

One best practice that I rarely see used by companies is a version file that denotes what is currently in Production. Let’s step back a bit and use a real-life situation. A company released a new version of their Web application to Production from master (using the git-flow model). Some hours go by and its now late into the night when the application fails. Unfortunately, all of the developers are now at home and only the poor operator (who is on-call support) is left wondering what happened. The software didn’t fail in the test environment, what could possibly have gone wrong. ...

November 10, 2014 · 2 min · 411 words · Scott Brown

Be Careful with the Order of Ansible Handlers

I recently stumbed across an gotcha with Ansible that I wasn’t aware of. It happened when I was writing notification handlers that should run after a new version of code is downloaded to a server. In my task file I was downloading (via Git) the latest code from the repository: --- # roles/app-code/tasks/install_code.yml - name: ensure code repository is downloaded git: > accept_hostkey=yes key_file={{ app_code_bitbucket_private_key_file }} repo={{ app_code_git_repository }} dest={{ app_code_home_dir }} version={{ app_code_git_version }} sudo: yes sudo_user: '{{ app_user_name }}' notify: - update gems - precompile assets - add hash marker file - restart app server Whenever new code is downloaded to the system, the task will show CHANGED and each notification handler will be called. In this case, we want each notification to happen in a specific order because you don’t want to restart the application server before the assets and third-party libraries are configured. In this case, using an array may not execute the handlers in this order even though you’d expect it to. ...

November 9, 2014 · 2 min · 385 words · Scott Brown

Simple Per-User Bash Profile Configuration

While creating Ansible scripts to automate the configuration of servers, I frequently stumble across an issue where I need to setup a user’s profile on the server that has a custom path. The issue that arises is that the .bash_profile file is a single file where any number of PATH exports can be provided. Any step in a provisioning tool like Ansible should be aware that this only adds state. I have seen other DevOps workers use modules like lineinfile, which I abhor because you can never be certain that the module will work. You will always ask yourself, “did the PATH on line 5 get set correctly, or did someone change one character (or perhaps add a comment) that now breaks the lineinfile module task?” ...

November 6, 2014 · 3 min · 483 words · Scott Brown

Anatomy of an Ansible Bug

Tracking down Ansible bugs becomes difficult when you are playing with issues between local and remote systems. For the last couple days I was racking my brains why my database import script, written in Ansible, was not importing the data into the database. I had 3 separate imports, and only 1 was working. I looked at everything, but it wasn’t until I walked away, came back, and realized that I had mistyped one character in the path to the dump. ...

June 17, 2014 · 8 min · 1612 words · Scott Brown

Ansible Tips Part 4: Encrypt Sensitive Data

Everyday I pray to Lord Turing that I never see another Production database password in version control again. Unfortunately, I doubt my prayers will be answered because it seems to be an epidemic in Tech to store an application’s production configuration file in version control without any thought to security or privacy. So if developers cannot stop themselves from storing passwords in version control, does anyone honestly think a sysadmin will think twice about storing passwords for their Ansible provisioning in version control? ...

June 16, 2014 · 3 min · 492 words · Scott Brown

Ansible Tips Part 3: Write First, Use Variables Later

When first starting out writing tasks within a role, write the entire task as you normally would. do not include any variables or things that may change. by doing this, you keep to the simplest form of Ansible provisioning possible. In the software development world, this is a two-part form of YAGNI and premature optimization. Consider this first cut of the role a draft, requiring proofreading before committing to version control. --- # roles/ssh/tasks/main.yml - name: configure sshd daemon template: > src=sshd_config.j2 dest=/etc/ssh/sshd_config owner=root group=root mode=644 sudo: yes notify: Restart ssh Then, once you have finished with the role, re-read each task in the role and look for things that stand out as hard-coded strings. For example, paths to configuration files, owners and groups, or even permissions. Think of each of these as a possible candidate for a variable. Using the above example, I can rewrite the task using variables. ...

June 13, 2014 · 2 min · 381 words · Scott Brown

Ansible Tips Part 2: Don't Format Lists of Things

Something I’ve encountered while searching for answers to Ansible around the Internet is how to deal with configuration values that are character-delimited. For instance, the fail2ban jail file allows you to specify a set of hostname/IPs to whitelist. ... # /etc/fail2ban/jail.conf # "ignoreip" can be an IP address, a CIDR mask or a DNS host #ignoreip = 127.0.0.1/8 ignoreip = 127.0.0.1/8 1.2.3.4/8 bantime = 600 ... I have commented out the default value for ignoreip so that you can see a before-and-after view of the configuration setting. ...

June 9, 2014 · 2 min · 417 words · Scott Brown

Ansible Tips Part 1: When in Doubt, Be Explicit

When copying files, using templates, or creating just about anything on a target machine via Ansible, make sure that you are as explicit as possible. Don’t assume that a file will be created with a specific owner unless you specify that owner in the Ansible task. For example, you are providing your own SSH configuration file, overridding whatever is on the system, your task will look like this: --- # roles/ssh/tasks/main.yml - name: configure ssh client configuration template: src=ssh_config.j2 dest=/etc/ssh/ssh_config sudo: yes notify: Restart ssh In this situation, you are running the task with sudo privileges, so you are assuming that this file will be owned by root:root. Looking at an Ubuntu machine confirms that this file, by default, is also owned by root:root: ...

June 5, 2014 · 2 min · 288 words · Scott Brown

Ansible Tips Series Starting Soon

I’m in the process of automating the provision step for a client’s project in Ansible, from a Vagrant environment through to the Production environment. Along the way, and in previous Ansible projects, I’ve accumulated some tips which I’ll enumerate here in a series of articles. They are meant to be short, yet detailed. I intended to write all of the tips in one article, but then the article became too long and nobody is going to take an hour to read it. Better to chop it up into bite-sized pieces. ...

June 5, 2014 · 1 min · 193 words · Scott Brown