【MES学习笔记系列】07 - MES 部署与运维

目标读者:DevOps 工程师、系统运维工程师

阅读时间:约 25 分钟

前置知识:Docker、Kubernetes 基础


一、部署方案

1.1 部署架构概述

MES 系统的部署架构根据企业规模和需求分为三种方案:

方案 适用场景 复杂度 成本
单机 Docker Compose 开发测试、小型工厂
Kubernetes 集群 中大型工厂、多产线
混合云部署 集团多工厂、高可用

1.2 方案一:Docker Compose 单机部署

java 复制代码
# docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: mes-mysql
    environment:
      MYSQL_ROOT_PASSWORD: Mes@2026
      MYSQL_DATABASE: mes_order
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./sql/init:/docker-entrypoint-initdb.d
    restart: always

  redis:
    image: redis:7-alpine
    container_name: mes-redis
    ports:
      - "6379:6379"
    command: redis-server --requirepass Mes@2026
    volumes:
      - redis_data:/data
    restart: always

  # MES 工单服务
  mes-order:
    build: ./mes-order
    container_name: mes-order
    ports:
      - "8081:8081"
    environment:
      SPRING_PROFILES_ACTIVE: docker
      DB_URL: jdbc:mysql://mysql:3306/mes_order
      DB_USER: root
      DB_PASS: Mes@2026
      REDIS_HOST: redis
      REDIS_PASS: Mes@2026
    depends_on:
      - mysql
      - redis
    restart: always

  # MES 质量服务
  mes-quality:
    build: ./mes-quality
    container_name: mes-quality
    ports:
      - "8082:8082"
    environment:
      SPRING_PROFILES_ACTIVE: docker
    depends_on:
      - mysql
      - redis
    restart: always

  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    container_name: mes-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
    depends_on:
      - mes-order
      - mes-quality
    restart: always

  # 前端
  mes-web:
    build: ./mes-web
    container_name: mes-web
    ports:
      - "3000:80"
    restart: always

volumes:
  mysql_data:
  redis_data:

1.3 方案二:Kubernetes 集群部署

java 复制代码
# k8s/mes-order-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mes-order
  namespace: mes
  labels:
    app: mes-order
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mes-order
  template:
    metadata:
      labels:
        app: mes-order
    spec:
      containers:
        - name: mes-order
          image: registry.example.com/mes-order:1.0.0
          ports:
            - containerPort: 8081
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "k8s"
            - name: DB_URL
              valueFrom:
                secretKeyRef:
                  name: mes-db-secret
                  key: url
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: mes-db-secret
                  key: username
            - name: DB_PASS
              valueFrom:
                secretKeyRef:
                  name: mes-db-secret
                  key: password
          resources:
            requests:
              memory: "512Mi"
              cpu: "250m"
            limits:
              memory: "1Gi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8081
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8081
            initialDelaySeconds: 15
            periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: mes-order-svc
  namespace: mes
spec:
  selector:
    app: mes-order
  ports:
    - port: 8081
      targetPort: 8081
  type: ClusterIP

---
# HPA 自动扩缩
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: mes-order-hpa
  namespace: mes
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mes-order
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

1.4 Nginx 反向代理配置

javascript 复制代码
# nginx/nginx.conf
upstream mes-order {
    server mes-order:8081;
}

upstream mes-quality {
    server mes-quality:8082;
}

