znlgis 博客

GIS开发与技术分享

第九章:系统部署与运维指南

目录

  1. 部署环境准备
  2. 后端项目发布
  3. 前端项目构建
  4. Windows部署
  5. Linux部署
  6. Docker容器化部署
  7. Nginx反向代理配置
  8. 运维监控与日志管理

1. 部署环境准备

1.1 服务器要求

最低配置

推荐配置

1.2 软件环境

必需软件: | 软件 | 版本 | 用途 | |——|——|——| | .NET Runtime | 8.0 | 运行后端应用 | | Nginx | 最新版 | 反向代理 | | MySQL/SQL Server | 8.0/2019 | 数据库 | | Redis | 7.x | 缓存服务 |

可选软件: | 软件 | 用途 | |——|——| | Docker | 容器化部署 | | Docker Compose | 容器编排 | | Supervisor | 进程管理 | | Elasticsearch | 日志存储 |

1.3 网络规划

                    Internet
                        │
                        ▼
               ┌────────────────┐
               │     防火墙      │
               │   (80, 443)    │
               └────────────────┘
                        │
                        ▼
               ┌────────────────┐
               │     Nginx      │
               │  (反向代理)    │
               └────────────────┘
                   │         │
         ┌─────────┘         └─────────┐
         ▼                             ▼
┌────────────────┐           ┌────────────────┐
│   前端静态文件  │           │    后端API     │
│   (Vue3 dist)  │           │   (5005端口)   │
└────────────────┘           └────────────────┘
                                    │
                   ┌────────────────┼────────────────┐
                   ▼                ▼                ▼
          ┌────────────┐    ┌────────────┐   ┌────────────┐
          │   MySQL    │    │   Redis    │   │   MinIO    │
          │  (3306)    │    │  (6379)    │   │  (9000)    │
          └────────────┘    └────────────┘   └────────────┘

1.4 安全配置

防火墙规则

# 只开放必要端口
# HTTP
sudo ufw allow 80/tcp
# HTTPS
sudo ufw allow 443/tcp
# SSH
sudo ufw allow 22/tcp

# 启用防火墙
sudo ufw enable

SSL证书

# 使用Let's Encrypt免费证书
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com

2. 后端项目发布

2.1 发布配置

修改appsettings.Production.json

