2026-02-28 20:24:55 +00:00
|
|
|
---
|
|
|
|
|
- name: Bootstrap Kubernetes cluster
|
|
|
|
|
hosts: cluster
|
|
|
|
|
become: true
|
|
|
|
|
gather_facts: true
|
|
|
|
|
|
|
|
|
|
pre_tasks:
|
|
|
|
|
- name: Wait for SSH
|
|
|
|
|
wait_for_connection:
|
|
|
|
|
delay: 10
|
|
|
|
|
timeout: 300
|
|
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- common
|
|
|
|
|
|
|
|
|
|
- name: Setup primary control plane
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
vars:
|
|
|
|
|
k3s_primary: true
|
|
|
|
|
k3s_token: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
|
2026-03-01 03:08:56 +00:00
|
|
|
k3s_primary_private_ip: "{{ k3s_private_ip }}"
|
|
|
|
|
k3s_primary_public_ip: "{{ ansible_host }}"
|
|
|
|
|
k3s_primary_ip: "{{ k3s_private_ip }}"
|
|
|
|
|
k3s_node_ip: "{{ k3s_private_ip }}"
|
2026-02-28 20:24:55 +00:00
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- k3s-server
|
|
|
|
|
|
|
|
|
|
- name: Get join info from primary
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
tasks:
|
|
|
|
|
- name: Fetch node token
|
|
|
|
|
command: cat /var/lib/rancher/k3s/server/node-token
|
|
|
|
|
register: node_token
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
|
|
|
|
- name: Set join token fact
|
|
|
|
|
set_fact:
|
|
|
|
|
k3s_token: "{{ node_token.stdout }}"
|
2026-03-01 03:08:56 +00:00
|
|
|
k3s_primary_private_ip: "{{ k3s_private_ip }}"
|
|
|
|
|
k3s_primary_public_ip: "{{ ansible_host }}"
|
2026-02-28 20:24:55 +00:00
|
|
|
|
|
|
|
|
- name: Fetch kubeconfig
|
|
|
|
|
fetch:
|
|
|
|
|
src: /etc/rancher/k3s/k3s.yaml
|
|
|
|
|
dest: ../outputs/kubeconfig
|
|
|
|
|
flat: true
|
|
|
|
|
|
|
|
|
|
- name: Setup secondary control planes
|
|
|
|
|
hosts: control_plane[1:]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
vars:
|
|
|
|
|
k3s_primary: false
|
|
|
|
|
k3s_token: "{{ hostvars[groups['control_plane'][0]]['k3s_token'] }}"
|
2026-03-01 02:45:00 +00:00
|
|
|
k3s_primary_ip: "{{ hostvars[groups['control_plane'][0]]['k3s_primary_private_ip'] }}"
|
|
|
|
|
k3s_primary_public_ip: "{{ hostvars[groups['control_plane'][0]]['k3s_primary_public_ip'] }}"
|
2026-03-01 03:08:56 +00:00
|
|
|
k3s_node_ip: "{{ k3s_private_ip }}"
|
2026-02-28 20:24:55 +00:00
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- k3s-server
|
|
|
|
|
|
|
|
|
|
- name: Setup workers
|
|
|
|
|
hosts: workers
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
vars:
|
|
|
|
|
k3s_token: "{{ hostvars[groups['control_plane'][0]]['k3s_token'] }}"
|
2026-03-01 02:45:00 +00:00
|
|
|
k3s_server_url: "https://{{ hostvars[groups['control_plane'][0]]['k3s_primary_private_ip'] }}:6443"
|
2026-03-01 03:08:56 +00:00
|
|
|
k3s_node_ip: "{{ k3s_private_ip }}"
|
2026-02-28 20:24:55 +00:00
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- k3s-agent
|
|
|
|
|
|
|
|
|
|
- name: Deploy Hetzner CCM
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- ccm
|
|
|
|
|
|
2026-03-01 17:12:12 +00:00
|
|
|
- name: Deploy Hetzner CSI
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- csi
|
|
|
|
|
|
2026-03-02 20:28:51 +00:00
|
|
|
- name: Deploy Tailscale Kubernetes Operator
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- tailscale-operator
|
|
|
|
|
|
2026-03-02 01:33:41 +00:00
|
|
|
- name: Deploy observability stack
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
roles:
|
2026-03-05 00:17:25 +00:00
|
|
|
- role: observability
|
|
|
|
|
when: not (observability_gitops_enabled | default(true) | bool)
|
2026-03-02 01:33:41 +00:00
|
|
|
|
2026-03-04 03:36:01 +00:00
|
|
|
- name: Provision Grafana content
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
|
|
|
|
|
roles:
|
2026-03-05 00:17:25 +00:00
|
|
|
- role: observability-content
|
|
|
|
|
when: not (observability_gitops_enabled | default(true) | bool)
|
2026-03-04 03:36:01 +00:00
|
|
|
|
2026-03-08 04:16:06 +00:00
|
|
|
- name: Configure private tailnet access
|
|
|
|
|
hosts: control_plane[0]
|
|
|
|
|
become: true
|
|
|
|
|
vars:
|
|
|
|
|
private_access_grafana_port: 30080
|
|
|
|
|
private_access_prometheus_port: 30990
|
|
|
|
|
private_access_flux_port: 30901
|
|
|
|
|
|
|
|
|
|
roles:
|
|
|
|
|
- private-access
|
|
|
|
|
|
2026-02-28 20:24:55 +00:00
|
|
|
- name: Finalize
|
|
|
|
|
hosts: localhost
|
|
|
|
|
connection: local
|
|
|
|
|
tasks:
|
|
|
|
|
- name: Update kubeconfig server address
|
|
|
|
|
command: |
|
2026-03-01 17:12:12 +00:00
|
|
|
sed -i 's/127.0.0.1/{{ groups["control_plane"][0] }}.{{ tailscale_tailnet }}/g' ../outputs/kubeconfig
|
2026-02-28 20:24:55 +00:00
|
|
|
changed_when: true
|
|
|
|
|
|
|
|
|
|
- name: Display success message
|
|
|
|
|
debug:
|
|
|
|
|
msg: |
|
|
|
|
|
Cluster setup complete!
|
|
|
|
|
Control planes: {{ groups['control_plane'] | length }}
|
|
|
|
|
Workers: {{ groups['workers'] | length }}
|
|
|
|
|
To access the cluster:
|
|
|
|
|
export KUBECONFIG={{ playbook_dir }}/../outputs/kubeconfig
|
|
|
|
|
kubectl get nodes
|