第16章:docker企业级实战综合项目

第16章:企业级实战综合项目

本章目标:通过一个完整的电商项目,综合运用所学 Docker 知识,搭建生产级容器化应用。


16.1 项目概述

16.1.1 项目架构

复制代码
┌─────────────────────────────────────────────────────────────┐
│                 电商系统容器化架构                             │
│                                                             │
│  用户 → Nginx → API Gateway → 微服务 → 数据库/缓存          │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    接入层                            │   │
│  │  ┌──────────────┐  ┌──────────────┐                │   │
│  │  │   Nginx LB   │  │   Nginx LB   │  (主备)       │   │
│  │  └──────┬───────┘  └──────┬───────┘                │   │
│  └─────────┼─────────────────┼────────────────────────┘   │
│            │                 │                             │
│  ┌─────────┼─────────────────┼────────────────────────┐   │
│  │         ▼                 ▼        应用服务层         │   │
│  │  ┌──────────────┐  ┌──────────────┐                │   │
│  │  │   Gateway    │  │   Gateway    │  (API 网关)    │   │
│  │  └──────┬───────┘  └──────┬───────┘                │   │
│  │         │                 │                         │   │
│  │  ┌──────┴─────┬───────────┴──────┬──────────┐     │   │
│  │  ▼            ▼                  ▼          ▼     │   │
│  │ ┌────┐    ┌────┐            ┌────┐     ┌────┐   │   │
│  │ │用户│    │商品│            │订单│     │支付│   │   │
│  │ │服务│    │服务│            │服务│     │服务│   │   │
│  │ └────┘    └────┘            └────┘     └────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    数据层                            │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐         │   │
│  │  │  MySQL   │  │  Redis   │  │ MongoDB  │         │   │
│  │  │ (主从)   │  │ (集群)   │  │ (文档库) │         │   │
│  │  └──────────┘  └──────────┘  └──────────┘         │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

16.1.2 技术栈

组件 技术选型 说明
反向代理 Nginx 负载均衡、SSL 终止
API 网关 Kong / Traefik 路由、限流、认证
用户服务 Python/Go 用户注册、登录、权限
商品服务 Python/Go 商品管理、搜索
订单服务 Python/Go 订单创建、状态管理
支付服务 Python/Go 支付对接、回调处理
数据库 MySQL 8.0 业务数据存储
缓存 Redis 7 热点数据缓存
消息队列 RabbitMQ 异步消息处理
搜索引擎 Elasticsearch 商品搜索
监控 Prometheus + Grafana 指标监控
日志 ELK Stack 日志收集分析

16.2 项目结构

复制代码
ecommerce-docker/
├── docker-compose.yml              # 主配置
├── docker-compose.prod.yml         # 生产环境配置
├── .env                            # 环境变量
├── .env.prod                       # 生产环境变量
│
├── nginx/                          # Nginx 配置
│   ├── nginx.conf
│   └── conf.d/
│       ├── api.conf
│       └── frontend.conf
│
├── services/                       # 微服务
│   ├── gateway/                    # API 网关
│   │   ├── Dockerfile
│   │   └── kong.yml
│   │
│   ├── user-service/               # 用户服务
│   │   ├── Dockerfile
│   │   ├── requirements.txt
│   │   └── app/
│   │
│   ├── product-service/            # 商品服务
│   │   ├── Dockerfile
│   │   ├── requirements.txt
│   │   └── app/
│   │
│   ├── order-service/              # 订单服务
│   │   ├── Dockerfile
│   │   ├── requirements.txt
│   │   └── app/
│   │
│   └── payment-service/            # 支付服务
│       ├── Dockerfile
│       ├── requirements.txt
│       └── app/
│
├── mysql/                          # MySQL 配置
│   ├── my.cnf
│   └── initdb/
│       ├── 01-users.sql
│       ├── 02-products.sql
│       └── 03-orders.sql
│
├── redis/                          # Redis 配置
│   └── redis.conf
│
├── elasticsearch/                  # Elasticsearch 配置
│   └── elasticsearch.yml
│
├── prometheus/                     # Prometheus 配置
│   ├── prometheus.yml
│   └── rules/
│       └── alerts.yml
│
├── grafana/                        # Grafana 配置
│   ├── dashboards/
│   └── datasources/
│
├── scripts/                        # 脚本
│   ├── backup.sh
│   ├── deploy.sh
│   └── health-check.sh
│
└── docs/                           # 文档
    ├── api.md
    └── deployment.md

