单节点K8s迁移阿里云ECS:若依微服务平滑迁移与压测实践
2026/9/18 2:53:41 网站建设 项目流程

最近一周我都在处理一件事:把原来跑在一台单节点Kubernetes上的若依微服务整套环境,整体迁移到阿里云的ECS上。团队和业务侧的要求很直接——准不停服、不丢数据,迁完之后还要配合压测人员用JMeter脚本做高并发测试,验证新环境到底能扛住多少流量。

单节点K8s这套东西,平时“能跑就行”的感觉挺强,可真到迁移这一刻,整个单点结构、数据同步方式、应用编排里的历史包袱就全暴露了。这篇文章我想用这次迁移的完整过程,把方案选型、数据层怎么同步、应用层怎么平滑切换、压测结果怎么看都讲透。如果你正准备把一套自建K8s往阿里云挪,或者在折腾若依这类Spring Cloud微服务体系,这篇应该能帮你少踩不少坑。

1. 迁移前先想清楚:原环境的风险与迁移方案选型

1.1 单节点K8s为什么“能跑”却让人不踏实

我接手这套若依环境时,它跑在一台配置并不高的机器上,组件全堆在一起:etcd、kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、容器运行时,以及所有业务Pod都挤在同一台机器里。这套结构最直接的感受是“省心”,一台机器搞定,没有复杂的网络和存储配置,日常测试和演示确实够用。但真放到生产视角去看,隐患非常明显。

第一,单点是最大的敌人。机器只要宕机或重启,整个集群的管理面和业务面一起挂掉。你别说“我们不会遇到宕机”,磁盘写满、内核panic、云厂商宿主机维护触发迁移,这些事都真实存在。第二,资源互相抢。etcd是IO敏感型组件,业务Pod里的Java进程又是内存大户,两者抢CPU、抢磁盘IO,表现就是集群突然卡顿,Pod频繁重启。第三,升级和证书处理困难。K8s版本升级时,控制平面组件都在同一台机器上,升级一个组件就可能导致整个集群不可用。kubeadm的证书默认一年有效期,忘了renew就会出现集群突然不可用的情况。

所以这次迁移,本质上不只是“换一台更好的服务器”,而是借机把单点结构梳理掉。我也理解很多小团队选单节点是因为费用和运维能力有限,那至少要做到:数据组件单独部署、定期快照、证书续期提醒、备份可恢复。

1.2 为什么选“重建+数据同步”,而不是整机迁移

刚开始也有人提方案:把旧机器做成自定义镜像,再在阿里云上通过该镜像创建新的ECS,这不就迁移了吗?确实快,但问题一大堆:镜像里带着旧内核、旧容器运行时版本、旧证书,还有一堆历史遗留的配置和脏数据;原机器的IP、hosts、磁盘分区也不一定适合新环境;更重要的是这种迁移方式缺少“数据校验”和“干净重建”的确定性。

我最终选了“重建+数据同步”路线:在阿里云上新建一套K8s集群,应用通过Kubernetes清单文件重新编排,数据层用备份/同步工具做在线迁移,最后把流量切换过去。这套方案最大的好处是可控:应用层每一份清单都是新的、可追溯的;数据层可以做全量校验;切换前可以随时回滚,旧环境保留一段时间观察,风险大大降低。

“准不停服、不丢数据”具体怎么落地,后面细讲。核心思路是:数据层做增量同步,应用层做滚动替换,入口流量最后切。

1.3 目标架构怎么设计:阿里云上的角色划分

在阿里云上搭目标环境,我主要考虑了三层:底层基础设施、集群层、应用层。

底层基础设施,按预算选了ECS。这里有个选择题:用阿里云ACK托管版,还是自己用kubeadm在ECS上搭自建K8s。ACK托管版的好处是控制面不用自己维护,升级、etcd备份都由平台处理;自建的好处是成本更灵活,组件版本可控,问题排查时能贴近底层。我们这次为了保留完整运维能力,选择了ECS自建。但说句实在话,如果团队没有专职K8s运维,我更推荐ACK托管版,别把时间耗在控制面组件上。

