3 min read

Run your first Ansible playbook

Run your first Ansible playbook

We used to upload applications using FTP to upload code directly to the server, running scripts to prepare the stack or create a fresh server. Doing the same thing over and over again with no pattern.

Ansible was created to solve this mess! Wake up, guy, if you're in that situation! Dinosaurs no longer exist. Or no? 🤔

Tell me more!

Ansible is an IT solution designed for IT developers and System administrators that focuses on automation, configuration management, application deployment, orchestration, and other tasks. Most importantly, Ansible works without an agent installed on the server.

How to use?

You can set up your demo boards (raspberry), your DD-WRT, collect server logs, upload files, schedule tasks, deploy apps, scale applications, and add a node to Kubernetes or Docker Swarm, over other things.

Ansible is often used on pipelines to deploy apps, for example GitHub Actions, GitLab Pipelines and Bitbucket Pipelines.

Security Notice!

SSH is used to perform tasks, remember to configure Ansible user privileges, as you can have multiple users. Root privileges are required for setup, but not for deploying Docker containers. So, be careful when using the Sudo user or root user inside your pipeline.

Ansible must be installed first.

You can install Ansible using your preferred method, as a Python package, or as part of your operating system; see oficial docs Installing Ansible to prepare your environment.

Remember to use the most recent version of Ansible (>= 2.10).

I'd rather install as a Python package.

python3 -m pip install --user ansible

Quick sample, please!

The playbook will manage docker build image, testing, and up containers, which are frequently used in deployment pipelines.

Application

Now, let's create a Python Flask application that includes tests for the build and test pipelines.

First, configure the dependencies.

  • requirements.txt
# Flask Framework
Flask==2.2.2
pytest==7.2.0

Nothing new here, a coin flip that returns heads or tails!

  • api.py
from flask import Flask
import random

app = Flask(__name__)


@app.route('/')
def main():
    coin = random.choice(["heads", "tails"])
    return 'You got {0}!'.format(coin)
  • main.py
from api import app

app.run(host='0.0.0.0', port=3000)

Adding API coverage tests.

  • test_coin_flip.py
from api import app


def test_coin_flip_route():
    response = app.test_client().get('/')

    assert response.status_code == 200

Creating the Python Flask dockerfile.

  • Dockerfile
FROM python:3.9.15-alpine
COPY app /app
RUN pip install -r /app/requirements.txt
CMD ["python","/app/main.py"]
EXPOSE 3000
  • docker-compose.yml
version: "3.9"

services:
  api:
    build: ./
    ports:
      - "3000:3000"
    healthcheck:
      test: ["CMD", "nc", "-z", "-v", "localhost", "3000"]
      interval: 10s
      timeout: 5s
      retries: 5

  tests:
    build: ./
    entrypoint: pytest /app

Show me a playbook!

The playbook will create a Docker image and containers, perform tests, and if all goes well, the application will listen on port 3000.

  • first-playbook.yml
---
- name: Run your first playbook and deploy docker containers
  gather_facts: no
  hosts: localhost
  connection: local

  tasks:
    - name: Clean up images and containers.
      shell: docker-compose down --rmi local

    - name: Build a docker images.
      shell: docker-compose -f docker-compose.yml build

    - name: Testing application inside a docker container.
      shell: docker-compose -f docker-compose.yml run --rm tests

    - name: Running a docker container.
      shell: docker-compose -f docker-compose.yml up -d api

    - name: Health checks for container exposed port 3000.
      wait_for: host=localhost port=3000 timeout=1
      retries: 10
      delay: 3
  • gather_facts: no, called by playbooks to gather useful variables about remote hosts that can be used in playbooks;
  • host: localhost and connection: local, the method for running a playbook locally rather than via SSH;
  • tasks, we named the tasks and used two Ansible built-in modules (wait for and shell);

Everything is completed! We'll put Python Flask to a final test.

ansible-playbook first-playbook.yml
curl http://localhost:3000
# You got ???!
If you prefer, you can clone the repository. https://github.com/williampsena/ansible-recipes.

Next steps?

Ansible has a large number of modules available on the core, as well as excellent and detailed documentation. To keep things simple, I used shell to build docker compose in this example, however there is an Ansible docker-compose module if you want.

Take a glance through the Ansible Galaxy for plugins to help you make your next playbook, and don't forget to learn more about Inventory, which is useful for setup ssh and variables for each server.

You should use Ansible as your automation tool to avoid manual tasks.

Bye, God bless your day and your kernel!

References