--- - name: Join a server node to an existing k3s HA cluster hosts: k3s become: true serial: 1 vars: k3s_server_url: "https://{{ k3s_first_server_ip }}:6443" pre_tasks: - name: Detect network interface for ansible_host ansible.builtin.shell: | set -o pipefail ip route get {{ ansible_host }} | grep -oP 'dev \K\w+' | head -1 register: detected_iface changed_when: false failed_when: false - name: Set fact for node interface ansible.builtin.set_fact: k3s_node_iface: "{{ detected_iface.stdout | default('') }}" when: detected_iface.rc == 0 and detected_iface.stdout | length > 0 - name: Warn if mac-shim interface detected ansible.builtin.debug: msg: "WARNING: mac-shim-like interface detected on {{ inventory_hostname }} (iface: {{ k3s_node_iface }}). This can cause k3s cluster join issues." when: - k3s_node_iface is defined - "'mac' in k3s_node_iface or 'shim' in k3s_node_iface" - name: Check if k3s is installed ansible.builtin.command: k3s --version register: k3s_installed changed_when: false failed_when: false - name: Check if k3s service is active ansible.builtin.systemd: name: k3s register: k3s_service_active changed_when: false failed_when: false - name: Check if node is already in the cluster ansible.builtin.shell: | set -o pipefail k3s kubectl get nodes --no-headers | grep -w "{{ ansible_hostname }}" || true register: node_in_cluster changed_when: false failed_when: false when: k3s_service_active.status.ActiveState | default('') == 'active' - name: Set fact if already installed and joined ansible.builtin.set_fact: k3s_already_joined: true when: - k3s_installed.rc == 0 - k3s_service_active.status.ActiveState | default('') == 'active' - node_in_cluster.stdout | default('') | length > 0 - name: Display status if already joined ansible.builtin.debug: msg: "k3s is already installed and joined to the cluster on {{ inventory_hostname }}" when: k3s_already_joined | default(false) | bool - name: Validate required vault variables ansible.builtin.assert: that: - k3s_token is defined - k3s_token | length > 0 fail_msg: "k3s_token is not defined. Create vault/k3s-cluster.yml with 'ansible-vault create vault/k3s-cluster.yml' and set k3s_token." success_msg: "k3s_token is defined and accessible" when: not (k3s_already_joined | default(false) | bool) tasks: - name: Create k3s config directory ansible.builtin.file: path: /etc/rancher/k3s state: directory mode: '0755' when: not (k3s_already_joined | default(false) | bool) - name: Deploy k3s server configuration ansible.builtin.template: src: config.yaml dest: /etc/rancher/k3s/config.yaml mode: '0644' when: not (k3s_already_joined | default(false) | bool) - name: Download k3s install script ansible.builtin.get_url: url: https://get.k3s.io dest: /tmp/k3s-install.sh mode: '0755' force: true when: not (k3s_already_joined | default(false) | bool) - name: Install and join server to the k3s cluster ansible.builtin.command: cmd: /tmp/k3s-install.sh server --server {{ k3s_server_url }} environment: K3S_TOKEN: "{{ k3s_token }}" register: k3s_join_result changed_when: "'already installed' not in k3s_join_result.stdout" when: not (k3s_already_joined | default(false) | bool) - name: Wait for k3s service to become active ansible.builtin.systemd: name: k3s state: started enabled: true register: k3s_service when: not (k3s_already_joined | default(false) | bool) - name: Verify node has joined the cluster ansible.builtin.command: k3s kubectl get nodes register: nodes_result changed_when: false retries: 10 delay: 10 until: nodes_result.rc == 0 and ansible_hostname in nodes_result.stdout when: not (k3s_already_joined | default(false) | bool) - name: Display cluster nodes ansible.builtin.debug: msg: "{{ nodes_result.stdout_lines }}" when: not (k3s_already_joined | default(false) | bool) post_tasks: - name: Create .kube directory in ansible_user home ansible.builtin.file: path: "~{{ ansible_user }}/.kube" state: directory mode: '0755' owner: "{{ ansible_user }}" group: "{{ ansible_user }}" - name: Copy kubeconfig to ansible_user home ansible.builtin.copy: src: /etc/rancher/k3s/k3s.yaml dest: "~{{ ansible_user }}/.kube/config" mode: '0644' owner: "{{ ansible_user }}" group: "{{ ansible_user }}" remote_src: true when: not (k3s_already_joined | default(false) | bool) - name: Set KUBECONFIG in ansible_user profile ansible.builtin.lineinfile: path: "~{{ ansible_user }}/.profile" line: "export KUBECONFIG=~{{ ansible_user }}/.kube/config" regexp: "^export KUBECONFIG=.*" create: true mode: '0644' owner: "{{ ansible_user }}" group: "{{ ansible_user }}" - name: Verify secrets encryption is enabled ansible.builtin.command: k3s secrets-encrypt status register: encryption_status changed_when: false failed_when: false when: not (k3s_already_joined | default(false) | bool) - name: Display encryption status ansible.builtin.debug: msg: "{{ encryption_status.stdout_lines }}" when: - not (k3s_already_joined | default(false) | bool) - encryption_status is defined - encryption_status.stdout_lines is defined