AAP is running. Now we wire it up to deploy the K3s cluster. This phase covers creating a GitHub project, configuring credentials, building the inventory, and launching job templates — all through the AAP web UI.
By the end, you’ll deploy a 4-node K3s cluster with two clicks.
No AAP? Skip to the Vanilla Ansible section at the bottom for the command-line equivalent.
1. Playbook Overview
We use two playbooks stored in a GitHub repository:
prep_k3s.yml — OS Preparation
Runs on all nodes. Handles package updates, installs dependencies, and disables swap (required for Kubernetes).
---
- name: Prepare Ubuntu Nodes for K3s
hosts: all
become: true
tasks:
- name: Update apt cache and upgrade packages
apt:
update_cache: yes
upgrade: dist
- name: Install required dependencies
apt:
name: [curl, nfs-common, jq]
state: present
- name: Disable Swap (Required for K8s)
command: swapoff -a
when: ansible_swaptotal_mb > 0
- name: Remove Swap from fstab
replace:
path: /etc/fstab
regexp: '^([^#].*?\sswap\s+.*)$'
replace: '# \1'install_k3s.yml — Cluster Bootstrap
Installs K3s on the master, reads the join token, then joins all agents. Key patterns:
when: inventory_hostname == k3s_master_ip— targets only the master for server installdelegate_to+run_once: true— reads the token from the master, runs onceargs: creates:— idempotent; skips if K3s is already installedslurp+b64decode— reads the token file and decodes it in one step
---
- name: Build my K3s Lab
hosts: all
become: true
vars:
k3s_master_ip: "192.168.5.40"
tasks:
- name: Ensure curl is installed
apt:
name: curl
state: present
update_cache: yes
- name: Install K3s Server on the Master node
shell: curl -sfL https://get.k3s.io | sh -
when: inventory_hostname == k3s_master_ip
args:
creates: /usr/local/bin/k3s
- name: Get K3s Node Token from Master
slurp:
src: /var/lib/rancher/k3s/server/node-token
register: node_token_encoded
delegate_to: "{{ k3s_master_ip }}"
run_once: true
- name: Install K3s on Agents and join Cluster
shell: >
curl -sfL https://get.k3s.io | K3S_URL=https://{{ k3s_master_ip }}:6443
K3S_TOKEN={{ node_token_encoded['content'] | b64decode | trim }} sh -
when: inventory_hostname != k3s_master_ip
args:
creates: /usr/local/bin/k3s2. Push Playbooks to GitHub
Create the two playbook files locally, then push them so AAP can pull from the repo.
mkdir k3s-lab-automation && cd k3s-lab-automationSave the YAML from Section 1 as:
prep_k3s.ymlinstall_k3s.yml
Then push:
git init
git add .
git commit -m "add k3s preparation and install playbooks"
git remote add origin https://github.com/<your-username>/k3s-lab-automation.git
git push -u origin mainEverything else — inventory, credentials, project — is configured in the AAP web UI in the following steps.
3. Create a Project in AAP
A Project in AAP is a pointer to a Git repository containing playbooks.
- Navigate to Resources → Projects → Add
- Fill in:
| Field | Value |
|---|---|
| Name | K3s Lab Automation |
| Organization | Default |
| Source Control Type | Git |
| Source Control URL | https://github.com/<your-username>/k3s-lab-automation.git |
| Source Control Branch/Tag | main |
| Source Control Credential | (leave blank for public repos; select PAT credential for private) |
- Click Save
- Wait for the Status column to show a green checkmark (successful sync)
4. Configure Credentials
AAP needs two credentials: one to SSH into the Ubuntu nodes, and one to pull from GitHub (private repos only).
Machine Credential (SSH to K3s Nodes)
- Navigate to Resources → Credentials → Add
- Fill in:
| Field | Value |
|---|---|
| Name | K3s Node SSH |
| Credential Type | Machine |
| Username | jmartinez (your SSH user on the Ubuntu nodes) |
| Privilege Escalation Method | sudo |
| Password or SSH Key | Your SSH private key or password |
- Click Save
Source Control Credential (Private GitHub Only)
- Navigate to Resources → Credentials → Add
- Generate a PAT in GitHub: Settings → Developer Settings → Tokens (classic) → Generate
- Select scope:
repo
- Select scope:
- Fill in AAP:
| Field | Value |
|---|---|
| Name | GitHub PAT |
| Credential Type | Source Control |
| Username | Your GitHub username |
| Password | The generated PAT |
- Click Save
5. Build the Inventory
AAP needs its own inventory (separate from the file-based one in the repo). This is the “map” it uses to know which hosts to target.
Create the Inventory
- Navigate to Resources → Inventories → Add → Add Inventory
- Fill in:
| Field | Value |
|---|---|
| Name | K3s Cluster |
| Organization | Default |
- Click Save
Add Groups
- Open the K3s Cluster inventory
- Go to the Groups tab → Add
- Create two groups:
| Group Name | Purpose |
|---|---|
k3s_server | K3s master/control plane |
k3s_agents | K3s worker nodes |
Add Hosts
- Go to the Hosts tab → Add
- Add each node:
| Host Name | Variables | Groups |
|---|---|---|
k3s-master-01 | ansible_host: 192.168.5.40 | k3s_server |
k3s-worker-01 | ansible_host: 192.168.5.41 | k3s_agents |
k3s-worker-02 | ansible_host: 192.168.5.42 | k3s_agents |
k3s-worker-03 | ansible_host: 192.168.5.43 | k3s_agents |
For each host, set the Variables field (YAML):
ansible_host: 192.168.5.40
ansible_user: jmartinezVerify Connectivity
From the Hosts tab, select all hosts → Run Command → choose the ping module. All four should return pong.
6. Create Job Templates
Job Templates define what playbook to run, against which inventory, with which credentials.
Template 1: 01 - Prepare Nodes
This runs prep_k3s.yml to prepare the OS on all 4 nodes.
- Navigate to Resources → Templates → Add → Add Job Template
- Fill in:
| Field | Value |
|---|---|
| Name | 01 - Prepare Nodes |
| Job Type | Run |
| Inventory | K3s Cluster |
| Project | K3s Lab Automation |
| Playbook | prep_k3s.yml |
| Credentials | K3s Node SSH |
| Forks | 2 (limits parallel SSH connections to save RAM) |
- Click Save
Template 2: 02 - Install K3s Cluster
This runs install_k3s.yml to bootstrap the cluster.
- Navigate to Resources → Templates → Add → Add Job Template
- Fill in:
| Field | Value |
|---|---|
| Name | 02 - Install K3s Cluster |
| Job Type | Run |
| Inventory | K3s Cluster |
| Project | K3s Lab Automation |
| Playbook | install_k3s.yml |
| Credentials | K3s Node SSH |
| Forks | 2 |
- Click Save
7. Deploy the Cluster
Run the templates in order.
Step 1: Prepare Nodes
- Navigate to Resources → Templates
- Click the rocket icon next to 01 - Prepare Nodes
- Watch the output in real time
Expected output:
TASK [Update apt cache and upgrade packages] ********
changed: [k3s-master-01]
changed: [k3s-worker-01]
...
TASK [Disable Swap (Required for K8s)] **************
changed: [k3s-master-01]
changed: [k3s-worker-01]
...
Step 2: Install K3s
- Return to Resources → Templates
- Click the rocket icon next to 02 - Install K3s Cluster
- Watch the output
Expected output:
TASK [Install K3s Server on the Master node] ********
changed: [k3s-master-01]
TASK [Get K3s Node Token from Master] ***************
ok: [k3s-master-01]
TASK [Install K3s on Agents and join Cluster] *******
changed: [k3s-worker-01]
changed: [k3s-worker-02]
changed: [k3s-worker-03]
8. Verify the Cluster
SSH into the master node and check cluster status:
ssh jmartinez@192.168.5.40
k3s kubectl get nodesExpected output:
NAME STATUS ROLES AGE VERSION
k3s-master-01 Ready control-plane,master 2m v1.31.x+k3s1
k3s-worker-01 Ready <none> 1m v1.31.x+k3s1
k3s-worker-02 Ready <none> 1m v1.31.x+k3s1
k3s-worker-03 Ready <none> 1m v1.31.x+k3s1
Optional: Verification Playbook via AAP
Create a third job template using this playbook to verify from AAP:
---
- name: Verify K3s Cluster Status
hosts: k3s_server
become: true
tasks:
- name: Check K3s Node Status
command: k3s kubectl get nodes
register: nodes_output
- name: Display Cluster Health
debug:
msg: "{{ nodes_output.stdout_lines }}"9. Troubleshooting
Template Fails: “Project Sync Failed”
- Verify the GitHub URL is correct
- For private repos, confirm the Source Control credential has the right PAT
- Re-sync manually: Resources → Projects → K3s Lab Automation → Sync
SSH Connection Timeout
- Verify
ansible_hostis set on each host in the AAP inventory - Confirm SSH key was added to the Machine credential
- Test from AAP host:
ssh jmartinez@192.168.5.40
K3s Install Fails on Agents
- Ensure
prep_k3s.ymlran first (swap must be disabled) - Check the master is reachable:
curl -k https://192.168.5.40:6443 - Verify the join token hasn’t expired (tokens are valid by default)
Forks Setting
If the AAP host runs out of memory during playbook execution, reduce Forks to 1. This runs tasks sequentially but uses less RAM.
Alternative: Vanilla Ansible (No AAP)
If you don’t want to deploy AAP, you can run the playbooks directly from the command line. This skips Phase 1 entirely.
Prerequisites
Install Ansible on your control node (your workstation or the RHEL host):
# RHEL 10
sudo dnf install -y ansible-core
# Ubuntu
sudo apt update && sudo apt install -y ansibleCreate the Inventory
Save this as inventory.yml in your project directory:
all:
children:
k3s_server:
hosts:
k3s-master-01:
ansible_host: 192.168.5.40
ansible_user: jmartinez
k3s_agents:
hosts:
k3s-worker-01:
ansible_host: 192.168.5.41
ansible_user: jmartinez
k3s-worker-02:
ansible_host: 192.168.5.42
ansible_user: jmartinez
k3s-worker-03:
ansible_host: 192.168.5.43
ansible_user: jmartinezVerify Connectivity
ansible -i inventory.yml all -m pingAll four nodes should return pong.
Prepare the Nodes
ansible-playbook -i inventory.yml prep_k3s.ymlInstall the Cluster
ansible-playbook -i inventory.yml install_k3s.ymlVerify
ssh jmartinez@192.168.5.40 "k3s kubectl get nodes"Useful Flags
| Flag | Purpose |
|---|---|
--check | Dry run — no changes made |
--diff | Show what would change |
-vvv | Verbose output for debugging |
--limit k3s-master-01 | Run on a single host |
--become | Escalate to root (already in playbooks) |
What’s Next
Your 4-node K3s cluster is up and running, deployed entirely through AAP’s web UI. In Phase 3, we cover post-install tasks: non-root cluster administration, Ansible Vault integration, and production hardening.