mock实践:基于Mockoon + Nginx + K8S 的mock解决方案

背景介绍

业务说明:微服务message通过K8S部署在linux服务器上,它需要把短信验证码,通过https请求推到第三方系统(域名是sms.yunpian.com),并在接收到成功的响应后,将验证码写入数据库(此时才生效)。
要做的事:拦截message发送到第三方系统的https请求,并返回成功的响应

实现概述

  1. 部署Mockoon服务模拟第三方系统,对请求进行响应(默认是http协议,监听3000接口)
  2. 在Nginx中配置反代理,将https请求转到Mockoon服务提供的http服务上
  3. 在message中配置/etc/hosts,把域名sms.yunpian.com映射为Nginx服务所在的IP

这样message发送到sms.yunpian.com的https请求,会发送到Nginx,Nginx再把请求转发到Mockoon服务,Mockoon服务返回发送成功的响应,完成模拟

详细实现步骤

1. Mockoon 服务部署和配置

  • 首先保证服务器上安装有node.js工具,没有安装的可自行安装。node.js的版本和mockoon版本要对应,安装了node的直接查询版本
node --version
  • 因为服务器上node.js版本是16,所以Mockoon要选择较低的5.0.0版本,使用 npm 全局安装 @mockoon/cli,
npm install -g @mockoon/cli@5.0.0

安装完成后,运行以下命令检查是否成功:

mockoon-cli --help

能看到输出的帮助信息,说明安装成功
在这里插入图片描述

  • 编写一个简单的配置文件sms-mock.json,用于对请求进行响应
# 创建 Mockoon 配置文件 (sms-mock.json)
{
  "name": "SMS Mock Service",
  "port": 3000,
  "routes": [
    {
      "method": "POST",
      "path": "/v2/sms/single_send.json",
      "responses": [
        {
          "statusCode": 200,
          "body": "{\"code\":0,\"msg\":\"success\",\"count\":1}"
        }
      ]
    }
  ]
}
  • 切换到配置文件目录下,启动Mockoon 服务
mockoon-cli start --data sms-mock.json --y
  • 用另一个服务器发送请求进行测试
 curl -X POST http://10.0.31.51:3000/v2/sms/single_send.json

成功返回配置文件中的响应体,Mockoon服务部署和配置完成

2. Nginx 反向代理配置

2.1 生成证书

因为https请求,需要证书,因此使用openssl命令生成自签名证书:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout private-key.key \
    -out certificate.crt \
    -subj "/CN=sms.yunpian.com"
2.2 配置Nginx反代理

说明:nginx支持配置多个域名,新增一个server即可

