Professor Sloth

Free web performance master class

Learn about web performance and how to make your site faster, delivered straight to your inbox.

Episode 3.5: Basic Ansible With SSH Keys

We finally use our new SSH key to provision our Linux dev server with Ansible. Witness the “Hello World” of Ansible setups. Now that we have a SSH key, we can configure the server to host our ASP.NET Core application. We use Ansible for this because of its relative simplicity vs many of the other available tools.

Before we do any real configuration we need to verify Ansible can connect to and execute commands on the server. Ansible playbooks can only be run from linux. Happily, Windows users are not out of luck because Ansible works perfectly fine from Windows Subsystem For Linux(WSL). Some extra steps are needed however when running Ansible running in WSL.

Why Ansible?

We’ve used Ansible successfully for many years on TrackJS. We picked Ansible again for Request Metrics because the reasons we picked it from TrackJS apply:

  • No Server Agent Target servers need nothing besides python installed
  • No “Master” Server No additional infrastructure needed just for provisioning
  • Simple Conceptually It’s “just” SSH
  • Simple to Start Initial playbooks can be very small and grown as needed

Installing Ansible

Ansible is Python based and can installed using pip or the package manager (depending on your distribution). We use pip to more easily control which version we run:

  1. Update your package lists if necessary:
> sudo apt-get update
  1. Make sure Python 2 and pip are installed:
> sudo apt-get install python-pip python
  1. Install Ansible using pip:

> sudo -H pip install ansible
# Or specify a specific version (optional)
> sudo -H pip install ansible==2.4.1.0

Ansible on Windows With WSL

There is one big gotcha with using SSH keys in WSL. They can’t be in the normal Windows file system. If you attempt to use a key located there (eg - /c/path/myprivate.key), OpenSSH will refuse to use the key and show the message: WARNING: UNPROTECTED PRIVATE KEY FILE! PERMISSIONS 0555 for 'myprivate.key' are too open. This error can be avoided by copying the key into the WSL file system:

  1. Open a WSL command prompt
  2. Copy your key into the WSL user’s home directory:
> cp /c/some/path/myprivate.key ~/.ssh/
  1. Lock down the key’s permissions so that SSH will use it:
> chmod 400 ~/.ssh/myprivate.key

A Basic Ansible Project

Starting a new Ansible project can be intimidating because there are a fair number of file and directory conventions. Luckily we don’t have to use all of them out of the gate. We start with two or three basic files to test that Ansible can communicate with our server:

  • Inventory File Tell Ansible what servers you’d like to operate on

[myGroupName]
my.server.com
; or, the SSH key can be specified right inline
my.server.com ansible_ssh_private_key_file=~/.ssh/myprivate.key
myInventory
  • Playbook Tell Ansible what you’d like to change about the servers in your inventory

---
- hosts: myGroupName
  remote_user: remote_server_username
  tasks:
    - name: Test Connection
      ping: # Just prove that Ansible can connect to the machine
basic-playbook.yml
  • Run playbook Execute the playbook using the myInventory inventory file
> ansible-playbook -i myInventory basic-playbook.yml

Ansible Configuration With ansible.cfg

When a configuration file named ansible.cfg is placed in the root of the project, Ansible will apply its settings to all playbooks within that directory structure. There are a number of settings which are quite handy:


[defaults]
; Don't type "yes" for every new server in your inventory.
; This is very useful when many servers are being configured.
host_key_checking = False

; An alternative to specifying "ansible_ssh_private_key_file" over
; and over in the inventory file
private_key_file = ~/.ssh/myprivate.key

; Run playbooks faster. There are some gotchas so read the docs before using this one!
pipelining = True

; Default hosts value in a playbook to a bogus value.
; Prevents running a playbook against all servers on accident.
hosts = noDefaultForSafety
ansible.cfg

Now we have a basic project skeleton and we have proven Ansible can communicate with our server. Next, we’ll grow the playbooks with provisioning and configuration of the server to support our .NET Core application. Finally, we will deploy code to the server from TeamCity.

Jordan Griffin
VP Engineering Request Metrics