Ansible: How to Update Lots of Servers

So, usually I don't post snippets on the ol' blog, but sometimes I don't want to forget something—or in this case two somethings.

I've been using Ansible to manage servers at work, and it's been a fantastic tool. While I leave tons of stuff up to Puppet with respect to configuration and security management, it doesn't help out much with updating the servers.

So, without further ado:

Install Ansible

  1. First, install Ansible via the pacman command.
    sudo pacman -S ansible
  2. Honestly, it's not tough to set up. I usually place it in a directory like ~/Code/ansible just to keep things straight.
    mkdir -p ~/Code/ansible
    cd ~/Code/ansible
  3. Create a subdirectory for the update playbook. We'll call it update_servers since it's catchy. I try to create a directory for every kind of playbook that I write.
    mkdir update_servers

Configure Hosts

  1. For each server you want to update at the same time, ensure that you log into them via ssh. We're going to assume that you've set up each server to used shared keys to access them. This will ensure that each host in the list has had their key fingerprinted.

    You can get around this by disabling this key check in the /etc/ssh/sshd_config file, but I don't recommend it.

    ssh database.cerberus.local
    The authenticity of host 'database.cerberus.local (10.0.2.6)' can't be established.  
    ECDSA key fingerprint is SHA256:7xMN0I07obwitJwBhxEEihkvLzvZhwScrM+kGXw1u/V.  
    Are you sure you want to continue connecting (yes/no)? yes  
    Warning: Permanently added 'database.cerberus.local' (ECDSA) to the list of known hosts.  
    Last login: Mon Jan  2 01:07:43 2017 from 10.0.0.155
  2. Okay, now we add our hosts to a file named hosts. It's pretty simple to start with though it's pretty powerful.

    I'll label this server group as archlinux to keep 'em organized since I do have other Linux distros that I work with.

    vim ~/Code/ansible/update_servers/hosts
    [archlinux]
    webserver.cerberus.local  
    database.cerberus.local  
    ntp.cerberus.local

The Quick Update Playbook

Before I get hate-mail on this one, always research released packages before blindly running updates. I'm lazy as I have more than three Arch Linux servers to update at a time, but even I verify that there isn't going to be a catastrophe when I update.

Also, I don't recommend doing this if you have very, very complicated builds. I do recommend using Ansible, but maybe not using it to update if it's that complicated.

  1. Navigate to the update_servers directory if you're not already there. We're gonna build a YAML file!
    cd ~/Code/ansible/update_servers
  2. Open up your favorite editor, and create the update_servers.yaml file. This is where the magic happens. We're going to use the pacman module that comes with Ansible to accomplish everything.
    vim update_servers.yaml
  3. In the YAML content below, it should be pretty self-explanatory. The hosts line pulls the group of servers out of the inventory file via the label we used. The become line allows us to escalate privileges on the servers after we log in.

    The pacman tasks tell it to update the package cache before actually updating. I like breaking up the command so I know exactly where the process fails at. A few more lines, but a bit more information

    Edit the pertinent parts below, and save it.

    # vim:ts=2:sts=2:sw=2:et
    ---
    - hosts: archlinux
      remote_user: jweatherly
      become: true
      tasks:
      - name: Update 'pacman' cache
        pacman:
          update_cache: true
      - name: Update Arch Linux via 'pacman'
        pacman:
          upgrade: yes

Running Updates

Using the ansible-playbook command, lets kick the tires on our new playbook.

cd ~/Code/ansible/update_servers  
ansible-playbook -i hosts -K update_servers.yaml  
SUDO password: 

PLAY [arch] ********************************************************************

TASK [setup] *******************************************************************  
ok: [database.cerberus.local]  
ok: [webserver.cerberus.local]  
ok: [ntp.cerberus.local]

TASK [Updating 'pacman' cache] ******************************************  
changed: [webserver.cerberus.local]  
changed: [database.cerberus.local]  
changed: [ntp.cerberus.local]

TASK [Upgrading Arch Linux via 'pacman'] ****************************************************  
ok: [database.cerberus.local]  
ok: [webserver.cerberus.local]  
ok: [ntp.cerberus.local]

PLAY RECAP *********************************************************************  
database.cerberus.local    : ok=3    changed=1    unreachable=0    failed=0  
webserver.cerberus.local   : ok=3    changed=1    unreachable=0    failed=0  
ntp.cerberus.local         : ok=3    changed=1    unreachable=0    failed=0

If everything was typed in correctly, then you should see ansible-playbook log into each server, grab some information, then start in on the tasks defined in the update_servers.yaml file.

The -i option allows you to specify an inventory file. The -K option tells ansible-playbook to use sudo to elevate privileges. You can also use the -k option to specify a password to login to the target servers. This will only work if you've installed the sshpass package, and hopefully all of your servers have the same password associated with the user account you're using—basically the reason I use keys.