server {
    listen 443 ssl http2;
    server_name sms.yunpian.com;
    
    # 证书位置
    ssl_certificate /root/mocks/certificate.crt;
    ssl_certificate_key /root/mocks/private-key.key;
    
    # 短信发送接口代理
    location /v2/sms/single_send.json {
        proxy_pass http://10.0.31.51:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

3. Kubernetes 容器证书信任配置

3.1 生成证书的 ConfigMap

将第二步生成的证书复制一份到容器所在的服务器,生成 ConfigMap

kubectl create configmap sms-certificate --from-file=certificate.crt=./certificate.crt -n $NAMESPACE

其中sms-certificate 为起的别名,$NAMESPACE为pod部署的空间名称

3.2 编写pod资源配置文件
spec:
  template:
    spec:
      initContainers:
      - name: import-certificate
        image: $CURRENT_IMAGE
        command: ["sh", "-c"]
        args:
        - |-
          set -e
          echo "开始导入 SSL 证书..."
          
          # 复制原始信任库
          cp /opt/java/openjdk/lib/security/cacerts /truststore-volume/cacerts
          
          # 导入证书到 Java 信任库
          /opt/java/openjdk/bin/keytool -import -noprompt -trustcacerts \
            -alias sms.yunpian.com \
            -file /cert/certificate.crt \
            -keystore /truststore-volume/cacerts \
            -storepass changeit
          echo "证书成功导入 Java 信任库"
          
        volumeMounts:
        - name: cert-volume
          mountPath: /cert
          readOnly: true
        - name: truststore-volume
          mountPath: /truststore-volume

      containers:
      - name: $CONTAINER_NAME
        command: ["sh", "-c"]
        args:
        - |
          cp /truststore-volume/cacerts \$JAVA_HOME/lib/security/cacerts
          # 添加 hosts 条目
          echo '10.0.31.51 sms.yunpian.com' >> /etc/hosts
          echo "Hosts 条目添加成功"
          # 以下是原pod文件中的内容
          [ -d /opt/logs/\${HOSTNAME} ] || mkdir -p /opt/logs/\${HOSTNAME}
          ln -sf /opt/logs/\${HOSTNAME} /opt/acx/acx-message/logs
          [ -d /opt/sensor/\${HOSTNAME} ] || mkdir -p /opt/sensor/\${HOSTNAME}
          ln -sf /opt/sensor/\${HOSTNAME} /opt/acx/acx-message/sensor
          bash /opt/acx/acx-message/script/start.sh
        volumeMounts:
        - name: truststore-volume
          mountPath: /truststore-volume
          readOnly: true
      volumes:
      - name: cert-volume
        configMap:
          name: sms-certificate-itos2
      - name: truststore-volume
        emptyDir: {}

脚本中2个的变量获取

CURRENT_IMAGE=$(kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.template.spec.containers[0].image}')
CONTAINER_NAME=$(kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.template.spec.containers[0].name}')

实现说明:

  • initContainers: 初始化容器,在主容器启动前执行一次性任务

把 JDK 原始 /opt/java/openjdk/lib/security/cacerts 复制到 /truststore-volume/cacerts。 用 keytool -import … 把/cert/certificate.crt 以别名 sms.yunpian.com导入/truststore-volume/cacerts,生成“官方库 + 自定义证书”的新信任库。此时truststore-volume里已有主容器可直接使用的 cacerts。

  • containers: 主应用容器

使用命令 cp /truststore-volume/cacerts$JAVA_HOME/lib/security/cacerts,用 init 容器准备好的文件覆盖 JVM 默认信任库。 后续 JVM进程启动时,整个运行时环境天然信任这张证书,无需再指定 -Djavax.net.ssl.trustStore 等参数,完成“自定义证书对 Java 应用透明生效”。同时将在/etc/hosts文件中,添加映射,强制将sms.yunpian.com解析到内网IP。

  • volumes: 定义存储卷

把第一步中自定义证书(certificate.crt)的ConfigMap(sms-certificate)挂进 Pod,同时声明一个 emptyDir 卷truststore-volume,供 init 容器与主容器共享。

3.3 将pod配置文件合并到当前的配置中
kubectl patch deployment $DEPLOYMENT_NAME -n $NAMESPACE --type='strategic' --patch-file="$PATCH_FILE"

其中,$PATCH_FILE为第二步中配置文件的名称

至此完成了Mockoon + Nginx + K8S 的整个方案的部署,系统发送短信后,会被成功的拦截并返回成功

3.4 包装成一个shell脚本
  • 为了方便后面的执行,将第三步内容写进shell脚本,备份原有的配置文件,完成新增部分配置文件的编写和合并,并对执行情况进行检查
#!/bin/bash
set -e

# 配置变量
NAMESPACE="k8s-wyf"
DEPLOYMENT_NAME="acx-message-v1-server"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

echo "步骤 1: 备份当前 Deployment 配置"
kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o yaml > deployment-backup-${TIMESTAMP}.yaml

echo "步骤 2: 动态获取当前镜像版本和容器名称"
CURRENT_IMAGE=$(kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.template.spec.containers[0].image}')
CONTAINER_NAME=$(kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.template.spec.containers[0].name}')
echo "当前镜像版本: $CURRENT_IMAGE"
echo "容器名称: $CONTAINER_NAME"

echo "步骤 3: 创建 Strategic Merge Patch 文件并应用"
PATCH_FILE=$(mktemp)
cat > "$PATCH_FILE" <<EOF
spec:
  template:
    spec:
      initContainers:
      - name: import-certificate
        image: $CURRENT_IMAGE
        command: ["sh", "-c"]
        args:
        - |-
          set -e
          echo "开始导入 SSL 证书..."
          
          # 复制原始信任库
          cp /opt/java/openjdk/lib/security/cacerts /truststore-volume/cacerts
          
          # 导入证书到 Java 信任库
          /opt/java/openjdk/bin/keytool -import -noprompt -trustcacerts \
            -alias sms.yunpian.com \
            -file /cert/certificate.crt \
            -keystore /truststore-volume/cacerts \
            -storepass changeit
          echo "证书成功导入 Java 信任库"

        volumeMounts:
        - name: cert-volume
          mountPath: /cert
          readOnly: true
        - name: truststore-volume
          mountPath: /truststore-volume

      containers:
      - name: $CONTAINER_NAME
        command: ["sh", "-c"]
        volumeMounts:
        - name: truststore-volume
          mountPath: /truststore-volume
          readOnly: true
        - name: startup-script
          mountPath: /scripts
      volumes:
      - name: cert-volume
        configMap:
          name: sms-certificate
      - name: truststore-volume
        emptyDir: {}
EOF

echo "应用 Strategic Merge Patch..."
kubectl patch deployment $DEPLOYMENT_NAME -n $NAMESPACE --type='strategic' --patch-file="$PATCH_FILE"

# 清理临时文件
rm -f "$PATCH_FILE"

echo "步骤 4: 等待 Pod 重启..."
echo "等待 10 秒让 Deployment 开始更新..."
sleep 10

# 等待 Pod 就绪
echo "等待新 Pod 就绪..."
for i in {1..30}; do
    if kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.status.readyReplicas}' | grep -q 1; then
        echo "Pod 已就绪"
        break
    fi
    echo "等待中... ($i/30)"
    sleep 5
done

echo "步骤 6: 验证部署"
NEW_POD=$(kubectl get pods -n $NAMESPACE -l app=message-v1 -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)

if [ -n "$NEW_POD" ] && kubectl get pod $NEW_POD -n $NAMESPACE >/dev/null 2>&1; then
  echo "新 Pod 名称: $NEW_POD"
  
  POD_STATUS=$(kubectl get pod $NEW_POD -n $NAMESPACE -o jsonpath='{.status.phase}')
  echo "Pod 状态: $POD_STATUS"
  
  if [ "$POD_STATUS" = "Running" ]; then
    echo "检查 initContainer 日志:"
    kubectl logs $NEW_POD -n $NAMESPACE -c import-certificate --tail=50 || echo "无法获取 initContainer 日志"
    
    echo "检查证书是否已导入 Java 信任库:"
    kubectl exec $NEW_POD -n $NAMESPACE -- /opt/java/openjdk/bin/keytool -list -cacerts -storepass changeit | grep "sms.yunpian.com" && echo "Java 信任库中找到证书" || echo "Java 信任库中未找到证书"
    
    echo "检查 /etc/hosts 文件:"
    kubectl exec $NEW_POD -n $NAMESPACE -- grep "sms.yunpian.com" /etc/hosts && echo "找到 hosts 条目" || echo "未找到 hosts 条目"
    
    echo "检查应用日志:"
    kubectl logs $NEW_POD -n $NAMESPACE --tail=10 || echo "无法获取应用日志"
  else
    echo "Pod 未处于 Running 状态,检查详情:"
    kubectl describe pod $NEW_POD -n $NAMESPACE
  fi
else
  echo "未找到运行中的 Pod"
  echo "检查 Deployment 状态:"
  kubectl get deployment $DEPLOYMENT_NAME -n $NAMESPACE
fi

echo "自动化配置完成!"
echo "备份文件已保存: deployment-backup-${TIMESTAMP}.yaml"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值