Ansible

Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates. Ansible manages machines in an agent-less manner. There is never a question of how to upgrade remote daemons or the problem of not being able to manage systems because daemons are uninstalled.

Installing Ansible

Install Pre-requisites

  • Ubuntu Linux environment 14.04+
  • Setup SSH keys

Install Steps

While the Ubuntu default repository includes an Ansible package, it is very far behind the upstream project in versioning. Recommend to use the version from the ppa. Instructions taken from http://docs.ansible.com/ansible/intro_installation.html#latest-releases-via-apt-ubuntu.

  1. sudo apt-get install software-properties-common
  2. sudo apt-add-repository ppa:ansible/ansible
  3. sudo apt-get update
  4. sudo apt-get install ansible

Verify that the installed version is > 2.1 via: ansible –version

Configure Ansible Playbooks

Ansible Playbooks run the configurations against the hosts.

1. Set save credentials:

export TF_AUTO_SAVE_CREDENTIALS=1

2. Test: run an Ansible Playbook as a test:

# add host to your ssh known_hosts
ssh server-name-01
#
# note the setup:
# 1. Playbook.yml, 2. -i (inventory), 3. pass common vars, including password vault, 4. pass extra vars, including hostname and environment, 5. unlock the password vault
#
ansible-playbook configure-apt.yml -i "server-name-01," -e @common_vars/common_vars.yml --extra-vars 'env=local variable_host=server-name-01' -v -C --vault-password-file ~/vars/.common.txt
  1. Optional: Test by running an Ansible command
    1. Ansible role-name –ssh-extra-args=”-o PubKeyAuthentication=no -o StrictHostKeyChecking=no” -m ping -k
  2. Optional: Deploy your public ssh key to an Ansible host to test
    1. Recommend getting someone who already has keys deployed to run the recipe the first time
    2. Otherwise, you’ll need to connect as a sudo account using password
      1. In the ansible-playbook command, disable PubKeyAuthentication and StrictHostKeyChecking if running manually as a specific remote_user
      2. –ssh-extra-args=”-o PubKeyAuthentication=no -o StrictHostKeyChecking=no”

Further Configuration

While Ansible will work via ssh and prompting for passwords, it is better practice to use ssh keys for authentication. Use a playbook to push SSH keys out to hosts.

Create Ansible Playbook

The following are various examples to refer to when building an Ansible Playbook:

Playbook

Ansible Playbooks require a name, hosts lists the inventory, roles begin a set of tasks.

Hosts

Run a specific task against a set of hosts, called a host inventory (note the default):

---
- name: Test Playbook to run a shell command
hosts: "{{ variable_host | default('host-group-name')}}"
become: yes
tasks:
- name: run this command and ignore the result
  shell: /usr/bin/somecommand
  ignore_errors: True
...

Pass the host list as a variable:

hosts: "{{ variable_host | default('web')}}"
# command
ansible-playbook server.yml --extra-vars "variable_host=server-name-01"

Roles

Use roles instead of tasks:

---
- name: Test Playbook to run a role
hosts: host-group-name
become: yes
roles:
- role-name-of-role
...

Output Debug Message

- debug:
    msg: "Host: {{ variable_host }} has a message to output."

Hosts

Use a host variable, or use a host inventory:

Host Variable

hosts: "{{ variable_host | default('web')}}"
# command
ansible-playbook server.yml --extra-vars "variable_host=server-name-01"

Host Inventory

/ansible-playbooks/ansible_inventory

Lists a host group and list of hosts.

[host-group-name]
server-name-01 ansible_host=server-name-01.company.com
server-name-02 ansible_host=server-name-02.company.com
server-name-03 ansible_host=server-name-03.company.com
server-name-04 ansible_host=server-name-04.company.com

Group Vars

/group_vars/name-of-group.yml

---
env: dev
variable-name-01: "/path/to/somewhere"
variable-name-02: "some variable"
variable-name-03: "user name 01"
...

Roles

Roles in Ansible build on the idea of include files and combine them to form clean, reusable abstractions. Roles allow you to focus more on the big picture and only dive down into the details when needed.

Within a role:

Files

For example: /roles/role-name/files/dev/file.keytab

Any copy, script, template or include tasks (in the role) can reference files in roles without having to path them relatively or absolutely.

Tasks

For example: /roles/dsiq-product-dictionary/tasks/main.yml