集群层,至少两台ECS:一台作为master,打上污点不让业务Pod往里塞;一台作为worker。如果预算非常有限,单节点也能跑,但那种情况下我会建议数据库直接用云数据库RDS,至少把数据和业务的承载分离。应用层就比较标准了:若依微服务包含Nacos、Gateway、Auth、System、Gen、File等模块,外加MySQL、Redis。数据库这块我直接选了RDS MySQL,自带备份、高可用、性能监控,比自己在ECS里装一套省心得多;Redis也用云数据库Redis版,少背一个运维包袱。这样“云上承载能力”的验证,其实也包含了云数据库这部分能力的验证,压测结果更有说服力。

2. 核心细节拆解:镜像、配置与“不丢数据”的关键

2.1 镜像仓库与镜像加速:先把“拉取”理顺

迁移过程中最容易被低估的环节就是镜像。很多团队开发机上的镜像是直接打在本地的Docker daemon里的,没有统一仓库。如果沿用这种习惯,新集群里每一台节点都要去开发机拉镜像,流程既慢又不可控。

我这次的做法是先把所有业务镜像推到阿里云容器镜像服务ACR的个人版上。个人版免费,额度对中小项目完全够用。推送之前注意几点:镜像tag要规范,建议按“模块名-环境-时间”命名;若依这类多模块项目,提前梳理需要迁移的镜像清单,包括nacos、mysql、redis、ruoyi-gateway、ruoyi-auth、ruoyi-system、ruoyi-file、ruoyi-job,还有前端镜像。推送就是常规操作:docker login registry.cn-hangzhou.aliyuncs.com,然后给本地镜像打上对应阿里云仓库的tag再push。

然后是镜像加速配置。K8s节点在拉取镜像时,如果走默认Docker Hub,速度会非常慢,尤其在国内网络环境下,经常出现ImagePullBackOff。阿里云容器镜像服务控制台里每个账号都有专属加速地址。如果你用的是containerd,配置文件通常在/etc/containerd/config.toml,需要在registry.mirrors下面配置endpoint;如果是Docker,就修改/etc/docker/daemon.json里的registry-mirrors。这个配置一定提前做,别等部署报错再临时补。

还有个容易被忽略的加速点:Maven依赖。构建后端镜像时,依赖下载极其耗时。建议在构建基础镜像或CI流水线里配置阿里云Maven镜像仓库,把依赖下载源切到国内,构建速度会有非常直观的提升。这个细节很多人不注意,迁移当天才去临时拉依赖,一等就是半小时起步。

2.2 Kubernetes清单文件迁移:别走“导出即用”的老路

清单文件这块,我见过不少人直接kubectl get deployment xxx -o yaml --export导出,然后在新环境apply。老版本的--export会丢掉一些关键字段,而且导出的yaml里常常带着status、metadata.managedFields这类当前运行态的冗余信息,直接使用会很乱。建议用kubectl get deploy xxx -o yaml再做字段清理,或者干脆用Helm/Kustomize把清单规范化。

这次迁移时,我把所有服务的部署清单统一用Kustomize管理,为每个环境维护一份base和overlay,差异点集中在镜像地址、副本数、资源限制、环境变量。迁移时只需要生成对应阿里云环境的overlay。这样做的好处是:换环境、换镜像、调副本数都只要改几个字段,不用复制一堆yaml。

改造清单时要重点检查这几个点:

  • imagePullPolicy,生产环境建议IfNotPresent或Always,别让节点用缓存旧镜像。
  • resources.requests/limits,这一步非常关键,没有资源限制的Pod会把节点内存打满,K8s会开始无差别驱逐Pod。
  • 持久化存储的StorageClass名称,阿里云有alicloud-disk-essd这类存储类,旧的StorageClass名字在新环境不通用,需要修改。
  • Service、Ingress的域名、端口映射是否匹配。
  • 环境变量配置和ConfigMap挂载路径是否正确。

