Skip to main content

Ansible Playground: Simple Playbook & Role Structure, Collection of Common Used Ansible Tasks

1068 words·
Ansible Debian
Table of Contents

Ansible Installation (Debian)
#

Official Documentation: https://docs.ansible.com/ansible/latest/installation_guide/installation_distros.html#installing-ansible-on-debian

# Install requirements
sudo apt install gnupg -y
# Ansible installation script for Debian 12

UBUNTU_CODENAME=jammy
wget -O- "https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=get&search=0x6125E2A8C77F2818FB7BD15B93C4A3FD7BB9C367" | sudo gpg --dearmour -o /usr/share/keyrings/ansible-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/ansible-archive-keyring.gpg] http://ppa.launchpad.net/ansible/ansible/ubuntu $UBUNTU_CODENAME main" | sudo tee /etc/apt/sources.list.d/ansible.list
sudo apt update && sudo apt install ansible -y
# Verify installation / list version
ansible --version



Ansible Playground
#

File & Folder Structure
#

# The file and folder structure looks like this:
ansible-playground
├── ansible.cfg
├── inventory
├── playbooks
│   └── example_playbook.yml
└── roles
    └── example_role
        └── tasks
            └── main.yml
# Create the folder structure
mkdir -p \
  ansible-playground/playbooks \
  ansible-playground/roles/example_role/tasks \
  && cd ansible-playground

Ansible Configuration
#

  • ansible.cfg
[defaults]
roles_path = ./roles

Inventory File
#

  • inventory
[example_hosts]
192.168.30.161 ansible_user=debian

Example Playbook
#

  • playbooks/example_playbook.yml
---
- name: Example Playbook
  hosts: example_hosts
  become: true
  gather_facts: true

  roles:
    - example_role

Example Role
#

  • roles/example_role/tasks/main.yml

Add the tasks to the main.yml file.


Task: Create Directory
#

---
- name: Ensure directory exists
  ansible.builtin.file:
    path: /opt/example-directory
    state: directory
    owner: debian
    group: debian
    recurse: yes
  become: true

Task: Create File with Content
#

---
- name: Ensure file exists
  ansible.builtin.copy:
    dest: /tmp/example-file
    content: |
      some text
      more text      
    owner: debian
    group: debian

Task: Create Symlink #

- name: Create symlink
  ansible.builtin.file:
    src: /tmp/some-script
    dest: /usr/local/bin/some-script
    state: link
  become: true

Task: Clone Git Repository
#

The following task clones a git repository from GitHub and pulls the latest version, every time the playbook triggers the task:

---
- name: Ensure git repository exists
  ansible.builtin.git:
    repo: https://github.com/octocat/Hello-World.git
    dest: /tmp/github-repository # The content of the git repo gets cloned into this directory
    version: master
    update: yes
    clone: yes
    force: yes
  become_user: debian

Task: Install Packages
#

---
- name: Ensure packages are installed
  ansible.builtin.apt:
    name: "{{ item }}"
    state: latest
    update_cache: true
    cache_valid_time: 0
  loop:
    - sudo
    - git
    - curl
    - neovim

Task: Install Docker & Docker Compose
#

---
# Install required dependencies for Docker
- name: Install dependencies
  ansible.builtin.apt:
    name: "{{ item }}"
    state: latest
    update_cache: true
    cache_valid_time: 0
  loop:
    - ca-certificates
    - curl
    - git
    - gnupg
    - lsb-release


# Install Docker & Docker Compose
- name: Ensure /etc/apt/keyrings directory exists
  ansible.builtin.file:
    path: /etc/apt/keyrings
    state: directory
    mode: '0755'

- name: Add Docker GPG key
  ansible.builtin.get_url:
    url: https://download.docker.com/linux/debian/gpg
    dest: /etc/apt/keyrings/docker.asc
    mode: '0644'

- name: Add Docker APT repository
  ansible.builtin.apt_repository:
    repo: "deb [arch={{ (ansible_architecture == 'aarch64') | ternary('arm64', (ansible_architecture == 'x86_64') | ternary('amd64', ansible_architecture)) }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
    state: present
    filename: docker

- name: Install docker
  ansible.builtin.apt:
    name: "{{ item }}"
    state: present
    update_cache: true
    cache_valid_time: 0
  loop:
    - docker-ce
    - docker-ce-cli
    - containerd.io
    - docker-buildx-plugin
    - docker-compose-plugin


# Add user to Docker group
- name: Ensure user is in the Docker group
  ansible.builtin.user:
    name: debian
    groups: docker
    append: yes

# Reboot
- name: Reboot if needed (optional)
  ansible.builtin.reboot:
    msg: "Rebooting to apply docker group membership"
    reboot_timeout: 120
  when: reboot_required | default(true)

Task: Start Docker Container
#