server {
    listen 80;
    server_name mes.example.com;

    # 强制 HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name mes.example.com;

    ssl_certificate     /etc/nginx/ssl/mes.crt;
    ssl_certificate_key /etc/nginx/ssl/mes.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    # 工单服务
    location /api/v1/work-orders/ {
        proxy_pass http://mes-order;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 质量服务
    location /api/v1/quality/ {
        proxy_pass http://mes-quality;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 前端静态资源
    location / {
        proxy_pass http://mes-web:80;
    }

    # WebSocket 看板推送
    location /ws/ {
        proxy_pass http://mes-order;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

二、CI/CD 流水线

2.1 GitLab CI 配置

java 复制代码
# .gitlab-ci.yml
stages:
  - build
  - test
  - docker-build
  - deploy

variables:
  REGISTRY: registry.example.com
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

# 阶段一:构建
build:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths:
      - mes-order/target/*.jar
      - mes-quality/target/*.jar
    expire_in: 1 hour

# 阶段二:测试
unit-test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn test
  artifacts:
    reports:
      junit:
        - "*/target/surefire-reports/TEST-*.xml"

# 代码质量扫描
sonarqube:
  stage: test
  image: sonarsource/sonar-scanner-cli
  script:
    - sonar-scanner
      -Dsonar.projectKey=mes
      -Dsonar.host.url=$SONAR_HOST_URL
      -Dsonar.login=$SONAR_TOKEN
  only:
    - main
    - merge_requests

# 阶段三:构建 Docker 镜像
docker-build:
  stage: docker-build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u $REGISTRY_USER -p $REGISTRY_PASS $REGISTRY
  script:
    - cd mes-order
    - docker build -t $REGISTRY/mes-order:$IMAGE_TAG .
    - docker push $REGISTRY/mes-order:$IMAGE_TAG
    - cd ../mes-quality
    - docker build -t $REGISTRY/mes-quality:$IMAGE_TAG .
    - docker push $REGISTRY/mes-quality:$IMAGE_TAG
    - cd ../mes-web
    - docker build -t $REGISTRY/mes-web:$IMAGE_TAG .
    - docker push $REGISTRY/mes-web:$IMAGE_TAG
  only:
    - main

# 阶段四:部署到 K8s
deploy-staging:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/mes-order mes-order=$REGISTRY/mes-order:$IMAGE_TAG -n mes-staging
    - kubectl set image deployment/mes-quality mes-quality=$REGISTRY/mes-quality:$IMAGE_TAG -n mes-staging
    - kubectl rollout status deployment/mes-order -n mes-staging
  environment:
    name: staging
  only:
    - develop

deploy-production:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/mes-order mes-order=$REGISTRY/mes-order:$IMAGE_TAG -n mes-prod
    - kubectl rollout status deployment/mes-order -n mes-prod
  environment:
    name: production
  only:
    - main
  when: manual  # 生产部署需手动触发

2.2 Dockerfile 示例

java 复制代码
# mes-order/Dockerfile
FROM eclipse-temurin:17-jre-alpine

RUN addgroup -S mes && adduser -S mes -G mes
USER mes

WORKDIR /app
COPY target/mes-order-*.jar app.jar

EXPOSE 8081

ENTRYPOINT ["java", "-Xms512m", "-Xmx1g", "-jar", "app.jar"]

三、监控告警

3.1 监控架构

复制代码

3.2 Spring Boot Micrometer 指标暴露

java 复制代码
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: ${spring.application.name}

3.3 Prometheus 配置

java 复制代码
# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'mes-order'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['mes-order:8081']
        labels:
          service: 'mes-order'

  - job_name: 'mes-quality'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['mes-quality:8082']
        labels:
          service: 'mes-quality'

3.4 核心告警规则

java 复制代码
# alert.rules.yml
groups:
  - name: mes-critical
    rules:
      - alert: HighErrorRate
        expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) > 0.05
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "服务 {{ $labels.service }} 5xx 错误率超过 5%"

      - alert: HighResponseTime
        expr: histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m])) > 3
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "服务 {{ $labels.service }} P99 延迟超过 3 秒"

      - alert: DatabaseConnectionPoolExhausted
        expr: hikaricp_connections_active / hikaricp_connections_max > 0.9
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "数据库连接池使用率超过 90%"

      - alert: ServiceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "服务 {{ $labels.job }} 已宕机"

3.5 ELK 日志收集

java 复制代码
# docker-compose 添加 ELK 服务
  elasticsearch:
    image: elasticsearch:8.11
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
    ports:
      - "9200:9200"
    volumes:
      - es_data:/usr/share/elasticsearch/data

  logstash:
    image: logstash:8.11
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
    depends_on:
      - elasticsearch

  kibana:
    image: kibana:8.11
    ports:
      - "5601:5601"
    environment:
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200
    depends_on:
      - elasticsearch

