mirror of
https://github.com/dredx/prole.git
synced 2026-09-27 12:44:31 +00:00
456 lines
15 KiB
YAML
456 lines
15 KiB
YAML
---
|
|
|
|
- name: Skip k3s when state is absent
|
|
ansible.builtin.meta: end_host
|
|
when: k3s_state == "absent"
|
|
|
|
- name: Set k3s service name
|
|
ansible.builtin.set_fact:
|
|
k3s_service_name: "{{ 'k3s' if k3s_role == 'server' else 'k3s-agent' }}"
|
|
|
|
- name: Check if k3s service is installed
|
|
ansible.builtin.stat:
|
|
path: "/etc/systemd/system/{{ k3s_service_name }}.service"
|
|
register: k3s_service
|
|
|
|
- name: Check if k3s binary exists
|
|
ansible.builtin.stat:
|
|
path: /usr/local/bin/k3s
|
|
register: k3s_bin
|
|
|
|
- name: Determine if k3s needs installation
|
|
ansible.builtin.set_fact:
|
|
k3s_needs_install: "{{ not k3s_bin.stat.exists or not k3s_service.stat.exists }}"
|
|
|
|
- name: Install k3s dependencies
|
|
ansible.builtin.package:
|
|
name:
|
|
- curl
|
|
- iptables
|
|
state: present
|
|
|
|
- name: Preflight - ensure rancher mountpoint is mounted
|
|
ansible.builtin.command: "findmnt -n {{ k3s_rancher_mountpoint | default('/var/lib/rancher') }}"
|
|
register: rancher_mounted
|
|
changed_when: false
|
|
failed_when: rancher_mounted.rc != 0
|
|
|
|
- name: Preflight - ensure cgroup kernel params are present
|
|
ansible.builtin.command: "cat /proc/cmdline"
|
|
register: k3s_proc_cmdline
|
|
changed_when: false
|
|
|
|
- name: Fail if cgroup params are missing (reboot required)
|
|
ansible.builtin.fail:
|
|
msg: "Missing cgroup params in /proc/cmdline: {{ ['cgroup_memory=1', 'cgroup_enable=memory'] | reject('in', k3s_proc_cmdline.stdout) | list }}. Reboot required before k3s install."
|
|
when: (['cgroup_memory=1', 'cgroup_enable=memory'] | reject('in', k3s_proc_cmdline.stdout) | list) | length > 0
|
|
|
|
- name: Guardrail - ensure rancher mountpoint is not on SD/rootfs
|
|
ansible.builtin.command: "findmnt -n -o SOURCE {{ k3s_rancher_mountpoint | default('/var/lib/rancher') }}"
|
|
register: rancher_source
|
|
changed_when: false
|
|
|
|
- name: Fail if rancher mountpoint is on SD
|
|
ansible.builtin.fail:
|
|
msg: "{{ k3s_rancher_mountpoint | default('/var/lib/rancher') }} is on SD/rootfs ({{ rancher_source.stdout }}). Refusing to proceed."
|
|
when: rancher_source.stdout is search("mmcblk0") or rancher_source.stdout is search("/dev/mmc")
|
|
|
|
- name: Preflight - ensure required mountpoints are mounted
|
|
ansible.builtin.command: "findmnt -n {{ item }}"
|
|
register: k3s_required_mounts_present
|
|
changed_when: false
|
|
failed_when: k3s_required_mounts_present.rc != 0
|
|
loop: "{{ k3s_required_mounts | default([]) }}"
|
|
when: (k3s_required_mounts | default([])) | length > 0
|
|
|
|
- name: Guardrail - ensure required mountpoints are not on SD
|
|
ansible.builtin.command: "findmnt -n -o SOURCE {{ item }}"
|
|
register: k3s_required_mounts_sources
|
|
changed_when: false
|
|
loop: "{{ k3s_required_mounts | default([]) }}"
|
|
when: (k3s_required_mounts | default([])) | length > 0
|
|
|
|
- name: Fail if required mountpoint is on SD
|
|
ansible.builtin.fail:
|
|
msg: "{{ item.item }} is on SD/rootfs ({{ item.stdout }}). Refusing to proceed."
|
|
loop: "{{ k3s_required_mounts_sources.results }}"
|
|
when: item.stdout is search("mmcblk0") or item.stdout is search("/dev/mmc")
|
|
|
|
- name: Read k3s node token for sharing
|
|
ansible.builtin.slurp:
|
|
src: /var/lib/rancher/k3s/server/node-token
|
|
register: k3s_node_token_slurp
|
|
when: k3s_role == "server" and k3s_cluster_init | bool
|
|
ignore_errors: true
|
|
|
|
- name: Set k3s_token_discovered fact
|
|
ansible.builtin.set_fact:
|
|
k3s_token_discovered: "{{ k3s_node_token_slurp.content | b64decode | trim }}"
|
|
when:
|
|
- k3s_node_token_slurp is defined
|
|
- k3s_node_token_slurp.content is defined
|
|
|
|
- name: Discover k3s token from other hosts
|
|
ansible.builtin.set_fact:
|
|
k3s_token: "{{ hostvars[item].k3s_token_discovered }}"
|
|
loop: "{{ groups['k3s_hosts'] }}"
|
|
when:
|
|
- (k3s_token | default('') | length == 0)
|
|
- hostvars[item].k3s_token_discovered | default('') | length > 0
|
|
|
|
- name: Validate join configuration
|
|
ansible.builtin.assert:
|
|
that:
|
|
- k3s_server_url is defined
|
|
- k3s_server_url | length > 0
|
|
- k3s_token is defined
|
|
- k3s_token | length > 0
|
|
fail_msg: "k3s_server_url and k3s_token are required for non-init nodes."
|
|
when: not k3s_cluster_init | bool
|
|
|
|
- name: Check for existing k3s server node token
|
|
ansible.builtin.stat:
|
|
path: /var/lib/rancher/k3s/server/node-token
|
|
register: k3s_server_node_token
|
|
when:
|
|
- k3s_guard_token_drift | bool
|
|
- k3s_role == "server"
|
|
- k3s_cluster_init | bool
|
|
|
|
- name: Read existing k3s server node token
|
|
ansible.builtin.slurp:
|
|
src: /var/lib/rancher/k3s/server/node-token
|
|
register: k3s_server_node_token_raw
|
|
when:
|
|
- k3s_guard_token_drift | bool
|
|
- k3s_role == "server"
|
|
- k3s_cluster_init | bool
|
|
- k3s_server_node_token.stat.exists
|
|
|
|
- name: Fail when vault k3s token is missing for existing cluster
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
vault_k3s_token is empty but /var/lib/rancher/k3s/server/node-token exists.
|
|
Refusing to overwrite k3s config. Update vault_k3s.yml or run the k3s sync playbook.
|
|
when:
|
|
- k3s_guard_token_drift | bool
|
|
- k3s_role == "server"
|
|
- k3s_cluster_init | bool
|
|
- k3s_server_node_token.stat.exists
|
|
- (k3s_token | default('') | trim) | length == 0
|
|
|
|
- name: Fail on k3s token drift from live cluster
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
vault_k3s_token does not match the live k3s server node-token.
|
|
Refusing to overwrite k3s config. Run infrastructure/playbooks/k3s_sync.yml
|
|
or update vault_k3s.yml to match the live token.
|
|
when:
|
|
- k3s_guard_token_drift | bool
|
|
- k3s_role == "server"
|
|
- k3s_cluster_init | bool
|
|
- k3s_server_node_token.stat.exists
|
|
- (k3s_token | default('') | trim) | length > 0
|
|
- (k3s_server_node_token_raw.content | b64decode | trim) != (k3s_token | default('') | trim)
|
|
|
|
- name: Ensure k3s config directory exists
|
|
ansible.builtin.file:
|
|
path: /etc/rancher/k3s
|
|
state: directory
|
|
mode: "0755"
|
|
|
|
- name: Load registry defaults from prole.cfg
|
|
ansible.builtin.set_fact:
|
|
k3s_prole_k3s_server_cfg: "{{ lookup('ansible.builtin.ini', 'PROLE_K3S_SERVER section=Global file=' + playbook_dir + '/../../conf/prole.cfg', default='') }}"
|
|
k3s_prole_service_namespace_cfg: "{{ lookup('ansible.builtin.ini', 'SERVICE_NAMESPACE section=Global file=' + playbook_dir + '/../../conf/prole.cfg', default='') }}"
|
|
when: k3s_state == "present" and k3s_registry_config_enabled | bool
|
|
|
|
- name: Resolve k3s registry host
|
|
ansible.builtin.set_fact:
|
|
k3s_registry_host_resolved: >-
|
|
{{ (k3s_registry_host | default('')) if (k3s_registry_host | default('') | length > 0)
|
|
else (k3s_prole_k3s_server_cfg | default('')) if (k3s_prole_k3s_server_cfg | default('') | length > 0)
|
|
else (k3s_server_url | default('')) if (k3s_server_url | default('') | length > 0)
|
|
else inventory_hostname }}
|
|
when: k3s_state == "present" and k3s_registry_config_enabled | bool
|
|
|
|
- name: Normalize k3s registry host
|
|
ansible.builtin.set_fact:
|
|
k3s_registry_host_resolved: "{{ k3s_registry_host_resolved | regex_replace('^https?://', '') | regex_replace('/.*$', '') | regex_replace(':.*$', '') }}"
|
|
when: k3s_state == "present" and k3s_registry_config_enabled | bool
|
|
|
|
- name: Resolve k3s registry namespace
|
|
ansible.builtin.set_fact:
|
|
k3s_registry_namespace_resolved: >-
|
|
{{ (k3s_registry_namespace | default('')) if (k3s_registry_namespace | default('') | length > 0)
|
|
else (k3s_prole_service_namespace_cfg | default('')) if (k3s_prole_service_namespace_cfg | default('') | length > 0)
|
|
else 'default' }}
|
|
when: k3s_state == "present" and k3s_registry_config_enabled | bool
|
|
|
|
- name: Validate k3s registry host
|
|
ansible.builtin.assert:
|
|
that:
|
|
- k3s_registry_host_resolved | length > 0
|
|
fail_msg: "k3s registry host could not be resolved (set k3s_registry_host or PROLE_K3S_SERVER)."
|
|
when: k3s_state == "present" and k3s_registry_config_enabled | bool
|
|
|
|
- name: Render k3s registries config
|
|
ansible.builtin.template:
|
|
src: registries.yaml.j2
|
|
dest: "{{ k3s_registry_config_path }}"
|
|
mode: "0644"
|
|
notify: Restart k3s
|
|
when: k3s_state == "present" and k3s_registry_config_enabled | bool
|
|
|
|
- name: Ensure kubeconfig group exists
|
|
ansible.builtin.group:
|
|
name: "{{ k3s_kubeconfig_group }}"
|
|
state: present
|
|
|
|
- name: Ensure kubeconfig users are in group (server)
|
|
ansible.builtin.user:
|
|
name: "{{ item }}"
|
|
groups: "{{ k3s_kubeconfig_group }}"
|
|
append: true
|
|
loop: "{{ k3s_kubeconfig_users }}"
|
|
when: k3s_role == "server" and (k3s_kubeconfig_users | length) > 0
|
|
|
|
- name: Ensure rancher directories are group-accessible
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
owner: root
|
|
group: "{{ k3s_kubeconfig_group }}"
|
|
mode: "0750"
|
|
loop:
|
|
- /etc/rancher
|
|
- /etc/rancher/k3s
|
|
- "{{ k3s_rancher_mountpoint | default('/var/lib/rancher') }}"
|
|
when: k3s_state != "absent"
|
|
|
|
- name: Render k3s config
|
|
ansible.builtin.template:
|
|
src: config.yaml.j2
|
|
dest: /etc/rancher/k3s/config.yaml
|
|
mode: "0640"
|
|
notify: Restart k3s
|
|
|
|
- name: Build k3s install environment
|
|
ansible.builtin.set_fact:
|
|
k3s_install_env: >-
|
|
{{ {'INSTALL_K3S_EXEC': k3s_role}
|
|
| combine((k3s_version | length > 0) | ternary({'INSTALL_K3S_VERSION': k3s_version}, {})) }}
|
|
|
|
- name: Install k3s
|
|
ansible.builtin.shell: |
|
|
curl -sfL https://get.k3s.io | sh -
|
|
environment:
|
|
"{{ k3s_install_env }}"
|
|
args:
|
|
creates: /usr/local/bin/k3s
|
|
when: k3s_needs_install
|
|
|
|
- name: Ensure k3s service state
|
|
ansible.builtin.service:
|
|
name: "{{ k3s_service_name }}"
|
|
state: "{{ 'started' if k3s_state == 'present' else 'stopped' }}"
|
|
enabled: "{{ k3s_state == 'present' }}"
|
|
when: k3s_service.stat.exists or k3s_bin.stat.exists
|
|
|
|
- name: Wait for k3s to be ready
|
|
ansible.builtin.shell: k3s kubectl get nodes | grep -w "Ready"
|
|
register: k3s_ready
|
|
until: k3s_ready.rc == 0
|
|
retries: 20
|
|
delay: 5
|
|
changed_when: false
|
|
when: k3s_state == "present" and k3s_role == "server"
|
|
|
|
- name: Pause to allow k3s API to stabilize
|
|
ansible.builtin.pause:
|
|
seconds: 10
|
|
when: k3s_state == "present" and k3s_role == "server" and k3s_ready.changed | default(true)
|
|
|
|
- name: Read k3s node token after install for sharing
|
|
ansible.builtin.slurp:
|
|
src: /var/lib/rancher/k3s/server/node-token
|
|
register: k3s_node_token_slurp_post
|
|
when: k3s_role == "server" and k3s_cluster_init | bool and k3s_token_discovered is not defined
|
|
ignore_errors: true
|
|
|
|
- name: Set k3s_token_discovered fact (post-install)
|
|
ansible.builtin.set_fact:
|
|
k3s_token_discovered: "{{ k3s_node_token_slurp_post.content | b64decode | trim }}"
|
|
when:
|
|
- k3s_node_token_slurp_post is defined
|
|
- k3s_node_token_slurp_post.content is defined
|
|
|
|
- name: Pre-stage k3s images
|
|
ansible.builtin.shell: "crictl pull {{ item }}"
|
|
loop:
|
|
- docker.io/library/registry:2
|
|
- docker.io/prom/prometheus:latest
|
|
- docker.io/prom/alertmanager:latest
|
|
- quay.io/prometheus/node-exporter:latest
|
|
- quay.io/prometheus-operator/prometheus-operator:latest
|
|
- ghcr.io/openbao/openbao:latest
|
|
when: k3s_state == "present"
|
|
ignore_errors: true
|
|
|
|
- name: Ensure prole config directory exists
|
|
ansible.builtin.file:
|
|
path: "{{ prole_conf }}"
|
|
state: directory
|
|
mode: "0755"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Sync prole.cfg to k3s hosts
|
|
ansible.builtin.copy:
|
|
src: "{{ playbook_dir }}/../../conf/prole.cfg"
|
|
dest: "{{ prole_conf }}/prole.cfg"
|
|
mode: "0644"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Ensure prole home directory exists
|
|
ansible.builtin.file:
|
|
path: "{{ prole_home }}"
|
|
state: directory
|
|
mode: "0755"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Ensure prole service directory exists
|
|
ansible.builtin.file:
|
|
path: "{{ prole_home }}/etc"
|
|
state: directory
|
|
mode: "0755"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Sync init_port_forwards.sh to k3s hosts
|
|
ansible.builtin.copy:
|
|
src: "{{ playbook_dir }}/../../etc/init_port_forwards.sh"
|
|
dest: "{{ prole_home }}/etc/init_port_forwards.sh"
|
|
mode: "0755"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Sync prole_cfg.sh to k3s hosts
|
|
ansible.builtin.copy:
|
|
src: "{{ playbook_dir }}/../../etc/prole_cfg.sh"
|
|
dest: "{{ prole_home }}/etc/prole_cfg.sh"
|
|
mode: "0755"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Select k3s init server for port-forward token
|
|
ansible.builtin.set_fact:
|
|
prole_port_forward_source_host: "{{ item }}"
|
|
loop: "{{ groups['k3s_hosts'] }}"
|
|
when: hostvars[item].k3s_cluster_init | default(false) | bool
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
run_once: true
|
|
|
|
- name: Require k3s init server for port-forward token
|
|
ansible.builtin.assert:
|
|
that:
|
|
- hostvars['localhost'].prole_port_forward_source_host | default('') | length > 0
|
|
fail_msg: "No k3s init server found for port-forward token."
|
|
delegate_to: localhost
|
|
run_once: true
|
|
|
|
- name: Ensure prole-installer service account exists
|
|
ansible.builtin.shell: |
|
|
k3s kubectl -n kube-system apply -f - <<'EOF'
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: prole-installer
|
|
namespace: kube-system
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
name: prole-installer-admin
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: prole-installer
|
|
namespace: kube-system
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: cluster-admin
|
|
apiGroup: rbac.authorization.k8s.io
|
|
EOF
|
|
register: k3s_sa_apply
|
|
until: k3s_sa_apply.rc == 0
|
|
retries: 5
|
|
delay: 5
|
|
delegate_to: "{{ hostvars['localhost'].prole_port_forward_source_host }}"
|
|
run_once: true
|
|
when: k3s_state == "present"
|
|
|
|
- name: Ensure prole-installer token secret exists
|
|
ansible.builtin.shell: |
|
|
k3s kubectl -n kube-system apply -f - <<'EOF'
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: prole-installer-token
|
|
annotations:
|
|
kubernetes.io/service-account.name: prole-installer
|
|
type: kubernetes.io/service-account-token
|
|
EOF
|
|
register: k3s_secret_apply
|
|
until: k3s_secret_apply.rc == 0
|
|
retries: 5
|
|
delay: 5
|
|
delegate_to: "{{ hostvars['localhost'].prole_port_forward_source_host }}"
|
|
run_once: true
|
|
when: k3s_state == "present"
|
|
|
|
- name: Read prole-installer token for port forwards
|
|
ansible.builtin.shell: >
|
|
k3s kubectl -n kube-system get secret prole-installer-token
|
|
-o jsonpath='{.data.token}' | base64 -d
|
|
delegate_to: "{{ hostvars['localhost'].prole_port_forward_source_host }}"
|
|
run_once: true
|
|
register: prole_installer_token
|
|
changed_when: false
|
|
when: k3s_state == "present"
|
|
|
|
- name: Store prole-installer token on controller
|
|
ansible.builtin.set_fact:
|
|
prole_port_forward_token: "{{ prole_installer_token.stdout | default('') }}"
|
|
delegate_to: localhost
|
|
delegate_facts: true
|
|
run_once: true
|
|
when: k3s_state == "present"
|
|
|
|
- name: Set prole port-forward token for host
|
|
ansible.builtin.set_fact:
|
|
prole_port_forward_token: "{{ hostvars['localhost'].prole_port_forward_token }}"
|
|
when:
|
|
- k3s_state == "present"
|
|
- hostvars['localhost'].prole_port_forward_token | default('') | length > 0
|
|
|
|
- name: Render kubeconfig for port forwards
|
|
ansible.builtin.template:
|
|
src: prole-kubeconfig.yaml.j2
|
|
dest: "{{ prole_port_forward_kubeconfig }}"
|
|
mode: "0640"
|
|
owner: root
|
|
group: "{{ k3s_kubeconfig_group }}"
|
|
when: k3s_state == "present"
|
|
|
|
- name: Stop and disable prole port-forwards service
|
|
ansible.builtin.systemd:
|
|
name: "{{ prole_port_forward_service_name }}"
|
|
enabled: false
|
|
state: stopped
|
|
daemon_reload: true
|
|
when: k3s_state == "present"
|
|
failed_when: false
|
|
|
|
- name: Remove prole port-forwards systemd unit
|
|
ansible.builtin.file:
|
|
path: "/etc/systemd/system/{{ prole_port_forward_service_name }}.service"
|
|
state: absent
|
|
when: k3s_state == "present"
|