2.3 数据不丢失:数据库与中间件同步策略

这是整个迁移里最核心、也是最容易出问题的部分。若依微服务用到的主要数据组件是MySQL和Redis,MySQL又分为业务库、Nacos配置库等若干库。我做数据迁移分三步:全量、增量、校验。

MySQL如果继续用ECS自建,最直接的方式是mysqldump导出全量,再到目标库导入,随后通过binlog做增量。但这种方式配置比较繁琐,而且需要业务侧配合暂停写入。如果你和我一样选了RDS MySQL,强烈建议用阿里云数据传输服务DTS来做“结构迁移+全量数据迁移+增量数据同步”。DTS的特点是能一边同步一边追增量,你可以在业务低峰期先启动迁移,等增量追平后,在一个极短的维护窗口内切连接串,完成切换。这样“准不停服、不丢数据”就落地了:业务不停,只是切换瞬间应用滚动更新。

Redis迁移相对简单。如果旧环境Redis数据量不大,几百MB以内,可以直接在目标Redis上执行数据同步或使用快照迁移。云数据库Redis版一般自带迁移工具;自建Redis之间建议用redis-shake,能在线同步并支持增量。这里要提醒的是,Redis里如果有缓存前缀,迁移后检查一遍key是否完整,可以用dbsize对比数量,再抽样几个key看值是否一致。

最后是Nacos的配置存储。Nacos默认把配置存在数据库表config_info里,如果只迁移业务库而漏了Nacos库,新环境启动后服务会全部拿着空配置,后果很惨。迁移Nacos时,建议连配置库一起同步,或者在目标Nacos控制台里重新发布所有配置,并在迁移后逐个服务检查配置是否加载正常。

2.4 配置、密钥与SSL证书:细节里藏着的坑

应用配置里最常见的错误是把数据库密码、Redis密码直接写进Deployment的env里,甚至写进镜像里。这种习惯非常不安全,迁移时也容易因连接串不同而到处找配置。正确的做法是用ConfigMap放普通配置,用Secret放账号、密码。若依微服务本身基于Spring Cloud,Nacos已经承担了大部分配置中心职责,所以很多配置可以放在Nacos里维护,应用替换只是换了部署方式,配置随Nacos走。

SSL证书部分,如果业务域名要对外提供HTTPS,建议在阿里云SSL证书服务里申请免费证书,并设置到期提醒或自动续期。证书绑定域名后,在Ingress层挂载证书,对外只暴露HTTPS,内部服务之间走HTTP没问题。很多人用的免费证书一年一换,最容易翻车的就是忘了续期,建议直接开启自动续期,或者至少提前一个月设置日历提醒。

安全组也别忘了。ECS安全组如果不放行对应端口,比如K8s的6443、NodePort范围、Ingress的80/443,外部流量进不来。本地调试时curl不通,第一反应往往是“服务没起来”,其实多半是安全组拦了。迁移期间建议把安全组规则整理成表:管理端口、业务端口、VPC内部互通分别开放给谁,避免出问题后排查半天。

3. 实操过程:从零拉起阿里云K8s并完成迁移

3.1 ECS初始化与K8s集群部署

目标环境我用两台ECS,一台master一台worker。操作系统建议用Rocky Linux或AlmaLinux,CentOS 7虽然用着顺手,但已经停止维护,新环境不建议再选。初始化时先做几件基础配置:

  • 配置主机名,改/etc/hosts,保证两台机器通过内网IP互通。
  • 关闭swap,swapoff -a并注释掉fstab里的swap行,K8s默认不支持节点上开swap,开着会导致kubelet启动报错。
  • 调整内核参数,比如net.bridge.bridge-nf-call-iptables=1、net.ipv4.ip_forward=1,这些是K8s网络组件正常工作的前提。
  • 安装containerd并配置好镜像加速。

