用户反馈:部署时报错只说「未找到 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 <API>/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 拆分。
156 lines
7.7 KiB
Markdown
156 lines
7.7 KiB
Markdown
# opsxsql 部署到 Kubernetes
|
||
|
||
## 文件
|
||
|
||
| 文件 | 说明 |
|
||
|---|---|
|
||
| `install.sh` | **一键部署**(推荐):云探测/SC 探测/本地 PV 兜底/密钥/清单渲染/失败诊断 |
|
||
| `namespace.yaml` | `opsxsql` 命名空间 |
|
||
| `pvc.yaml` | 数据卷(默认 10Gi,集群默认 StorageClass) |
|
||
| `deployment.yaml` | 平台本体,**单副本 + Recreate** |
|
||
| `service.yaml` | ClusterIP `opsxsql:80` |
|
||
| `service-nodeport.yaml` | 可选 NodePort 入口(`:30900`) |
|
||
| `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 <ns>` 非 `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 <ns>`,列出部署所需的具体资源权限 |
|
||
| `x509` / `certificate` / `tls:` | 证书过期或域名不匹配 | 确认 API Server 证书;可信内网可临时 `--insecure-skip-tls-verify` 排障 |
|
||
| `connection refused` / `no such host` / `context deadline exceeded` / `i/o timeout` | 网络不通 | ①`curl -k <API>/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 <API Server>/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 / 自建)
|
||
与 StorageClass(显式指定 > default 注解 > 唯一 SC);**自建集群无 SC 时自动创建零依赖的节点本地 PV**
|
||
(hostPath + nodeAffinity 锁节点 + Retain,无需 local-path-provisioner 镜像);部署失败时按云平台给出
|
||
镜像仓库/SC 定制诊断。幂等:重复执行不覆盖密钥、不重建数据卷。
|
||
|
||
```bash
|
||
# 默认(镜像 opsxsql:latest)
|
||
bash kubernetes/install.sh
|
||
|
||
# 指定镜像 + NodePort 入口
|
||
IMAGE=registry.example.com/opsxsql:v1.0.0 bash kubernetes/install.sh --nodeport
|
||
|
||
# 指定镜像 + 通用 nginx Ingress 域名(其他云模板见 examples/)
|
||
IMAGE=registry.example.com/opsxsql:v1.1.0 bash kubernetes/install.sh --ingress opsxsql.example.com
|
||
|
||
# 自定义命名空间 / 卷大小 / 手动指定 StorageClass / 强制本地存储
|
||
NS=sql-audit PVC_SIZE=20Gi bash kubernetes/install.sh
|
||
STORAGE_CLASS=alicloud-disk-essd bash kubernetes/install.sh
|
||
LOCAL_STORAGE=force NODE_NAME=node1 bash kubernetes/install.sh # 数据固定 node1:/var/lib/opsxsql-data
|
||
```
|
||
|
||
| 环境变量 | 默认 | 说明 |
|
||
|---|---|---|
|
||
| `IMAGE` | `opsxsql:latest` | 镜像(构建:仓库根 `docker compose build` 或 `docker build .`) |
|
||
| `NS` | `opsxsql` | 命名空间 |
|
||
| `STORAGE_CLASS` | 自动探测 | 指定 StorageClass |
|
||
| `PVC_SIZE` | `10Gi` | 数据卷容量 |
|
||
| `WITH_NODEPORT` / `--nodeport` | `0` | 附带 NodePort `:30900` 入口 |
|
||
| `LOCAL_STORAGE` | `auto` | 无 SC 时:`auto` 自动建本地 PV / `off` 仅提示 / `force` 强制本地 |
|
||
| `NODE_NAME` / `PV_PATH` | 自动 / `/var/lib/opsxsql-data` | 本地存储落点 |
|
||
|
||
## 分步部署(等价于 install.sh)
|
||
|
||
```bash
|
||
# 1) 密钥(只生成一次;SECRET_KEY 丢失会导致已加密的实例/LDAP 密码无法解密)
|
||
kubectl -n opsxsql create secret generic opsxsql-secrets \
|
||
--from-literal=SECRET_KEY="$(openssl rand -hex 32)" \
|
||
--from-literal=JWT_SECRET="$(openssl rand -hex 32)"
|
||
|
||
# 2) 清单(先把 deployment.yaml 里的 image 改成实际仓库地址)
|
||
kubectl apply -f kubernetes/namespace.yaml
|
||
kubectl apply -f kubernetes/pvc.yaml
|
||
kubectl apply -f kubernetes/deployment.yaml
|
||
kubectl apply -f kubernetes/service.yaml
|
||
|
||
# 3) 可选入口
|
||
kubectl apply -f kubernetes/service-nodeport.yaml # 或 ingress.yaml
|
||
```
|
||
|
||
## 持久化(重要)
|
||
|
||
- `/app/data` 挂 PVC,保存 SQLite 数据库与持久化 JWT 密钥。
|
||
- **必须 `replicas: 1` + `strategy: Recreate`**:SQLite 是单写者,滚动更新时两个 Pod 同时挂同一 RWO PVC 会互相覆盖(install.sh 已内置该约束)。
|
||
- 备份(冷备一条命令):
|
||
|
||
```bash
|
||
kubectl -n opsxsql exec deploy/opsxsql -- sqlite3 /app/data/sqlite3.db '.backup /app/data/backup-$(date +%F).db'
|
||
kubectl -n opsxsql cp deploy/opsxsql:/app/data/backup-$(date +%F).db ./backup.db
|
||
```
|
||
|
||
- 云盘快照走 CSI VolumeSnapshot(AWS EBS / 腾讯 CBS / 华为 EVS / 阿里 ESSD 同一套 API):
|
||
|
||
```yaml
|
||
apiVersion: snapshot.storage.k8s.io/v1
|
||
kind: VolumeSnapshot
|
||
metadata:
|
||
name: opsxsql-data-20261026
|
||
namespace: sql
|
||
spec:
|
||
volumeSnapshotClassName: <集群的 snapshotClass>
|
||
source:
|
||
persistentVolumeClaimName: opsxsql-data
|
||
```
|
||
|
||
## 多云兼容
|
||
|
||
| 项 | 做法 |
|
||
|---|---|
|
||
| 存储类 | `pvc.yaml` 不写 `storageClassName` 用默认 SC;无默认 SC 时填云厂名(AWS `gp3` / 腾讯 `cbs` / 华为 `csi-disk` / 阿里 `alicloud-disk-essd`) |
|
||
| 镜像仓库 | `deployment.yaml` 的 `image` 填目标云可拉的仓库(Harbor / ACR / TCR / SWR),或本仓库根 `Dockerfile` 自行构建 |
|
||
| gh-ost | 镜像内置(在线大表 DDL 用);不用该功能可忽略,无需外置依赖 |
|
||
|
||
## 升级 / 卸载
|
||
|
||
```bash
|
||
# 升级:换镜像 tag 重新 install(Recreate 策略自动重建,数据卷不动)
|
||
IMAGE=registry.example.com/opsxsql:v1.1.0 bash kubernetes/install.sh --nodeport
|
||
|
||
# 卸载(数据卷保留;需要连数据一起删加 --include-data)
|
||
kubectl -n opsxsql delete deploy,svc,ingress opsxsql opsxsql-nodeport 2>/dev/null
|
||
kubectl delete ns opsxsql # 会连 PVC 一起删,谨慎
|
||
```
|