{
  "Urls": "http://*:5005",
  "DbSettings": {
    "EnableInitDb": false,
    "EnableInitSeed": false,
    "EnableSqlLog": false,
    "DbConfigs": [
      {
        "ConfigId": "1300000000001",
        "DbType": "MySql",
        "ConnectionString": "Data Source=localhost;Database=AdminNET;User ID=admin;Password=StrongPassword123!;pooling=true;port=3306;sslmode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true",
        "IsAutoCloseConnection": true
      }
    ]
  },
  "Cache": {
    "CacheType": "Redis",
    "Redis": {
      "ConnectionString": "localhost:6379,password=RedisPassword123!,defaultDatabase=0"
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

2.2 命令行发布

# 进入后端项目目录
cd Admin.NET/Admin.NET

# 发布Release版本
dotnet publish Admin.NET.Web.Entry -c Release -o ./publish

# 发布到指定运行时
# Windows
dotnet publish Admin.NET.Web.Entry -c Release -r win-x64 --self-contained false -o ./publish/win

# Linux
dotnet publish Admin.NET.Web.Entry -c Release -r linux-x64 --self-contained false -o ./publish/linux

# 独立部署(包含运行时)
dotnet publish Admin.NET.Web.Entry -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -o ./publish/linux-self

2.3 Visual Studio发布

  1. 右键点击Admin.NET.Web.Entry项目
  2. 选择”发布”
  3. 选择目标:
    • 文件夹(用于手动部署)
    • FTP/FTPS
    • Web服务器(IIS)
    • Azure
  4. 配置发布选项:
    • 配置:Release
    • 目标框架:net8.0
    • 部署模式:框架依赖
    • 目标运行时:可移植
  5. 点击”发布”

2.4 发布文件说明

publish/
├── Admin.NET.Web.Entry.dll      # 主程序
├── Admin.NET.Web.Entry.pdb      # 调试符号
├── Admin.NET.Core.dll           # 核心层
├── Admin.NET.Application.dll    # 应用层
├── appsettings.json            # 配置文件
├── appsettings.Production.json # 生产环境配置
├── wwwroot/                    # 静态文件
├── web.config                  # IIS配置
└── runtimes/                   # 运行时依赖

3. 前端项目构建

3.1 环境配置

修改.env.production

# 生产环境配置
VITE_PORT = 2800
VITE_OPEN = false
VITE_PROXY_URL = 

# API地址(实际部署地址)
VITE_API_URL = https://api.yourdomain.com

# 是否启用压缩
VITE_BUILD_COMPRESS = gzip
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false

3.2 构建命令

# 进入前端项目目录
cd Web

# 安装依赖(如果没有)
pnpm install

# 生产环境构建
pnpm build

# 构建并预览
pnpm build && pnpm preview

3.3 构建输出

dist/
├── index.html                  # 入口文件
├── assets/                     # 静态资源
│   ├── css/                    # 样式文件
│   │   └── index.[hash].css
│   ├── js/                     # JS文件
│   │   ├── index.[hash].js
│   │   └── vendor.[hash].js
│   └── images/                 # 图片
├── static/                     # 静态资源
└── favicon.ico                 # 图标

3.4 构建优化

vite.config.ts配置

export default defineConfig({
  build: {
    // 指定输出目录
    outDir: 'dist',
    // 资源内联阈值
    assetsInlineLimit: 4096,
    // CSS代码分割
    cssCodeSplit: true,
    // 生成sourcemap
    sourcemap: false,
    // 代码压缩
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    },
    // 分块策略
    rollupOptions: {
      output: {
        chunkFileNames: 'assets/js/[name]-[hash].js',
        entryFileNames: 'assets/js/[name]-[hash].js',
        assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
        manualChunks: {
          'vue-vendor': ['vue', 'vue-router', 'pinia'],
          'element-plus': ['element-plus'],
          'utils': ['axios', 'dayjs', 'lodash-es']
        }
      }
    }
  }
})

4. Windows部署

4.1 IIS部署

安装IIS和ASP.NET Core托管模块

  1. 打开”服务器管理器”
  2. 添加角色和功能
  3. 选择”Web服务器(IIS)”
  4. 下载并安装ASP.NET Core托管捆绑包: https://dotnet.microsoft.com/download/dotnet/8.0

配置IIS站点

  1. 打开IIS管理器
  2. 添加网站:
    • 网站名称:AdminNET
    • 物理路径:C:\inetpub\wwwroot\AdminNET
    • 绑定:http://yourdomain.com:80
  3. 配置应用程序池:
    • .NET CLR版本:无托管代码
    • 托管管道模式:集成
    • 标识:ApplicationPoolIdentity

web.config配置

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\Admin.NET.Web.Entry.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="InProcess">
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

4.2 Windows Service部署

安装为Windows服务

# 创建服务
sc create AdminNET binPath= "C:\AdminNET\Admin.NET.Web.Entry.exe" start= auto

# 启动服务
sc start AdminNET

# 停止服务
sc stop AdminNET

# 删除服务
sc delete AdminNET

使用NSSM管理

# 下载NSSM
# https://nssm.cc/download

# 安装服务
nssm install AdminNET

# 配置路径
# Application: C:\AdminNET\Admin.NET.Web.Entry.exe
# Startup directory: C:\AdminNET
# Arguments: 

# 服务管理
nssm start AdminNET
nssm stop AdminNET
nssm restart AdminNET

5. Linux部署

5.1 安装.NET运行时

Ubuntu/Debian

# 添加Microsoft包源
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

# 安装运行时
sudo apt-get update
sudo apt-get install -y aspnetcore-runtime-8.0

# 验证安装
dotnet --list-runtimes

CentOS/RHEL

# 添加Microsoft仓库
sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm

# 安装运行时
sudo yum install aspnetcore-runtime-8.0

5.2 部署应用

# 创建应用目录
sudo mkdir -p /var/www/adminnet
sudo chown -R $USER:$USER /var/www/adminnet

# 上传发布文件
scp -r ./publish/* user@server:/var/www/adminnet/

# 设置执行权限
chmod +x /var/www/adminnet/Admin.NET.Web.Entry

# 测试运行
cd /var/www/adminnet
dotnet Admin.NET.Web.Entry.dll

5.3 使用Systemd管理

创建服务文件

sudo nano /etc/systemd/system/adminnet.service
[Unit]
Description=Admin.NET Web Application
After=network.target

[Service]
WorkingDirectory=/var/www/adminnet
ExecStart=/usr/bin/dotnet /var/www/adminnet/Admin.NET.Web.Entry.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=adminnet
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

管理服务

# 重新加载配置
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start adminnet

# 停止服务
sudo systemctl stop adminnet

# 重启服务
sudo systemctl restart adminnet

# 开机启动
sudo systemctl enable adminnet

# 查看状态
sudo systemctl status adminnet

# 查看日志
sudo journalctl -u adminnet -f

5.4 使用Supervisor管理

安装Supervisor

sudo apt-get install supervisor

创建配置文件

sudo nano /etc/supervisor/conf.d/adminnet.conf
[program:adminnet]
command=/usr/bin/dotnet /var/www/adminnet/Admin.NET.Web.Entry.dll
directory=/var/www/adminnet
autostart=true
autorestart=true
stderr_logfile=/var/log/adminnet/err.log
stdout_logfile=/var/log/adminnet/out.log
environment=ASPNETCORE_ENVIRONMENT=Production
user=www-data
stopsignal=INT

管理应用

# 创建日志目录
sudo mkdir -p /var/log/adminnet

# 重新加载配置
sudo supervisorctl reread
sudo supervisorctl update

# 启动应用
sudo supervisorctl start adminnet

# 停止应用
sudo supervisorctl stop adminnet

# 重启应用
sudo supervisorctl restart adminnet

# 查看状态
sudo supervisorctl status

6. Docker容器化部署

6.1 创建Dockerfile

后端Dockerfile

# Admin.NET/Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5005

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Admin.NET/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj", "Admin.NET.Web.Entry/"]
COPY ["Admin.NET/Admin.NET.Web.Core/Admin.NET.Web.Core.csproj", "Admin.NET.Web.Core/"]
COPY ["Admin.NET/Admin.NET.Application/Admin.NET.Application.csproj", "Admin.NET.Application/"]
COPY ["Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj", "Admin.NET.Core/"]
RUN dotnet restore "Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj"
COPY Admin.NET/ .
WORKDIR "/src/Admin.NET.Web.Entry"
RUN dotnet build "Admin.NET.Web.Entry.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Admin.NET.Web.Entry.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Admin.NET.Web.Entry.dll"]

前端Dockerfile

# Web/Dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install
COPY . .
RUN pnpm build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

6.2 Docker Compose编排

# docker-compose.yml
version: '3.8'

services:
  # MySQL数据库
  mysql:
    image: mysql:8.0
    container_name: adminnet-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: AdminNET
      MYSQL_USER: admin
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "3306:3306"
    networks:
      - adminnet-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis缓存
  redis:
    image: redis:7-alpine
    container_name: adminnet-redis
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    ports:
      - "6379:6379"
    networks:
      - adminnet-network

  # 后端API
  api:
    build:
      context: .
      dockerfile: Admin.NET/Dockerfile
    container_name: adminnet-api
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - ASPNETCORE_URLS=http://+:5005
      - ConnectionStrings__Default=Server=mysql;Database=AdminNET;Uid=admin;Pwd=${MYSQL_PASSWORD};
      - Redis__ConnectionString=redis:6379,password=${REDIS_PASSWORD}
    ports:
      - "5005:5005"
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - adminnet-network
    restart: unless-stopped

  # 前端Web
  web:
    build:
      context: ./Web
      dockerfile: Dockerfile
    container_name: adminnet-web
    ports:
      - "80:80"
    depends_on:
      - api
    networks:
      - adminnet-network
    restart: unless-stopped

volumes:
  mysql_data:
  redis_data:

networks:
  adminnet-network:
    driver: bridge

6.3 部署命令

# 创建环境变量文件
cat > .env << EOF
MYSQL_ROOT_PASSWORD=RootPassword123!
MYSQL_PASSWORD=AdminPassword123!
REDIS_PASSWORD=RedisPassword123!
EOF

# 构建镜像
docker-compose build

# 启动所有服务
docker-compose up -d

# 查看日志
docker-compose logs -f

# 停止服务
docker-compose down

# 停止并删除数据
docker-compose down -v

7. Nginx反向代理配置

7.1 安装Nginx

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install nginx

# CentOS
sudo yum install epel-release
sudo yum install nginx

# 启动Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

7.2 配置文件

# /etc/nginx/conf.d/adminnet.conf

# 上游服务器
upstream adminnet_api {
    server 127.0.0.1:5005;
    keepalive 32;
}

# HTTP重定向到HTTPS
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

# HTTPS配置
server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL证书
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # SSL安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;

    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/xml+rss;

    # 前端静态文件
    location / {
        root /var/www/adminnet/web;
        index index.html;
        try_files $uri $uri/ /index.html;

        # 缓存静态资源
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    # API代理
    location /api {
        proxy_pass http://adminnet_api;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        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;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }

    # SignalR WebSocket代理
    location /hubs {
        proxy_pass http://adminnet_api;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
        proxy_read_timeout 86400;
    }

    # Swagger文档
    location /swagger {
        proxy_pass http://adminnet_api;
        proxy_http_version 1.1;
        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 /health {
        proxy_pass http://adminnet_api/health;
        access_log off;
    }

    # 错误页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

7.3 验证并重启

# 测试配置
sudo nginx -t

# 重新加载配置
sudo nginx -s reload

# 重启Nginx
sudo systemctl restart nginx

8. 运维监控与日志管理

8.1 健康检查

配置健康检查端点

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
        .AddDbContextCheck<DbContext>()
        .AddRedis("redis连接字符串")
        .AddCheck("disk", () =>
        {
            var driveInfo = new DriveInfo("C:");
            var freeSpacePercent = (double)driveInfo.AvailableFreeSpace / driveInfo.TotalSize * 100;
            return freeSpacePercent > 10 
                ? HealthCheckResult.Healthy() 
                : HealthCheckResult.Unhealthy("磁盘空间不足");
        });
}

public void Configure(IApplicationBuilder app)
{
    app.UseHealthChecks("/health", new HealthCheckOptions
    {
        ResponseWriter = async (context, report) =>
        {
            context.Response.ContentType = "application/json";
            var result = new
            {
                status = report.Status.ToString(),
                checks = report.Entries.Select(e => new
                {
                    name = e.Key,
                    status = e.Value.Status.ToString(),
                    description = e.Value.Description
                })
            };
            await context.Response.WriteAsJsonAsync(result);
        }
    });
}

8.2 日志配置

Serilog配置

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "logs/log-.txt",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 30,
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "Elasticsearch",
        "Args": {
          "nodeUris": "http://localhost:9200",
          "indexFormat": "adminnet-{0:yyyy.MM.dd}",
          "autoRegisterTemplate": true
        }
      }
    ],
    "Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"]
  }
}

8.3 监控脚本

服务监控脚本

#!/bin/bash
# /usr/local/bin/monitor_adminnet.sh

# 配置
SERVICE_NAME="adminnet"
HEALTH_URL="http://localhost:5005/health"
ALERT_EMAIL="admin@example.com"

# 检查服务状态
check_service() {
    if ! systemctl is-active --quiet $SERVICE_NAME; then
        echo "服务未运行,正在重启..."
        systemctl restart $SERVICE_NAME
        send_alert "服务重启" "Admin.NET服务异常,已自动重启"
    fi
}

# 检查健康状态
check_health() {
    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)
    if [ "$HTTP_CODE" != "200" ]; then
        echo "健康检查失败,HTTP状态码:$HTTP_CODE"
        send_alert "健康检查失败" "Admin.NET健康检查返回:$HTTP_CODE"
    fi
}

# 检查磁盘空间
check_disk() {
    DISK_USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
    if [ "$DISK_USAGE" -gt 90 ]; then
        send_alert "磁盘告警" "磁盘使用率已达${DISK_USAGE}%"
    fi
}

# 检查内存
check_memory() {
    MEM_USAGE=$(free | grep Mem | awk '{print int($3/$2 * 100)}')
    if [ "$MEM_USAGE" -gt 90 ]; then
        send_alert "内存告警" "内存使用率已达${MEM_USAGE}%"
    fi
}

# 发送告警
send_alert() {
    SUBJECT=$1
    BODY=$2
    echo "$BODY" | mail -s "[Admin.NET告警] $SUBJECT" $ALERT_EMAIL
}

# 执行检查
check_service
check_health
check_disk
check_memory

添加定时任务

# 编辑crontab
crontab -e

# 每5分钟执行一次监控
*/5 * * * * /usr/local/bin/monitor_adminnet.sh >> /var/log/adminnet/monitor.log 2>&1

8.4 日志分析

使用Logrotate管理日志

# /etc/logrotate.d/adminnet
/var/www/adminnet/logs/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload adminnet > /dev/null 2>&1 || true
    endscript
}

8.5 性能监控

Prometheus + Grafana

// 添加Prometheus指标
services.AddHealthChecks()
    .AddPrometheus();

app.UseHttpMetrics();
app.UseGrpcMetrics();

app.UseEndpoints(endpoints =>
{
    endpoints.MapMetrics();  // /metrics端点
});

总结

本章详细介绍了Admin.NET的部署与运维:

  1. 环境准备:服务器要求、软件环境、网络规划
  2. 后端发布:配置修改、命令行发布、VS发布
  3. 前端构建:环境配置、构建优化、输出文件
  4. Windows部署:IIS部署、Windows服务
  5. Linux部署:Systemd、Supervisor管理
  6. Docker部署:Dockerfile、Docker Compose
  7. Nginx配置:反向代理、SSL、WebSocket
  8. 运维监控:健康检查、日志管理、监控告警

掌握这些部署运维知识,可以确保Admin.NET应用稳定运行。在下一章中,我们将学习最佳实践和常见问题解答。