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