fixing tailscaled routes

This commit is contained in:
juvdiaz 2026-05-24 08:15:10 -06:00
parent d5d94001e0
commit a9012d8777
3 changed files with 132 additions and 8 deletions

View File

@ -43,6 +43,25 @@ worker_nodes = {
Stateful apps currently pin retained local PVs to the `debian` node. Move or Stateful apps currently pin retained local PVs to the `debian` node. Move or
duplicate those PV manifests when you want storage on another node. duplicate those PV manifests when you want storage on another node.
The website NodePort is reachable from the OCI jump box through the Raspberry Pi
Tailscale interface. `bootstrap/cluster` installs a persistent
`homelab-tailscale-nodeport.service` on the configured worker to restore the
route, rp_filter settings, and iptables rules after reboot. Override the
defaults through `tailscale_nodeport_access` when the jump-box IP, Pi Tailscale
IP, pod CIDR, or NodePort changes:
```hcl
tailscale_nodeport_access = {
enabled = true
worker_key = "raspberrypi"
peer_ip = "100.118.255.19"
node_tailscale_ip = "100.77.80.72"
pod_cidr = "10.244.0.0/16"
node_port = 30080
target_port = 80
}
```
For `./lab.sh nuke`, set `WORKER_SSH_TARGETS` to a space-separated list of For `./lab.sh nuke`, set `WORKER_SSH_TARGETS` to a space-separated list of
remote SSH targets when more worker nodes exist. Set it to an empty string for a remote SSH targets when more worker nodes exist. Set it to an empty string for a
single-node rebuild. single-node rebuild.

View File

@ -290,14 +290,21 @@ resource "null_resource" "kubeadm_worker" {
depends_on = [data.external.kubeadm_join_command] depends_on = [data.external.kubeadm_join_command]
triggers = { triggers = {
node_name = each.value.node_name node_name = each.value.node_name
host = each.value.host host = each.value.host
user = each.value.user user = each.value.user
ssh_key_path = each.value.ssh_key_path ssh_key_path = each.value.ssh_key_path
registry_endpoint = var.registry_endpoint registry_endpoint = var.registry_endpoint
registry_config_version = "6" registry_config_version = "6"
node_dns_servers = join(" ", var.node_dns_servers) node_dns_servers = join(" ", var.node_dns_servers)
persistent_volume_dirs = join(",", var.persistent_volume_dirs) persistent_volume_dirs = join(",", var.persistent_volume_dirs)
tailscale_nodeport_version = "1"
tailscale_nodeport_enabled = var.tailscale_nodeport_access.enabled && each.key == var.tailscale_nodeport_access.worker_key ? "true" : "false"
tailscale_nodeport_peer_ip = var.tailscale_nodeport_access.peer_ip
tailscale_nodeport_node_tailscale_ip = var.tailscale_nodeport_access.node_tailscale_ip
tailscale_nodeport_pod_cidr = var.tailscale_nodeport_access.pod_cidr
tailscale_nodeport_node_port = tostring(var.tailscale_nodeport_access.node_port)
tailscale_nodeport_target_port = tostring(var.tailscale_nodeport_access.target_port)
} }
connection { connection {
@ -518,6 +525,82 @@ if ! getent hosts "${self.triggers.node_name}" >/dev/null; then
printf '%s %s\n' "${self.triggers.host}" "${self.triggers.node_name}" | sudo tee -a /etc/hosts >/dev/null printf '%s %s\n' "${self.triggers.host}" "${self.triggers.node_name}" | sudo tee -a /etc/hosts >/dev/null
fi fi
configure_tailscale_nodeport_access() {
local enabled="$1"
local peer_ip="$2"
local node_tailscale_ip="$3"
local pod_cidr="$4"
local node_port="$5"
local target_port="$6"
if [ "$enabled" != "true" ]; then
return 0
fi
sudo mkdir -p /usr/local/sbin /etc/sysctl.d
sudo tee /etc/sysctl.d/98-homelab-tailscale-nodeport.conf >/dev/null <<NODEPORT_SYSCTL_EOT
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.tailscale0.rp_filter = 0
NODEPORT_SYSCTL_EOT
sudo tee /usr/local/sbin/homelab-tailscale-nodeport.sh >/dev/null <<NODEPORT_SCRIPT_EOT
#!/bin/sh
set -eu
PEER_IP="$peer_ip"
NODE_TAILSCALE_IP="$node_tailscale_ip"
POD_CIDR="$pod_cidr"
NODE_PORT="$node_port"
TARGET_PORT="$target_port"
sysctl -w net.ipv4.conf.all.rp_filter=0 >/dev/null
sysctl -w net.ipv4.conf.tailscale0.rp_filter=0 >/dev/null 2>&1 || true
if ! ip link show tailscale0 >/dev/null 2>&1; then
echo "tailscale0 is not present; skipping Tailscale NodePort routing"
exit 0
fi
ip route replace "$PEER_IP/32" dev tailscale0 src "$NODE_TAILSCALE_IP"
iptables -C INPUT -i tailscale0 -p tcp --dport "$NODE_PORT" -j ACCEPT 2>/dev/null ||
iptables -I INPUT 1 -i tailscale0 -p tcp --dport "$NODE_PORT" -j ACCEPT
iptables -C FORWARD -i tailscale0 -d "$POD_CIDR" -p tcp --dport "$TARGET_PORT" -j ACCEPT 2>/dev/null ||
iptables -I FORWARD 1 -i tailscale0 -d "$POD_CIDR" -p tcp --dport "$TARGET_PORT" -j ACCEPT
iptables -C FORWARD -s "$POD_CIDR" -o tailscale0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null ||
iptables -I FORWARD 1 -s "$POD_CIDR" -o tailscale0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -C POSTROUTING -s 100.64.0.0/10 -d "$POD_CIDR" -p tcp --dport "$TARGET_PORT" -m comment --comment tailscale-nodeport-to-pods -j MASQUERADE 2>/dev/null ||
iptables -t nat -I POSTROUTING 1 -s 100.64.0.0/10 -d "$POD_CIDR" -p tcp --dport "$TARGET_PORT" -m comment --comment tailscale-nodeport-to-pods -j MASQUERADE
NODEPORT_SCRIPT_EOT
sudo chmod 0755 /usr/local/sbin/homelab-tailscale-nodeport.sh
sudo tee /etc/systemd/system/homelab-tailscale-nodeport.service >/dev/null <<'NODEPORT_SERVICE_EOT'
[Unit]
Description=Homelab Tailscale NodePort routing
After=network-online.target tailscaled.service kubelet.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/homelab-tailscale-nodeport.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
NODEPORT_SERVICE_EOT
sudo systemctl daemon-reload
sudo systemctl enable homelab-tailscale-nodeport.service >/dev/null
sudo systemctl restart homelab-tailscale-nodeport.service
}
configure_tailscale_nodeport_access \
"${self.triggers.tailscale_nodeport_enabled}" \
"${self.triggers.tailscale_nodeport_peer_ip}" \
"${self.triggers.tailscale_nodeport_node_tailscale_ip}" \
"${self.triggers.tailscale_nodeport_pod_cidr}" \
"${self.triggers.tailscale_nodeport_node_port}" \
"${self.triggers.tailscale_nodeport_target_port}"
configure_containerd_registry "${self.triggers.registry_endpoint}" configure_containerd_registry "${self.triggers.registry_endpoint}"
pv_dirs="${self.triggers.persistent_volume_dirs}" pv_dirs="${self.triggers.persistent_volume_dirs}"

View File

@ -61,3 +61,25 @@ variable "worker_nodes" {
} }
} }
} }
variable "tailscale_nodeport_access" {
type = object({
enabled = bool
worker_key = string
peer_ip = string
node_tailscale_ip = string
pod_cidr = string
node_port = number
target_port = number
})
default = {
enabled = true
worker_key = "raspberrypi"
peer_ip = "100.118.255.19"
node_tailscale_ip = "100.77.80.72"
pod_cidr = "10.244.0.0/16"
node_port = 30080
target_port = 80
}
}