1. 为什么你的微服务部署还在“停机维护”聊聊蓝绿部署那点事嘿朋友们我是老王一个在微服务和容器化领域摸爬滚打了十来年的老码农。不知道你们有没有经历过这种场景半夜三更整个团队如临大敌发布公告写好服务准备下线就为了更新一个功能。用户看着“系统维护中”的页面你在屏幕前祈祷一切顺利千万别回滚。这种体验说实话糟透了。后来我们引入了滚动更新情况好了不少但心里还是不踏实。新版本Pod一个个起来老版本Pod一个个下线流量在中间“摇摆”万一新版本有隐藏的Bug一部分用户已经“中招”了。直到我们把目光投向了蓝绿部署才真正找到了那种“优雅”和“从容”的感觉。简单来说蓝绿部署就是准备两套完全独立的环境一套是当前正在服务线上流量的“绿”环境另一套是部署了新版本的“蓝”环境。当“蓝”环境经过充分验证后我们通过一个“开关”瞬间将所有流量从“绿”环境切换到“蓝”环境。如果“蓝”环境有问题再瞬间切回“绿”环境。整个过程对用户来说是无感的真正实现了零停机和瞬时回滚。听起来很美好对吧但实操起来自己搭建两套K8s集群管理两套负载均衡维护成本高得吓人。别急今天我就手把手带你用阿里云云效和ACK阿里云容器服务Kubernetes版在不增加额外硬件和复杂配置的情况下玩转微服务的蓝绿部署。你会发现借助成熟的云原生工具链这件事比你想象的要简单得多。2. 环境准备给你的ACK集群和云效流水线“热身”工欲善其事必先利其器。在开始编排我们的蓝绿交响曲之前得先把舞台和乐器准备好。这里不需要你从零开始搭建K8s阿里云ACK已经为我们提供了托管的、高可用的Kubernetes集群省去了大量运维的心力。2.1 搭建你的ACK“双舞台”蓝绿部署的核心是两套独立的环境。在ACK里我们不需要真的搞两个物理集群那样太奢侈了。一个更巧妙的做法是利用Kubernetes的命名空间Namespace进行逻辑隔离。登录阿里云容器服务控制台创建一个标准的ACK托管版集群。节点配置根据你的业务量来初期2-4个节点足够。关键步骤来了为蓝绿环境创建两个独立的命名空间。# 创建蓝色环境命名空间 kubectl create namespace production-blue # 创建绿色环境命名空间 kubectl create namespace production-green你可以为这两个命名空间打上不同的标签方便后续管理# blue-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: production-blue labels: env: production deployment-color: blue --- # green-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: production-green labels: env: production deployment-color: green接下来我们需要一个统一的“流量指挥家”——阿里云应用型负载均衡ALB。在ACK集群中创建一个ALB实例它将成为我们对外暴露服务的唯一入口也是后续实现流量瞬间切换的关键。在ALB的控制台创建一个监听器指向我们后端的ACK集群。先别急着配置具体路由这个我们后面会通过Ingress来动态管理。2.2 配置云效流水线你的自动化“指挥棒”环境搭好了我们需要一个自动化的“指挥棒”来协调整个部署流程。这就是阿里云云效的流水线。云效的好处是它与ACK、ACR容器镜像服务同属阿里云生态集成起来异常顺畅。首先在云效中创建一个新的“企业级”流水线。在代码源部分关联你的Git仓库比如Gitee或GitLab。然后我们需要精心设计流水线的阶段。一个典型的蓝绿部署流水线会包含以下阶段代码质量门禁自动运行单元测试、代码扫描。构建与打包编译代码构建Docker镜像。镜像推送将镜像推送到ACR并打上包含Git提交哈希和构建时间的标签。部署到预备环境蓝将新版本部署到“蓝色”命名空间。自动化验证对蓝色环境进行接口测试、集成测试。流量切换通过更新ALB/Ingress配置将流量从绿色切换到蓝色。观察与回滚监控蓝色环境运行状态如有问题一键切回绿色。在流水线配置中最关键的是要能识别当前“线上”是哪个颜色以及决定本次部署的目标颜色。我常用的一个策略是在云效的“环境变量”或“参数”中用一个变量如ACTIVE_COLOR来记录当前生产环境活跃的颜色。每次部署流程都会读取这个变量然后部署到非活跃的那个颜色环境。3. 核心实战一步步实现蓝绿部署流水线理论说再多不如动手干。下面我们就来拆解流水线中最核心的几个环节看看具体的配置和命令是怎么写的。3.1 镜像构建与推送打好每一次发布的“标签”构建阶段的核心是生成一个唯一的、可追溯的Docker镜像。我强烈建议不要只用latest标签这不利于回滚。我的组合拳是分支名-git提交短哈希-时间戳。在云效的“构建”阶段添加一个“执行命令”的步骤#!/bin/bash # 获取Git提交短哈希 GIT_SHA$(git rev-parse --short HEAD) # 获取当前时间戳 TIMESTAMP$(date %Y%m%d%H%M%S) # 定义镜像标签 IMAGE_TAG${CI_COMMIT_REF_NAME}-${GIT_SHA}-${TIMESTAMP} # 构建镜像 docker build -t $REGISTRY/$IMAGE_REPO:$IMAGE_TAG . # 额外打一个latest标签指向本次构建 docker tag $REGISTRY/$IMAGE_REPO:$IMAGE_TAG $REGISTRY/$IMAGE_REPO:latest # 推送镜像 docker push $REGISTRY/$IMAGE_REPO:$IMAGE_TAG docker push $REGISTRY/$IMAGE_REPO:latest这里CI_COMMIT_REF_NAME和REGISTRY等都可以作为云效的预定义变量或自定义变量传入。这样每次构建的镜像都有唯一标识在ACR中一目了然。3.2 部署到“蓝色”环境让新版本先“彩排”假设当前ACTIVE_COLORgreen那么本次部署的目标就是blue命名空间。我们需要准备一套Kubernetes的部署清单YAML文件但其中关于镜像版本和命名空间的部分需要被流水线动态替换。我的做法是在代码库中存放一套模板文件例如deployment-bluegreen-template.yaml。在云效的“部署”阶段使用sed或envsubst命令进行渲染#!/bin/bash # 确定目标颜色 if [ $ACTIVE_COLOR green ]; then TARGET_COLORblue TARGET_NAMESPACEproduction-blue else TARGET_COLORgreen TARGET_NAMESPACEproduction-green fi # 渲染 Kubernetes 配置文件 export DEPLOYMENT_COLOR$TARGET_COLOR export IMAGE_URL$REGISTRY/$IMAGE_REPO:$IMAGE_TAG export NAMESPACE$TARGET_NAMESPACE # 使用 envsubst 替换模板中的变量 envsubst k8s/deployment-bluegreen-template.yaml k8s/deployment-$TARGET_COLOR.yaml envsubst k8s/service-template.yaml k8s/service-$TARGET_COLOR.yaml envsubst k8s/ingress-template.yaml k8s/ingress-$TARGET_COLOR.yaml # 应用配置到目标命名空间 kubectl apply -f k8s/deployment-$TARGET_COLOR.yaml -n $TARGET_NAMESPACE kubectl apply -f k8s/service-$TARGET_COLOR.yaml -n $TARGET_NAMESPACE # 注意Ingress暂时不应用等验证通过后再切换模板文件deployment-bluegreen-template.yaml长这样apiVersion: apps/v1 kind: Deployment metadata: name: myapp-${DEPLOYMENT_COLOR} labels: app: myapp version: ${DEPLOYMENT_COLOR} spec: replicas: 2 selector: matchLabels: app: myapp version: ${DEPLOYMENT_COLOR} # 关键通过version标签区分蓝绿 template: metadata: labels: app: myapp version: ${DEPLOYMENT_COLOR} spec: containers: - name: myapp image: ${IMAGE_URL} # 动态替换为本次构建的镜像 ports: - containerPort: 8080 readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 5这里有个关键点Deployment 和 Pod 的标签里我增加了一个version: blue/green的标签。后续Service和Ingress正是通过选择这个标签来决定将流量路由到哪一组Pod。3.3 流量切换的魔法Ingress与Service的联动这是蓝绿部署最精髓的一步。我们之前创建了ALB作为入口现在需要在ACK集群内创建Ingress资源来定义路由规则。为了让流量能在蓝绿环境间切换我们需要两套Service但只有一个Ingress。创建蓝绿Service分别为蓝色和绿色环境创建ClusterIP类型的Service。它们通过selector中的version标签来分别指向各自环境的Pod。# service-blue.yaml apiVersion: v1 kind: Service metadata: name: myapp-service-blue namespace: production-blue spec: selector: app: myapp version: blue # 选择蓝色环境的Pod ports: - port: 80 targetPort: 8080创建统一的Ingress这个Ingress定义路由规则但其后端服务serviceName指向哪个Service是可以动态修改的。初始状态下它指向绿色环境的Service。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress annotations: # 使用阿里云ALB的注解 alb.ingress.kubernetes.io/backend-protocol: HTTP alb.ingress.kubernetes.io/healthcheck-path: /actuator/health spec: ingressClassName: alb rules: - host: api.yourdomain.com http: paths: - path: / pathType: Prefix backend: service: name: myapp-service-green # 初始指向绿色服务 port: number: 80执行切换当蓝色环境部署并验证通过后流量切换就变成了一个极其简单的操作——修改Ingress的一个字段。在云效流水线中添加一个“流量切换”步骤# 将Ingress的后端服务从绿色改为蓝色 kubectl patch ingress myapp-ingress -p {spec:{rules:[{host:api.yourdomain.com,http:{paths:[{path:/,backend:{service:{name:myapp-service-blue,port:{number:80}}},pathType:Prefix}]}}]}}这条kubectl patch命令会直接更新Ingress的配置。阿里云ALB控制器会实时监听到这个变化并在几秒内将ALB的后端服务器组从绿色的Pod切换到蓝色的Pod。这个过程是瞬间的不会丢弃任何在线连接。3.4 自动化验证与安全回滚切换流量不是结束。我们必须观察蓝色环境在承接真实流量后的表现。在云效流水线中可以在切换后加入一个“观察期”例如5-10分钟并配置自动化验证。自动化验证添加一个步骤使用curl或专业的API测试工具对新环境的核心接口进行一轮快速冒烟测试检查响应状态码、关键业务字段是否正确。监控告警对接确保你的应用监控如ARMS和日志服务SLS已经就绪。在观察期内密切关注错误率、延迟等关键指标。可以设置一个云效的“人工卡点”让负责人查看监控仪表盘确认无误后再继续。一键回滚如果发现蓝色环境有严重问题回滚操作和切换操作一样简单——将Ingress的backend改回原来的绿色Service。因为绿色环境一直保持运行且未做任何改动所以回滚是瞬时且安全的。# 回滚到绿色环境 kubectl patch ingress myapp-ingress -p {spec:{rules:[{host:api.yourdomain.com,http:{paths:[{path:/,backend:{service:{name:myapp-service-green,port:{number:80}}},pathType:Prefix}]}}]}}环境清理与状态更新确认蓝色环境稳定运行一段时间例如30分钟后流水线可以执行最后一步更新环境状态变量将ACTIVE_COLOR从green改为blue并为下一轮部署做好准备。此时旧的绿色环境可以保留一段时间作为热备也可以选择将其下线以节省资源。4. 避坑指南我在蓝绿部署中踩过的那些“雷”看起来流程很顺畅在实际操作中我踩过不少坑这里分享给你希望能帮你省下几个小时甚至几天的排查时间。第一个大坑会话Session保持问题。如果你的应用是有状态的用户登录信息存在了绿色环境的Pod内存里流量突然切到蓝色环境用户会话就丢了直接导致“被登出”。解决方案有两个一是将会话数据外部化存到Redis等共享存储中这是云原生应用的最佳实践二是在ALB层面开启会话保持基于Cookie或源IP确保同一个用户的请求在切换窗口期内仍落到同一个颜色环境但这会延长整体切换时间。第二个坑数据库与缓存的数据兼容性。新版本蓝色的数据库表结构或缓存数据结构如果与旧版本绿色不兼容切换后立刻就会报错。务必把数据库迁移Migration作为部署流程的一部分并在切换前确保迁移已完成且可回退。对于缓存可以考虑在部署后让蓝色环境预热缓存或者使用双写策略来平滑过渡。第三个坑配置管理混乱。蓝色和绿色环境除了代码版本配置如Nacos中的配置项也必须严格区分。我的经验是使用不同的命名空间Namespace或分组Group来隔离蓝绿环境的配置。在应用启动时通过环境变量注入当前的颜色标识从而拉取对应环境的配置。第四个坑健康检查不充分。就绪探针Readiness Probe没配置好Pod还没真正启动完成比如没注册到Nacos、数据库连接池没初始化好就被标记为Ready流量切过来直接500错误。一定要确保就绪探针检查的是应用的业务就绪状态而不仅仅是Web端口监听。Spring Boot Actuator的/actuator/health/readiness端点是个好选择但要记得自定义健康指示器把关键外部依赖数据库、Redis、注册中心的健康状态都包含进去。5. 高阶玩法与优化让部署更丝滑基础流程跑通后我们可以玩点更高级的进一步提升安全性和用户体验。金丝雀发布与蓝绿部署结合蓝绿是“全有或全无”的切换风险依然集中。我们可以先进行金丝雀发布——只将一小部分流量比如1%导入蓝色环境观察监控指标。如果一切正常再逐步放大蓝色环境的流量比例5%10%50%最后完成100%切换。阿里云ALB原生支持基于权重的流量转发你可以通过修改Ingress的注解轻松实现按权重的流量分发这比单纯的蓝绿切换更平滑。自动化测试集成在部署到蓝色环境后、切换流量前插入一个自动化集成测试阶段。这个阶段可以自动运行一套针对蓝色环境API的测试用例只有全部通过才允许进行流量切换。云效流水线支持调用自定义的测试任务你可以把测试框架如Postman Collection, Jmeter脚本集成进来。基础设施即代码IaC我们上面手动创建命名空间、Service、Ingress的过程完全可以代码化。使用Terraform或阿里云资源编排服务ROS来定义和管理这些K8s资源。这样你的蓝绿环境本身也是可版本化、可重复创建和销毁的。将环境准备也纳入流水线实现真正的“一键部署”。成本优化维护两套完全一样的环境资源成本是双倍的。一个优化策略是在非活跃环境比如当前的绿色环境将Pod副本数缩容到1甚至0。当需要部署新版本时先扩容绿色环境部署完成并测试后再进行蓝绿切换切换完成后再将蓝色环境现在是旧版本缩容。这样在大部分时间你只承担一套完整环境一个最小化备用环境的成本。踩过这些坑优化过这些流程后你会发现蓝绿部署不再是那个听起来高大上却不敢轻易尝试的技术。它变成了一种可靠的、可预测的发布标准流程。团队对发布的信心增强了再也不用在深夜提心吊胆。更重要的是它把发布从一个“运维事件”变成了一个“常规开发活动”极大地提升了业务的迭代速度。希望这篇实战指南能帮你顺利落地这套流程如果有任何问题欢迎随时交流。