---
- name: setup-file-keytab-dir
  file:
    path: "{{ variable-name-01 }}"
    owner: "{{ variable-name-02 }}"
    group: "{{ variable-name-03 }}"
    mode: 0770
    state: directory
- name: copy-file-keytab-dir
  copy:
    dest: "{{ variable-name-01 }}"
    src: "{{ env }}/"
    owner: "{{ variable-name-0}}"
    group: "{{ variable-name-03 }}"
    mode: 0770
...

Run a Command within a Task

You may find it necessary to run a command on the command-line within a task.

---
# playbook to restart a service
- name: restart-service
  hosts: "{{ variable_host }}"
  become: yes
  user: root
  tasks:
    - name: stop-start-if-service
      commandbash -c "ifdown eth0 && ifup eth0"
...

Defaults

Example: /roles/role-name/defaults/main.yml

To create defaults, simply add a defaults/main.yml file in your role directory. These variables will have the lowest priority of any variables available, and can be easily overridden by any other variable, including inventory variables.

---
env: dev
variable-name-01: "/another/path/to/somewhere"
variable-name-02: "another variable"
variable-name-03: "override user name 01"
...

Example Commands

Command Line

Generic Ansible Command (automation script)

# browse to your list of playbooks
cd /dir/`whoami`/to/ansible-playbooks
#
# run playbook with validation flag to test host, authentication, and the validity of the playbook itself. Include env and host vars
ansible-playbook configure-apt.yml -i "server-name-01," -e @common_vars/common_vars.yml --extra-vars 'env=local variable_host=server-name-01' -v --vault-password-file ~/vars/.common.txt

Add hostname to known_hosts

Useful for running against a large set of hosts as the playbooks will not be broken apart by the question to add the host to the known_hosts file. Simply call this from your playbook:

ansible-playbook -i "server-name-01," dsiq-ssh-keyscan.yml -v

Run a command against a host list

Using -l to indicate host list:

ansible-playbook configure-ssh-keys.yml -l host-names --list-hosts
ansible-playbook configure-dev.yml -l additional-hosts --list-hosts -C

Run a playbook against a host pass encrypted credentials on the command-line using the password vault

Using -i to indicate inventory (and host vars to pass the host name to the playbook):

ansible-playbook configure-apt.yml -i "server-name-01," -e @common_vars/common_vars.yml --extra-vars 'env=local variable_host=server-name-01' -v -C --vault-password-file ~/vars/.common.txt

Run a command against an inventory

Create a directory, set permissions on the directory, and copy a file:

cd /dir/to/ansible-playbooks/
# apply to the hosts-dev group
ansible hosts-dev-a "sudo mkdir -p /dir/name/ owner=root group=root" -v
ansible hosts-dev -a "sudo chmod -R 777 /dir/name/" -v
ansible hosts-dev -a "sudo chown -R root:root /dir/name/" -v
ansible hosts-dev -m copy -a "src=~/from/dir/name/file.keytab dest=/dir/name/ mode=700 owner=root group=root" -v
ansible hosts-dev -a "sudo chmod -R 700 /dir/name/" -v

Run a command against a single server

There’s a cute little trick that lets you specify a single host on the command line (or multiple hosts, I guess), without an intermediary inventory:

ansible "server-name-01," -a "sudo chmod -R 770 /dir/name/" -v --list-hosts

Note the comma (,) at the end; this signals that it’s a list, not a file.

Run multiple Shell commands

ansible "erver-name-01," -m shell -a 'sudo mkdir -p /dir/name/;sudo chmod -R 777 /dir/name/;' -v

Run command using the automation account

If you don’t have permissions to access a server, chances are the automation account does…

The automation account is used to script ansible commands. The account uses an encrypted password when run as a script and allows ansible access to all servers.

Use the –ask-vault-pass to inject the account – the password will be asked for on the command line

ansible hosts-list -a "sudo mkdir -p /dir/name/" -v --ask-vault-pass

Passing Variables On The Command Line

In addition to vars_prompt and vars_files, it is possible to send variables over the Ansible command line. This is particularly useful when writing a generic release playbook where you may want to pass in the version of the application to deploy:

ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"

This is useful, for, among other things, setting the hosts group or the user for the playbook.

Example:

– hosts: ‘{{ hosts }}’
remote_user: ‘{{ user }}’

tasks:

ansible-playbook release.yml --extra-vars "hosts=vipers user=starbuck"