ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

单节点K8s迁移阿里云ECS:若依微服务平滑迁移与压测实践

单节点K8s迁移阿里云ECS:若依微服务平滑迁移与压测实践 最近一周我都在处理一件事把原来跑在一台单节点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和RedisMySQL又分为业务库、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 CloudNacos已经承担了大部分配置中心职责所以很多配置可以放在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或AlmaLinuxCentOS 7虽然用着顺手但已经停止维护新环境不建议再选。初始化时先做几件基础配置配置主机名改/etc/hosts保证两台机器通过内网IP互通。关闭swapswapoff -a并注释掉fstab里的swap行K8s默认不支持节点上开swap开着会导致kubelet启动报错。调整内核参数比如net.bridge.bridge-nf-call-iptables1、net.ipv4.ip_forward1这些是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平均响应时间小于300msP95小于500ms错误率低于0.1%且长时间运行后Pod没有OOM、RDS没有锁等待堆积、Redis没有连接数打满。我会把最终结果整理成一张表发给团队和压测方并发数、TPS、平均响应时间、P99、错误率、各节点CPU/内存、数据库连接数。这样“承载能力”就有了数据支撑后续扩容、买多少台ECS、RDS规格多大都拿这份数据去论证。压测结束后记得清掉压测产生的脏数据比如创建的测试用户、写入的测试记录恢复环境干净状态再做一次业务回归确认一切正常。5. 常见问题与避坑速查表5.1 部署与迁移阶段的典型问题把这次迁移和平时帮人排查的K8s问题整理成一个速查表方便按图索骥问题现象大概率原因快速处理Pod一直Pending节点资源不足、没有匹配的StorageClasskubectl describe pod看Event扩容节点或调整调度ImagePullBackOff镜像拉取失败、仓库登录凭证缺失检查镜像地址、配置镜像加速、创建imagePullSecretCrashLoopBackOff配置错误、数据库连不上、启动命令不对看容器日志重点查环境变量和连接串服务注册不上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这几年最深的体会是迁移这种事最怕的不是技术难而是没想清楚“数据怎么保、流量怎么切、回滚怎么走”。这次把若依整套环境挪到阿里云方案看着很常规真正落地时全是一块一块补细节补出来的。如果你正准备做类似的迁移建议先把数据同步和回滚预案想透再动手折腾应用。
返回列表