续:排错记
上篇文章记录了从零搭建集群、解决镜像拉取失败(ImagePullBackOff)和存储卷绑定(PVC Pending)的过程。
🔥 挑战 5(延续):数据库表不存在
现象:
后端接口返回 500 错误
排错思路:
第一步:确认数据库 Pod 状态
kubectl get pods -l app=iot-database
Pod 是 Running,说明数据库容器本身正常。
第二步:确认数据库和表是否存在
kubectl exec -it $(kubectl get pod -l app=iot-database -o jsonpath='{.items[0].metadata.name}') -- mysql -uroot -pjjsg_2yj -e "SHOW DATABASES;"
输出显示 iot 数据库存在。
kubectl exec -it ... -- mysql -uroot -pjjsg_2yj -e "USE iot; SHOW TABLES;"
输出为空,说明 device 表不存在。
第三步:确认 SQL 文件是否被自动执行
检查数据库初始化日志:
kubectl logs -l app=iot-database | grep -i "iot.sql\|device"
没有相关输出,说明 MySQL 容器启动时跳过了初始化脚本(因为 PVC 已有数据,不是第一次启动)。
第四步:手动建表
从 iot.sql 文件中提取 CREATE TABLE 语句,手动执行:
bash
kubectl exec -it $(kubectl get pod -l app=iot-database -o jsonpath='{.items[0].metadata.name}') -- mysql -uroot -pjjsg_2yj iot -e "
CREATE TABLE device (
device_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '设备主键',
device_name VARCHAR(100) NOT NULL COMMENT '设备名称',
device_type VARCHAR(50) NOT NULL COMMENT '设备类型',
serial_number VARCHAR(64) NOT NULL COMMENT '序列号',
status ENUM('online','offline','error','maintenance') NOT NULL DEFAULT 'offline',
last_heartbeat DATETIME DEFAULT NULL,
location VARCHAR(255) DEFAULT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (device_id),
UNIQUE KEY ux_devices_serial (serial_number)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
"
第五步:验证
kubectl exec -it ... -- mysql -uroot -pjjsg_2yj -e "USE iot; SHOW TABLES;"
输出 device,表创建成功
curl http://10.109.210.199:8080/device/list
返回 {"data":{"records":[],"total":0,...},"success":true},不再是 500 错误。
核心结论:
MySQL 容器只在第一次启动时执行 /docker-entrypoint-initdb.d/ 下的 SQL 文件。如果 PVC 已有数据,会跳过初始化。此时手动建表是最快的恢复方式。
🔥 挑战 6:浏览器缓存导致前端无法加载最新配置
现象:
修改了 config.js 中的后端地址,重新构建镜像并部署后,浏览器仍然请求旧的 localhost:8080,前端无法调用 API。
排错思路:
- 确认服务端是否正确 :进入 Pod 查看
config.js内容,确认文件已更新
- 确认网络层是否正确 :用
curl直接请求 JS 文件,确认 Nginx 返回的是新内容
-
定位问题层级 :服务端正确,但浏览器控制台显示旧值 → 问题出在浏览器缓存
-
尝试常规清除:清空缓存、无痕模式、硬刷新 → 无效无痕模式下仍显示 localhost
-
绕过缓存:修改 Service NodePort,让浏览器访问新地址
结果:
访问新端口,控制台显示正确的 BASE_URL,前端正常调用后端 API。
核心结论:
浏览器强缓存无法通过常规手段清除时,最快的验证方法是换一个从未访问过的端口或地址。生产环境应通过 Cache-Control 响应头或静态资源版本号来规避此类问题。
一点感悟
这次实验从零开始,CentOS 7.9,内网环境。磕磕绊绊走下来,踩过的坑比想象的多:
版本不兼容(K8S 1.22 + Docker 20.10 就是不行)
网络不通(镜像拉不下来,离线导入折腾半天)
配置细节(cgroup 驱动不一致、PVC 忘记建、SQL 脚本没自动执行)
浏览器缓存(改完代码不生效,最后换端口解决)
每一个问题单独看都不大,但串在一起,每一步都可能卡住。
下一步
如果还有时间,可能会继续折腾:
用 Ingress 代替 NodePort,通过域名访问
配置健康检查和资源限制
试试滚动更新和回滚
这篇博客记录的不是标准答案,而是一个普通开发者在真实环境里手搓的过程。有不对的地方,欢迎指正









