Skip to main content

Ansible Tower Practical Examples

Guangzhou, China

I now set up Ansible Tower and want to integrate it into my CI Pipelines. Here are a couple of Tasks that I previously started by SSH'ing into those servers or by manually starting Ansible Plays. Let's see how I can add them to the Tower UI.

Updating a Discourse Forum

To update our Forum I have to:

  1. login to the respective server
  2. change to the directory that holds the source code
  3. git pull the latest updates
  4. rebuild the app using the Discourse CLI

Let's automate this!

Create an Inventory

In the Tower UI click on Resources / Inventories and switch to the Hosts tab. Click on Add and add your Server IP address and SSH port:

---
ansible_host: 112.11.1.221
ansible_port: 12345

Ansible Tower Practical Examples

Save the Host and Inventory.

Adding Server Credentials

In the Tower UI click on Resources / Credentials and click on Add. Choose Machine as credential type and add your server SSH username and password:

Ansible Tower Practical Examples

Save your settings.

Adding the Project

Before actually adding the Project we need a second Credential that allows us to download the Ansible Playbook from a private Gitlab server. For this, create a user in Gitlab (or on Github, in Subversion, etc.) that has access to the repositories you want to use. Back in the Tower UI Resources / Credentials and click on Add. This time choose Source Control as Credential Type and add your Gitlab username and password:

Ansible Tower Practical Examples

Make sure to add your SSH Key in the field at the bottom of the form!

Save your settings and switch to the Resources / Projects menu. Click on Add to add your project:

Ansible Tower Practical Examples

Choose your Source Control Credential Type - for Gitlab that is Git - and add the HTTPS URL to the repository that holds your Ansibel Playbook. To be able to clone the repository add the Gitlab user you just created, as Source Control Credential.

The repository holds a single file:

forumDE_rebuild_discourse.yml

---
- hosts: ForumDE-Discourse
gather_facts: no

vars:
ansible_python_interpreter: /bin/python3

tasks:

- name: Pull latest Release & Update the Discourse Forum
ansible.builtin.shell:
cmd: git pull && ./launcher rebuild app
chdir: /opt/discourse/

This play does everything I listed as requirement above.

Note: I ran into a couple of issues with Ansible refusing to run on my minion server. The solution was to make Python3 the default version of Python on my minion and adding the path to the Python3 binary to my play.

Save the project and back on the Projects overview page click click on Sync to have Ansible Tower download your Playbook from Gitlab.

Adding the Job Template

Go to Resources / Template and click on Add to add a Job template. Now here everything we did before comes to together:

  1. Add your Inventory
  2. Add your Project
  3. Choose the Play (Ansible Tower will list all the valid plays that it can find in your Playbook)
  4. Add your Server Credentials

As job type I choose Check and ticked Prompt on Launch. This way I can first do a dry run and on the second go choose Run instead. And while we are at it - save your settings and go back to Templates. Your Job will be listed here. Click on launch and choose to either dry run or run. See if everything is working.

Ansible Tower Practical Examples

Adding a Workflow

Now I am ready to wrap things up into a workflow - this works just like a Job Template but allows you to connect a bunch of jobs into a chain of nodes with some if-this-then-that logic - if you wish.

Ansible Tower Practical Examples

Go to Resources / Template and click on Add to add a Workflow template. Just add the Inventory you are working from and hit Save.

Ansible Tower Practical Examples

This now opens the Visualizer where I am going to add two nodes:

  1. Update the Playbook we are working with
  2. Run the Ansible Play

For the first choose Project Sync and choose the project from the list below. This will make sure that we are always using the latest playbook that was committed to the repository:

Ansible Tower Practical Examples

And the second is a Job Template node where you have to select the job we created:

Ansible Tower Practical Examples

Working with Docker Container

Installing Docker

Now without so much details - the steps are identical to the example above. To work with Docker on our host we first have to make sure that Docker is set up. I am doing this using Ansible Roles:

- hosts: Wiki_Virtual
gather_facts: yes

vars:
ansible_python_interpreter: /bin/python3
pip_install_packages:
- name: docker
- name: setuptools
- name: docker-compose

roles:
- geerlingguy.pip
- geerlingguy.docker

To be able to use roles create a roles folder in your Playbook repository and add the folders inside for your roles - e.g. :

- roles
- geerlingguy.pip
- geerlingguy.docker
- install-docker-playbook.yml

And git clone the source code of those roles into their corresponding folders:

When you now run install-docker-playbook.yml those roles will be found by Ansible. Now go to the steps above until you have a job template that uses this playbook. Run the playbook in Ansible Tower to install Docker and Docker-Compose on your minion server.

Running Containers

I now want to add my Docker App to an existing Docker Cluster - as described in an earlier Tutorial

The playbook downloads the latest Version of the Docker image, kills the running container (in case that we are updating our app) and then spawns a new container based on the latest image:

---
- hosts: Wiki_Virtual
gather_facts: no

