IBM Kubernetes 上的 Strangler Fig:在不影响生产的情况下现代化单体应用

发布: (2026年2月4日 GMT+8 08:18)
7 分钟阅读
原文: Dev.to

I’m happy to help translate the article, but I don’t have the full text of the post. Could you please paste the article’s content here (excluding the source line you already provided)? Once I have the text, I’ll translate it into Simplified Chinese while preserving the formatting, markdown, and any code blocks or URLs.

在本指南结束时,您将能够:

  1. 将现有的单体应用容器化
  2. 将其部署到 IBM Cloud Kubernetes Service
  3. 将其放置在 Ingress 后面
  4. 部署新的“边缘”服务
  5. 使用基于路径的路由逐步切换流量
  6. 保持回滚简单安全

先决条件

项目详情
IBM Cloud 账户
现有 IKS 集群
本地工具ibmcloud, kubectl, docker
登录bash<br>ibmcloud login -a https://cloud.ibm.com<br>ibmcloud target -r <region> -g <resource-group><br>

1. 设置一个干净的命名空间

kubectl create namespace monolith-demo
kubectl config set-context --current --namespace=monolith-demo
kubectl get ns

Goal: No behavior change – just package the monolith. (目标:不改变行为——仅对单体进行打包。)

2. 将单体容器化

Dockerfile(Node.js 单体)

# ---- Build stage ----
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .

# ---- Runtime stage ----
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app /app
EXPOSE 8080
CMD ["npm","start"]

添加最小健康端点(如果尚未拥有)

// Example endpoints
app.get("/health", (req, res) => res.status(200).send("ok"));
app.get("/ready",  (req, res) => res.status(200).send("ready"));

构建镜像

docker build -t monolith:1.0.0 .

推送到 IBM Cloud 容器注册表

# Log in (one‑time)
ibmcloud cr login
ibmcloud cr namespace-add <your-namespace>

# Tag & push
docker tag monolith:1.0.0 <registry>/<namespace>/monolith:1.0.0
docker push <registry>/<namespace>/monolith:1.0.0

# Verify
ibmcloud cr images | grep monolith

3. 部署单体

3.1 部署清单 (deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: monolith
spec:
  replicas: 2
  selector:
    matchLabels:
      app: monolith
  template:
    metadata:
      labels:
        app: monolith
    spec:
      containers:
        - name: monolith
          image: <registry>/<namespace>/monolith:1.0.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 10
kubectl apply -f deployment.yaml
kubectl rollout status deploy/monolith
kubectl get pods -l app=monolith

3.2 Service 清单 (service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: monolith-svc
spec:
  selector:
    app: monolith
  ports:
    - name: http
      port: 80
      targetPort: 8080
  type: ClusterIP
kubectl apply -f service.yaml
kubectl get svc monolith-svc

快速本地测试

kubectl port-forward svc/monolith-svc 8080:80
curl -i http://localhost:8080/health

4. 通过 Ingress 暴露(路由控制平面)

Ingress 清单 (ingress.yaml)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  rules:
    - host: <your-host>
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: monolith-svc
                port:
                  number: 80
kubectl apply -f ingress.yaml
kubectl get ingress app-ingress -o wide

此时: 100 % 的流量仍然进入单体应用。

5. 选择一个低风险的首个切片进行“绞杀”

好的首选候选:/api/auth/*
在本演练中,我们将提取 auth API。

最小示例端点(添加到单体)

app.get("/api/auth/ping", (req, res) => {
  res.json({ service: "auth-service", status: "pong" });
});

6. 构建新的 Auth 服务

Dockerfile (Dockerfile)

FROM node:20-alpine
WORKDIR /app
COPY . .
EXPOSE 8081
CMD ["node","server.js"]

构建并推送

docker build -t auth-service:1.0.0 .
docker tag auth-service:1.0.0 <registry>/<namespace>/auth-service:1.0.0
docker push <registry>/<namespace>/auth-service:1.0.0

7. 部署 Auth 服务

7.1 部署清单 (auth-deploy.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: auth-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: auth-service
  template:
    metadata:
      labels:
        app: auth-service
    spec:
      containers:
        - name: auth-service
          image: <registry>/<namespace>/auth-service:1.0.0
          ports:
            - containerPort: 8081
          readinessProbe:
            httpGet:
              path: /ready
              port: 8081
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 8081
            initialDelaySeconds: 15
            periodSeconds: 10
kubectl apply -f auth-deploy.yaml
kubectl rollout status deploy/auth-service
kubectl get pods -l app=auth-service

7.2 服务清单 (auth-svc.yaml)

apiVersion: v1
kind: Service
metadata:
  name: auth-svc
spec:
  selector:
    app: auth-service
  ports:
    - name: http
      port: 80
      targetPort: 8081
  type: ClusterIP
kubectl apply -f auth-svc.yaml
kubectl get svc auth-svc

8. 更新 Ingress 以将 /api/auth/* 路由到新服务

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  rules:
    - host: <your-host>
      http:
        paths:
          # New route for auth
          - path: /api/auth
            pathType: Prefix
            backend:
              service:
                name: auth-svc
                port:
                  number: 80
          # Fallback to monolith for everything else
          - path: /
            pathType: Prefix
            backend:
              service:
                name: monolith-svc
                port:
                  number: 80
kubectl apply -f ingress.yaml
kubectl get ingress app-ingress -o wide

现在,对 /api/auth/* 的流量由新的 auth‑service 提供服务,而所有其他请求仍然会命中 monolith。

9. 渐进式发布与回滚

  1. 验证新端点

    curl -i https://<your-host>/api/auth/ping
  2. 增加流量(如果使用流量拆分控制器)或直接监控新服务的指标和日志。

  3. 回滚(如有需要)

    # Remove the auth path from the Ingress
    kubectl edit ingress app-ingress   # delete the /api/auth block
    # Or delete the auth deployment/service
    kubectl delete -f auth-deploy.yaml
    kubectl delete -f auth-svc.yaml

因为单体应用在 Ingress 后保持不变,你可以随时立即恢复。

10. 清理(当你准备好时)

kubectl delete -f ingress.yaml
kubectl delete -f service.yaml
kubectl delete -f deployment.yaml
kubectl delete namespace monolith-demo

🎉 您刚刚在真实的 IBM Cloud Kubernetes 环境中应用了 Strangler Fig 模式!

继续使用相同的方法提取更多功能切片(例如 /api/orders/*/api/payments/*),直至可以安全地退役单体应用。

保持回滚简单且快速

选项 A – 路由回单体

编辑 Ingress 并移除 /api/auth 路径(或将其指向 monolith-svc),然后重新应用:

kubectl apply -f ingress.yaml

选项 B – 撤销部署滚动更新

kubectl rollout undo deploy/auth-service

过程

  1. 稳定首个提取的能力
  2. 选择下一个受限域
  3. 将其构建为独立服务
  4. 部署它
  5. 使用 Ingress 进行路由
  6. 在每一步保持回滚可用

随着时间的推移

  • 单体系统逐渐缩小。
  • 现代化变成日常工作,而不是“一次性大迁移”。
  • 没有停机时间。

Strangler Fig 模式 能够奏效,因为它尊重现实——你可以在不删除过去的情况下进行现代化。

如果你现在仍在使用单体系统,这种方法可以让你在不破坏已有功能的前提下前进。

Back to Blog

相关文章

阅读更多 »

当 AI 给你一巴掌

当 AI 给你当头一棒:在 Adama 中调试 Claude 生成的代码。你是否曾让 AI “vibe‑code” 一个复杂功能,却花了数小时调试细微的 bug……