125 lines
4.5 KiB
Bash
125 lines
4.5 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
[ -r "./env-k0s" ] && . ./env-k0s
|
|
|
|
K0S_VERSION="${K0S_VERSION:-1.35.3+k0s.0}"
|
|
K0S_ROLE="${K0S_ROLE:-controller+worker}"
|
|
K0S_DATA_DIR="${K0S_DATA_DIR:-/var/lib/k0s}"
|
|
K0S_DISABLE_IPV6="${K0S_DISABLE_IPV6:-true}"
|
|
K0S_CLUSTER_NAME="${K0S_CLUSTER_NAME:-k0s}"
|
|
K0S_DISABLE_KUBE_PROXY="${K0S_DISABLE_KUBE_PROXY:-true}"
|
|
K0S_STORAGE_BACKEND="${K0S_STORAGE_BACKEND:-dqlite}"
|
|
K0S_KINE_DIR="${K0S_KINE_DIR:-}"
|
|
|
|
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/' -e 's/armv7l/arm/')"
|
|
K0S_TAG="v${K0S_VERSION}"
|
|
K0S_BINARY_URL="https://github.com/k0sproject/k0s/releases/download/${K0S_TAG}/k0s-${K0S_TAG}-${ARCH}"
|
|
|
|
CMD_TASK="${1:-install}"
|
|
|
|
echo "=== k0s: checking prerequisites (cmd=${CMD_TASK}) ==="
|
|
|
|
if [ "${CMD_TASK}" = "reinstall" ]; then
|
|
echo "=== k0s: reinstall — stopping and resetting cluster ==="
|
|
systemctl stop k0scontroller 2>/dev/null || true
|
|
k0s reset --data-dir "${K0S_DATA_DIR}" 2>/dev/null || true
|
|
systemctl daemon-reload
|
|
echo "=== k0s: cluster reset complete, proceeding with fresh install ==="
|
|
elif k0s version 2>/dev/null | grep -q "${K0S_VERSION}"; then
|
|
if systemctl is-active --quiet k0scontroller 2>/dev/null; then
|
|
echo "=== k0s: v${K0S_VERSION} already running — skipping install ==="
|
|
exit 0
|
|
fi
|
|
# Service stopped but binary present: run reset to clean partial state before reinstall
|
|
echo "=== k0s: binary present but service stopped — cleaning state ==="
|
|
systemctl stop k0scontroller 2>/dev/null || true
|
|
k0s reset --data-dir "${K0S_DATA_DIR}" 2>/dev/null || true
|
|
systemctl daemon-reload
|
|
fi
|
|
|
|
echo "=== k0s: installing v${K0S_VERSION} (${ARCH}, role=${K0S_ROLE}) ==="
|
|
|
|
# Disable IPv6 before k0s starts — avoids dual-stack complexity
|
|
if [ "${K0S_DISABLE_IPV6}" = "true" ]; then
|
|
echo "=== k0s: disabling IPv6 ==="
|
|
sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
|
sysctl -w net.ipv6.conf.default.disable_ipv6=1
|
|
sysctl -w net.ipv6.conf.lo.disable_ipv6=1
|
|
|
|
if ! grep -q "net.ipv6.conf.all.disable_ipv6" /etc/sysctl.d/99-k0s.conf 2>/dev/null; then
|
|
cat > /etc/sysctl.d/99-k0s.conf <<'EOF'
|
|
net.ipv6.conf.all.disable_ipv6=1
|
|
net.ipv6.conf.default.disable_ipv6=1
|
|
net.ipv6.conf.lo.disable_ipv6=1
|
|
EOF
|
|
fi
|
|
fi
|
|
|
|
# Download and install k0s binary
|
|
curl -sSfL "${K0S_BINARY_URL}" -o /usr/local/bin/k0s
|
|
chmod 0755 /usr/local/bin/k0s
|
|
|
|
echo "=== k0s: version $(k0s version) installed ==="
|
|
|
|
KINE_DIR="${K0S_KINE_DIR:-${K0S_DATA_DIR}/kine}"
|
|
mkdir -p /etc/k0s "${K0S_DATA_DIR}" "${KINE_DIR}"
|
|
if [ -f ./templates/k0s.yaml ]; then
|
|
cp ./templates/k0s.yaml /etc/k0s/k0s.yaml
|
|
echo "=== k0s: config deployed from bundle ==="
|
|
elif [ ! -f /etc/k0s/k0s.yaml ]; then
|
|
echo "ERROR: /etc/k0s/k0s.yaml not found and templates/k0s.yaml not in bundle" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "=== k0s: config at /etc/k0s/k0s.yaml (storage=${K0S_STORAGE_BACKEND}, kubeProxy.disabled=${K0S_DISABLE_KUBE_PROXY}) ==="
|
|
|
|
# Install as systemd service
|
|
echo "=== k0s: installing systemd service (role=${K0S_ROLE}) ==="
|
|
k0s install controller \
|
|
--enable-worker \
|
|
--config /etc/k0s/k0s.yaml \
|
|
--data-dir "${K0S_DATA_DIR}"
|
|
|
|
echo "=== k0s: starting service ==="
|
|
k0s start
|
|
|
|
echo "=== k0s: waiting for API server ==="
|
|
RETRIES=30
|
|
for i in $(seq 1 ${RETRIES}); do
|
|
if k0s kubectl get nodes --no-headers 2>/dev/null | grep -q "Ready"; then
|
|
echo "=== k0s: node Ready ==="
|
|
break
|
|
fi
|
|
if [ "${i}" -eq "${RETRIES}" ]; then
|
|
echo "ERROR: k0s node did not reach Ready after ${RETRIES} attempts" >&2
|
|
exit 1
|
|
fi
|
|
sleep 10
|
|
done
|
|
|
|
# Single-node (controller+worker): remove control-plane taint so workloads can schedule
|
|
if [ "${K0S_ROLE}" = "controller_worker" ] || [ "${K0S_ROLE}" = "controller+worker" ]; then
|
|
NODE_NAME="$(k0s kubectl get nodes --no-headers -o custom-columns=':metadata.name' | head -1)"
|
|
if [ -n "${NODE_NAME}" ]; then
|
|
k0s kubectl taint nodes "${NODE_NAME}" node-role.kubernetes.io/control-plane:NoSchedule- 2>/dev/null || true
|
|
echo "=== k0s: removed control-plane taint from ${NODE_NAME} ==="
|
|
fi
|
|
fi
|
|
|
|
# Symlink kubelet paths for CSI drivers that expect /var/lib/kubelet/
|
|
if [ "${K0S_DATA_DIR}" != "/var/lib/k0s" ]; then
|
|
mkdir -p /var/lib/kubelet
|
|
for subdir in plugins_registry plugins pods; do
|
|
[ -d "${K0S_DATA_DIR}/kubelet/${subdir}" ] && \
|
|
ln -sfn "${K0S_DATA_DIR}/kubelet/${subdir}" "/var/lib/kubelet/${subdir}" 2>/dev/null || true
|
|
done
|
|
echo "=== k0s: kubelet symlinks created for CSI compatibility ==="
|
|
fi
|
|
|
|
# Export kubeconfig to standard location
|
|
mkdir -p /root/.kube
|
|
k0s kubeconfig admin > /root/.kube/config
|
|
chmod 600 /root/.kube/config
|
|
|
|
echo "=== k0s: ready (version=v${K0S_VERSION}, cluster=${K0S_CLUSTER_NAME}, data_dir=${K0S_DATA_DIR}) ==="
|