From c759e111ec0fd72f650bc1b1700ba6601440fa40 Mon Sep 17 00:00:00 2001 From: opsx Date: Wed, 28 Oct 2026 07:25:15 +0000 Subject: [PATCH] =?UTF-8?q?feat(k8s):=20install.sh=20=E4=B8=89=E7=BA=A7?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E9=A2=84=E6=A3=80=E2=80=94=E2=80=94kubectl?= =?UTF-8?q?=20=E7=BC=BA=E5=A4=B1/=E8=BF=9E=E4=B8=8D=E4=B8=8A=E9=9B=86?= =?UTF-8?q?=E7=BE=A4=E6=97=B6=E7=BB=99=E5=87=BA=E5=8F=AF=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=9A=84=E5=85=B7=E4=BD=93=E4=BF=AE=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户反馈:部署时报错只说「未找到 kubectl,请先安装」「kubectl 无法连接集群, 请检查 kubeconfig」,对新人等于没说 —— 不知道是没装工具、网络不通、凭据过期 还是 RBAC 没权限,也不知道下一步查什么。 原实现只有两行: command -v kubectl || die "未找到 kubectl,请先安装" kubectl version --request-timeout=5s || die "kubectl 无法连接集群,请检查 kubeconfig" 改为三级预检 + 一级软检查: 【0.1 kubectl 是否存在】 按 CentOS/TencentOS、Ubuntu/Debian、macOS 分别给安装命令; 额外给「机器没有外网」的替代路径(控制台下载 / 内网跳板机 / 只 scp 二进制)。 【0.2 kubeconfig 文件是否存在】← 新增,堵一个误判 KUBECONFIG 指向不存在的文件时,kubectl 会忽略它并退回默认规则, 最终报出 "Authentication required" / "connection refused" 这类误导性错误, 让人白查凭据和网络。现在单独判一次,直接给出查找路径 + 各云控制台下载入口。 支持 KUBECONFIG 用 : 分隔多路径,任一存在即通过。 【0.3 能否连上 API Server】按错误类型分类,各给专属修法 · context 不存在 → get-contexts / use-context / 重新下载 · 401 认证失败 → 云厂商 token 有效期几小时,重新下载;自建查客户端证书 · 403 RBAC 拒绝 → auth whoami / auth can-i --list,列出部署所需的具体资源 · x509 证书问题 → 确认证书过期;可信内网可临时 insecure-skip-tls-verify · 网络不通 → curl -k /version、VPN/专线、安全组放行 6443、换跳板机 · 其他 → 原样打印 kubectl 错误 + 通用排查清单 【0.4 部署权限软检查】auth can-i 非 yes 时只告警不阻断 (首次部署时目标命名空间可能还不存在,硬拦会误伤正常流程) 失败时统一打印环境信息(kubeconfig 路径 / context / API Server / 当前用户), 一眼看出连的是哪个集群。连接超时可用 KUBECTL_TIMEOUT=15s 放宽(默认 8s)。 README 同步新增「前置条件」章节:预检项对照表 + 错误分类表 + 失败输出示例。 === 验证 === 从真实 install.sh 抽出预检段,用假 kubectl 精确模拟 8 种场景(两个脚本各跑一遍): A 没有 kubectl → 退出 1,打印各系统安装命令 ✅ B API Server 超时 → 退出 1,提示 VPN/专线/安全组 ✅ C 没有 context → 退出 1,提示 get-contexts/use-context ✅ D 401 凭据过期 → 退出 1,提示重新下载 kubeconfig ✅ E 403 权限不足 → 退出 1,列出所需资源权限 ✅ F x509 证书过期 → 退出 1,提示证书/insecure 排障 ✅ G 正常环境(真实集群) → 通过预检,退出 0 ✅ H kubeconfig 文件不存在 → 退出 1,提示下载位置(不误报成 401)✅ 结果:阻断 7/7、正常通过 1/1;bash -n 语法检查通过 ⚠️ 踩坑记录:kubeconfig 多路径判断最初写成 while IFS= read -r _p; do ...; done < <(printf "%s" "$PATHS" | tr ":" "\n") printf 输出没有结尾换行 → read 带着数据返回非 0(EOF)→ 循环体一次都不执行, 导致所有场景都误报「找不到 kubeconfig」。改用 IFS=":" + for 拆分。 --- kubernetes/README.md | 46 ++++++++++++ kubernetes/install.sh | 168 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 212 insertions(+), 2 deletions(-) diff --git a/kubernetes/README.md b/kubernetes/README.md index d9c3772..f1ae24d 100644 --- a/kubernetes/README.md +++ b/kubernetes/README.md @@ -65,6 +65,52 @@ WITH_NODEPORT=1 bash kubernetes/install.sh | 镜像 | 节点可拉 `lghost/lokistack:latest`(或改成自己的 Harbor/ACR/TCR/SWR) | | 权限 | 有 `log` 命名空间的 create/apply 权限 | + +## 前置条件(`install.sh` 会自动检查,不通过直接给出具体修法) + +脚本启动时做**三级预检 + 一级软检查**,任何一级不通过都会立即退出并打印「是哪一类问题、 +下一步做什么」,不会跑到一半才报错: + +| 预检项 | 不通过时的提示内容 | +|--------|-------------------| +| **kubectl 是否安装** | 按 CentOS/TencentOS、Ubuntu/Debian、macOS 分别给安装命令;并给出「机器没有外网」时的替代方案(控制台下载 / 内网跳板机执行 / 只 scp 二进制) | +| **kubeconfig 是否存在** | 打印实际查找路径(`$KUBECONFIG` 或 `~/.kube/config`),给出腾讯云 TKE / 阿里云 ACK / AWS EKS 各自下载 kubeconfig 的入口,以及 `chmod 600` 建议 | +| **能否连上 API Server** | **按错误类型分类**(见下表),不是笼统一句「请检查 kubeconfig」 | +| **部署权限(软检查)** | `kubectl auth can-i create deployments.apps -n ` 非 `yes` 时告警,提示绑定 Role 或改用管理员 kubeconfig;**不阻断**,避免首次部署时命名空间尚未创建导致误拦 | + +### 连不上集群时的分类提示 + +| 实际错误 | 脚本的判断 | 给出的处理方向 | +|---------|-----------|---------------| +| `current-context is not set` / `context does not exist` | kubeconfig 没有可用 context | `kubectl config get-contexts` → `use-context` → 重新下载 kubeconfig | +| `Unauthorized` / `Authentication required` | 认证失败(云厂商 token 几小时就过期) | 回控制台重新下载 kubeconfig;自建集群查客户端证书 | +| `Forbidden` / `403` | 已连上集群但 RBAC 拒绝 | `kubectl auth whoami`、`auth can-i --list -n `,列出部署所需的具体资源权限 | +| `x509` / `certificate` / `tls:` | 证书过期或域名不匹配 | 确认 API Server 证书;可信内网可临时 `--insecure-skip-tls-verify` 排障 | +| `connection refused` / `no such host` / `context deadline exceeded` / `i/o timeout` | 网络不通 | ①`curl -k /version` ②**内网地址需 VPN/专线** ③安全组放行 6443 ④查集群状态 ⑤换成跳板机试 | + +失败时的完整输出形如: + +```text +❌ 连不上集群 API Server(网络不通) + + kubeconfig : /root/.kube/config + 当前 context : tke-pre + API Server : https://172.19.16.13:443 + 当前用户 : admin + + 实际报错: Unable to connect to the server: context deadline exceeded (...) + + ── 按顺序排查 ─────────────────────────────────────────────────────── + 1) 地址对不对?用上面打印的 API Server 测一下: curl -k --max-time 5 /version + 2) 要不要 VPN / 专线?云上 API Server 常是内网地址(10.x / 172.16~31.x / 192.168.x)... + 3) 安全组 / 防火墙:云厂商默认只放行运维网段访问 6443 端口 + 4) 集群本身是否正常:控制台看集群状态是否「运行中」 + 5) 换台机器试:在能访问集群的跳板机上执行本脚本,可排除本机网络问题 +``` + +> 预检只读不写、耗时 < 1 秒。API Server 连接超时可用 `KUBECTL_TIMEOUT=15s` 放宽(默认 8s)。 + + ## 脚本自动处理什么 `install.sh` 不是无脑 apply,它会先探测环境再动手: diff --git a/kubernetes/install.sh b/kubernetes/install.sh index a3fc7fe..c50631e 100755 --- a/kubernetes/install.sh +++ b/kubernetes/install.sh @@ -25,9 +25,173 @@ die() { printf '\033[1;31m❌\033[0m %s\n' "$*" >&2; exit 1; } # ============================================================================ # 0) 前置检查 +# +# 分三级:kubectl 是否存在 → 能否连上集群 → 有没有部署权限。 +# 设计原则:每级失败都要说清「是哪一类问题 + 下一步具体做什么」。 +# 只丢一句「请检查 kubeconfig」等于没说 —— 新人根本不知道该查什么, +# 也不知道是没装工具、网络不通、凭据过期、还是 RBAC 没权限。 # ============================================================================ -command -v kubectl >/dev/null 2>&1 || die "未找到 kubectl,请先安装" -kubectl version --request-timeout=5s >/dev/null 2>&1 || die "kubectl 无法连接集群,请检查 kubeconfig" +KUBECTL_TIMEOUT="${KUBECTL_TIMEOUT:-8s}" + +# 当前 context / server / user:失败时一起打印,一眼看出连的是哪个集群 +k8s_env_info() { + local ctx server user kc + ctx=$(kubectl config current-context 2>/dev/null || echo "(无)") + server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null || true) + user=$(kubectl config view --minify -o jsonpath='{.users[0].name}' 2>/dev/null || true) + kc="${KUBECONFIG:-$HOME/.kube/config}" + printf ' kubeconfig : %s\n' "$kc" >&2 + printf ' 当前 context : %s\n' "$ctx" >&2 + printf ' API Server : %s\n' "${server:-(未知)}" >&2 + printf ' 当前用户 : %s\n' "${user:-(未知)}" >&2 +} + +# 统一失败出口:一句话结论 + 环境信息 + 可执行的处理步骤 +k8s_die() { + printf '\n\033[1;31m❌ %s\033[0m\n\n' "$1" >&2 + k8s_env_info + printf '\n%b\n\n' "$2" >&2 + exit 1 +} + +# ── 0.1 kubectl 是否存在 ────────────────────────────────────────────── +if ! command -v kubectl >/dev/null 2>&1; then + printf '\n\033[1;31m❌ 找不到 kubectl 命令\033[0m\n\n' >&2 + cat >&2 <<'KUBECTL_INSTALL_HELP' + 本脚本通过 kubectl 操作 K8s 集群,需要先安装这个命令行工具。 + + ── 安装方式 ─────────────────────────────────────────────────────── + 通用 Linux(官方二进制,最省事): + curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + + CentOS / TencentOS / RHEL : sudo yum install -y kubectl + Ubuntu / Debian : sudo apt-get update && sudo apt-get install -y kubectl + macOS : brew install kubectl + + ── 装完自检 ─────────────────────────────────────────────────────── + kubectl version --client + + ── 这台机器没有外网怎么办 ───────────────────────────────────────── + · 云控制台「集群 → 连接信息」一般可直接下载 kubectl 与 kubeconfig + · 或者在内网跳板机 / 能访问集群的机器上执行本脚本 + · 只需把 kubectl 二进制 scp 过来即可,不依赖 Docker / Jenkins +KUBECTL_INSTALL_HELP + exit 1 +fi + +# ── 0.2 kubeconfig 文件是否存在 ──────────────────────────────────────── +# 必须先单独判一次:KUBECONFIG 指向不存在的文件时,kubectl 会忽略它并 +# 退回默认规则,最终报出的往往是 "Authentication required"/"connection refused" +# 这类**误导性**错误,让人以为是凭据或网络问题,实际只是配置没放对位置。 +_KC_PATHS="${KUBECONFIG:-$HOME/.kube/config}" +# KUBECONFIG 允许用 ':' 分隔多个路径,任意一个存在即算通过。 +# 注意不要写成 while read 循环:printf 输出没有结尾换行时,read 会 +# 带着数据返回非 0(EOF),`while read` 的循环体一次都不会执行 —— 踩过。 +_kc_found=0 +_OLD_IFS="${IFS}" +IFS=':' +for _p in ${_KC_PATHS}; do + if [ -n "${_p}" ] && [ -f "${_p}" ]; then + _kc_found=1 + break + fi +done +IFS="${_OLD_IFS}" + +if [ "${_kc_found}" -eq 0 ]; then + k8s_die "找不到 kubeconfig 文件(不知道该连哪个集群)" \ +" 查找位置: ${_KC_PATHS} + (KUBECONFIG 环境变量未设置时,默认只找 ~/.kube/config) + + ── 怎么修 ───────────────────────────────────────────────────────── + 1) 从云控制台下载 kubeconfig: + 腾讯云 TKE : 集群 → 基本信息 → 连接信息 → 下载 kubeconfig + 阿里云 ACK : 集群 → 集群信息 → 连接信息 → 复制/下载 kubeconfig + AWS EKS : aws eks update-kubeconfig --name <集群名> --region <区域> + 2) 放到默认位置(推荐): + mkdir -p ~/.kube && mv <下载的文件> ~/.kube/config && chmod 600 ~/.kube/config + 3) 或者用环境变量指向任意路径: + export KUBECONFIG=/path/to/kubeconfig + 4) 确认生效: kubectl config get-contexts + 5) 重新执行本脚本" + +fi + +# ── 0.3 能否连上集群(探测一次,按错误类型分别给建议)──────────────── +if ! PROBE_OUT="$(kubectl version --request-timeout="${KUBECTL_TIMEOUT}" 2>&1)"; then + case "${PROBE_OUT}" in + *"does not exist"*|*"no context exists"*|*"current-context is not set"*|*"context was not found"*) + k8s_die "kubeconfig 里没有可用的 context(集群配置不对)" \ +" ── 怎么修 ───────────────────────────────────────────────────────── + 1) 确认 kubeconfig 在哪: echo \$KUBECONFIG ls -l ~/.kube/config + 2) 看有哪些 context: kubectl config get-contexts + 3) 切到正确的那一个: kubectl config use-context <名字> + 4) 完全没有配置就下载: 腾讯云 → 集群 → 基本信息 → 连接信息 → 下载 kubeconfig + 放到 ~/.kube/config,或 export KUBECONFIG=/path/to/config + 5) 重新执行本脚本" ;; + + *"Unauthorized"*|*"Authentication required"*|*"credentials"*|*"invalid bearer token"*) + k8s_die "集群认证失败(凭据无效或已过期)" \ +" ── 怎么修 ───────────────────────────────────────────────────────── + · 云厂商 kubeconfig 里一般是**临时 token**,有效期几小时,过期就 401 + → 回控制台重新下载 kubeconfig,覆盖 ~/.kube/config + · 自建集群看客户端证书是否过期: + kubectl config view --minify --raw | grep client-certificate-data + · 验证当前身份: kubectl auth whoami (旧版用 kubectl get ns 试)" ;; + + *"Forbidden"*|*"(403)"*) + k8s_die "已经连上集群,但当前账号没有权限(RBAC 拒绝)" \ +" ── 怎么修 ───────────────────────────────────────────────────────── + · 确认身份: kubectl auth whoami + · 看能干什么: kubectl auth can-i --list -n ${NS} + · 部署本平台需要在 ${NS} 命名空间具备: + deployments.apps / services / persistentvolumeclaims / configmaps / secrets 的 create、get + 若该命名空间还不存在,还需要集群级 create namespaces + · 找集群管理员绑定具备上述权限的 Role,或直接用管理员 kubeconfig 执行本脚本" ;; + + *"x509"*|*"certificate"*|*"tls:"*|*"TLS"*) + k8s_die "集群证书校验失败(证书过期 / 域名不匹配 / 自签证书)" \ +" ── 怎么修 ───────────────────────────────────────────────────────── + · 云托管集群极少出现,多见于自建集群;先确认 API Server 证书是否过期 + · 可信内网内临时跳过校验(仅用于排障,不要长期使用): + kubectl --insecure-skip-tls-verify=true get ns + · 检查 kubeconfig 里 server 的地址/域名是否在证书 SAN 内" ;; + + *"connection refused"*|*"no such host"*|*"i/o timeout"*|*"context deadline exceeded"*|*"network is unreachable"*|*"Unable to connect to the server"*|*"timeout"*) + k8s_die "连不上集群 API Server(网络不通)" \ +" 实际报错: $(printf '%s' "${PROBE_OUT}" | tail -1) + + ── 按顺序排查 ─────────────────────────────────────────────────────── + 1) 地址对不对?用上面打印的 API Server 测一下: + curl -k --max-time 5 /version + 2) 要不要 VPN / 专线?云上 API Server 常是**内网地址**(10.x / 172.16~31.x / 192.168.x), + 本机不在同一 VPC 时,必须先连 VPN、走专线,或把本机 IP 加进安全组白名单 + 3) 安全组 / 防火墙:云厂商默认只放行运维网段访问 6443 端口 + 4) 集群本身是否正常:控制台看集群状态是否「运行中」 + 5) 换台机器试:在能访问集群的跳板机上执行本脚本,可排除本机网络问题" ;; + + *) + k8s_die "kubectl 无法连接集群" \ +" 实际报错: +$(printf '%s\n' "${PROBE_OUT}" | sed 's/^/ /') + + ── 通用排查 ───────────────────────────────────────────────────────── + · kubectl config get-contexts # 当前用的是哪个 context + · kubectl cluster-info # API Server 是否可达 + · echo \$KUBECONFIG # 确认读到的是哪个 kubeconfig + · 容器/精简镜像里执行时,注意镜像内可能没有 ca-certificates 与 kubectl" ;; + + esac +fi + +# ── 0.4 部署权限预检(只告警,不阻断)──────────────────────────────── +# 说明:第一次部署时目标命名空间可能还不存在,can-i 对命名空间级资源会返回 no, +# 为避免误拦正常流程这里只提示;真正的拒绝会在 apply 阶段以 Forbidden 暴露。 +if [ "$(kubectl auth can-i create deployments.apps -n "${NS}" --request-timeout="${KUBECTL_TIMEOUT}" 2>/dev/null || echo unknown)" != "yes" ]; then + warn "当前账号在命名空间 ${NS} 未确认具备部署权限(kubectl auth can-i 非 yes)" + warn "若随后 apply 报 Forbidden:请改用管理员 kubeconfig,或让管理员绑定 Role 后再执行" +fi # ============================================================================ # 0.1) 云平台识别(信息展示 + 后续诊断用)