artifacts/scripts/ingress-installer.sh
shenlan 79c63515a3
Update ingress-installer.sh
Signed-off-by: shenlan <manbuzhe2009@qq.com>
2025-09-14 17:03:52 +08:00

272 lines
8.0 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# scripts/ingress-installer.sh
# 目标:一键“离线安装” NGINX Ingress,兼容 K3s 1.29~1.33(containerd)
set -euo pipefail
# ======================
# Config & Defaults(仅支持环境变量覆盖)
# ======================
: "${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-5.1.1}"
: "${OCI_CERT_REF:=kube-webhook-certgen}"
# 目录布局固定:charts、images、脚本位于离线包根目录
: "${CHART_DIR:=./charts/nginx-ingress}"
: "${NAMESPACE:=ingress}"
: "${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}"
# Ingress 暴露 IP(默认取本机第一块网卡 IP),节点选择器可选(key=value)
INGRESS_IP="${INGRESS_IP:-$(hostname -I 2>/dev/null | awk '{print $1}')}"
NODE_LABEL="${NODE_LABEL:-}"
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
log() { echo -e "$@"; }
die() { echo "❌ $*" >&2; exit 1; }
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)
# ======================
install_nerdctl() {
if [ -f "${NERDCTL_TAR}" ]; then
log "📦 安装 nerdctl(wrapper)..."
$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-archive)
# ======================
import_images_from_oci() {
detect_containerd
log "🔌 containerd socket: ${CTR_SOCK:-<not found>}"
# 首选:OCI 归档(oci-archive)—— 标准且最稳
if [ -f "${OCI_ARCHIVE}" ]; then
log "📦 从 OCI 归档导入镜像:${OCI_ARCHIVE}"
# 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}"
skopeo --insecure-policy copy --all "oci-archive:${OCI_ARCHIVE}:${OCI_CERT_REF}" "docker-daemon:${CERT_IMG}"
ok "OCI → docker-daemon 导入完成"
return
else
warn "docker 环境未安装 skopeo,改用 containerd 路径。"
fi
fi
# 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 "未检测到可用于 OCI 导入的 containerd,将尝试 docker-archive 回退。"
fi
# 回退: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
# 兜底: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})"
}
# ======================
# Kubernetes & Helm
# ======================
ensure_namespace() {
log "📁 创建命名空间 ${NAMESPACE}(如已存在忽略)"
kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -
}
generate_values() {
log "🧾 生成 Helm values.yaml"
local repo tag
repo="${NGINX_IC_IMAGE%:*}"
tag="${NGINX_IC_IMAGE##*:}"
cat > values.yaml <<EOF
controller:
ingressClass:
name: nginx
create: true
setAsDefaultIngress: false
replicaCount: 2
image:
repository: ${repo}
tag: "${tag}"
service:
enabled: true
type: NodePort
externalIPs:
- ${INGRESS_IP}
nodePorts:
http: 80
https: 443
EOF
if [[ -n "${NODE_LABEL}" ]]; then
cat >> values.yaml <<EOF
nodeSelector:
${NODE_LABEL%%=*}: "${NODE_LABEL#*=}"
EOF
fi
}
install_chart() {
[ -d "${CHART_DIR}" ] || die "未找到 Chart 目录:${CHART_DIR}"
log "🧭 使用本地 Chart 安装/升级:${CHART_DIR}"
helm upgrade --install nginx "${CHART_DIR}" \
--namespace "${NAMESPACE}" -f values.yaml \
--wait --timeout 10m
}
apply_configmap_tuning() {
log "🛠️ 应用 ConfigMap 调优参数"
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-nginx-ingress
namespace: ${NAMESPACE}
data:
proxy-connect-timeout: "10"
proxy-read-timeout: "10"
client-header-buffer-size: 64k
client-body-buffer-size: 64k
client-max-body-size: 1000m
proxy-buffers: "8 32k"
proxy-buffer-size: 32k
EOF
}
# ======================
# Main
# ======================
log "🚀 Ingress 离线部署开始"
log " Ingress IP: ${INGRESS_IP:-<auto>}"
log " Namespace: ${NAMESPACE}"
log " Chart Dir: ${CHART_DIR}"
log " Images: ${NGINX_IC_IMAGE} , ${CERT_IMG}"
install_nerdctl
import_images_from_oci
ensure_namespace
generate_values
install_chart
apply_configmap_tuning
ok "离线安装完成,Ingress IP: ${INGRESS_IP}"