Ansible All Distro Docker Install
As part of my SysAdmin journey, I’ve begun to play with Ansible. For a while I’ve been using very simple playbooks to update my homelab’s VMs and LXC containers, but it’s time to take that a bit further.
Desired Outcome
The goal today is to start using playbooks in a modular way, thus allowing more flexibility and the reuse of playbooks across multiple projects.
The idea here, is to have one main playbook that determines the OS on the host, namely Debian, Ubuntu, or a RedHat derivative OS (such as CentOS, Rocky, Fedora etc.)
From there, a chain of appropriate task.yml
files will begin updating the host OS, installing Docker, and finally copying over a test webpage and starting up an Nginx Docker container to serve the webpage.
If we see the image below, we’re golden.
Playbooks and task.yml files
First up we have the main playbook that triggers everything.
main playbook
os_specific_vm_setup.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
- name: Update OS and install Docker
hosts: all
become: true
gather_facts: yes
tasks:
- name: Run update and install Docker for UBUNTU
include_tasks: ubuntu_vm_setup.yml
when: ansible_facts['distribution'] == 'Ubuntu'
- name: Run update and install Docker for DEBIAN
include_tasks: debian_vm_setup.yml
when: ansible_facts['distribution'] == 'Debian'
- name: Run update and install Docker for REDHAT
include_tasks: redhat_vm_setup.yml
when: ansible_facts['distribution'] in ['CentOS', 'RedHat', 'Rocky', 'AlmaLinux', 'Oracle', 'Scientific', 'Fedora'] #'Rocky'
OS specific tasks
debian_vm_setup.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# pre_tasks
- name: Update cache if needed and update all installed apps
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
name: "*"
state: latest
# tasks
- name: Install base apps
import_tasks: tasks/base_apps_debian.yml
- name: Install Docker
import_tasks: tasks/docker_install_debian.yml # Debian host
- name: Setup Nginx container
import_tasks: tasks/docker_nginx_setup.yml
# post_tasks
- name: Do apt cleanup and autoremove dangling files
ansible.builtin.apt:
autoclean: yes
autoremove: yes
ubuntu_vm_setup.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# pre_tasks
- name: Update cache if needed and update all installed apps
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
name: "*"
state: latest
# tasks
- name: Install base apps
import_tasks: tasks/base_apps_debian.yml
- name: Install Docker
import_tasks: tasks/docker_install_ubuntu.yml # Ubuntu host
- name: Setup Nginx container
import_tasks: tasks/docker_nginx_setup.yml
# post_tasks
- name: Do apt cleanup and autoremove dangling files
ansible.builtin.apt:
autoclean: yes
autoremove: yes
redhat_vm_setup.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# pre_tasks
- name: Update cache if needed and update all installed apps
ansible.builtin.dnf:
update_cache: true
name: "*"
state: latest
# tasks
- name: Install base apps
import_tasks: tasks/base_apps_redhat.yml
- name: Install Docker
import_tasks: tasks/docker_install_redhat.yml # Redhat;Rock Linux host
- name: Setup Nginx container
import_tasks: tasks/docker_nginx_setup.yml
# post_tasks
- name: Do apt cleanup and autoremove dangling files
ansible.builtin.dnf:
autoremove: yes
OS specific base app install tasks
base_apps_debian.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
- name: Install commonly used OS apps
ansible.builtin.apt:
pkg: # install a list of packages
- net-tools
- curl
- zip
- unzip
- git
- fail2ban
- tree
- iperf3
state: latest
update_cache: true
base_apps_redhat.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- name: Install EPEL repo
ansible.builtin.dnf:
pkg:
- epel-release # necessary for certain dnf packages
state: latest
update_cache: true
- name: Install commonly used OS apps
ansible.builtin.dnf:
pkg: # install a list of packages
- net-tools
- curl
- zip
- unzip
- git
- fail2ban
- tree
- iperf3
- python3-pip
state: latest
update_cache: true
OS specfic Docker install tasks
docker_install_debian.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- name: Install Docker dependencies
ansible.builtin.apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- python3-pip
- virtualenv
- python3-setuptools
state: latest
update_cache: true
- name: Add Docker GPG apt Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker repo
ansible.builtin.apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/debian bookworm stable # update for correct Ubuntu version: jammy=22.04 LTS
state: present
- name: Update apt and install docker-ce
ansible.builtin.apt:
pkg:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: latest
update_cache: true
- name: Add non-root Docker user
ansible.builtin.shell:
cmd: usermod -aG docker testuser
docker_install_ubuntu.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Docker environment install for Ubuntu
- name: Install Docker dependencies
ansible.builtin.apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- python3-pip
- virtualenv
- python3-setuptools
state: latest
update_cache: true
- name: Add Docker GPG apt Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker repo
ansible.builtin.apt_repository:
repo: deb https://download.docker.com/linux/ubuntu noble stable # update for correct Ubuntu version: noble=24.04 LTS; jammy=22.04 LTS
state: present
- name: Update apt and install docker-ce
ansible.builtin.apt:
pkg:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: latest
update_cache: true
- name: Add non-root Docker user
ansible.builtin.shell:
cmd: usermod -aG docker testuser
docker_install_redhat.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Docker environment install for Redhat
- name: Add signing key
ansible.builtin.rpm_key:
key: "https://download.docker.com/linux/rhel/gpg"
state: present
- name: Add repo into repo.d list
ansible.builtin.yum_repository:
name: docker
description: docker repository
baseurl: "https://download.docker.com/linux/rhel/9/x86_64/stable"
# enable: true
gpgcheck: true
gpgkey: "https://download.docker.com/linux/rhel/gpg"
- name: Install Docker
ansible.builtin.yum:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: present
update_cache: true
- name: Install Python PIP dependencies
ansible.builtin.pip:
name:
- virtualenv
- requests
#- python3-wheels
state: present
- name: Start and Enable Docker service
ansible.builtin.service:
name: "docker"
enabled: true
state: started
- name: Add non-root Docker user
ansible.builtin.shell:
cmd: usermod -aG docker testuser
Nginx container setup
docker_nginx_setup.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- name: Create local Nginx folder structure
file:
path: /home/testuser/nginx
state: directory
- name: Copy over nginx folder
copy:
dest: /home/testuser/nginx/
src: nginx/
- name: Start Nginx container
ansible.builtin.docker_container:
name: "nginx"
image: "nginx:latest"
detach: yes
ports: "80:80"
volumes: "/home/testuser/nginx/site:/usr/share/nginx/html"
restart: "true"
ansible.cfg
ansible.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[testing:children]
debian
redhat
ubuntu
[debian]
192.168.10.156 # debian
[debian:vars]
ansible_ssh_user=testuser
#ansible_ssh_password=my-fancy-password
ansible_become_password=my-fancy-password
ansible_ssh_private_key_file=/home/testuser/.ssh/testing
[redhat]
192.168.10.153 # rocky
[redhat:vars]
ansible_ssh_user=testuser
#ansible_ssh_password=my-fancy-password
ansible_become_password=my-fancy-password
ansible_ssh_private_key_file=/home/testuser/.ssh/testing
[ubuntu]
192.168.10.152 # ubuntu
[ubuntu:vars]
ansible_ssh_user=testuser
#ansible_ssh_password=my-fancy-password
ansible_become_password=my-fancy-password
ansible_ssh_private_key_file=/home/testuser/.ssh/testing
## ENABLE SSH AGENT once before testing/application to avoid retyping password
## eval "$(ssh-agent -s)"
## ssh-add ~/.ssh/testing
inventory.ini
inventory.ini
1
2
3
4
5
[defaults]
inventory = inventory.ini
deprecation_warnings=False # to stop getting annoying warnings in purple text
#host_key_checking=false # comment out once SSH keys are in use
ansible_python_interpreter=/usr/bin/python3
Technical Difficulties
Honestly, the issues were mostly around me needing to do some trial and error, and more and more trial and error. Especially regarding the differences between Debian/Ubuntu and RedHat prerequisite apps. Much the same with the various ansible.modules
. It took a lot of research, but I got there.
Lessons Learned
Time, and practice is needed. Documentation is your friend. Slowly writing commands in myself versus copy and pasting everything is the best way to learn, as it helps my brain to understand how everything interconnects.