Chapter 1: Build Your Practice Lab

Prepare the control node

Phases 10 and 11: turn workstation into the Ansible control node, with the same ansible-core generation RHEL 9 uses, ansible-navigator in its own virtual environment, and SSH keys to every server. Optionally, add the utility server that serves practice files.

Everything in Phase 10 happens on workstation as student. Get there with:

lxc exec workstation -- su - student

Phase 10 · Prepare workstation as the control node (~15 min)

  • Install ansible-core 2.14 and its companions from Rocky’s repositories.
  • Install ansible-navigator without shadowing the home-lab ansible-core.
  • Add the ansible.posix and community.general collections, pinned to versions that support ansible-core 2.14.
  • Configure navigator and SSH keys to every managed host.
  • Install the home-lab lab command, so lab start works here as it does in a classroom.

VM: install Ansible from Rocky's repositories

This home-lab baseline uses ansible-core 2.14 from Rocky Linux 9. It supports this course's labs; check the objectives for your booked exam version separately.

sudo dnf install -y ansible-core rhel-system-roles podman git python3.11 tree
ansible --version | head -1          # ansible [core 2.14.18]

VM: add the collections the exercises use

From chapter 3 on, the exercises use modules such as ansible.posix.firewalld and ansible.posix.authorized_key. In the classroom they come inside the execution environment; here you install them once, system-wide, where every project finds them. Pin the versions: the latest releases need ansible-core 2.16 or newer and refuse to run on 2.14.

sudo ansible-galaxy collection install -p /usr/share/ansible/collections \
  ansible.posix:1.5.4 community.general:9.5.13        # sudo password: student
ansible-galaxy collection list
# ansible.posix 1.5.4 · community.general 9.5.13 · redhat.rhel_system_roles 1.120.5
CollectionWhy this version
ansible.posix 1.5.4Last release that supports ansible-core 2.14 (1.6 and later need 2.15+)
community.general 9.5.13Last 9.x release; 10.x needs 2.15+, the current 13.x needs 2.18+

VM: install ansible-navigator in a virtual environment