K8s部署用kubeadm。master节点上执行kubeadm init,初始化时指定apiserver的advertise-address和Pod网段。初始化完成后,把生成的join命令保存好,在worker节点上执行kubeadm join即可。网络组件我推荐Calico,模式用IPIP就行,简单稳定,不需要额外搞BGP。另外记得部署metrics-server,不然kubectl top命令不可用,后面压测排查会很不方便。

这套流程看起来不难,但新手最容易在版本匹配上翻车:kubeadm、kubelet、kubectl版本要一致,containerd版本要和K8s版本匹配,网络插件版本也要在官方支持范围内。建议先查好版本兼容矩阵再动手,别用“最新版+最新版”盲目组合。

3.2 中间件与应用编排:按依赖顺序拉起整套服务

集群就绪后,先部署中间件,再部署业务应用。这个顺序不能乱,否则应用起来后注册不上Nacos,日志里全是连接报错。

第一步,部署MySQL或直接用RDS,并初始化若依需要的数据库。若依体系下需要创建主业务库,还要执行官方提供的SQL脚本。如果用RDS,直接通过DMS执行SQL即可。第二步,部署Redis,设置好密码。如果在K8s里部署Redis,注意用StatefulSet跑并配置PV,别用宿主机路径就完事,Pod漂移后数据就丢了。第三步,部署Nacos,建议也用StatefulSet,因为它需要持久化配置数据;Nacos依赖MySQL,连接串要指向第一步准备好的数据库。第四步,部署业务服务。顺序上建议先启动网关和认证中心,再启动系统服务等业务模块,最后启动前端。每个服务起来后,去Nacos控制台看服务列表是否注册成功,再通过网关访问认证接口验证链路。

这里再提醒一个细节:所有业务Pod尽量设置resources limits。压测前如果发现Pod被OOMKilled,先看是不是limits给得太低;压测后如果节点被拖垮,也要看是不是有Pod没设requests。

3.3 准不停服的切换细节:数据先切、流量后切

迁移最紧张的是切换窗口。我的做法分三步走。

第一步,数据层切换。先启动DTS的结构迁移、全量迁移和增量同步,让新RDS里数据先追平。业务低峰期,把应用连接串切到新库,应用滚动重启。由于增量同步的延迟很可能只有几秒钟,即使这段时间有少量写入,DTS也会在切换前追平,理论上不丢数据。第二步,验证应用。切换连接串后,先不急着切用户流量,自己在新环境里完成登录、增删改查、上传下载等核心操作,确认功能正常。第三步,流量切换。如果原来有域名,提前把DNS解析的TTL调低到几十秒,在切换窗口内把域名解析到新环境的SLB或EIP,同时观察Ingress日志和错误率,确认无误后再把TTL调回正常值。

回滚预案也很重要。我把旧环境在迁移后保留了一周,一旦新环境出现严重问题,能把DNS切回去,应用数据最多损失几秒同步延迟,这个可接受范围一定要提前和业务方确认。

3.4 迁移完成后的自检清单

迁移完成后,我整理了一个简易清单,逐项打勾确认:

  • kubectl get nodes,所有节点Ready。
  • kubectl get pods -A,所有Pod处于Running/Completed状态,没有CrashLoopBackOff。
  • 登录Nacos控制台,确认所有服务实例都注册成功,重复实例清理干净。
  • 用测试账号走一遍核心流程:登录、验证码、查询、新增、修改、删除、文件上传下载、定时任务触发。
  • 检查日志里是否有连接超时、注册失败、序列化异常等关键字。
  • 检查磁盘、内存、CPU使用率,确认新环境负载符合预期。
  • 接入云监控,配置报警规则,比如Pod重启、节点磁盘超过80%、RDS连接数过高等告警。

