93 lines
3.3 KiB
Bash
Executable File
93 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# MetalLB — makes `Service type: LoadBalancer` actually get an address.
|
|
# The pool is derived from the kind Docker network at install time.
|
|
# Notes: docs/notes/addons.md
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
source ./lib/config.sh
|
|
load_config
|
|
|
|
K="kubectl --context ${KUBECONTEXT}"
|
|
|
|
# ── work out an address range ──────────────────────────────────────────────
|
|
# kind hands node addresses out from the bottom of the subnet, so the top is
|
|
# free. Taking a slice there avoids collisions with current and future nodes.
|
|
subnet=$(docker network inspect kind \
|
|
-f '{{range .IPAM.Config}}{{.Subnet}} {{end}}' 2>/dev/null \
|
|
| tr ' ' '\n' | grep -E '^[0-9]+\.' | head -1)
|
|
|
|
if [ -z "$subnet" ]; then
|
|
echo " ! could not read the kind Docker network subnet" >&2
|
|
echo " (is the cluster up? MetalLB needs the network to exist first)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
base="${subnet%/*}"; prefix="${subnet#*/}"
|
|
o1=$(echo "$base" | cut -d. -f1); o2=$(echo "$base" | cut -d. -f2)
|
|
o3=$(echo "$base" | cut -d. -f3)
|
|
|
|
case "$prefix" in
|
|
16) pool_start="${o1}.${o2}.255.200"; pool_end="${o1}.${o2}.255.250" ;;
|
|
24) pool_start="${o1}.${o2}.${o3}.200"; pool_end="${o1}.${o2}.${o3}.250" ;;
|
|
*)
|
|
# Guessing a range inside an unexpected prefix risks handing out
|
|
# addresses that belong to something else. Say so instead.
|
|
echo " ! kind network is $subnet — only /16 and /24 are handled" >&2
|
|
echo " set the pool by hand in ctrl/addons/metallb.sh" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo " kind network $subnet → pool ${pool_start}-${pool_end}"
|
|
|
|
# ── install ────────────────────────────────────────────────────────────────
|
|
|
|
if $K get deployment -n metallb-system controller >/dev/null 2>&1; then
|
|
echo " already installed"
|
|
else
|
|
$K apply -f "https://raw.githubusercontent.com/metallb/metallb/${METALLB_VERSION}/config/manifests/metallb-native.yaml"
|
|
fi
|
|
|
|
# `rollout status`, not `kubectl wait`: wait errors out while the pod doesn't exist yet.
|
|
echo " waiting for the controller..."
|
|
$K rollout status deployment/controller -n metallb-system --timeout=240s
|
|
$K rollout status daemonset/speaker -n metallb-system --timeout=240s
|
|
|
|
# The webhook rejects IPAddressPools until it is actually serving, and it comes
|
|
# up a moment after the pod is Ready — so retry rather than fail the whole run
|
|
# on a race that resolves itself in seconds.
|
|
echo " configuring the address pool"
|
|
for attempt in 1 2 3 4 5 6 7 8 9 10; do
|
|
if $K apply -f - >/dev/null 2>&1 <<YAML
|
|
apiVersion: metallb.io/v1beta1
|
|
kind: IPAddressPool
|
|
metadata:
|
|
name: default
|
|
namespace: metallb-system
|
|
spec:
|
|
addresses:
|
|
- ${pool_start}-${pool_end}
|
|
---
|
|
# Layer 2 mode: one node answers ARP for each address. No BGP peer needed, which
|
|
# is what makes this work on a laptop.
|
|
apiVersion: metallb.io/v1beta1
|
|
kind: L2Advertisement
|
|
metadata:
|
|
name: default
|
|
namespace: metallb-system
|
|
spec:
|
|
ipAddressPools:
|
|
- default
|
|
YAML
|
|
then
|
|
echo " pool ready: ${pool_start}-${pool_end}"
|
|
exit 0
|
|
fi
|
|
sleep 3
|
|
done
|
|
|
|
echo " ! the pool was rejected after 10 attempts — is the webhook up?" >&2
|
|
$K get pods -n metallb-system >&2
|
|
exit 1
|