Add a post-join control-plane readiness gate so a half-succeeded server
join on a degraded etcd can no longer pass as success. Retry the MetalLB
IPAddressPool/L2Advertisement applies to ride out the validating-webhook
startup race. Narrow the k3sup cleanup glob, quiet the final k3sup ready
tip, and clarify two comments.
README: add networking caveats (VIP/LB outside the DHCP pool, same-subnet
ARP/L2, interface naming), certName key placement, a post-run verification
section, machine-count/admin-box notes, and fix the RAW_BASE description.
- join all nodes to --server-ip $vip (the readiness-gated VIP) so no single
master is the registration SPOF; drop the dead --server-user on joins
(a --node-token is already supplied, so k3sup doesn't SSH the server)
- add --tls-san=$vip to every server's args (not just master1's install) so
master2/3 declare the VIP SAN uniformly
- pin --flannel-iface/--node-ip on workers too (correct on multi-NIC nodes)
- filter k3sup's repeated 'slicervm.com' promo tip on install/join (sed, so
pipefail still surfaces a real failure)
- guard 'kubectl expose' with || true so a re-run doesn't abort on AlreadyExists
Re-validated on the 6-VM Multipass e2e: 5 nodes Ready, VIP serves the API,
MetalLB LoadBalancer reachable.
- match the global README.md convention; update the reference in k3s.sh
- pad the options table so it reads cleanly in raw and rendered views,
kept under the 80-col markdownlint limit
Found running the deploy end-to-end on a multi-node cluster:
- k3sup: get.k3sup.dev leaves an arch-suffixed binary (k3sup-arm64) when
run unprivileged; install whichever binary it produced, not a literal
'k3sup' that may not exist.
- kube-vip: scp landed the manifest in the ssh user's home, but the mv
ran as root (sudo bash -s) where ~ is /root; scp to /tmp and mv from
the absolute path instead.
- rewrite only the server URL (https://master1:6443 -> VIP) instead of a
global regex substitution whose dots could over-match cert data
- poll the VIP /readyz after repointing the kubeconfig, so a broken
kube-vip fails early with a clear message instead of downstream
The kubeadm default mounts /etc/kubernetes/admin.conf, which does not
exist on k3s. --inCluster uses the kube-vip ServiceAccount (provided by
the applied rbac.yaml) instead, which is the correct mode for k3s.
* Fix RKE2 MetalLB L2Advertisement to honor custom lb_pool_name (#135)
The apply-manifests role rendered the IPAddressPool from a template using
lb_pool_name, but applied the L2Advertisement from a hardcoded remote file
where the pool name was baked in as 'first-pool'. Setting lb_pool_name to
anything else left the L2Advertisement pointing at a non-existent pool, so
MetalLB assigned LoadBalancer IPs but never advertised them (services got an
external IP but were unreachable).
Template the L2Advertisement locally from lb_pool_name, mirroring the
IPAddressPool pattern, so both manifests always reference the same pool.
* Add explicit become: true to apply-manifests kubectl tasks
These tasks set become_user without a task-level become, tripping
ansible-lint's partial-become rule. become is already enabled globally via
ansible_become in group_vars/all.yaml, so the tasks already escalate to the
ansible user — but that is invisible to the linter (and to anyone reading the
task in isolation). Make it explicit with become: true alongside become_user.
Behavior-neutral: verified with ansible-playbook -vvv that the escalation
target is unchanged (sudo -u ansible; chown ansible on the temp files), so
kubectl still runs as the ansible user that owns ~/.kube/config.