vars:
ansible_python_interpreter: /bin/python3

tasks:

- name: Include vault for registry login
include_vars:
file: vault.yml

- name: Log into Docker Registry and force re-authorization
docker_login:
registry: my.gitlab.com
username: "{{ username }}"
password: "{{ password }}"
reauthorize: yes

- name: Download the latest Wiki build images
shell: docker pull my.gitlab.com:12345/wiki/{{ item }}
with_items:
- wiki_en_mdx

- name: Remove the EN Wiki Container
docker_container:
name: wiki_en
state: absent

- name: Rebuild the EN Wiki Container
docker_container:
name: wiki_en
image: my.gitlab.com:12345/wiki/wiki_en_mdx
state: started
restart_policy: unless-stopped
networks:
- name: wikinet
networks_cli_compatible: yes

The new part here is the use of an Ansible Vault to get our Docker Registry login. I already showed how to create this vault. Add your username and password there and add the vault to your Playbook repository.

We now need to add the Vault Credentials to Ansible Tower. For this create a new Credential, choose Credential Type Vault and add your vault password.

Ansible Tower Practical Examples

The Job Template that uses this Playbook now needs two credentials - the minion SSH login and the vault password. Otherwise, it is identical to the example earlier:

Ansible Tower Practical Examples

Test run the job. Then create the workflow. Just as before.

Setup Certbot

This is pretty much the same as setting up Docker using a ready-made Ansible role (s. above):

---
- hosts: Wiki_Virtual

vars:
ansible_python_interpreter: /bin/python3
certbot_admin_email: m.polinowski@instar.com
certbot_create_if_missing: true
certbot_create_standalone_stop_services:
- docker
certbot_certs:
- domains:
- my.first.domain.com
- my.second.domain.com
- my.third.domain.com

roles:
- geerlingguy.certbot

Note: My NGINX Ingress runs inside a Docker container. That is why I need Certbot to restart the Docker process so that NGINX starts using the new certs after an update. Otherwise, just restart whatever service is using the certificate.

Setting Up Elasticsearch

I am using a Docker Compose file that I store on Gitlab to run Elasticsearch. Again I am using an Ansible Vault file to log in to Gitlab and pull the latest version of this file to /opt/wiki_elk. After that I execute this file with Docker Compose:

Installation

---
- hosts: Wiki_Virtual
gather_facts: no

vars:
ansible_python_interpreter: /bin/python3

tasks:

- name: Include vault for registry login
include_vars:
file: vault.yml

- name: Get updated files from git repository
git:
repo: https://{{ username | urlencode }}:{{ password | urlencode }}@my.gitlab.com/wiki/wiki_elk.git
clone: yes
force: yes
update: yes
dest: /opt/wiki_elk

- name: Start the Elasticsearch services
docker_compose:
project_src: /opt/wiki_elk

Cert Renewal

---
- hosts: Wiki_Virtual
gather_facts: no

vars:
ansible_python_interpreter: /bin/python3

tasks:

- name: Run Certbot Renew and Restart Docker
shell: certbot renew --pre-hook "service docker stop" --post-hook "service docker start"

Adding a server to Zabbix Monitor

I am using the software Zabbix to Monitor my Servers. With the following script I am able to setup the Zabbix Agent on my minion servers:

---
- hosts: Wiki_Virtual
gather_facts: no

vars:
ansible_python_interpreter: /bin/python3

tasks:

- name: Create directory for Zabbix Keyfile
file:
path: /opt/zabbix
state: directory
mode: '0755'

- name: Check if Zabbix Keyfile is already present
stat:
path: /opt/zabbix/agent_tls.psk
register: check_key_result

- name: Create Zabbix Keyfile
shell: openssl rand -hex 32 > agent_tls.psk
args:
chdir: /opt/zabbix/
when: not check_key_result.stat.exists

- name: Read Zabbix Keyfile
shell: cat /opt/zabbix/agent_tls.psk
register: zabbix_key

- name: Print Zabbix Keyfile
debug: var=zabbix_key

- name: Installing Zabbix Agent 2
docker_container:
name: zabbix-agent2
image: zabbix/zabbix-agent2:latest
pull: yes
restart: yes
networks:
- name: wikinet
networks_cli_compatible: yes
privileged: yes
state: started
restart_policy: unless-stopped
ports:
- "10050:10050"
volumes:
- /opt/zabbix:/var/lib/zabbix/enc
env:
ZBX_HOSTNAME: <Set a Name you want to use to add this Server to Zabbix>
ZBX_SERVER_HOST: <IP Address of the Zabbix Master Server>
ZBX_SERVER_PORT: <Set the Zabbix Active Server Port>
ZBX_TLSCONNECT: "psk"
ZBX_TLSACCEPT: "psk"
ZBX_TLSPSKIDENTITY: <Set a Name you want to use to add this Server to Zabbix>
ZBX_TLSPSKFILE: "agent_tls.psk"