引言
随着.NET Core的发布和后续.NET 5/6/7的发展,C#应用程序已能完美运行在Linux环境中。本文将全面介绍如何将C#应用部署到Linux服务器,涵盖从基础环境配置到高级部署策略的完整流程,帮助开发者实现从Windows开发环境到Linux生产环境的无缝迁移。
1. 环境准备
1.1 选择Linux发行版
主流支持的选择:
- Ubuntu (20.04/22.04 LTS) – 最常用的部署选择
- Debian (10/11) – 稳定性优先
- CentOS/RHEL (7/8) – 企业级环境
- Alpine Linux – 容器化部署首选
1.2 安装.NET运行时
Ubuntu/Debian示例:
# 添加微软包仓库
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
# 安装.NET SDK
sudo apt-get update
sudo apt-get install -y dotnet-sdk-6.0
# 仅安装运行时(生产环境)
sudo apt-get install -y aspnetcore-runtime-6.0
验证安装:
dotnet --info
2. 应用发布方式
2.1 框架依赖发布(FDD)
dotnet publish -c Release -f net6.0
- 需要目标机器安装对应运行时
- 部署包较小
- 需确保运行时版本匹配
2.2 独立发布(SCD)
dotnet publish -c Release -f net6.0 -r linux-x64 --self-contained true
- 包含所有依赖
- 部署包较大
- 无需安装运行时
2.3 单文件发布
dotnet publish -c Release -f net6.0 -r linux-x64 --self-contained true /p:PublishSingleFile=true
- 所有依赖打包到单个可执行文件
- 启动更快
- 调试信息需单独处理
3. 部署到Linux服务器
3.1 手动部署流程
- 本地发布应用:
dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish
- 上传到服务器:
scp -r ./publish user@server:/var/www/myapp
- 设置执行权限:
chmod +x /var/www/myapp/MyApp
- 测试运行:
cd /var/www/myapp
./MyApp
3.2 自动化部署脚本
#!/bin/bash
# deploy.sh
APP_NAME="MyApp"
DEPLOY_DIR="/var/www/$APP_NAME"
TEMP_DIR="/tmp/$APP_NAME-build"
# 清理旧构建
rm -rf $TEMP_DIR
mkdir -p $TEMP_DIR
# 发布应用
dotnet publish -c Release -r linux-x64 --self-contained true -o $TEMP_DIR
# 停止现有服务
sudo systemctl stop $APP_NAME.service
# 部署新版本
sudo rm -rf $DEPLOY_DIR
sudo mkdir -p $DEPLOY_DIR
sudo cp -r $TEMP_DIR/* $DEPLOY_DIR
sudo chmod +x $DEPLOY_DIR/$APP_NAME
# 启动服务
sudo systemctl start $APP_NAME.service
4. 作为系统服务运行
4.1 创建systemd服务单元
/etc/systemd/system/myapp.service
:
[Unit]
Description=My .NET Application
After=network.target
[Service]
Type=notify
WorkingDirectory=/var/www/myapp
ExecStart=/var/www/myapp/MyApp
Restart=always
RestartSec=10
KillSignal=SIGINT
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
4.2 管理服务
# 重载服务配置
sudo systemctl daemon-reload
# 启用开机启动
sudo systemctl enable myapp.service
# 启动服务
sudo systemctl start myapp.service
# 查看状态
sudo systemctl status myapp.service
# 查看日志
journalctl -u myapp.service -f
5. 反向代理配置
5.1 Nginx配置示例
/etc/nginx/sites-available/myapp
:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
启用配置:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
5.2 Kestrel配置调整
appsettings.json
:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
}
}
}
}
6. 容器化部署
6.1 Dockerfile示例
# 构建阶段
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
# 运行时阶段
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.dll"]
6.2 构建和运行
docker build -t myapp .
docker run -d -p 8080:80 --name myapp-container myapp
6.3 使用Docker Compose
docker-compose.yml
:
version: '3.8'
services:
myapp:
image: myapp
build: .
ports:
- "8080:80"
environment:
- ASPNETCORE_ENVIRONMENT=Production
restart: unless-stopped
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- myapp
7. 高级部署策略
7.1 零停机部署
使用Nginx的流量切换:
upstream backend {
server 127.0.0.1:5000;
server 127.0.0.1:5001 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
部署流程:
- 启动新版本到5001端口
- 测试新版本
- 切换Nginx配置
- 停止旧版本
7.2 蓝绿部署
- 准备两个相同环境(蓝/绿)
- 当前生产流量指向蓝环境
- 部署新版本到绿环境并测试
- 切换流量到绿环境
- 蓝环境变为待机状态
8. 监控与维护
8.1 日志管理
配置日志轮转:
# /etc/logrotate.d/myapp
/var/www/myapp/logs/*.log {
daily
rotate 7
missingok
compress
delaycompress
notifempty
create 644 root root
}
8.2 健康检查端点
app.MapHealthChecks("/health");
app.MapGet("/version", () => Assembly.GetEntryAssembly()?.GetName().Version?.ToString());
8.3 使用Prometheus监控
安装NuGet包:
dotnet add package prometheus-net.AspNetCore
配置中间件:
app.UseMetricServer();
app.UseHttpMetrics();
9. 常见问题解决
9.1 文件权限问题
sudo chown -R www-data:www-data /var/www/myapp
sudo chmod -R 755 /var/www/myapp
9.2 端口冲突
netstat -tulnp | grep :5000
sudo kill <PID>
9.3 依赖缺失错误
ldd MyApp # 检查依赖库
sudo apt-get install libunwind8 libicu66
10. 安全最佳实践
- 最小权限原则:
sudo useradd -r -s /bin/false myappuser
sudo chown -R myappuser:myappuser /var/www/myapp
- 防火墙配置:
sudo ufw allow 80/tcp
sudo ufw enable
- 定期更新:
sudo apt-get update
sudo apt-get upgrade
- 禁用不必要服务:
sudo systemctl disable unnecessary-service
结语
将C#应用程序部署到Linux环境已成为现代开发的标准实践。通过本文介绍的方法,开发者可以构建稳定、高效且易于维护的Linux部署方案。无论是选择传统的系统服务部署,还是采用现代化的容器化方案,.NET在Linux平台上的表现都能满足企业级应用的需求。随着.NET平台的持续发展,Linux环境下的C#应用部署将变得更加简单高效。