Add Tailscale bootstrap for Pimox workers
This commit is contained in:
parent
a2ef9b7627
commit
df5702de34
22
README.md
22
README.md
|
|
@ -187,6 +187,24 @@ worker index `1` and VMID `9010` when `LAB_PIMOX_WORKER_COUNT=1`. Set
|
||||||
must be left untouched, or set `LAB_PIMOX_WORKER_COUNT=2` to manage both VMID
|
must be left untouched, or set `LAB_PIMOX_WORKER_COUNT=2` to manage both VMID
|
||||||
`9010` and VMID `9011`.
|
`9010` and VMID `9011`.
|
||||||
|
|
||||||
|
Pimox workers can join the tailnet during cluster worker bootstrap. Keep the
|
||||||
|
ephemeral or pre-authorized auth key outside Git, either in
|
||||||
|
`~/.config/homelab/tailscale-pimox-worker.authkey` on the Debian host or in
|
||||||
|
`LAB_PIMOX_WORKER_TAILSCALE_AUTH_KEY`. Then run the cluster pipeline with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LAB_PIMOX_WORKER_TAILSCALE_ENABLED=true ./jeannie up
|
||||||
|
```
|
||||||
|
|
||||||
|
Worker Tailscale defaults to `--accept-routes=true` and enables pod egress SNAT
|
||||||
|
from the Kubernetes pod CIDR to `tailscale0`, so pods on Pimox workers can reach
|
||||||
|
tailnet-only services. Override with
|
||||||
|
`LAB_PIMOX_WORKER_TAILSCALE_ACCEPT_ROUTES=false` or
|
||||||
|
`LAB_PIMOX_WORKER_TAILSCALE_POD_EGRESS_SNAT=false` when that behavior is not
|
||||||
|
wanted. `./jeannie doctor-cluster` checks Pimox worker tailnet egress
|
||||||
|
against `${LAB_PIMOX_WORKER_TAILNET_PROBE_HOST:-LAB_DEBIAN_TAILSCALE_IP}` and
|
||||||
|
`${LAB_PIMOX_WORKER_TAILNET_PROBE_PORT:-LAB_GITEA_HTTP_PORT}`.
|
||||||
|
|
||||||
OpenWrt firewall VM automation is available as a standalone command because it
|
OpenWrt firewall VM automation is available as a standalone command because it
|
||||||
attaches to both WAN and LAN bridges. Run `./jeannie openwrt` after `vmbr1`
|
attaches to both WAN and LAN bridges. Run `./jeannie openwrt` after `vmbr1`
|
||||||
already exists on the Orange Pi. The pipeline downloads the OpenWrt ARM
|
already exists on the Orange Pi. The pipeline downloads the OpenWrt ARM
|
||||||
|
|
@ -456,6 +474,10 @@ next step:
|
||||||
./jeannie doctor-cluster
|
./jeannie doctor-cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`doctor-cluster` also checks whether Pimox workers have Tailscale installed,
|
||||||
|
`tailscaled` active, a Tailscale IP, and TCP egress to the configured tailnet
|
||||||
|
probe service.
|
||||||
|
|
||||||
## RPi Services
|
## RPi Services
|
||||||
|
|
||||||
The Raspberry Pi runs lightweight always-on services outside Kubernetes from
|
The Raspberry Pi runs lightweight always-on services outside Kubernetes from
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,24 @@ worker index `1` and VMID `9010` when `LAB_PIMOX_WORKER_COUNT=1`. Set
|
||||||
must be left untouched, or set `LAB_PIMOX_WORKER_COUNT=2` to manage both VMID
|
must be left untouched, or set `LAB_PIMOX_WORKER_COUNT=2` to manage both VMID
|
||||||
`9010` and VMID `9011`.
|
`9010` and VMID `9011`.
|
||||||
|
|
||||||
|
Pimox workers can join the tailnet during cluster worker bootstrap. Keep the
|
||||||
|
ephemeral or pre-authorized auth key outside Git, either in
|
||||||
|
`~/.config/homelab/tailscale-pimox-worker.authkey` on the Debian host or in
|
||||||
|
`LAB_PIMOX_WORKER_TAILSCALE_AUTH_KEY`. Then run the cluster pipeline with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LAB_PIMOX_WORKER_TAILSCALE_ENABLED=true ./{{ main_script }} up
|
||||||
|
```
|
||||||
|
|
||||||
|
Worker Tailscale defaults to `--accept-routes=true` and enables pod egress SNAT
|
||||||
|
from the Kubernetes pod CIDR to `tailscale0`, so pods on Pimox workers can reach
|
||||||
|
tailnet-only services. Override with
|
||||||
|
`LAB_PIMOX_WORKER_TAILSCALE_ACCEPT_ROUTES=false` or
|
||||||
|
`LAB_PIMOX_WORKER_TAILSCALE_POD_EGRESS_SNAT=false` when that behavior is not
|
||||||
|
wanted. `./{{ main_script }} doctor-cluster` checks Pimox worker tailnet egress
|
||||||
|
against `${LAB_PIMOX_WORKER_TAILNET_PROBE_HOST:-LAB_DEBIAN_TAILSCALE_IP}` and
|
||||||
|
`${LAB_PIMOX_WORKER_TAILNET_PROBE_PORT:-LAB_GITEA_HTTP_PORT}`.
|
||||||
|
|
||||||
OpenWrt firewall VM automation is available as a standalone command because it
|
OpenWrt firewall VM automation is available as a standalone command because it
|
||||||
attaches to both WAN and LAN bridges. Run `./{{ main_script }} openwrt` after `vmbr1`
|
attaches to both WAN and LAN bridges. Run `./{{ main_script }} openwrt` after `vmbr1`
|
||||||
already exists on the Orange Pi. The pipeline downloads the OpenWrt ARM
|
already exists on the Orange Pi. The pipeline downloads the OpenWrt ARM
|
||||||
|
|
@ -456,6 +474,10 @@ next step:
|
||||||
./{{ main_script }} doctor-cluster
|
./{{ main_script }} doctor-cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`doctor-cluster` also checks whether Pimox workers have Tailscale installed,
|
||||||
|
`tailscaled` active, a Tailscale IP, and TCP egress to the configured tailnet
|
||||||
|
probe service.
|
||||||
|
|
||||||
## RPi Services
|
## RPi Services
|
||||||
|
|
||||||
The Raspberry Pi runs lightweight always-on services outside Kubernetes from
|
The Raspberry Pi runs lightweight always-on services outside Kubernetes from
|
||||||
|
|
|
||||||
|
|
@ -415,6 +415,10 @@ resource "null_resource" "kubeadm_worker" {
|
||||||
worker_rejoin_reset_version = "2"
|
worker_rejoin_reset_version = "2"
|
||||||
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)
|
||||||
|
worker_tailscale_version = "1"
|
||||||
|
worker_tailscale_enabled = tostring(var.worker_tailscale_enabled)
|
||||||
|
worker_tailscale_accept_routes = tostring(var.worker_tailscale_accept_routes)
|
||||||
|
worker_tailscale_pod_egress_snat = tostring(var.worker_tailscale_pod_egress_snat)
|
||||||
tailscale_nodeport_version = "3"
|
tailscale_nodeport_version = "3"
|
||||||
tailscale_nodeport_enabled = var.tailscale_nodeport_access.enabled && each.key == var.tailscale_nodeport_access.worker_key ? "true" : "false"
|
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_peer_ip = var.tailscale_nodeport_access.peer_ip
|
||||||
|
|
@ -478,6 +482,84 @@ DOCKER_SOURCES
|
||||||
sudo apt-mark hold containerd.io
|
sudo apt-mark hold containerd.io
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_tailscale() {
|
||||||
|
if [ "${self.triggers.worker_tailscale_enabled}" != "true" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v tailscale >/dev/null 2>&1 && systemctl list-unit-files tailscaled.service >/dev/null 2>&1; then
|
||||||
|
sudo systemctl enable --now tailscaled
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
codename="$(. /etc/os-release && printf '%s' "$${VERSION_CODENAME:-trixie}")"
|
||||||
|
sudo install -d -m 0755 /usr/share/keyrings
|
||||||
|
curl -fsSL "https://pkgs.tailscale.com/stable/debian/$${codename}.noarmor.gpg" |
|
||||||
|
sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
|
||||||
|
curl -fsSL "https://pkgs.tailscale.com/stable/debian/$${codename}.tailscale-keyring.list" |
|
||||||
|
sudo tee /etc/apt/sources.list.d/tailscale.list >/dev/null
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends tailscale
|
||||||
|
sudo systemctl enable --now tailscaled
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_tailscale_pod_egress_snat() {
|
||||||
|
local enabled="$1"
|
||||||
|
local pod_cidr="$2"
|
||||||
|
|
||||||
|
if [ "${self.triggers.worker_tailscale_enabled}" != "true" ] || [ "$enabled" != "true" ]; then
|
||||||
|
sudo systemctl disable --now homelab-tailscale-pod-egress.service >/dev/null 2>&1 || true
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo mkdir -p /usr/local/sbin /etc/sysctl.d
|
||||||
|
sudo tee /etc/sysctl.d/98-homelab-tailscale-pod-egress.conf >/dev/null <<POD_EGRESS_SYSCTL_EOT
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
|
net.ipv4.conf.all.rp_filter = 0
|
||||||
|
net.ipv4.conf.tailscale0.rp_filter = 0
|
||||||
|
POD_EGRESS_SYSCTL_EOT
|
||||||
|
|
||||||
|
sudo tee /usr/local/sbin/homelab-tailscale-pod-egress.sh >/dev/null <<POD_EGRESS_SCRIPT_EOT
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
sysctl -w net.ipv4.ip_forward=1 >/dev/null
|
||||||
|
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 pod egress SNAT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
iptables -C FORWARD -s "$pod_cidr" -o tailscale0 -j ACCEPT 2>/dev/null ||
|
||||||
|
iptables -I FORWARD 1 -s "$pod_cidr" -o tailscale0 -j ACCEPT
|
||||||
|
iptables -C FORWARD -i tailscale0 -d "$pod_cidr" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null ||
|
||||||
|
iptables -I FORWARD 1 -i tailscale0 -d "$pod_cidr" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -t nat -C POSTROUTING -s "$pod_cidr" -o tailscale0 -m comment --comment homelab-tailscale-pod-egress -j MASQUERADE 2>/dev/null ||
|
||||||
|
iptables -t nat -A POSTROUTING -s "$pod_cidr" -o tailscale0 -m comment --comment homelab-tailscale-pod-egress -j MASQUERADE
|
||||||
|
POD_EGRESS_SCRIPT_EOT
|
||||||
|
sudo chmod 0755 /usr/local/sbin/homelab-tailscale-pod-egress.sh
|
||||||
|
|
||||||
|
sudo tee /etc/systemd/system/homelab-tailscale-pod-egress.service >/dev/null <<'POD_EGRESS_SERVICE_EOT'
|
||||||
|
[Unit]
|
||||||
|
Description=Homelab Tailscale pod egress SNAT
|
||||||
|
After=network-online.target tailscaled.service kubelet.service
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/sbin/homelab-tailscale-pod-egress.sh
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
POD_EGRESS_SERVICE_EOT
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable homelab-tailscale-pod-egress.service >/dev/null
|
||||||
|
sudo systemctl restart homelab-tailscale-pod-egress.service
|
||||||
|
}
|
||||||
|
|
||||||
configure_node_dns() {
|
configure_node_dns() {
|
||||||
dns_servers="${self.triggers.node_dns_servers}"
|
dns_servers="${self.triggers.node_dns_servers}"
|
||||||
if [ -z "$dns_servers" ]; then
|
if [ -z "$dns_servers" ]; then
|
||||||
|
|
@ -705,6 +787,7 @@ REGISTRY_EOT
|
||||||
configure_node_dns
|
configure_node_dns
|
||||||
install_missing_packages ca-certificates curl gpg apt-transport-https containernetworking-plugins open-iscsi nfs-common
|
install_missing_packages ca-certificates curl gpg apt-transport-https containernetworking-plugins open-iscsi nfs-common
|
||||||
install_containerd_runtime
|
install_containerd_runtime
|
||||||
|
install_tailscale
|
||||||
install_cni_plugins
|
install_cni_plugins
|
||||||
sudo systemctl enable --now iscsid
|
sudo systemctl enable --now iscsid
|
||||||
sudo systemctl enable kubelet || true
|
sudo systemctl enable kubelet || true
|
||||||
|
|
@ -739,6 +822,10 @@ 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_pod_egress_snat \
|
||||||
|
"${self.triggers.worker_tailscale_pod_egress_snat}" \
|
||||||
|
"${self.triggers.tailscale_nodeport_pod_cidr}"
|
||||||
|
|
||||||
configure_tailscale_nodeport_access() {
|
configure_tailscale_nodeport_access() {
|
||||||
local enabled="$1"
|
local enabled="$1"
|
||||||
local peer_ip="$2"
|
local peer_ip="$2"
|
||||||
|
|
@ -887,6 +974,52 @@ EOT
|
||||||
command = <<EOT
|
command = <<EOT
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ '${self.triggers.worker_tailscale_enabled}' != 'true' ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh_target='${self.triggers.user}@${self.triggers.host}'
|
||||||
|
ssh_key='${self.triggers.ssh_key_path}'
|
||||||
|
node_name='${self.triggers.node_name}'
|
||||||
|
accept_routes='${self.triggers.worker_tailscale_accept_routes}'
|
||||||
|
|
||||||
|
if ! ssh -i "$ssh_key" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$ssh_target" \
|
||||||
|
'command -v tailscale >/dev/null 2>&1 && sudo systemctl is-active --quiet tailscaled'; then
|
||||||
|
echo "tailscale is not installed or tailscaled is not active on $ssh_target" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ssh -i "$ssh_key" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$ssh_target" \
|
||||||
|
'tailscale status --json >/dev/null 2>&1'; then
|
||||||
|
ssh -i "$ssh_key" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$ssh_target" \
|
||||||
|
"sudo tailscale set --accept-routes=$accept_routes"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
auth_key="$${LAB_PIMOX_WORKER_TAILSCALE_AUTH_KEY:-}"
|
||||||
|
auth_key_file="$${LAB_PIMOX_WORKER_TAILSCALE_AUTH_KEY_FILE:-$${HOME}/.config/homelab/tailscale-pimox-worker.authkey}"
|
||||||
|
if [ -z "$auth_key" ] && [ -s "$auth_key_file" ]; then
|
||||||
|
auth_key="$(tr -d '\n\r' <"$auth_key_file")"
|
||||||
|
fi
|
||||||
|
if [ -z "$auth_key" ]; then
|
||||||
|
echo "Pimox worker Tailscale is enabled, but no auth key was provided." >&2
|
||||||
|
echo "Set LAB_PIMOX_WORKER_TAILSCALE_AUTH_KEY or create $auth_key_file outside Git." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "$auth_key" |
|
||||||
|
ssh -i "$ssh_key" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$ssh_target" \
|
||||||
|
"read -r auth_key && sudo tailscale up --auth-key \"\$auth_key\" --hostname '$node_name' --accept-routes=$accept_routes --reset"
|
||||||
|
|
||||||
|
ssh -i "$ssh_key" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$ssh_target" \
|
||||||
|
'sudo systemctl restart homelab-tailscale-pod-egress.service 2>/dev/null || true'
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "local-exec" {
|
||||||
|
command = <<EOT
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
ssh_target='${self.triggers.user}@${self.triggers.host}'
|
ssh_target='${self.triggers.user}@${self.triggers.host}'
|
||||||
ssh_key='${self.triggers.ssh_key_path}'
|
ssh_key='${self.triggers.ssh_key_path}'
|
||||||
node_name='${self.triggers.node_name}'
|
node_name='${self.triggers.node_name}'
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,21 @@ variable "force_worker_rejoin" {
|
||||||
default = false
|
default = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "worker_tailscale_enabled" {
|
||||||
|
type = bool
|
||||||
|
default = false
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "worker_tailscale_accept_routes" {
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "worker_tailscale_pod_egress_snat" {
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "tailscale_nodeport_access" {
|
variable "tailscale_nodeport_access" {
|
||||||
type = object({
|
type = object({
|
||||||
enabled = bool
|
enabled = bool
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,8 @@ health.
|
||||||
Uptime Kuma, and Docker root state.
|
Uptime Kuma, and Docker root state.
|
||||||
|
|
||||||
`doctor-cluster`
|
`doctor-cluster`
|
||||||
: Diagnose Kubernetes API, nodes, core pods, MetalLB, Traefik, and app health.
|
: Diagnose Kubernetes API, nodes, core pods, MetalLB, Traefik, app health, and
|
||||||
|
Pimox worker tailnet egress.
|
||||||
|
|
||||||
`inventory-check`
|
`inventory-check`
|
||||||
: Validate `homelab.yml` with a real YAML parser when available.
|
: Validate `homelab.yml` with a real YAML parser when available.
|
||||||
|
|
|
||||||
52
jeannie
52
jeannie
|
|
@ -196,6 +196,9 @@ export_homelab_inventory_tf_vars() {
|
||||||
export_if_unset TF_VAR_gitea_backend_host "${LAB_DEBIAN_TAILSCALE_IP:-}"
|
export_if_unset TF_VAR_gitea_backend_host "${LAB_DEBIAN_TAILSCALE_IP:-}"
|
||||||
export_if_unset TF_VAR_gitea_backend_port "${LAB_GITEA_HTTP_PORT:-}"
|
export_if_unset TF_VAR_gitea_backend_port "${LAB_GITEA_HTTP_PORT:-}"
|
||||||
export_if_unset TF_VAR_gitops_repo_url "${LAB_GITOPS_REPO_URL:-}"
|
export_if_unset TF_VAR_gitops_repo_url "${LAB_GITOPS_REPO_URL:-}"
|
||||||
|
export_if_unset TF_VAR_worker_tailscale_enabled "${LAB_PIMOX_WORKER_TAILSCALE_ENABLED:-}"
|
||||||
|
export_if_unset TF_VAR_worker_tailscale_accept_routes "${LAB_PIMOX_WORKER_TAILSCALE_ACCEPT_ROUTES:-}"
|
||||||
|
export_if_unset TF_VAR_worker_tailscale_pod_egress_snat "${LAB_PIMOX_WORKER_TAILSCALE_POD_EGRESS_SNAT:-}"
|
||||||
}
|
}
|
||||||
|
|
||||||
export_homelab_inventory_tf_vars
|
export_homelab_inventory_tf_vars
|
||||||
|
|
@ -4607,6 +4610,53 @@ status_run() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_pimox_worker_tailnet_egress() {
|
||||||
|
local spec_file="${REPO_ROOT}/.lab/pimox-workers.tsv"
|
||||||
|
local probe_host="${LAB_PIMOX_WORKER_TAILNET_PROBE_HOST:-${LAB_DEBIAN_TAILSCALE_IP:-}}"
|
||||||
|
local probe_port="${LAB_PIMOX_WORKER_TAILNET_PROBE_PORT:-${LAB_GITEA_HTTP_PORT:-3000}}"
|
||||||
|
local failures=0
|
||||||
|
local found=0
|
||||||
|
local worker_key
|
||||||
|
local host
|
||||||
|
local user
|
||||||
|
local node_name
|
||||||
|
local key_path
|
||||||
|
|
||||||
|
if [[ ! -s "${spec_file}" ]]; then
|
||||||
|
echo "No Pimox worker spec found at ${spec_file}; run ./jeannie up or set LAB_CLUSTER_VAR_FILE."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ -z "${probe_host}" ]]; then
|
||||||
|
echo "No tailnet probe host configured; set LAB_PIMOX_WORKER_TAILNET_PROBE_HOST or LAB_DEBIAN_TAILSCALE_IP."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r worker_key host user node_name key_path; do
|
||||||
|
[[ -n "${worker_key}" && -n "${host}" && -n "${user}" && -n "${node_name}" && -n "${key_path}" ]] || continue
|
||||||
|
found=1
|
||||||
|
printf '%-28s ' "${node_name}"
|
||||||
|
if ssh -n -i "${key_path}" -o BatchMode=yes -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new "${user}@${host}" "
|
||||||
|
set -eu
|
||||||
|
command -v tailscale >/dev/null
|
||||||
|
sudo systemctl is-active --quiet tailscaled
|
||||||
|
tailscale ip -4 >/dev/null
|
||||||
|
timeout 6 bash -c 'exec 3<>/dev/tcp/${probe_host}/${probe_port}'
|
||||||
|
" >/dev/null 2>&1; then
|
||||||
|
printf 'ok - %s:%s reachable over tailnet\n' "${probe_host}" "${probe_port}"
|
||||||
|
else
|
||||||
|
printf 'fail - cannot reach %s:%s over tailnet\n' "${probe_host}" "${probe_port}"
|
||||||
|
failures=$((failures + 1))
|
||||||
|
fi
|
||||||
|
done <"${spec_file}"
|
||||||
|
|
||||||
|
if ((found == 0)); then
|
||||||
|
echo "No Pimox workers were listed in ${spec_file}."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
((failures == 0))
|
||||||
|
}
|
||||||
|
|
||||||
status_http() {
|
status_http() {
|
||||||
local name="$1"
|
local name="$1"
|
||||||
local url="$2"
|
local url="$2"
|
||||||
|
|
@ -5455,6 +5505,7 @@ doctor_cluster() {
|
||||||
status_systemd_units kubelet containerd docker
|
status_systemd_units kubelet containerd docker
|
||||||
status_kubernetes
|
status_kubernetes
|
||||||
status_pimox_workers
|
status_pimox_workers
|
||||||
|
status_run "pimox worker tailnet egress" check_pimox_worker_tailnet_egress
|
||||||
status_http "traefik lb" "http://${LAB_TRAEFIK_LB_IP:?LAB_TRAEFIK_LB_IP is required from homelab.yml}/"
|
status_http "traefik lb" "http://${LAB_TRAEFIK_LB_IP:?LAB_TRAEFIK_LB_IP is required from homelab.yml}/"
|
||||||
|
|
||||||
printf '\n-- local CRI containers\n'
|
printf '\n-- local CRI containers\n'
|
||||||
|
|
@ -5480,6 +5531,7 @@ Kubeconfig path: ${KUBECONFIG_PATH}
|
||||||
Traefik LoadBalancer IP: ${LAB_TRAEFIK_LB_IP:?LAB_TRAEFIK_LB_IP is required from homelab.yml}
|
Traefik LoadBalancer IP: ${LAB_TRAEFIK_LB_IP:?LAB_TRAEFIK_LB_IP is required from homelab.yml}
|
||||||
Pimox host: ${LAB_PIMOX_USER:-${TF_VAR_pimox_user:-jv}}@${LAB_PIMOX_HOST:-${TF_VAR_pimox_host:-192.168.100.80}}
|
Pimox host: ${LAB_PIMOX_USER:-${TF_VAR_pimox_user:-jv}}@${LAB_PIMOX_HOST:-${TF_VAR_pimox_host:-192.168.100.80}}
|
||||||
Worker storage: ${LAB_PIMOX_WORKER_STORAGE:-${TF_VAR_pimox_worker_storage:-opi5_ssd}}
|
Worker storage: ${LAB_PIMOX_WORKER_STORAGE:-${TF_VAR_pimox_worker_storage:-opi5_ssd}}
|
||||||
|
Pimox worker tailnet probe: ${LAB_PIMOX_WORKER_TAILNET_PROBE_HOST:-${LAB_DEBIAN_TAILSCALE_IP:-unset}}:${LAB_PIMOX_WORKER_TAILNET_PROBE_PORT:-${LAB_GITEA_HTTP_PORT:-3000}}
|
||||||
Known runbook: docs/runbooks/cluster-stop-start-failures.md
|
Known runbook: docs/runbooks/cluster-stop-start-failures.md
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue