容器化部署newbee-mall:Docker+Kubernetes实战指南
一、痛点直击:传统部署的3大困境
你是否还在为电商系统部署面临以下问题而烦恼?
- 环境一致性噩梦:开发、测试、生产环境差异导致"在我电脑上能运行"的尴尬
- 扩缩容繁琐:促销活动流量激增时,手动扩容耗时费力且易出错
- 运维成本高:多实例部署时,配置管理、日志收集、监控告警复杂度呈指数级增长
本文将通过Docker容器化和Kubernetes编排技术,为你提供一套可复用的newbee-mall电商系统容器化解决方案,实现环境一致性、弹性伸缩和自动化运维。
读完本文你将掌握:
- 使用Docker Compose快速搭建本地开发环境
- 构建高可用的生产级Docker镜像
- 在Kubernetes集群部署多实例电商服务
- 实现服务健康检查、自动扩缩容和滚动更新
- 配置完善的监控告警体系
二、技术选型与架构设计
2.1 容器化技术栈选型
| 技术 | 版本 | 作用 | 优势 |
|---|---|---|---|
| Docker | 20.10+ | 容器引擎 | 轻量级虚拟化,环境一致性 |
| Docker Compose | 2.10+ | 多容器编排 | 本地开发环境一键部署 |
| Kubernetes | 1.24+ | 容器编排平台 | 自动化运维,弹性伸缩 |
| Helm | 3.8+ | Kubernetes包管理 | 应用生命周期管理 |
| Nginx | 1.21+ | 反向代理 | 负载均衡,静态资源缓存 |
| MySQL | 8.0+ | 数据库 | 稳定可靠,社区活跃 |
| Redis | 6.2+ | 缓存 | 减轻数据库压力,会话存储 |
2.2 系统架构设计
2.3 容器化改造关键点
- 外部化配置:将数据库连接、端口号等配置通过环境变量注入
- 无状态设计:确保应用可水平扩展,会话状态存储到Redis
- 健康检查:实现/health接口,支持容器健康状态检测
- 日志处理:标准输出日志,便于容器平台统一收集
- 资源限制:合理设置CPU、内存资源请求和限制
三、Docker容器化实践
3.1 构建多阶段Docker镜像
新建项目根目录下的Dockerfile:
# 构建阶段
FROM maven:3.8.5-openjdk-11-slim AS builder
WORKDIR /app
COPY pom.xml .
# 缓存Maven依赖
RUN mvn dependency:go-offline -B
COPY src ./src
# 编译打包
RUN mvn package -DskipTests
# 运行阶段
FROM openjdk:11-jre-slim
WORKDIR /app
# 添加时区支持
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' > /etc/timezone
# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 复制jar包
COPY --from=builder /app/target/*.jar app.jar
# 赋予执行权限
RUN chown -R appuser:appuser /app
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -q -O /dev/null http://localhost:8080/health || exit 1
# JVM参数优化
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
3.2 使用Docker Compose搭建开发环境
创建docker-compose.yml文件:
version: '3.8'
services:
mall:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/newbee_mall?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=root
- SPRING_REDIS_HOST=redis
- SPRING_REDIS_PORT=6379
volumes:
- ./src:/app/src
- ./pom.xml:/app/pom.xml
depends_on:
- mysql
- redis
restart: unless-stopped
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=newbee_mall
- TZ=Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./sql:/docker-entrypoint-initdb.d
restart: unless-stopped
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: unless-stopped
volumes:
mysql-data:
redis-data:
3.3 开发环境一键启动脚本
创建start-dev.sh:
#!/bin/bash
# 构建并启动开发环境
docker-compose up -d --build
# 等待数据库初始化完成
echo "Waiting for database to be ready..."
until docker-compose exec -T mysql mysql -uroot -proot -e "SELECT 1" >/dev/null 2>&1; do
sleep 1
done
# 执行数据库迁移脚本
docker-compose exec -T mall mvn flyway:migrate
# 查看服务日志
docker-compose logs -f mall
赋予执行权限并运行:
chmod +x start-dev.sh
./start-dev.sh
四、生产环境Docker镜像优化
4.1 镜像安全加固
- 使用非root用户运行:在Dockerfile中创建专用用户
- 减少镜像层数:合并RUN指令,清理无用依赖
- 扫描镜像漏洞:集成Trivy到CI/CD流程
# 安全加固后的生产环境Dockerfile片段
FROM openjdk:11-jre-slim AS production
WORKDIR /app
# 添加时区支持
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo 'Asia/Shanghai' > /etc/timezone && \
# 创建非root用户
groupadd -r appuser && useradd -r -g appuser appuser && \
# 安装必要工具
apt-get update && apt-get install -y --no-install-recommends wget && \
# 清理缓存
apt-get clean && rm -rf /var/lib/apt/lists/*
# 复制jar包
COPY --from=builder /app/target/*.jar app.jar
# 设置权限
RUN chown -R appuser:appuser /app
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -q -O /dev/null http://localhost:8080/health || exit 1
# JVM参数优化
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/app/logs/heapdump.hprof -Djava.security.egd=file:/dev/./urandom"
# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
4.2 多阶段构建优化
# 阶段1: 构建
FROM maven:3.8.5-openjdk-11-slim AS builder
WORKDIR /app
COPY pom.xml .
# 缓存依赖
RUN mvn dependency:go-offline -B
COPY src ./src
# 编译打包
RUN mvn package -DskipTests -Dmaven.test.skip=true
# 阶段2: 提取依赖
FROM maven:3.8.5-openjdk-11-slim AS extractor
WORKDIR /app
COPY --from=builder /app/pom.xml .
COPY --from=builder /app/target/*.jar app.jar
# 提取依赖到lib目录
RUN mkdir -p lib && jar -xf app.jar BOOT-INF/lib && mv BOOT-INF/lib/* lib/
# 阶段3: 运行时
FROM openjdk:11-jre-slim AS production
# ... (省略前面已有的安全加固配置)
# 复制依赖和应用
COPY --from=extractor /app/lib ./lib
COPY --from=builder /app/target/*.jar app.jar
# 启动命令优化 (使用类路径方式启动,提升JVM启动速度)
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -cp 'app.jar:lib/*' ltd.newbee.mall.NewBeeMallApplication"]
4.3 镜像构建最佳实践
创建.dockerignore文件排除不必要文件:
.git
.gitignore
.idea
.vscode
*.iml
*.log
target/*
!target/*.jar
src/test
sql
logs
tmp
五、Kubernetes部署实战
5.1 命名空间与RBAC配置
创建namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: newbee-mall
labels:
name: newbee-mall
创建rbac.yaml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: newbee-mall-sa
namespace: newbee-mall
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: newbee-mall-role
namespace: newbee-mall
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: newbee-mall-rolebinding
namespace: newbee-mall
subjects:
- kind: ServiceAccount
name: newbee-mall-sa
namespace: newbee-mall
roleRef:
kind: Role
name: newbee-mall-role
apiGroup: rbac.authorization.k8s.io
5.2 配置文件与密钥管理
创建configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: newbee-mall-config
namespace: newbee-mall
data:
SPRING_PROFILES_ACTIVE: "prod"
SERVER_PORT: "8080"
LOG_LEVEL: "INFO"
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: "health,info,metrics,prometheus"
创建secret.yaml(注意:生产环境应使用外部密钥管理系统):
apiVersion: v1
kind: Secret
metadata:
name: newbee-mall-secret
namespace: newbee-mall
type: Opaque
data:
SPRING_DATASOURCE_URL: amRiYzpteXNxbDovL215c3FsOiMzMzA2L25ld2JlZV9tYWxsP3VzZVVuaWNvZGU9dHJ1ZSZjaGFyYWN0ZXJFbmNvZGluZz11dGY4JnNlcnZlclRpbWV6b25lPUFzaWEvU2hhbmdoYWk=
SPRING_DATASOURCE_USERNAME: cm9vdA==
SPRING_DATASOURCE_PASSWORD: cm9vdA==
SPRING_REDIS_PASSWORD: cmVkaXM=
5.3 部署应用Deployment
创建deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: newbee-mall
namespace: newbee-mall
labels:
app: newbee-mall
spec:
replicas: 3
selector:
matchLabels:
app: newbee-mall
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
labels:
app: newbee-mall
spec:
serviceAccountName: newbee-mall-sa
containers:
- name: newbee-mall
image: registry.example.com/newbee-mall:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
- name: SPRING_PROFILES_ACTIVE
valueFrom:
configMapKeyRef:
name: newbee-mall-config
key: SPRING_PROFILES_ACTIVE
- name: SERVER_PORT
valueFrom:
configMapKeyRef:
name: newbee-mall-config
key: SERVER_PORT
- name: SPRING_DATASOURCE_URL
valueFrom:
secretKeyRef:
name: newbee-mall-secret
key: SPRING_DATASOURCE_URL
- name: SPRING_DATASOURCE_USERNAME
valueFrom:
secretKeyRef:
name: newbee-mall-secret
key: SPRING_DATASOURCE_USERNAME
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: newbee-mall-secret
key: SPRING_DATASOURCE_PASSWORD
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: http
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: http
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
startupProbe:
httpGet:
path: /actuator/health
port: http
initialDelaySeconds: 20
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 10
volumeMounts:
- name: logs
mountPath: /app/logs
volumes:
- name: logs
emptyDir: {}
5.4 服务与Ingress配置
创建service.yaml:
apiVersion: v1
kind: Service
metadata:
name: newbee-mall-service
namespace: newbee-mall
spec:
selector:
app: newbee-mall
ports:
- port: 80
targetPort: http
name: http
type: ClusterIP
创建ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: newbee-mall-ingress
namespace: newbee-mall
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/rewrite-target: /$1
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- mall.example.com
secretName: newbee-mall-tls
rules:
- host: mall.example.com
http:
paths:
- path: /(.*)
pathType: Prefix
backend:
service:
name: newbee-mall-service
port:
name: http
5.5 自动扩缩容配置
创建hpa.yaml:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: newbee-mall-hpa
namespace: newbee-mall
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: newbee-mall
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 30
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 300
六、监控告警与日志管理
6.1 Spring Boot Actuator配置
在application-prod.yml中添加:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,loggers
endpoint:
health:
show-details: always
probes:
enabled: true
group:
readiness:
include: db,redis
metrics:
tags:
application: newbee-mall
export:
prometheus:
enabled: true
server:
port: 8081
6.2 Prometheus监控配置
创建prometheus-config.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: monitoring
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'newbee-mall'
metrics_path: '/actuator/prometheus'
kubernetes_sd_configs:
- role: pod
namespaces:
names: ['newbee-mall']
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
regex: newbee-mall
action: keep
- source_labels: [__meta_kubernetes_pod_container_port_name]
regex: http
action: keep
6.3 Grafana仪表盘
创建grafana-dashboard.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-dashboard-newbee-mall
namespace: monitoring
labels:
grafana_dashboard: "true"
data:
newbee-mall-dashboard.json: |
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 1,
"iteration": 1628367687266,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"links": []
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "7.5.5",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "rate(http_server_requests_seconds_count{application=\"newbee-mall\"}[5m])",
"interval": "",
"legendFormat": "{{status}}",
"refId": "A"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "请求量 QPS",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": "QPS",
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
// ... 省略其他面板配置
],
"refresh": "5s",
"schemaVersion": 27,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "newbee-mall监控面板",
"uid": "newbee-mall",
"version": 1
}
6.4 日志收集配置
创建logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="newbee-mall"/>
<springProperty scope="context" name="LOG_LEVEL" source="log.level" defaultValue="INFO"/>
<!-- JSON格式输出 -->
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/app/logs/${APP_NAME}.log</file>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>traceId</includeMdcKeyName>
<includeMdcKeyName>spanId</includeMdcKeyName>
<fieldNames>
<timestamp>timestamp</timestamp>
<message>message</message>
<logger>logger</logger>
<thread>thread</thread>
<level>level</level>
</fieldNames>
<customFields>{"application":"${APP_NAME}","pod_name":"${HOSTNAME}"}</customFields>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/app/logs/${APP_NAME}-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<root level="${LOG_LEVEL}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="JSON_FILE"/>
</root>
<!-- 第三方框架日志级别控制 -->
<logger name="org.springframework" level="WARN"/>
<logger name="com.fasterxml.jackson" level="WARN"/>
<logger name="io.undertow" level="WARN"/>
<logger name="org.hibernate" level="WARN"/>
</configuration>
七、部署流程与自动化
7.1 部署脚本
创建deploy-k8s.sh:
#!/bin/bash
set -euo pipefail
# 环境变量
NAMESPACE="newbee-mall"
VERSION="1.0.0"
DOCKER_REGISTRY="registry.example.com"
APP_NAME="newbee-mall"
# 构建镜像
echo "Building Docker image..."
docker build -t ${DOCKER_REGISTRY}/${APP_NAME}:${VERSION} -f Dockerfile .
# 推送镜像
echo "Pushing Docker image..."
docker push ${DOCKER_REGISTRY}/${APP_NAME}:${VERSION}
# 部署到Kubernetes
echo "Deploying to Kubernetes..."
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/rbac.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml
kubectl apply -f k8s/hpa.yaml
# 检查部署状态
echo "Checking deployment status..."
kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE}
echo "Deployment completed successfully!"
7.2 CI/CD流水线示例(GitLab CI)
创建.gitlab-ci.yml:
stages:
- test
- build
- deploy
variables:
DOCKER_REGISTRY: registry.example.com
NAMESPACE: newbee-mall
APP_NAME: newbee-mall
test:
stage: test
image: maven:3.8.5-openjdk-11
script:
- mvn clean test
artifacts:
reports:
junit: target/surefire-reports/TEST-*.xml
build:
stage: build
image: docker:20.10
services:
- docker:20.10-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $DOCKER_REGISTRY
- docker build -t $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA -f Dockerfile .
- docker push $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA
- |
if [[ $CI_COMMIT_BRANCH == "main" ]]; then
docker tag $DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA $DOCKER_REGISTRY/$APP_NAME:latest
docker push $DOCKER_REGISTRY/$APP_NAME:latest
fi
only:
- main
- develop
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl config use-context production
- sed -i "s|registry.example.com/newbee-mall:1.0.0|$DOCKER_REGISTRY/$APP_NAME:$CI_COMMIT_SHORT_SHA|g" k8s/deployment.yaml
- kubectl apply -f k8s/
- kubectl rollout status deployment/$APP_NAME -n $NAMESPACE
only:
- main
八、问题排查与最佳实践
8.1 常见问题排查流程
8.2 容器化最佳实践总结
-
镜像优化
- 使用多阶段构建减小镜像体积
- 合理设置镜像层,频繁变动的文件放在上层
- 避免在镜像中存储敏感信息
- 每个容器只运行一个应用进程
-
安全加固
- 使用非root用户运行容器
- 限制容器CPU、内存资源
- 配置只读文件系统(必要目录挂载为可写)
- 定期扫描镜像漏洞
-
Kubernetes部署最佳实践
- 为所有Pod配置健康检查和就绪探针
- 使用ConfigMap和Secret管理配置
- 合理设置资源请求和限制
- 配置PodDisruptionBudget确保可用性
- 使用命名空间隔离不同环境/应用
-
监控与可观测性
- 暴露Prometheus指标
- 输出结构化日志
- 实现分布式追踪
- 配置关键指标告警
九、总结与展望
通过Docker和Kubernetes实现newbee-mall电商系统的容器化部署,我们解决了传统部署方式的环境一致性、弹性扩缩容和运维复杂度问题。本文提供的方案不仅适用于newbee-mall,也可迁移到其他Spring Boot应用的容器化部署中。
未来优化方向:
- 微服务改造:将单体应用拆分为商品服务、订单服务、用户服务等微服务
- 服务网格:引入Istio实现更细粒度的流量控制、熔断降级和安全策略
- GitOps:使用ArgoCD实现声明式GitOps部署流程
- 混沌工程:通过故障注入测试系统弹性
希望本文能帮助你顺利实现newbee-mall的容器化部署,如有任何问题或建议,欢迎在项目Issue中交流讨论。
如果觉得本文对你有帮助,请点赞、收藏、关注三连,下期将为大家带来《newbee-mall微服务改造实战》!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



