当前位置: 首页 > news >正文

【技术底稿 36】Docker Compose 微服务迁移 K3s:离线导入、镜像挂载、Nginx 重定向全踩坑复盘

一、核心背景

在不新增服务器、沿用现有 16G 开发机前提下,将原本运行在 Docker Compose 上的微服务架构(MySQL、Redis、2个 Java 服务、Nginx)迁移至 K3s,同时保留 Milvus、Ollama、FTP 等 AI 相关中间件继续由 Docker Compose 托管。

硬件环境:单机 16G 内存,已有 Docker Compose 全套服务稳定运行中。

迁移目标

  • K3s 托管 Java 应用 + Nginx + MySQL + Redis

  • 完全离线导入镜像(服务器无外网)

  • K3s Pod 访问宿主机 Docker 中间件(Milvus、Ollama)

  • 迁移期间业务尽量不中断


二、最终落地架构

组件版本运行环境状态
MySQL8.0K3s(离线导入镜像)
Redis7.x(latest)K3s(离线导入镜像)
Admin(Java)1.0.0K3s(离线导入镜像)
API(Java)1.0.0K3s(离线导入镜像)⚠️ jar包待修复
NginxlatestK3s(离线导入镜像 + ConfigMap)
Milvus2.3.0Docker Compose(保留)
OllamalatestDocker Compose(保留)
FTP3.0.5宿主机原生服务

通信方式:K3s Pod 通过宿主机 IP192.168.18.100访问 Docker 中间件。


三、踩坑实录与根因分析

坑 1:镜像导入明明成功,K3s 却说找不到

现象

bash

ctr -n k8s.io images import mysql.tar # 显示成功 ctr -n k8s.io images ls # 能看到镜像 k3s kubectl apply -f mysql.yaml # Pod 报 ErrImageNeverPull

根因:K3s 使用独立的 containerd(socket:/run/k3s/containerd/containerd.sock),系统ctr操作的是默认 containerd(/run/containerd/containerd.sock),两个实例完全隔离。

解决:所有镜像操作必须用k3s ctr

bash

sudo k3s ctr -n k8s.io images import mysql.tar sudo k3s ctr -n k8s.io images ls

坑 2:imagePullPolicy: IfNotPresent 仍然尝试外网拉取

现象:离线环境下,即便镜像已导入,kubelet 仍报ErrImagePull

根因:镜像名包含docker.io域名时,kubelet 会尝试访问该域名进行元数据校验。

解决:强制使用imagePullPolicy: Never,且镜像名必须与k3s ctr images ls输出完全一致:

yaml

image: docker.io/library/mysql:8.0 imagePullPolicy: Never

坑 3:HostPath 挂载 jar 包失败

现象CreateContainerConfigError,describe 显示failed to prepare subPath for volumeMount

根因:K3s(containerd)不支持用subPath挂载单个文件。

解决:挂载整个目录,command 中指定完整路径:

yaml

volumeMounts: - name: jar mountPath: /app volumes: - name: jar hostPath: path: /home/xyy/k3s-shangzhuhui/jar type: Directory command: ["java", "-jar", "/app/shangzhuhui-admin-1.0.0.jar"]

坑 4:Nginx 配置文件挂载同样踩坑

现象:同样的failed to prepare subPath

解决:改用 ConfigMap 挂载单文件:

bash

kubectl create configmap nginx-config -n biz-shangzhuhui --from-file=nginx.conf

yaml

volumes: - name: nginx-config configMap: name: nginx-config

坑 5:Nginx 启动报 host not found

现象host not found in upstream "shangzhuhui-api"

根因:Nginx 启动时会解析proxy_pass中的域名,后端 Service 不存在则拒绝启动。

解决:注释掉不存在的后端配置,或先部署后端正则。

坑 6:Nginx 重定向丢失端口

现象:访问http://IP:30080/admin返回 301,Location: http://IP/admin(丢端口)

根因try_files $uri $uri/ /admin/index.html中的$uri/触发内部重定向,Nginx 默认用$host构造 Location,不带端口。

解决:添加port_in_redirect on;,或前端直接使用/admin/login等具体路径绕过。

坑 7:数据库名三处不一致

现象:应用报Unknown database 'shangzhuhui'

根因

  • MySQL YAML 中MYSQL_DATABASE: shangzhuhui_v2

  • SQL 脚本中CREATE DATABASE shanzhuhui(注意字母差异)

  • 应用连接串中shangzhuhui

解决:统一改为shangzhuhui,手动导入 SQL:

bash

kubectl exec -n biz-shangzhuhui mysql-xxx -- mysql -p111111 shangzhuhui < schema.sql

坑 8:K3s Pod 无法访问宿主机 Docker 中间件

现象:Java 应用启动报DEADLINE_EXCEEDED,无法连接 Milvus。

排障过程

  1. 先用curl测试网络:kubectl exec -it pod -- curl http://192.168.18.100:19530/api/v1/health返回 404

  2. 404 是 Milvus 健康检查接口路径问题,非网络不通——说明网络层正常

  3. 确认问题不在网络,而在应用 jar 包本身

  4. 健康检查接口最终返回milvus: "OK",确认网络连接正常

结论:网络层无问题,隔离正常。


四、迁移前后资源对比(16G 服务器)

对比数据

