diff --git a/kubernetes/README.md b/kubernetes/README.md index d6e4a09..4f9176c 100644 --- a/kubernetes/README.md +++ b/kubernetes/README.md @@ -13,6 +13,52 @@ | `ingress.yaml` | 可选,通用 nginx Ingress | | `examples/` | 跨云模板:阿里 ALB / 腾讯 qcloud Ingress、Secret 模板 | + +## 前置条件(`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` 自动探测云平台(阿里 ACK / 腾讯 TKE / AWS EKS / 华为 CCE / GCP GKE / Azure AKS / K3s / 自建) diff --git a/kubernetes/install.sh b/kubernetes/install.sh index fbc48c5..2b23827 100755 --- a/kubernetes/install.sh +++ b/kubernetes/install.sh @@ -43,9 +43,173 @@ done # ============================================================================ # 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) 云平台识别(信息展示 + 失败诊断用)