---
- name: Start Docker container
  docker_container:
    name: nginx
    image: "nginx:latest"
    restart_policy: unless-stopped
    ports:
      - "8080:80"

Task: Start Docker Container with Volume Mapping
#

---
- name: Ensure directory exists
  ansible.builtin.file:
    path: /opt/nginx/data
    state: directory
    mode: '0755'
    owner: debian
    group: debian
    recurse: yes
  become: true

- name: Ensure file exists
  ansible.builtin.copy:
    dest: /opt/nginx/data/index.html
    content: |
      hi there
      some text      
    owner: debian
    group: debian

- name: Start a Docker container with volume mapping
  docker_container:
    name: nginx
    image: "nginx:latest"
    restart_policy: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - "/opt/nginx/data:/usr/share/nginx/html"

Task: Stop Docker Container
#

---
- name: Stop Docker container without removing it
  docker_container:
    name: nginx
    state: stopped

Task: Stop & Remove Docker Container
#

---
- name: Stop and remove Docker container
  docker_container:
    name: nginx
    state: absent

Task: Start Docker Compose Stack
#

  • This task creates a “docker-compose.yml” file with the specified content. As an alternative, the file could be copied from a static file or template.

  • The stack is started using a command, which is not idempotent. The task runs even if the stack is already up, and Ansible will always report a “changed” status.

---
- name: Ensure directory exists
  ansible.builtin.file:
    path: /opt/nginx-stack
    state: directory
    owner: debian
    group: debian
    recurse: yes
  become: true

- name: Ensure file exists
  ansible.builtin.copy:
    dest: /opt/nginx-stack/docker-compose.yml
    content: |
      services:
        nginx:
          image: nginx:latest
          restart: unless-stopped
          ports:
            - "8080:80"      
    owner: debian
    group: debian
  become: true

- name: Start Docker Compose stack
  ansible.builtin.command: docker compose up -d
  args:
    chdir: /opt/nginx-stack
  become: true
  become_user: debian

Task: Stop Docker Compose Stack
#

---
- name: Stop Docker Compose stack
  ansible.builtin.command: docker compose down
  args:
    chdir: /opt/nginx-stack
  become: true

Task: Check Compose Status & Stop Stack
#

- name: Check if Docker Compose steck is up
  ansible.builtin.command: docker compose ps
  register: compose_status
  failed_when: false
  changed_when: false
  args:
    chdir: /opt/nginx-stack
  become: yes

<br>

- name: Stop Docker Compose stack
  ansible.builtin.command: docker compose down --remove-orphans
  args:
    chdir: /opt/nginx-stack
  when: "'Up' in compose_status.stdout"
  become: yes



Task: Copy Static File
#

# The file and folder structure looks like this:
ansible-playground
├── ansible.cfg
├── inventory
├── playbooks
│   └── example_playbook.yml
└── roles
    └── example_role
        ├── files
        │   └── example-file.txt
        └── tasks
            └── main.yml
# Create the folder structure
mkdir -p roles/example_role/files
# Create static file that will be copied
vi roles/example_role/files/example-file.txt
  • roles/example_role/tasks/main.yml
- name: configure gitlab docker dnd runner
  copy:
    src: example-file.txt
    dest: /tmp/destination-file.txt
    owner: debian
    group: debian
    mode: "600"



Task: Copy File from Template
#

# The file and folder structure looks like this:
ansible-playground
├── ansible.cfg
├── inventory
├── playbooks
│   └── example_playbook.yml
└── roles
    └── example_role
        ├── tasks
        │   └── main.yml
        └── templates
            └── config.toml.j2 # template file
# Create the folder structure
mkdir -p roles/example_role/templates

Create the template file:

  • roles/example_role/templates/config.toml.j2
concurrent = 5
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "example-runner"
  url = {{ gitlab_runner_url }}
  id = 1
  token = {{ gitlab_runner_token }}
  executor = "docker"

Define the varibales in the playbook:

  • playbooks/example_playbook.yml
---
- name: Example Playbook
  hosts: example_hosts
  become: true
  gather_facts: true
  # Define the variables that are used by the template
  vars:
    gitlab_runner_url: "https://gitlab.example.com/"
    gitlab_runner_token: "SOME-TOKEN"

  roles:
    - example_role

Create the task thak copies the file from the template:

  • roles/example_role/tasks/main.yml
---
- name: Ensure GitLab Runner config directory exists
  file:
    path: /etc/gitlab-runner
    state: directory
    owner: root
    group: root
    mode: '0755'

- name: Deploy GitLab Runner config from template
  template:
    src: config.toml.j2
    dest: /etc/gitlab-runner/config.toml
    owner: root
    group: root
    mode: '0644'



Run the Playbook
#

Run Playbook
#

cd ~/ansible-playground
ansible-playbook playbooks/example_playbook.yml -i inventory