这套自检走完,迁移的“上线感”才算真正落地。

4. Jmeter高并发压测:验证云上承载能力的完整实录

4.1 压测前准备:先说清楚测什么、怎么算达标

压测最怕“没目标就开跑”。这次和压测人员对需求,我主要确认了三件事:并发规模、接口范围、达标线。比如目标并发500、核心接口是登录和各业务列表接口、期望P95响应时间不超过500ms、错误率低于0.1%,这才算通过。

除了目标,还要确认压测机的网络位置。如果压测机在本地公网,压测结果会受带宽、延迟、运营商网络波动影响,容易误判服务能力。最理想是把压测机放到同一个阿里云地域,甚至同一个VPC内部,这样压测的是真实服务承载能力,而不是网络链路的瓶颈。如果做不到,至少要把公网带宽考虑进去,别压测时EIP带宽被拉满,服务其实还很空。

另外压测前的环境隔离很重要:不要在业务高峰期压,也不要在压测同时跑大数据任务或全量备份,避免结果互相干扰。

4.2 JMeter脚本与场景设计要点

压测人员最终用固定JMeter脚本执行,但我自己也提前准备了一套压测场景,便于环境自检。这里说几个要点。

线程组建议用阶梯加压,比如每30秒增加50并发,通过插件Stepping Thread Group实现。这样能观察服务从空载逐步加压时的表现,而不是一上来直接500并发,分不清是在多少并发下开始劣化的。脚本里要用CSV参数化用户数据,避免所有请求共用同一个登录token。若依有验证码机制,压测时要先关闭或通过测试接口绕过验证码,否则脚本跑起来全在验证码断言上失败。

响应断言也很关键,要校验HTTP状态码和关键字,不能只看请求数,否则接口返回500也算“成功”。JMeter命令行执行时加上监听器输出,建议用聚合报告和TPS曲线,保存结果到jtl后,再生成HTML报告:

jmeter -n -t test.jmx -l result.jtl -e -o report

压测结束后,不要马上看结果下结论,等一段时间让JVM释放连接、GC平稳后再看平均结果。如果是长时间压测,比如30分钟,还要关注是否有内存泄漏趋势,Pod内存是否一直往上走。

4.3 压测中最常见的瓶颈与排查思路

压测过程中,我遇到最多的问题集中在几个层面。

第一,数据库连接池。若依这种Spring Boot应用默认的连接池参数相对保守,高并发时数据库连接可能成为瓶颈。表现是接口超时、连接池获取连接异常。排查方式:看应用日志、连接池监控,必要时调大HikariCP的maximum-pool-size,同时确认RDS的最大连接数和规格是否足够。这里建议压测前先做预估:500并发、每个请求把连接拿多久,合理估算连接池大小,而不是随便调大到1000。

第二,网关线程和Tomcat线程。Spring Cloud Gateway默认线程配置如果没调,并发上来后线程池满,请求排队,响应时间快速抬高。这一步需要在压测前就确认,或者压测后根据TPS瓶颈调整。

第三,GC问题。Java应用在压测时最容易暴露的就是GC。通过jstat或者Spring Boot Admin监控,如果看到频繁Full GC,说明堆内存或者对象分配有问题,可能要把堆内存调大,或优化业务代码。

第四,Redis热点和缓存穿透。若依登录验证码、用户信息等都依赖Redis,压测时如果大量请求同一个key或者未命中缓存,Redis连接数会飙升。排查时看Redis的QPS、连接数、慢查询日志。

这里我做了一个排查速查表:

现象可能原因查看方式解决方向
Pod频繁重启,内存居高没有配置limits或配置过高kubectl top pods、kubectl describe pod设置合理的内存limits,排查内存泄漏
接口超时,错误率上升数据库连接池打满应用日志、RDS监控、HikariCP指标调大连接池、优化慢SQL、提升RDS规格
TPS上不去,CPU还有余量网关线程池或Tomcat线程池满查看网关线程监控调整线程池参数、增加网关副本
压测数据一大就慢慢SQL或锁等待RDS慢查询日志、数据库锁等待添加索引、优化事务、拆分大事务
所有请求都走同一个缓存key缓存热点Redis监控增加本地缓存、热点key分散

