--- # Install k3s as an HA server (embedded etcd) with Cilium-required components # disabled (ADR-0001, docs/02 stage 3 "Cluster-join"). The primary runs # --cluster-init; secondaries join it with the shared node-token. - name: Download the k3s install script ansible.builtin.get_url: url: "{{ k3s_install_url }}" dest: "{{ k3s_install_script }}" mode: "0755" - name: Compose the common k3s server flags ansible.builtin.set_fact: k3s_common_args: >- server --flannel-backend=none --disable-kube-proxy --disable-network-policy --disable={{ k3s_disable }} --write-kubeconfig-mode=644 --tls-san={{ k3s_api_host }} --node-ip={{ ansible_host }} # --- primary: found the cluster -------------------------------------------- - name: Install k3s primary (cluster-init, embedded etcd) ansible.builtin.command: cmd: "{{ k3s_install_script }} {{ k3s_common_args }} --cluster-init" creates: /etc/rancher/k3s/k3s.yaml environment: INSTALL_K3S_VERSION: "{{ k3s_version }}" when: k3s_server_mode == 'primary' - name: Wait for the k3s node-token to exist (primary) ansible.builtin.wait_for: path: /var/lib/rancher/k3s/server/token timeout: 180 when: k3s_server_mode == 'primary' - name: Read the k3s node-token (primary) ansible.builtin.slurp: src: /var/lib/rancher/k3s/server/token register: k3s_token_raw when: k3s_server_mode == 'primary' - name: Publish the node-token as a fact for secondaries (primary) ansible.builtin.set_fact: k3s_node_token: "{{ k3s_token_raw.content | b64decode | trim }}" when: k3s_server_mode == 'primary' # --- secondaries: obtain the join token, then join the existing cluster ----- # Fetch the token straight from the primary via delegate_to, falling back to it # only when the primary play didn't publish the fact this run. This makes a # single-node rejoin (`--limit k3s-dev-N`, primary NOT in the batch) self- # contained — delegate_to still reaches the primary even when it isn't a play # target, so the join no longer depends on a fact an earlier play had to set. # T-1.5 finding F2 (see DECISIONS-LOG.md). - name: Fetch the k3s node-token directly from the primary (secondary) ansible.builtin.slurp: src: /var/lib/rancher/k3s/server/token delegate_to: "{{ groups['k3s_primary'][0] }}" register: k3s_primary_token_raw when: - k3s_server_mode == 'secondary' - hostvars[groups['k3s_primary'][0]].k3s_node_token is not defined - name: Resolve the join token (secondary) ansible.builtin.set_fact: k3s_join_token: >- {{ hostvars[groups['k3s_primary'][0]].k3s_node_token | default(k3s_primary_token_raw.content | b64decode | trim, true) }} when: k3s_server_mode == 'secondary' - name: Install k3s secondary (join as server) ansible.builtin.command: cmd: >- {{ k3s_install_script }} {{ k3s_common_args }} --server https://{{ k3s_api_host }}:{{ k3s_api_port }} creates: /etc/rancher/k3s/k3s.yaml environment: INSTALL_K3S_VERSION: "{{ k3s_version }}" K3S_TOKEN: "{{ k3s_join_token }}" when: k3s_server_mode == 'secondary' - name: Wait for the k3s API to be serving locally ansible.builtin.wait_for: host: "127.0.0.1" port: "{{ k3s_api_port }}" timeout: 180