diff --git a/scripts/ingress-installer.sh b/scripts/ingress-installer.sh index e5131b1..d7417fb 100644 --- a/scripts/ingress-installer.sh +++ b/scripts/ingress-installer.sh @@ -1,23 +1,23 @@ #!/usr/bin/env bash -# gitops/scripts/ingress-installer.sh -# 目标:最小化参数/分支,专注“一键离线安装” +# scripts/ingress-installer.sh +# 目标:一键“离线安装” NGINX Ingress,兼容 K3s 1.29~1.33(containerd) set -euo pipefail # ====================== # Config & Defaults(仅支持环境变量覆盖) # ====================== -: "${NGINX_IC_IMAGE:=nginx/nginx-ingress:2.4.0}" +: "${NGINX_IC_IMAGE:=nginx/nginx-ingress:5.1.1}" : "${CERT_IMG:=registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407}" # 打包阶段写入的 OCI layout 内部引用名(如果你改了打包 ref.name,这里相应改) -: "${OCI_NGINX_REF:=nginx-ingress-2.4.0}" +: "${OCI_NGINX_REF:=nginx-ingress-5.1.1}" : "${OCI_CERT_REF:=kube-webhook-certgen}" # 目录布局固定:charts、images、脚本位于离线包根目录 : "${CHART_DIR:=./charts/nginx-ingress}" : "${NAMESPACE:=ingress}" -: "${OCI_ARCHIVE:=images/oci-archive.tar}" # 优先使用 -: "${DOCKER_IMG_TAR:=images/nginx-ingress.tar}" # 回退(docker save) +: "${OCI_ARCHIVE:=images/oci-archive.tar}" # 优先使用(oci-archive) +: "${DOCKER_IMG_TAR:=images/nginx-ingress.tar}" # 回退(docker-archive) : "${DOCKER_CERT_TAR:=images/kube-webhook-certgen.tar}" : "${NERDCTL_TAR:=nerdctl.tar.gz}" @@ -33,6 +33,57 @@ ok() { echo "✅ $*"; } warn() { echo "⚠️ $*"; } have() { command -v "$1" &>/dev/null; } +# ====================== +# Runtime Detection(K3s / containerd / docker / nerdctl) +# ====================== +NERDCTL_BIN="" +detect_nerdctl() { + # 优先使用离线包内置路径(install_nerdctl 会解到 /usr/local/bin/nerdctl) + if [ -x /usr/local/bin/nerdctl ]; then + NERDCTL_BIN="/usr/local/bin/nerdctl" + elif have nerdctl; then + NERDCTL_BIN="$(command -v nerdctl)" + else + NERDCTL_BIN="" + fi +} +have_nerdctl() { [ -n "${NERDCTL_BIN}" ]; } + +detect_containerd() { + # 优先使用 K3s 的 containerd + if [ -S /run/k3s/containerd/containerd.sock ]; then + CTR_SOCK="/run/k3s/containerd/containerd.sock" + CTR_NS="k8s.io" + if have k3s; then + CTR_BIN="k3s ctr" # 避免系统 ctr 指向其他 containerd + else + CTR_BIN="ctr --address ${CTR_SOCK}" + fi + NERDCTL_ADDR_OPT=(--address "${CTR_SOCK}" --namespace "${CTR_NS}") + return + fi + + # 其次使用系统 containerd + if [ -S /run/containerd/containerd.sock ]; then + CTR_SOCK="/run/containerd/containerd.sock" + CTR_NS="k8s.io" + CTR_BIN="ctr --address ${CTR_SOCK}" + NERDCTL_ADDR_OPT=(--address "${CTR_SOCK}" --namespace "${CTR_NS}") + return + fi + + CTR_SOCK="" +} + +# 统一的 ctr/nerdctl 执行器 +ctr_exec() { + # shellcheck disable=SC2086 + ${CTR_BIN} -n "${CTR_NS}" "$@" +} +nerdctl_exec() { + "${NERDCTL_BIN}" "${NERDCTL_ADDR_OPT[@]}" "$@" +} + # ====================== # Nerdctl Install (wrapper) # ====================== @@ -42,16 +93,26 @@ install_nerdctl() { $SUDO tar xzf "${NERDCTL_TAR}" -C /usr/local/bin/ $SUDO chmod +x /usr/local/bin/nerdctl || true fi + detect_nerdctl + if have_nerdctl; then + log "🧰 nerdctl 就绪:${NERDCTL_BIN}" + else + warn "未检测到 nerdctl,将仅依赖 ctr/docker 执行导入。" + fi } # ====================== -# Import images(优先 OCI,其次 docker save tar) +# Import images(优先 OCI,其次 docker-archive) # ====================== import_images_from_oci() { - # 首选:OCI 归档 + detect_containerd + log "🔌 containerd socket: ${CTR_SOCK:-}" + + # 首选:OCI 归档(oci-archive)—— 标准且最稳 if [ -f "${OCI_ARCHIVE}" ]; then log "📦 从 OCI 归档导入镜像:${OCI_ARCHIVE}" - # A) Docker 环境(需要 skopeo) + + # A) Docker 守护进程(需要 skopeo)—— 可选路径 if have docker && docker info &>/dev/null; then if have skopeo; then skopeo --insecure-policy copy --all "oci-archive:${OCI_ARCHIVE}:${OCI_NGINX_REF}" "docker-daemon:${NGINX_IC_IMAGE}" @@ -59,46 +120,68 @@ import_images_from_oci() { ok "OCI → docker-daemon 导入完成" return else - warn "docker 环境未安装 skopeo,改用 docker-archive 回退(需 images/*.tar)" + warn "docker 环境未安装 skopeo,改用 containerd 路径。" fi fi - # B) containerd 环境(K3s 或系统 containerd) - if [ -S /run/k3s/containerd/containerd.sock ] || [ -S /run/containerd/containerd.sock ]; then - local ns="k8s.io" - $SUDO ctr -n "${ns}" images import --all-platforms "${OCI_ARCHIVE}" - $SUDO ctr -n "${ns}" images tag "${OCI_NGINX_REF}" "${NGINX_IC_IMAGE}" || true - $SUDO ctr -n "${ns}" images tag "${OCI_CERT_REF}" "${CERT_IMG}" || true + + # B) containerd 环境(K3s 或系统 containerd)—— 主路径 + if [ -n "${CTR_SOCK}" ]; then + ctr_exec images import --all-platforms "${OCI_ARCHIVE}" + # 补打期望 tag(让 ctr/nerdctl/k8s 三方都一致) + ctr_exec images tag "${OCI_NGINX_REF}" "${NGINX_IC_IMAGE}" || true + ctr_exec images tag "${OCI_CERT_REF}" "${CERT_IMG}" || true + + # 若 nerdctl 可用,再用 nerdctl 做一次 tag(有助于命令行一致性) + if have_nerdctl; then + nerdctl_exec tag "${OCI_NGINX_REF}" "${NGINX_IC_IMAGE}" || true + nerdctl_exec tag "${OCI_CERT_REF}" "${CERT_IMG}" || true + fi + ok "OCI → containerd 导入完成" return fi - warn "未检测到 docker/skopo 或 containerd 可直接用 OCI 导入,尝试 docker-archive 回退。" + + warn "未检测到可用于 OCI 导入的 containerd,将尝试 docker-archive 回退。" fi - # 回退:docker save 的 tar 包 + # 回退:docker save 的 tar 包(docker-archive) if [ -f "${DOCKER_IMG_TAR}" ] && [ -f "${DOCKER_CERT_TAR}" ]; then log "📦 从 docker-archive tar 回退导入 images/*.tar" + + # 优先:nerdctl(离线包自带/系统均可) + if have_nerdctl; then + if [ -n "${CTR_SOCK}" ]; then + nerdctl_exec load -i "${DOCKER_IMG_TAR}" + nerdctl_exec load -i "${DOCKER_CERT_TAR}" + else + # 极少见:未探测到 socket,尝试 nerdctl 默认 + "${NERDCTL_BIN}" load -i "${DOCKER_IMG_TAR}" + "${NERDCTL_BIN}" load -i "${DOCKER_CERT_TAR}" + fi + ok "nerdctl load 完成" + return + fi + + # 其次:docker 守护进程 if have docker && docker info &>/dev/null; then docker load -i "${DOCKER_IMG_TAR}" docker load -i "${DOCKER_CERT_TAR}" ok "docker load 完成" return fi - if have nerdctl; then - nerdctl load -i "${DOCKER_IMG_TAR}" - nerdctl load -i "${DOCKER_CERT_TAR}" - ok "nerdctl load 完成" - return - fi - if [ -S /run/k3s/containerd/containerd.sock ] || [ -S /run/containerd/containerd.sock ]; then - $SUDO ctr -n k8s.io images import --all-platforms "${DOCKER_IMG_TAR}" - $SUDO ctr -n k8s.io images import --all-platforms "${DOCKER_CERT_TAR}" + + # 兜底:ctr(可导入 docker-archive,但不如 nerdctl 稳妥) + if [ -n "${CTR_SOCK}" ]; then + ctr_exec images import --all-platforms "${DOCKER_IMG_TAR}" + ctr_exec images import --all-platforms "${DOCKER_CERT_TAR}" ok "ctr import 完成" return fi + die "找不到可用容器运行时导入 images/*.tar" fi - die "未发现可用的镜像来源(缺少 ${OCI_ARCHIVE} 或 ${DOCKER_IMG_TAR}/${DOCKER_CERT_TAR)})" + die "未发现可用的镜像来源(缺少 ${OCI_ARCHIVE} 或 ${DOCKER_IMG_TAR}/${DOCKER_CERT_TAR})" } # ====================== @@ -116,29 +199,29 @@ generate_values() { tag="${NGINX_IC_IMAGE##*:}" cat > values.yaml <> values.yaml </dev/null; then + echo "[ERROR] 发现非 ${ARCH} 架构镜像" >&2 + exit 1 + fi +} +check_images(){ + echo "[INFO] 验证已加载镜像架构" + local out + out=$(sudo nerdctl --namespace k8s.io --address /run/k3s/containerd/containerd.sock images -a --format '{{.Repository}}:{{.Tag}} {{.ID}} {{.Platform}}') + echo "$out" + if echo "$out" | awk '{print $3}' | grep -v "linux/${ARCH}" >/dev/null; then + echo "[ERROR] 发现非 ${ARCH} 架构镜像" >&2 + exit 1 + fi +} + echo "[INFO] 安装 CLI → /usr/local/bin" install_bin "${BIN_DIR}/k3s-${ARCH}" /usr/local/bin/k3s install_bin "${BIN_DIR}/helm-${ARCH}" /usr/local/bin/helm