指标Docker ComposeK3s变化
系统总内存占用4.1G / 15G4.4G / 15G+0.3G
系统可用内存11G10G-1G
K3s 控制平面~1G+1G
MySQL424M389M-35M
Redis33M5M-28M
Nginx4.8M2M-2.8M
Admin(Java)493M391M-102M

核心结论

  • K3s 控制平面开销约 1G 内存(kubelet + containerd + flannel + apiserver 等)

  • 业务容器内存占用显著降低:Java 服务降低 20%,Redis 降低 85%

  • 净增仅 300MB 内存,换来完整 Kubernetes 编排能力

  • 资源代价极低,适合资源敏感型单机迁移场景


五、固化铁律(K3s 离线部署)

  1. 镜像导入:一律用sudo k3s ctr -n k8s.io images import,不用系统ctr

  2. imagePullPolicy:离线环境必须Never,镜像名与k3s ctr images ls完全一致

  3. HostPath 挂载:挂目录不挂单文件,避免subPath

  4. Nginx 配置:用 ConfigMap 挂载,不用 hostPath 单文件

  5. Nginx 重定向:添加port_in_redirect on,前端尽量使用具体路径

  6. 后端依赖:Nginx 中proxy_pass的后端 Service 必须先存在,否则注释

  7. 数据库:SQL、初始化环境变量、应用连接串,三处库名必须一致

  8. 排障优先级:先验镜像是否导入正确(k3s ctr images ls),再看 Pod 日志


六、常用命令速查

bash

# 导入镜像到 K3s 的 containerd sudo k3s ctr -n k8s.io images import <tar包> # 查看已导入的镜像 sudo k3s ctr -n k8s.io images ls # 重启 K3s 服务 sudo systemctl restart k3s # 查看命名空间下所有资源 kubectl get all -n <namespace> # 实时查看 Pod 日志(按标签筛选) kubectl logs -n <namespace> -l app=<label> -f # 创建 ConfigMap 从文件 kubectl create configmap <名称> -n <ns> --from-file=<文件> # 删除 ConfigMap kubectl delete configmap <名称> -n <ns> # 端口转发:本地工具连接 K3s 内 MySQL(临时调试用) kubectl port-forward -n <ns> svc/mysql 3306:3306 # 查看 Pod 资源占用(CPU/内存) kubectl top pods -n <namespace> # 进入容器调试 kubectl exec -it -n <namespace> <pod名> -- bash

七、底稿收尾

本文是《技术底稿》系列第 36 篇,记录 Docker Compose 微服务迁移 K3s 过程中的完整踩坑、排障、资源对比与规范固化。

核心价值

  • 8 条可复用的 K3s 离线部署铁律

  • 迁移前后真实资源对比数据

  • 单机混合架构(K3s + Docker Compose)通信方案

适合小团队单机迁移、无外网环境 K3s 落地的参考范本。

http://www.jsqmd.com/news/831659/

相关文章:

  • 如何在Blender中完美导入Rhino 3dm文件:终极解决方案指南
  • 免费仿真分析报告生成实战指南
  • 会话管理利器:从JWT到Redis,构建安全可扩展的用户认证系统
  • 从零读懂RDMA的钥匙机制:硬件如何用L_Key/R_Key保护你的内存
  • PyWxDump:从微信数据管理工具到开源合规的深刻教训
  • 从零做了一个 AI 面试陪练工具,聊聊全过程
  • AI Agent在科学研究中的辅助作用
  • 【python基础】使用python下载二进制文件
  • LSM6DS3TR-C与磁力计九轴融合:嵌入式姿态解算算法实现与优化
  • AI如何学习科学品味:从论文评估到智能文献筛选的实践路径
  • 基于PIR传感器与HalloWing的自动惊吓陷阱:嵌入式系统交互实践
  • Rider对非商业用途免费全球最受喜爱的 .NET 和游戏开发 IDE
  • 动画性能监控:打造流畅的用户体验
  • 3分钟解决iPhone在Windows无法上网的终极方案:苹果USB网络共享驱动一键安装指南
  • codex features
  • 降AI率软件越便宜越好吗?实测5个主流降AI工具,首选嘎嘎降!
  • Solon框架解析:轻量级Java应用开发新范式与云原生实践
  • AWorksLP嵌入式开发:基于FatFs的SD卡文件系统操作全解析
  • 2026年当下,长治整屋定制优选平台深度解析与联系指南 - 2026年企业推荐榜
  • Arm Cortex-A处理器缓存与TLB架构深度解析
  • 2026 首发|GEO 全域运营经典案例:公域引流到私域转化全链路完整复盘
  • HAProxy 如何实现 TCP 模式下的 MySQL 数据库负载均衡
  • 基于NLP的文本逻辑分析工具:思考词汇识别与可视化实践
  • 4.AI大模型-幻觉、记忆、参数-大模型底层运行机制
  • 【mv】戏剧结构为什么要设计幕 起承转合 这种设计
  • Harness 中的请求标识染色:端到端追踪
  • 2026年5月河南桥梁护栏项目优选供应商实力解析 - 2026年企业推荐榜
  • 51_《智能体微服务架构企业级实战教程》智能助手主应用服务之保存攻略节点
  • 芯片制程数字背后的真相:从摩尔定律到营销节点的演进
  • 硬件版【Cursor】?aily blockly IDE尝鲜封神,实战硬伤尽显