mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-22 12:16:52 +00:00
8883984f3f
* feat(eks): eks-server + eks-agent AMI manifests + builder INSTALL_FILES
Manifest-driven AMI build for the two EKS image variants (eks-v1.md Q12).
Lifted forward from cs-eks-6b so the K3s boot path can be smoke-tested in
isolation before CreateCluster orchestration lands.
Builder:
- build-system-image.sh gains optional INSTALL_FILES (src:dst pairs,
mode 0644, parent dirs auto-created). Symmetric with INSTALL_BINARIES.
- ENABLE_SERVICES moves after INSTALL_FILES + SETUP_SCRIPT so init scripts
the manifest references are on disk before rc-update enables them.
eks-server image (Alpine 3.21.7, q35, 4G):
- K3s v1.32.5+k3s1 (downloaded at bake time, SHA256 verified against the
upstream sha256sum-amd64.txt trust anchor).
- nats-cli v0.4.0 (not in Alpine main/community — pulled from upstream
release zip; unzip installed + purged in same setup step).
- OpenRC init scripts: k3s, eks-token-webhook, k3s-first-boot.
- Cron periodics under /etc/periodic/{15min,daily}/ for state-report +
etcd-snapshot.
- k3s-first-boot publishes node-token + admin kubeconfig over NATS on
first successful K3s healthz, then self-disables (sentinel + rc-update
del).
- config.yaml.skel without webhook-token-auth — wiring it before the real
webhook lands (cs-eks-6c) would block anonymous probes against /healthz.
Orchestrator drops the live config + restarts k3s.
eks-agent image (Alpine 3.21.7, q35, 2G):
- Same pinned K3s release for server/agent lock-step.
- k3s-agent OpenRC service refuses to start without K3S_URL+K3S_TOKEN —
fail-closed pre-orchestration.
eks-token-webhook stub (cmd/eks-token-webhook/main.go):
- 503 + Retry-After:30 on every path. Statically linked. Lets the AMI
build succeed and kube-apiserver boot cleanly. Replaced wholesale by
cs-eks-6c.
Init system divergence from spec wording: Alpine ships OpenRC, not
systemd. Unit files use .initd extensions and cron periodics instead of
.service / .timer. Bead-level intent (auto-enable on boot, periodic
execution) preserved.
Smoke-tested:
- eks-server: builds 300M qcow2; qemu q35 boot reaches K3s apiserver on
6443 within ~120s; HTTPS probes return valid k8s Status JSON (the 401
is K3s v1.32 default RBAC behaviour against anonymous, not a regression).
- eks-agent: builds 280M qcow2; qemu boot mounts root cleanly.
* feat(eks): make targets for eks-server + eks-agent AMI builds
- build-system-image gains subdir-manifest fallback: tries
scripts/images/$(IMAGE).conf first, then scripts/images/$(IMAGE)/manifest.conf
so the new EKS layout works alongside the existing flat lb manifest.
- build-eks-server-image / build-eks-agent-image — explicit convenience
targets that delegate to the generic one.
92 lines
3.4 KiB
Bash
92 lines
3.4 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
# k3s-first-boot — runs once after the K3s server reaches a healthy state.
|
|
# Reads the bootstrap node-token and admin kubeconfig that K3s writes during
|
|
# `--cluster-init`, rewrites the kubeconfig server address to the cluster's
|
|
# NLB endpoint (so workers and external kubectl can use it), and publishes
|
|
# both as one-shot NATS messages for the spinifex cluster reconciler to
|
|
# consume into KV.
|
|
#
|
|
# Required env (from cloud-init user-data /etc/spinifex-eks/first-boot.env):
|
|
# SPINIFEX_NATS_URL nats://...
|
|
# SPINIFEX_NATS_CREDS_FILE /etc/spinifex-eks/nats.creds
|
|
# EKS_ACCOUNT_ID
|
|
# EKS_CLUSTER_NAME
|
|
# EKS_NLB_ENDPOINT https://{cluster}.{accountID}.eks.{region}.{suffix}
|
|
#
|
|
# Idempotent: a sentinel file at /var/lib/spinifex-eks/first-boot.pending gates
|
|
# execution. On success the sentinel is removed and the OpenRC service is
|
|
# pulled from the default runlevel so it does not retry on subsequent boots.
|
|
|
|
SENTINEL=/var/lib/spinifex-eks/first-boot.pending
|
|
ENVFILE=/etc/spinifex-eks/first-boot.env
|
|
LOGTAG="k3s-first-boot"
|
|
|
|
log() { echo "[${LOGTAG}] $*"; }
|
|
die() { log "ERROR: $*"; exit 1; }
|
|
|
|
if [ ! -f "${SENTINEL}" ]; then
|
|
log "sentinel missing — first boot already complete"
|
|
exit 0
|
|
fi
|
|
|
|
if [ ! -f "${ENVFILE}" ]; then
|
|
die "${ENVFILE} not found — cloud-init did not seed first-boot env"
|
|
fi
|
|
|
|
# shellcheck disable=SC1090
|
|
. "${ENVFILE}"
|
|
|
|
for v in SPINIFEX_NATS_URL EKS_ACCOUNT_ID EKS_CLUSTER_NAME EKS_NLB_ENDPOINT; do
|
|
eval "val=\${$v:-}"
|
|
[ -n "${val}" ] || die "env ${v} not set"
|
|
done
|
|
|
|
# 1. Wait for K3s /healthz. K3s self-signs initially; --insecure-skip is fine
|
|
# here, we are on loopback.
|
|
log "waiting for K3s /healthz on 127.0.0.1:6443"
|
|
i=0
|
|
while [ "${i}" -lt 300 ]; do
|
|
if curl -sk --max-time 2 https://127.0.0.1:6443/healthz | grep -q '^ok$'; then
|
|
log "K3s healthz ok after ${i}s"
|
|
break
|
|
fi
|
|
i=$((i + 2))
|
|
sleep 2
|
|
done
|
|
[ "${i}" -lt 300 ] || die "K3s did not become healthy within 5 minutes"
|
|
|
|
# 2. Read node-token + admin kubeconfig.
|
|
TOKEN_FILE=/var/lib/rancher/k3s/server/node-token
|
|
KUBECONFIG_FILE=/etc/rancher/k3s/k3s.yaml
|
|
[ -r "${TOKEN_FILE}" ] || die "${TOKEN_FILE} unreadable"
|
|
[ -r "${KUBECONFIG_FILE}" ] || die "${KUBECONFIG_FILE} unreadable"
|
|
|
|
NODE_TOKEN=$(cat "${TOKEN_FILE}")
|
|
# K3s ships kubeconfig with server: https://127.0.0.1:6443 — rewrite to the
|
|
# NLB endpoint so it works from outside the control plane VM.
|
|
KUBECONFIG_REWRITTEN=$(sed "s|server: https://127\.0\.0\.1:6443|server: ${EKS_NLB_ENDPOINT}|" "${KUBECONFIG_FILE}")
|
|
|
|
# 3. Publish one-shot NATS messages. Subjects per eks-v1.md Q14 + Q15.
|
|
TOKEN_SUBJ="eks.bus.${EKS_ACCOUNT_ID}.${EKS_CLUSTER_NAME}.k3s-bootstrap-token"
|
|
KUBE_SUBJ="eks.bus.${EKS_ACCOUNT_ID}.${EKS_CLUSTER_NAME}.k3s-admin-kubeconfig"
|
|
|
|
NATS_ARGS="-s ${SPINIFEX_NATS_URL}"
|
|
if [ -n "${SPINIFEX_NATS_CREDS_FILE:-}" ] && [ -f "${SPINIFEX_NATS_CREDS_FILE}" ]; then
|
|
NATS_ARGS="${NATS_ARGS} --creds ${SPINIFEX_NATS_CREDS_FILE}"
|
|
fi
|
|
|
|
log "publishing node-token to ${TOKEN_SUBJ}"
|
|
# shellcheck disable=SC2086
|
|
printf '%s' "${NODE_TOKEN}" | nats ${NATS_ARGS} pub "${TOKEN_SUBJ}" --stdin
|
|
|
|
log "publishing admin kubeconfig to ${KUBE_SUBJ}"
|
|
# shellcheck disable=SC2086
|
|
printf '%s' "${KUBECONFIG_REWRITTEN}" | nats ${NATS_ARGS} pub "${KUBE_SUBJ}" --stdin
|
|
|
|
# 4. Self-disable. Remove sentinel, pull from runlevel.
|
|
rm -f "${SENTINEL}"
|
|
rc-update del k3s-first-boot default 2>/dev/null || true
|
|
log "first boot complete"
|