四、性能优化

4.1 优化清单

层级 优化项 措施 预期效果
JVM GC 调优 G1GC: -XX:+UseG1GC -XX:MaxGCPauseMillis=200 减少 STW 时间
数据库 连接池 HikariCP,maxPoolSize=20,minimumIdle=5 减少连接等待
数据库 慢 SQL 索引优化 分析慢查询日志,添加缺失索引 查询速度提升 10-100x
数据库 读写分离 主库写 + 从库读(ShardingSphere) 分散读压力
缓存 热点数据缓存 Redis 缓存工单列表、物料主数据 减少 DB 查询 60%+
缓存 缓存策略 TTL 5min + 写时失效 平衡实时性与性能
接口 分页查询 强制分页,默认 pageSize=20,最大 100 避免大结果集
接口 异步化 非核心业务异步处理 降低响应时间
前端 CDN 静态资源 CDN 分发 加快页面加载

4.2 数据库优化示例

sql 复制代码
-- 慢查询日志配置
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;  -- 0.5秒以上记录
SET GLOBAL log_queries_not_using_indexes = 1;

-- 常见优化:添加缺失索引
ALTER TABLE work_order_routing ADD INDEX idx_wo_status (work_order_id, status);

-- 分析执行计划
EXPLAIN SELECT * FROM work_order WHERE status = 'IN_PRODUCTION' ORDER BY priority ASC;

五、安全策略

5.1 安全防护措施

层面 措施
网络层 K8s NetworkPolicy + 防火墙 + WAF
传输层 TLS 1.3 加密,禁用 TLS 1.0/1.1
应用层 JWT 认证 + RBAC 权限 + 接口签名
数据层 敏感字段加密 + 数据库加密 + 备份加密
容器层 非 root 用户运行 + 只读根文件系统
审计层 所有关键操作日志不可篡改

5.2 K8s 安全上下文

java 复制代码
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  capabilities:
    drop:
      - ALL
  readOnlyRootFilesystem: true

六、灾备与恢复

能力 方案 RTO RPO
MySQL 主从 一主两从 + 自动故障转移 < 5 分钟 < 1 分钟
MySQL 备份 全量每日 + Binlog 实时 --- 可恢复到任意时间点
Redis 哨兵模式自动故障转移 < 1 分钟 少量数据丢失
应用层 K8s 多副本 + 自动重启 < 30 秒 0
异地灾备 MySQL 异地同步 + 每日备份 < 30 分钟 < 1 小时

七、运维 Checklist

日常巡检(每日)

  • 各服务健康检查(/actuator/health)
  • 数据库主从延迟检查
  • 磁盘空间使用率 < 80%
  • 应用错误日志无异常增长

周度维护

  • 慢查询日志分析
  • 缓存命中率检查
  • 安全漏洞扫描

月度维护

  • SSL 证书有效期检查
  • 备份恢复演练
  • 容量规划(QPS 趋势)
相关推荐
我的xiaodoujiao7 小时前
快速学习Python基础知识详细图文教程17--类型注解和断点调试
开发语言·python·学习·测试工具
ltl7 小时前
可观测性存储与成本:采样、下采样、冷热分层
运维
学代码的CJY8 小时前
Linux 库制作与原理:静态库、动态库、ELF 与动态链接完全指南
linux·运维·服务器
SatanII9 小时前
403 禁地:Nginx 拒绝所有生者进入
运维·nginx
IT古董9 小时前
【MES学习笔记系列】MES 厂商与产品对比
笔记·学习
wangyue_msn_869 小时前
Agent知识学习笔记——03 RAG
笔记·学习·ai编程
嘶哈哈哈9 小时前
# 异构十电机机架数学建模:从单电机力矩到受约束控制分配
笔记
呱呱巨基10 小时前
Linux 查找命令
linux·笔记·学习·查找命令
路由侠内网穿透10 小时前
本地部署企业级快速开发平台芋道管理后台并实现外部访问
运维·服务器·网络·网络协议
好评12410 小时前
【Linux】进程信号
linux·运维·服务器