16.3 Docker Compose 完整配置

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

services:
  # ==================== 接入层 ====================
  
  # Nginx 负载均衡
  nginx:
    image: nginx:1.25-alpine
    container_name: ecommerce-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    networks:
      - frontend
    depends_on:
      - gateway
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 512M

  # ==================== 应用服务层 ====================

  # API 网关
  gateway:
    build: ./services/gateway
    container_name: ecommerce-gateway
    environment:
      - KONG_DATABASE=off
      - KONG_DECLARATIVE_CONFIG=/etc/kong/kong.yml
      - KONG_PROXY_ACCESS_LOG=/dev/stdout
      - KONG_ADMIN_ACCESS_LOG=/dev/stdout
      - KONG_PROXY_ERROR_LOG=/dev/stderr
      - KONG_ADMIN_ERROR_LOG=/dev/stderr
    volumes:
      - ./services/gateway/kong.yml:/etc/kong/kong.yml:ro
    networks:
      - frontend
      - backend
    healthcheck:
      test: ["CMD", "kong", "health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

  # 用户服务
  user-service:
    build: ./services/user-service
    container_name: ecommerce-user
    environment:
      - APP_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=users
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    networks:
      - backend
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

  # 商品服务
  product-service:
    build: ./services/product-service
    container_name: ecommerce-product
    environment:
      - APP_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=products
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - ELASTICSEARCH_HOST=elasticsearch
      - ELASTICSEARCH_PORT=9200
    networks:
      - backend
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
      elasticsearch:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

  # 订单服务
  order-service:
    build: ./services/order-service
    container_name: ecommerce-order
    environment:
      - APP_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=orders
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - RABBITMQ_HOST=rabbitmq
      - RABBITMQ_PORT=5672
      - RABBITMQ_USER=${RABBITMQ_USER}
      - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
    networks:
      - backend
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

  # 支付服务
  payment-service:
    build: ./services/payment-service
    container_name: ecommerce-payment
    environment:
      - APP_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_NAME=payments
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - RABBITMQ_HOST=rabbitmq
      - RABBITMQ_PORT=5672
      - RABBITMQ_USER=${RABBITMQ_USER}
      - RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
    networks:
      - backend
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M

  # ==================== 数据层 ====================

  # MySQL 数据库
  mysql:
    image: mysql:8.0
    container_name: ecommerce-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
      - ./mysql/initdb:/docker-entrypoint-initdb.d
    ports:
      - "127.0.0.1:3306:3306"
    networks:
      - backend
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: ecommerce-redis
    command: redis-server /etc/redis/redis.conf
    volumes:
      - redis-data:/data
      - ./redis/redis.conf:/etc/redis/redis.conf:ro
    ports:
      - "127.0.0.1:6379:6379"
    networks:
      - backend
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G

  # RabbitMQ 消息队列
  rabbitmq:
    image: rabbitmq:3.12-management-alpine
    container_name: ecommerce-rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER}
      RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
    ports:
      - "127.0.0.1:5672:5672"
      - "127.0.0.1:15672:15672"
    networks:
      - backend
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_running"]
      interval: 30s
      timeout: 10s
      retries: 5
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G

  # Elasticsearch 搜索引擎
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    container_name: ecommerce-elasticsearch
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - elasticsearch-data:/usr/share/elasticsearch/data
    ports:
      - "127.0.0.1:9200:9200"
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G

  # ==================== 监控层 ====================

  # Prometheus 监控
  prometheus:
    image: prom/prometheus:latest
    container_name: ecommerce-prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    ports:
      - "127.0.0.1:9090:9090"
    networks:
      - monitoring
    restart: unless-stopped

  # Grafana 可视化
  grafana:
    image: grafana/grafana:latest
    container_name: ecommerce-grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards
      - ./grafana/datasources:/etc/grafana/provisioning/datasources
    ports:
      - "127.0.0.1:3000:3000"
    networks:
      - monitoring
    restart: unless-stopped

  # ==================== 日志层 ====================

  # Elasticsearch (日志)
  elasticsearch-log:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    container_name: ecommerce-elasticsearch-log
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - elasticsearch-log-data:/usr/share/elasticsearch/data
    networks:
      - logging
    restart: unless-stopped

  # Kibana 日志可视化
  kibana:
    image: docker.elastic.co/kibana/kibana:8.12.0
    container_name: ecommerce-kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch-log:9200
    ports:
      - "127.0.0.1:5601:5601"
    networks:
      - logging
    depends_on:
      - elasticsearch-log
    restart: unless-stopped

  # Filebeat 日志收集
  filebeat:
    image: docker.elastic.co/beats/filebeat:8.12.0
    container_name: ecommerce-filebeat
    user: root
    volumes:
      - ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - logging
    depends_on:
      - elasticsearch-log
    restart: unless-stopped

