Repository navigation
fix(cluster): wait for the join host after k3s's own tailscale up - #117
Merged
Merged
Conversation
k3s's --vpn-auth start runs tailscale up --reset on every start, which restarts the Tailscale backend from its cached network map, and dials the join host as soon as the command returns. On Tailscale's control plane the cached map can hold no peers, so the host was not yet a peer or a MagicDNS name, k3s exited with "no such host" and a joining node never joined. The entrypoint now writes a tailscale wrapper under the container's /run tmpfs and starts k3s with it first on PATH: it runs every command unchanged and, after up, waits until the join host is a peer and resolves, as the wait before k3s already does. Agents get it too, for the server they dial. Fixes #116
Mearman
marked this pull request as ready for review
October 20, 2026 20:37
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins. |
|
🎉 This PR is included in version 2.5.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
This was referenced Oct 20, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #116. A node joining a cluster on Tailscale's own control plane never joined: k3s's
StartVPNrunstailscale up --authkey ... --timeout=30s --reseton every start, the backend restarts from a cached network map that held no peers, and k3s looked the join host up before the peers came back, exiting with "no such host" on every restart of the container.The entrypoint now writes a
tailscalewrapper into/run/github-runner-node/bin(on the container's/runtmpfs, so it is written afresh at every start and never sits in front of the entrypoint's owntailscalecalls) and starts k3s with that directory first on itsPATH. The wrapper runs every command unchanged and, afterup, waits until the join host is a peer and MagicDNS answers for it, the same check the entrypoint already makes before k3s starts. A server gets it forK3S_JOIN_SERVER_URL, an agent forK3S_URL, and the bootstrap server, which joins nothing, gets none. Nothing in the Compose file changes, so no running node is recreated.tests/unit/test_cluster_join_wait.pyruns the wrapper against a stand-intailscalewhoseip -4answers only from its third call, and checks thatuppasses its arguments through and then waits, that other commands and a failingupare not held, where the entrypoint installs it for servers and agents, and that its directory is on a tmpfs of both services. Each was broken in turn and a test failed for each.On a throwaway three-server cluster built from v2.4.0 on Tailscale's control plane with the pinned Tailscale, both joining servers restarted in that loop. With a hand-written wrapper of the same kind in
/usr/local/sbin, each joined on its next start, the wait afteruplasting about a second. The wrapper as merged here, under/run, never runs, because Docker mounts that tmpfs noexec; #124 moves it onto the image's filesystem.