Navigator needs Python 3.10 or later (Rocky 9's system Python is 3.9, hence python3.11). Keep it in a virtual environment: pip also installs a newer ansible-core as a navigator dependency, and a plain pip install --user would put that copy in front of the exam-aligned one.

python3.11 -m venv ~/.venvs/navigator
~/.venvs/navigator/bin/pip install --upgrade pip
~/.venvs/navigator/bin/pip install "ansible-navigator==26.9.0"

# expose ONLY the navigator command; ~/.local/bin is already on PATH in Rocky's default ~/.bashrc
mkdir -p ~/.local/bin
ln -sf ~/.venvs/navigator/bin/ansible-navigator ~/.local/bin/ansible-navigator

ansible-navigator --version          # ansible-navigator 26.9.0
which -a ansible                     # /usr/bin/ansible only

VM: configure navigator

Plain output, no artifact files (which also lets Vault password prompts work, see chapter 4), and run playbooks with workstation's own ansible-core rather than inside a container. Create the file with one command so there is nothing to mistype:

cat > ~/.ansible-navigator.yml <<'EOF'
---
ansible-navigator:
  mode: stdout
  playbook-artifact:
    enable: false         # "enable" here...
  execution-environment:
    enabled: false        # ...but "enabled" here. Uses /usr/bin ansible-core 2.14
EOF

Prove which Ansible navigator uses:

cat > /tmp/version.yml <<'EOF'
- hosts: localhost
  gather_facts: false
  tasks:
    - ansible.builtin.debug:
        msg: "ansible-core {{ ansible_version.full }}"
EOF
ansible-navigator run /tmp/version.yml     # msg: ansible-core 2.14.18
rm /tmp/version.yml

If it prints a newer version, check which -a ansible-playbook: the first entry must be /usr/bin/ansible-playbook.

VM: SSH keys from student to devops on every machine

Enter the password redhat once for each machine. Workstation is in the list because some exercises manage it like any other host.

ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_ed25519
for h in workstation servera serverb serverc serverd; do
  ssh-copy-id -o StrictHostKeyChecking=accept-new devops@$h.lab.example.com
  ssh -o StrictHostKeyChecking=accept-new devops@$h true     # trust the short name too
done
ssh devops@servera sudo id           # uid=0(root), no password asked

VM: let the same key log in as student and root

In the classroom, student on workstation can also log in to every machine as student and as root without a password, and a few exercises rely on it (remote_user: root, or no remote_user at all). This reuses devops's sudo, so there are no more passwords to type:

pub=$(cat ~/.ssh/id_ed25519.pub)
for h in workstation servera serverb serverc serverd; do
  ssh devops@$h "for u in student root; do
      d=\$(getent passwd \$u | cut -d: -f6)/.ssh
      sudo install -d -m 700 -o \$u -g \$u \$d
      sudo grep -qxF '$pub' \$d/authorized_keys 2>/dev/null || echo '$pub' | sudo tee -a \$d/authorized_keys >/dev/null
      sudo chown \$u:\$u \$d/authorized_keys; sudo chmod 600 \$d/authorized_keys; sudo restorecon -R \$d
    done"
done
ssh root@servera id                  # uid=0(root)
ssh student@serverb hostname         # serverb.lab.example.com

Running it again is harmless: it adds the key only where it is missing.

VM: install the lab command

In a training classroom, each exercise starts with lab start NAME, which creates the exercise's project folder and starter files. That command exists only inside the classroom, so this guide provides its own small script with the same syntax. It downloads the starter files for an exercise from this site into ~/NAME. It is a short shell script; read it first if you like.

curl -fsSL https://kernelpath.dev/lab/lab -o ~/.local/bin/lab
chmod +x ~/.local/bin/lab
lab version                          # lab 6
lab list                             # every exercise that has starter files
lab check                            # key logins, collections and starter files: every line PASS
CommandWhat it does
lab start playbook-basicCreates ~/playbook-basic with that exercise's ansible.cfg, inventory and other starter files
lab finish playbook-basicMoves ~/playbook-basic into ~/lab-archive/, so your work is kept and your home directory is clear for the next exercise. Add --delete to remove it instead
lab start playbook-basic --forceStarts over in one step: archives the existing folder and creates a fresh one
lab checkTests that the lab is ready: key logins to every machine, collections, starter files
lab updateReplaces the command with the newest version from this site
lab grade playbook-basicRead-only project and host checks; use --json to export results

VM: set up vim for YAML

Two-space indentation and spaces instead of tabs, as chapter 3 recommends:

set autoindent
set tabstop=2
set shiftwidth=2
set expandtab

VM: don't create a project yet

Leave workstation as it is for now. Your first Ansible project comes in section 1.8, after the clean snapshot, so the baseline contains the tools but none of your work.

Phase 11 · The utility server, optional (~10 min)

  • Serve practice files over HTTP for "download this from utility" style tasks.

LXD UI: create utility

Create it as in section 1.5: name utility, ipv4.address: 172.25.250.8, no disk2. content.example.com and materials.example.com already point here, from the network's raw.dnsmasq lines.

VM: install a web server and the practice files

lxc exec utility -- bash
dnf install -y httpd ansible-core
mkdir -p /var/www/html/files && cd /var/www/html/files
systemctl enable --now httpd
firewall-cmd --permanent --add-service=http && firewall-cmd --reload   # firewalld is on, as in RHEL

# versions that work with ansible-core 2.14, as on workstation
ansible-galaxy collection download ansible.posix:1.5.4 community.general:9.5.13 -p /var/www/html/files

printf 'Hostname: inventory_hostname\nMemory: ansible_memory_mb\nProcessor count: ansible_proc_count\nDisk size sda: sda_size\nDisk size sdb: sdb_size\n' > hwreport.empty

cat > user_list.yml <<'EOF'
---
users:
  - name: bob
    job: developer
  - name: fred
    job: manager
  - name: susan
    job: developer
EOF
ls

VM: check it from workstation

curl http://utility.lab.example.com/files/
curl -s http://materials.example.com/files/user_list.yml