# ==================== 网络 ====================
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true
  monitoring:
    driver: bridge
  logging:
    driver: bridge

# ==================== 数据卷 ====================
volumes:
  mysql-data:
    driver: local
  redis-data:
    driver: local
  rabbitmq-data:
    driver: local
  elasticsearch-data:
    driver: local
  elasticsearch-log-data:
    driver: local
  prometheus-data:
    driver: local
  grafana-data:
    driver: local

16.4 服务 Dockerfile 示例

16.4.1 Python 微服务 Dockerfile

dockerfile 复制代码
# services/user-service/Dockerfile
FROM python:3.11-slim AS builder

WORKDIR /app

# 安装系统依赖
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        gcc \
        libffi-dev \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装 Python 依赖
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# ==================== 运行阶段 ====================
FROM python:3.11-slim AS production

# 设置元数据
LABEL maintainer="devops@example.com"
LABEL version="1.0"
LABEL description="User Service"

# 设置工作目录
WORKDIR /app

# 安装运行时依赖
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        curl \
    && rm -rf /var/lib/apt/lists/*

# 从 builder 阶段复制依赖
COPY --from=builder /install /usr/local

# 创建非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser

# 复制应用代码
COPY --chown=appuser:appuser . .

# 切换到非 root 用户
USER appuser

# 设置环境变量
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    APP_ENV=production \
    APP_PORT=8000

# 声明端口
EXPOSE 8000

# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD ["python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]

# 启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

16.4.2 Go 微服务 Dockerfile

dockerfile 复制代码
# services/product-service/Dockerfile (Go 版本)
# Stage 1: 构建
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 安装依赖
COPY go.mod go.sum ./
RUN go mod download

# 复制源码
COPY . .

# 静态编译
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server .

# Stage 2: 运行
FROM alpine:3.19

# 安装 ca-certificates(用于 HTTPS)
RUN apk --no-cache add ca-certificates

# 创建非 root 用户
RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup

WORKDIR /app

# 复制二进制文件
COPY --from=builder /app/server .

# 切换到非 root 用户
USER appuser

EXPOSE 8000

# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD ["wget", "--quiet", "--tries=1", "--spider", "http://localhost:8000/health"]

ENTRYPOINT ["./server"]

16.5 环境变量配置

bash 复制代码
# .env
# 数据库配置
DB_NAME=ecommerce
DB_USER=appuser
DB_PASSWORD=apppass123
DB_ROOT_PASSWORD=rootpass123

# Redis 配置
REDIS_PASSWORD=redis123

# RabbitMQ 配置
RABBITMQ_USER=appuser
RABBITMQ_PASSWORD=rabbithello123

# Grafana 配置
GRAFANA_PASSWORD=admin123

# 应用配置
APP_ENV=production
APP_SECRET_KEY=your-secret-key-change-in-production

16.6 部署脚本

bash 复制代码
#!/bin/bash
# scripts/deploy.sh - 自动化部署脚本

set -e

echo "=========================================="
echo "  电商系统 Docker 部署脚本"
echo "=========================================="

# 检查 Docker 和 Docker Compose
echo "[1/6] 检查环境..."
docker --version
docker compose version

# 停止旧服务
echo "[2/6] 停止旧服务..."
docker compose down

# 拉取最新镜像
echo "[3/6] 拉取最新镜像..."
docker compose pull

# 构建服务镜像
echo "[4/6] 构建服务镜像..."
docker compose build --no-cache

# 启动服务
echo "[5/6] 启动服务..."
docker compose up -d

# 等待服务健康
echo "[6/6] 等待服务健康..."
sleep 30

# 检查服务状态
echo "=========================================="
echo "  服务状态"
echo "=========================================="
docker compose ps

echo ""
echo "=========================================="
echo "  部署完成!"
echo "=========================================="
echo ""
echo "访问地址:"
echo "  前端: http://localhost"
echo "  API: http://localhost/api"
echo "  Grafana: http://localhost:3000"
echo "  Kibana: http://localhost:5601"
echo ""

16.7 健康检查脚本

bash 复制代码
#!/bin/bash
# scripts/health-check.sh - 健康检查脚本

echo "=========================================="
echo "  服务健康检查"
echo "=========================================="

# 检查所有容器状态
echo ""
echo "容器状态:"
docker compose ps

echo ""
echo "健康状态:"

# 检查 Nginx
if curl -f http://localhost/health > /dev/null 2>&1; then
    echo "✓ Nginx: 健康"
else
    echo "✗ Nginx: 不健康"
fi

# 检查 API 网关
if curl -f http://localhost:8001/status > /dev/null 2>&1; then
    echo "✓ API Gateway: 健康"
else
    echo "✗ API Gateway: 不健康"
fi

# 检查 MySQL
if docker exec ecommerce-mysql mysqladmin ping -h localhost > /dev/null 2>&1; then
    echo "✓ MySQL: 健康"
else
    echo "✗ MySQL: 不健康"
fi

# 检查 Redis
if docker exec ecommerce-redis redis-cli -a redis123 ping > /dev/null 2>&1; then
    echo "✓ Redis: 健康"
else
    echo "✗ Redis: 不健康"
fi

# 检查 RabbitMQ
if docker exec ecommerce-rabbitmq rabbitmq-diagnostics check_running > /dev/null 2>&1; then
    echo "✓ RabbitMQ: 健康"
else
    echo "✗ RabbitMQ: 不健康"
fi

# 检查 Elasticsearch
if curl -f http://localhost:9200/_cluster/health > /dev/null 2>&1; then
    echo "✓ Elasticsearch: 健康"
else
    echo "✗ Elasticsearch: 不健康"
fi

echo ""
echo "=========================================="
echo "  资源使用"
echo "=========================================="
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

16.8 本章小结

本章通过一个完整的电商项目,综合演示了:

章节 内容
架构设计 微服务架构、网络隔离、服务分层
Docker Compose 多服务编排、依赖管理、健康检查
Dockerfile 多阶段构建、安全加固、最佳实践
数据持久化 MySQL、Redis、RabbitMQ 数据存储
监控告警 Prometheus + Grafana 监控体系
日志管理 ELK 日志收集和分析
部署脚本 自动化部署和健康检查

16.9 课后练习

  1. 实践题:按照本章的架构,部署完整的电商系统。
  2. 优化题:优化 Dockerfile,减小镜像体积。
  3. 扩展题:添加更多监控指标和告警规则。

🎉 恭喜你完成了企业级 Docker 实战教程的全部内容!

希望这份文档能帮助你从零基础到掌握 Docker 的核心技能。

祝你在容器化技术的道路上越走越远!

相关推荐
Promise微笑1 小时前
工业微量水分监测:精密露点仪选型逻辑与行业应用实证深度报告
大数据·运维
Rocket-Luo1 小时前
谈谈企业中的网络安全
网络·安全·web安全
技术不好的崎鸣同学2 小时前
[BJDCTF2020]The mystery of ip 思路及解法
网络·安全·web安全
联盟分享专家3 小时前
垂直工具型 SaaS 的增长实战:如何把用户变成推广者?
运维
Bruce_Liuxiaowei4 小时前
2026年7月第1周网络安全形势周报
人工智能·安全·web安全·ai·智能体
偏爱自由 !4 小时前
一(0.1):配置git
java·git·intellij-idea
Leon-Ning Liu4 小时前
【真实经验分享】OGG抽取进程报错 ORA-07445 [kgherrordmp()+986] ORA-00600 [17114]分析步骤
运维·数据库
QWEDDRFTG4 小时前
运维长期经验总结:从故障倒推服务器电源线选购标准
运维·服务器
星幻元宇VR4 小时前
公共安全主题展厅设备【防洪防汛安全科普系统】
科技·学习·安全