mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
Update inventory/roles to keep K3s state on local storage and prevent iSCSI from managing /var/lib/rancher. Also add a single-host k3s install playbook, a systemd override template, and docs describing the installer ↔ Ansible boundary and slow-storage knobs. Co-authored-by: Junie <junie@jetbrains.com>
350 lines
12 KiB
YAML
350 lines
12 KiB
YAML
---
|
|
- name: Prepare k3s synchronization metadata
|
|
hosts: k3s_hosts
|
|
gather_facts: false
|
|
run_once: true
|
|
tasks:
|
|
- name: Initialize k3s sync source host
|
|
ansible.builtin.set_fact:
|
|
k3s_sync_source_host: ""
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Select k3s init server as sync source
|
|
ansible.builtin.set_fact:
|
|
k3s_sync_source_host: "{{ item }}"
|
|
loop: "{{ groups['k3s_hosts'] }}"
|
|
when:
|
|
- hostvars[item].k3s_role | default('agent') == 'server'
|
|
- hostvars[item].k3s_cluster_init | default(false) | bool
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Fallback to first k3s server as sync source
|
|
ansible.builtin.set_fact:
|
|
k3s_sync_source_host: "{{ item }}"
|
|
loop: "{{ groups['k3s_hosts'] }}"
|
|
when:
|
|
- (hostvars['localhost'].k3s_sync_source_host | length) == 0
|
|
- hostvars[item].k3s_role | default('agent') == 'server'
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Require a k3s server as sync source
|
|
ansible.builtin.assert:
|
|
that:
|
|
- hostvars['localhost'].k3s_sync_source_host | length > 0
|
|
fail_msg: >-
|
|
No k3s sync source found. Ensure at least one host has `k3s_role: server`.
|
|
(If you have multiple servers and want to prefer the bootstrap server,
|
|
set `k3s_cluster_init: true` on exactly one server.)
|
|
|
|
- name: Ensure sync source is included in this run
|
|
ansible.builtin.assert:
|
|
that:
|
|
- hostvars['localhost'].k3s_sync_source_host in ansible_play_hosts_all
|
|
fail_msg: "Sync source {{ hostvars['localhost'].k3s_sync_source_host }} is not in this run. Include it in --limit."
|
|
|
|
- name: Create local temp directory for k3s sync
|
|
ansible.builtin.command: mktemp -d -p /tmp k3s-sync-XXXXXX
|
|
register: k3s_sync_tmpdir
|
|
changed_when: true
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Ensure k3s sync temp directory is writable
|
|
ansible.builtin.file:
|
|
path: "{{ k3s_sync_tmpdir.stdout }}"
|
|
state: directory
|
|
mode: "1777"
|
|
delegate_to: localhost
|
|
|
|
- name: Store k3s sync metadata on controller
|
|
ansible.builtin.set_fact:
|
|
k3s_sync_source_host: "{{ hostvars['localhost'].k3s_sync_source_host }}"
|
|
k3s_sync_tmpdir_path: "{{ k3s_sync_tmpdir.stdout }}"
|
|
k3s_sync_tls_bundle: "{{ k3s_sync_tmpdir.stdout }}/k3s-tls.tgz"
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Collect k3s token and certs from init server
|
|
hosts: k3s_hosts
|
|
become: true
|
|
gather_facts: false
|
|
run_once: true
|
|
vars:
|
|
k3s_sync_source_host: "{{ hostvars['localhost'].k3s_sync_source_host | default('') }}"
|
|
k3s_sync_tls_bundle: "{{ hostvars['localhost'].k3s_sync_tls_bundle | default('') }}"
|
|
tasks:
|
|
- name: Require a k3s sync source
|
|
ansible.builtin.assert:
|
|
that:
|
|
- k3s_sync_source_host | length > 0
|
|
fail_msg: "k3s sync source is empty. Ensure the init server is reachable."
|
|
|
|
- name: Ensure k3s node token exists
|
|
ansible.builtin.stat:
|
|
path: "{{ k3s_data_dir }}/server/node-token"
|
|
register: k3s_node_token
|
|
delegate_to: "{{ k3s_sync_source_host }}"
|
|
|
|
- name: Fail when k3s node token is missing
|
|
ansible.builtin.fail:
|
|
msg: "k3s node token not found at {{ k3s_data_dir }}/server/node-token"
|
|
when: not k3s_node_token.stat.exists
|
|
|
|
- name: Read k3s node token
|
|
ansible.builtin.slurp:
|
|
src: "{{ k3s_data_dir }}/server/node-token"
|
|
register: k3s_node_token_raw
|
|
delegate_to: "{{ k3s_sync_source_host }}"
|
|
|
|
- name: Store k3s sync token on controller
|
|
ansible.builtin.set_fact:
|
|
k3s_sync_token: "{{ k3s_node_token_raw.content | b64decode | trim }}"
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Check for k3s tls directory
|
|
ansible.builtin.stat:
|
|
path: "{{ k3s_data_dir }}/server/tls"
|
|
register: k3s_tls_dir
|
|
delegate_to: "{{ k3s_sync_source_host }}"
|
|
|
|
- name: Create k3s tls bundle
|
|
ansible.builtin.archive:
|
|
path: "{{ k3s_data_dir }}/server/tls"
|
|
dest: /tmp/k3s-tls.tgz
|
|
format: gz
|
|
when: k3s_tls_dir.stat.exists
|
|
delegate_to: "{{ k3s_sync_source_host }}"
|
|
|
|
- name: Fetch k3s tls bundle
|
|
ansible.builtin.fetch:
|
|
src: /tmp/k3s-tls.tgz
|
|
dest: "{{ k3s_sync_tls_bundle }}"
|
|
flat: true
|
|
when: k3s_tls_dir.stat.exists
|
|
delegate_to: "{{ k3s_sync_source_host }}"
|
|
|
|
- name: Mark tls bundle presence on controller
|
|
ansible.builtin.set_fact:
|
|
k3s_sync_tls_bundle_present: "{{ k3s_tls_dir.stat.exists }}"
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Remove temporary tls bundle from source
|
|
ansible.builtin.file:
|
|
path: /tmp/k3s-tls.tgz
|
|
state: absent
|
|
when: k3s_tls_dir.stat.exists
|
|
delegate_to: "{{ k3s_sync_source_host }}"
|
|
|
|
- name: Synchronize k3s token and certs to servers
|
|
hosts: k3s_hosts
|
|
become: true
|
|
serial: 1
|
|
gather_facts: false
|
|
vars:
|
|
k3s_sync_source_host: "{{ hostvars['localhost'].k3s_sync_source_host }}"
|
|
k3s_sync_token: "{{ hostvars['localhost'].k3s_sync_token | default('') }}"
|
|
k3s_sync_tls_bundle: "{{ hostvars['localhost'].k3s_sync_tls_bundle | default('') }}"
|
|
k3s_sync_tls_bundle_present: "{{ hostvars['localhost'].k3s_sync_tls_bundle_present | default(false) }}"
|
|
pre_tasks:
|
|
- name: Require k3s sync token
|
|
ansible.builtin.assert:
|
|
that:
|
|
- k3s_sync_token | length > 0
|
|
fail_msg: "k3s sync token is empty. Check the init server token."
|
|
tasks:
|
|
- name: Stop k3s before syncing
|
|
ansible.builtin.import_role:
|
|
name: k3s
|
|
tasks_from: stop
|
|
when: inventory_hostname != k3s_sync_source_host
|
|
|
|
- name: Sync k3s token and certs
|
|
ansible.builtin.import_role:
|
|
name: k3s
|
|
tasks_from: sync
|
|
when: inventory_hostname != k3s_sync_source_host
|
|
|
|
- name: Start k3s after syncing
|
|
ansible.builtin.import_role:
|
|
name: k3s
|
|
tasks_from: start
|
|
when: inventory_hostname != k3s_sync_source_host
|
|
|
|
- name: Update k3s vault token on controller
|
|
hosts: k3s_hosts
|
|
gather_facts: false
|
|
run_once: true
|
|
vars:
|
|
k3s_sync_token: "{{ hostvars['localhost'].k3s_sync_token | default('') }}"
|
|
vault_k3s_path: "{{ playbook_dir }}/../inventory/group_vars/all/vault_k3s.yml"
|
|
vault_pass_default: "{{ playbook_dir }}/../../.vault_pass"
|
|
tasks:
|
|
- name: Skip vault update when disabled
|
|
ansible.builtin.meta: end_play
|
|
when: not (k3s_sync_update_vault | default(true) | bool)
|
|
|
|
- name: Require k3s sync token for vault update
|
|
ansible.builtin.assert:
|
|
that:
|
|
- k3s_sync_token | length > 0
|
|
fail_msg: "k3s sync token is empty. Unable to update vault."
|
|
|
|
- name: Check for default vault password file
|
|
ansible.builtin.stat:
|
|
path: "{{ vault_pass_default }}"
|
|
register: vault_pass_default_stat
|
|
delegate_to: localhost
|
|
|
|
- name: Determine vault password file
|
|
ansible.builtin.set_fact:
|
|
k3s_vault_password_file: >-
|
|
{{ k3s_vault_password_file
|
|
| default(lookup('env', 'ANSIBLE_VAULT_PASSWORD_FILE') | default('', true), true) }}
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Fallback to default vault password file
|
|
ansible.builtin.set_fact:
|
|
k3s_vault_password_file: "{{ vault_pass_default }}"
|
|
when:
|
|
- (hostvars['localhost'].k3s_vault_password_file | default('')) | length == 0
|
|
- vault_pass_default_stat.stat.exists
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Require vault password file
|
|
ansible.builtin.assert:
|
|
that:
|
|
- (hostvars['localhost'].k3s_vault_password_file | default('')) | length > 0
|
|
fail_msg: "Set k3s_vault_password_file or ANSIBLE_VAULT_PASSWORD_FILE to update vault."
|
|
|
|
- name: Ensure vault file exists
|
|
ansible.builtin.stat:
|
|
path: "{{ vault_k3s_path }}"
|
|
register: vault_k3s_file
|
|
delegate_to: localhost
|
|
|
|
- name: Fail when vault file is missing
|
|
ansible.builtin.fail:
|
|
msg: "Vault file not found at {{ vault_k3s_path }}"
|
|
when: not vault_k3s_file.stat.exists
|
|
|
|
- name: Check if vault file is encrypted
|
|
ansible.builtin.command: "head -n 1 {{ vault_k3s_path }}"
|
|
register: vault_k3s_head
|
|
changed_when: false
|
|
delegate_to: localhost
|
|
|
|
- name: Mark vault encryption state
|
|
ansible.builtin.set_fact:
|
|
vault_k3s_encrypted: "{{ (vault_k3s_head.stdout | default('')) is search('^\\$ANSIBLE_VAULT') }}"
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
|
|
- name: Decrypt vault_k3s.yml
|
|
ansible.builtin.command: >-
|
|
ansible-vault decrypt {{ vault_k3s_path }}
|
|
--vault-password-file {{ hostvars['localhost'].k3s_vault_password_file }}
|
|
changed_when: true
|
|
delegate_to: localhost
|
|
when: hostvars['localhost'].vault_k3s_encrypted | default(false)
|
|
|
|
- name: Update vault k3s token
|
|
ansible.builtin.lineinfile:
|
|
path: "{{ vault_k3s_path }}"
|
|
regexp: '^vault_k3s_token:'
|
|
line: "vault_k3s_token: \"{{ k3s_sync_token }}\""
|
|
delegate_to: localhost
|
|
|
|
- name: Encrypt vault_k3s.yml
|
|
ansible.builtin.command: >-
|
|
ansible-vault encrypt {{ vault_k3s_path }}
|
|
--vault-password-file {{ hostvars['localhost'].k3s_vault_password_file }}
|
|
changed_when: true
|
|
delegate_to: localhost
|
|
when: hostvars['localhost'].vault_k3s_encrypted | default(false)
|
|
|
|
- name: Refresh kubeconfig on controller
|
|
hosts: k3s_hosts
|
|
gather_facts: false
|
|
run_once: true
|
|
tasks:
|
|
- name: Fetch and save kubeconfig on controller
|
|
ansible.builtin.import_role:
|
|
name: k3s
|
|
tasks_from: fetch_kubeconfig
|
|
|
|
- name: Validate k3s nodes from controller
|
|
hosts: k3s_hosts
|
|
gather_facts: false
|
|
run_once: true
|
|
vars:
|
|
k3s_kubeconfig_service_path: "{{ playbook_dir }}/../../etc/secrets/k3s.kubeconfig"
|
|
k3s_kubeconfig_project_path: "{{ playbook_dir }}/../../prole-k3s.kubeconfig"
|
|
k3s_expected_node_count: "{{ groups['k3s_hosts'] | length }}"
|
|
tasks:
|
|
- name: Check for service kubeconfig
|
|
ansible.builtin.stat:
|
|
path: "{{ k3s_kubeconfig_service_path }}"
|
|
register: _k3s_kubeconfig_service_stat
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Check for project kubeconfig
|
|
ansible.builtin.stat:
|
|
path: "{{ k3s_kubeconfig_project_path }}"
|
|
register: _k3s_kubeconfig_project_stat
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Select kubeconfig path for validation
|
|
ansible.builtin.set_fact:
|
|
k3s_kubeconfig_validation_path: >-
|
|
{{ k3s_kubeconfig_service_path
|
|
if _k3s_kubeconfig_service_stat.stat.exists
|
|
else k3s_kubeconfig_project_path }}
|
|
changed_when: false
|
|
|
|
- name: Require a kubeconfig for validation
|
|
ansible.builtin.assert:
|
|
that:
|
|
- _k3s_kubeconfig_service_stat.stat.exists or _k3s_kubeconfig_project_stat.stat.exists
|
|
fail_msg: >-
|
|
No kubeconfig found at {{ k3s_kubeconfig_service_path }} or {{ k3s_kubeconfig_project_path }}.
|
|
Run `k3s_reset` or `k3s_sync` again and ensure the init server is reachable.
|
|
|
|
- name: Show nodes (kubectl get nodes -o wide)
|
|
ansible.builtin.command: "kubectl --kubeconfig {{ k3s_kubeconfig_validation_path }} get nodes -o wide"
|
|
register: _k3s_nodes_wide
|
|
changed_when: false
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Debug nodes output
|
|
ansible.builtin.debug:
|
|
var: _k3s_nodes_wide.stdout_lines
|
|
|
|
- name: Count nodes
|
|
ansible.builtin.shell: |
|
|
set -euo pipefail
|
|
kubectl --kubeconfig "{{ k3s_kubeconfig_validation_path }}" get nodes --no-headers | wc -l | tr -d ' '
|
|
args:
|
|
executable: /bin/bash
|
|
register: _k3s_node_count
|
|
changed_when: false
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Require expected node count
|
|
ansible.builtin.assert:
|
|
that:
|
|
- (_k3s_node_count.stdout | int) >= (k3s_expected_node_count | int)
|
|
fail_msg: >-
|
|
Expected at least {{ k3s_expected_node_count }} nodes, but kubectl reported {{ _k3s_node_count.stdout | default('0') }}.
|
|
Ensure all `k3s_hosts` are reachable and have rejoined, then re-run `k3s_sync`.
|