4.4 承载能力怎么判定:给结果一个可量化的标准

压测完不能只说“挺稳的”,要有可量化的结论。这次我们最终通过的标准是:目标并发500下,TPS不低于预设值(比如2000),平均响应时间小于300ms,P95小于500ms,错误率低于0.1%,且长时间运行后Pod没有OOM、RDS没有锁等待堆积、Redis没有连接数打满。

我会把最终结果整理成一张表发给团队和压测方:并发数、TPS、平均响应时间、P99、错误率、各节点CPU/内存、数据库连接数。这样“承载能力”就有了数据支撑,后续扩容、买多少台ECS、RDS规格多大,都拿这份数据去论证。

压测结束后,记得清掉压测产生的脏数据,比如创建的测试用户、写入的测试记录,恢复环境干净状态,再做一次业务回归,确认一切正常。

5. 常见问题与避坑速查表

5.1 部署与迁移阶段的典型问题

把这次迁移和平时帮人排查的K8s问题整理成一个速查表,方便按图索骥:

问题现象大概率原因快速处理
Pod一直Pending节点资源不足、没有匹配的StorageClasskubectl describe pod看Event,扩容节点或调整调度
ImagePullBackOff镜像拉取失败、仓库登录凭证缺失检查镜像地址、配置镜像加速、创建imagePullSecret
CrashLoopBackOff配置错误、数据库连不上、启动命令不对看容器日志,重点查环境变量和连接串
服务注册不上NacosNacos地址配错、网络不通看服务日志,检查配置文件,telnet测试端口
访问不了服务安全组未放行、NodePort/Ingress配置错误检查安全组、SVC Endpoints、Ingress规则
K8s证书过期kubeadm证书默认一年kubeadm cert renew,然后重启控制面组件
节点NotReadycontainerd异常、内存/磁盘满kubectl describe node,查看kubelet日志

5.2 压测阶段的典型问题

  • 错误率突然飙升:先看是不是数据库连接池满了,再看GC,别一上来就调代码。
  • TPS曲线波形抖动厉害:大概率有排队或资源争抢,需要对比各组件指标定位。
  • JMeter脚本一直报验证码错误:测试环境建议关闭验证码或走测试接口,别让断言干扰压测数据。
  • 压测时应用正常、网络偶发超时:检查安全组、带宽、负载均衡健康检查配置。

5.3 一些长期运营建议

最后再分享几个长期建议,都是这次迁移后我才真正重视起来的。

备份别嫌麻烦。数据库用RDS后,自动备份一定要开启;自建etcd的话,建议每天做快照并放到OSS保留一周以上。K8s应用资源也建议定期导出到Git仓库,出问题能快速重建。日志别散落各地,可以用阿里云SLS或自建Loki把Pod日志收拢,问题排查能省一半时间。这次压测能快速定位到连接池问题,就是因为日志集中了。

资源限额一定要设。没有limits的集群就像没刹车的车,一个Pod就能把整台机器拖垮,压测结果就是最好的调整依据。HPA按压测数据配置,给核心服务设好HorizontalPodAutoscaler,按CPU或自定义指标扩缩容,日常低峰期省成本,高峰期自动扛。

我个人折腾K8s这几年最深的体会是:迁移这种事,最怕的不是技术难,而是没想清楚“数据怎么保、流量怎么切、回滚怎么走”。这次把若依整套环境挪到阿里云,方案看着很常规,真正落地时全是一块一块补细节补出来的。如果你正准备做类似的迁移,建议先把数据同步和回滚预案想透,再动手折腾应用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询