CI / test (push) Failing after 30m3s
Found by a three-machine install on fresh VMs. The second standby's run asked for the floating address's interface with `ip route get <vip>`. The machine already held the address, so that answered lo, and keepalived would not start. The interface now comes from the route to the address's network. Every cluster's VRRP router id was 51, so the PoC's two control planes and the new three on one LAN each logged the other's adverts as an invalid password; the id now comes from the address. The Caddyfile, deploy/ha and install.md send clients to the control plane whose /leader is 200, not /ready: /ready is 503 on a leader with no model yet and would take the portal away with it. Setup no longer hides a key file's path as if it were a password, and the starter's text no longer says it runs elsewhere when this machine is a node. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
68 lines
2.2 KiB
Plaintext
68 lines
2.2 KiB
Plaintext
# A floating address for two control planes.
|
|
#
|
|
# One IP that lives on whichever machine is up. Clients and the reverse proxy
|
|
# in front of llmgw point at the address, not at either host, so a failover is
|
|
# invisible to them.
|
|
#
|
|
# This is not a load balancer: all traffic goes to the holder. That is usually
|
|
# the right trade for a control plane, which serves far less than the nodes
|
|
# it schedules.
|
|
#
|
|
# Copy to /etc/keepalived/keepalived.conf on both machines, changing state,
|
|
# priority and interface.
|
|
|
|
global_defs {
|
|
enable_script_security
|
|
script_user nobody
|
|
}
|
|
|
|
# The address moves only while llmgw can actually serve, not merely while the
|
|
# machine is powered on.
|
|
#
|
|
# /ready, not /health. /health is 200 on a standby, which is up, answering and
|
|
# holding no endpoints at all — so the address would sit on a host that refuses
|
|
# every request. /ready is 200 only when there is somewhere to send one.
|
|
#
|
|
# Not the admin port either: it serves pprof, which can dump the heap that
|
|
# holds every API key.
|
|
vrrp_script check_llmgw {
|
|
script "/usr/bin/curl -fsS --max-time 2 -o /dev/null http://127.0.0.1:8080/ready"
|
|
interval 2
|
|
timeout 3
|
|
# Two failures before giving up the address, so one slow moment does not
|
|
# move it. Two successes before taking it back, so a flapping gateway does
|
|
# not drag the address with it.
|
|
fall 2
|
|
rise 2
|
|
weight -40
|
|
}
|
|
|
|
vrrp_instance llmgw {
|
|
# MASTER on the machine you would rather serve; BACKUP on the other.
|
|
state MASTER
|
|
interface eth0
|
|
# Any number both machines agree on and nothing else on the segment uses:
|
|
# another cluster's keepalived with the same one reads as an invalid
|
|
# password. `llmgw server add --vip` derives one from the address.
|
|
virtual_router_id 51
|
|
# The higher one wins while both are healthy. The weight above is enough
|
|
# to invert this when the preferred machine's gateway is not answering.
|
|
priority 100
|
|
advert_int 1
|
|
|
|
authentication {
|
|
auth_type PASS
|
|
# Change this. It stops another host on the segment claiming the
|
|
# address, which is otherwise a single unicast packet away.
|
|
auth_pass CHANGEME
|
|
}
|
|
|
|
virtual_ipaddress {
|
|
10.0.0.150/24
|
|
}
|
|
|
|
track_script {
|
|
check_llmgw
|
|
}
|
|
}
|