
还记得那些深夜在服务器上手工部署的日子吗?一边祈祷着"千万别出错",一边小心翼翼地复制文件、重启服务。如果你曾经因为部署失败而被老板在凌晨三点叫醒,那么这篇文章就是为你准备的救命稻草!
今天我们来聊聊如何为ASP.NET Core Web项目实现自动化上线更新,让部署变得像点外卖一样简单。
CI (Continuous Integration):持续集成,简单理解就是"代码一提交,自动跑测试"。 CD (Continuous Deployment):持续部署,就是"测试通过了,自动发布上线"。
让我们先看看一个典型的ASP.NET Core项目自动化部署流程:

方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
GitHub Actions | 免费、配置简单、GitHub集成好 | 公共仓库有限制 | 开源项目、小团队 |
Azure DevOps | 功能强大、企业级、支持混合云 | 学习成本高 | 大型企业项目 |
Jenkins | 插件丰富、完全控制 | 需要维护服务器 | 有专门运维团队 |
GitLab CI | 一体化解决方案 | 需要GitLab环境 | 使用GitLab的团队 |

Docker就像给你的应用打包了一个"旅行箱",里面有运行所需的一切,到哪里都能完美运行。
创建一个多阶段构建的Dockerfile:
# 使用官方的 .NET SDK 镜像进行构建
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# 复制项目文件并还原依赖
COPY ["MyWebApp/MyWebApp.csproj", "MyWebApp/"]
RUN dotnet restore "MyWebApp/MyWebApp.csproj"
# 复制所有源代码并构建
COPY . .
WORKDIR "/src/MyWebApp"
RUN dotnet build "MyWebApp.csproj" -c Release -o /app/build
# 发布应用
FROM build AS publish
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish
# 使用运行时镜像
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# 复制发布的文件
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyWebApp.dll"]对于复杂的应用,使用docker-compose.yml:
version: '3.8'
services:
webapp:
build: .
ports:
- "8080:80"
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__DefaultConnection=Server=db;Database=MyApp;User=sa;Password=YourPassword123
depends_on:
- db
restart: unless-stopped
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=YourPassword123
ports:
- "1433:1433"
volumes:
- sqldata:/var/opt/mssql
restart: unless-stopped
volumes:
sqldata:在项目根目录创建.github/workflows/deploy.yml:
name: Deploy ASP.NET Core App
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: 📦 Checkout代码
uses: actions/checkout@v4
- name: 🔧 设置.NET环境
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
- name: 📥 还原依赖
run: dotnet restore
- name: 🔨 构建项目
run: dotnet build --no-restore --configuration Release
- name: 🧪 运行测试
run: dotnet test --no-build --configuration Release --verbosity normal
- name: 🐳 构建Docker镜像
run: |
docker build -t myapp:${{ github.sha }} .
docker tag myapp:${{ github.sha }} myapp:latest
- name: 🚀 部署到服务器
if: github.ref == 'refs/heads/main'
run: |
# 这里添加部署脚本
echo "部署到生产环境"name: Multi-Environment Deploy
on:
push:
branches: [ main, develop ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 运行测试
run: |
dotnet restore
dotnet test
deploy-staging:
needs: test
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment: staging
steps:
- name: 部署到测试环境
run: echo "部署到测试环境"
deploy-production:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- name: 部署到生产环境
run: echo "部署到生产环境"创建azure-pipelines.yml:
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
dockerRegistryServiceConnection: 'myDockerRegistry'
imageRepository: 'mywebapp'
containerRegistry: 'myregistry.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
tag: '$(Build.BuildId)'
stages:
- stage: Build
displayName: Build and Test
jobs:
- job: Build
displayName: Build
steps:
- task: DotNetCoreCLI@2
displayName: '还原NuGet包'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: '构建项目'
inputs:
command: 'build'
projects: '**/*.csproj'
arguments: '--configuration $(buildConfiguration)'
- task: DotNetCoreCLI@2
displayName: '运行测试'
inputs:
command: 'test'
projects: '**/*Tests/*.csproj'
arguments: '--configuration $(buildConfiguration) --collect "Code coverage"'
- task: Docker@2
displayName: '构建和推送Docker镜像'
inputs:
command: 'buildAndPush'
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
latest
- stage: Deploy
displayName: Deploy to Production
dependsOn: Build
condition: succeeded()
jobs:
- deployment: Deploy
displayName: Deploy
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
displayName: '部署到Azure Web App'
inputs:
azureSubscription: 'myAzureSubscription'
appName: 'mywebapp'
containers: '$(containerRegistry)/$(imageRepository):$(tag)'
在ASP.NET Core中添加健康检查:
// Program.cs
builder.Services.AddHealthChecks()
.AddDbContext<ApplicationDbContext>()
.AddUrlGroup(new Uri("https://example.com"), "external-service");
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});#!/bin/bash
# rollback.sh
CURRENT_VERSION=$(docker ps --format "table {{.Image}}" | grep myapp | head -1)
PREVIOUS_VERSION=$(docker images myapp --format "table {{.Tag}}" | sed -n '2p')
echo "当前版本: $CURRENT_VERSION"
echo "回滚到版本: $PREVIOUS_VERSION"
# 停止当前容器
docker stop myapp-container
# 启动上一个版本
docker run -d --name myapp-container-rollback myapp:$PREVIOUS_VERSION
# 健康检查
sleep 10
if curl -f http://localhost:8080/health; then
echo "回滚成功!"
docker rm myapp-container
else
echo "回滚失败!"
exit 1
fi解决方案:
# 优化的 Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# 先复制项目文件,利用层缓存
COPY ["*.csproj", "./"]
RUN dotnet restore
# 再复制源代码
COPY . .
RUN dotnet publish -c Release -o /app/publish解决方案: 使用InitContainer或者部署前脚本:
# docker-compose.yml
services:
migration:
image: myapp:latest
command: dotnet ef database update
environment:
- ConnectionStrings__DefaultConnection=...
depends_on:
- db
webapp:
image: myapp:latest
depends_on:
- migration解决方案: 使用环境变量和配置中心:
{
"ConnectionStrings": {
"DefaultConnection": "${DB_CONNECTION_STRING}"
},
"ApiSettings": {
"BaseUrl": "${API_BASE_URL:https://localhost:5001}"
}
}部署前确认:
自动化部署不是一蹴而就的,它是一个持续改进的过程。从简单的脚本开始,逐步完善监控、测试和回滚机制。记住,最好的架构是能够快速迭代和改进的架构。
现在,是时候告别那些让人焦虑的手工部署了!让我们拥抱自动化,让部署变得像喝咖啡一样轻松惬意。☕
**关键词:**深度解析:如何针对asp.net core web 项目实现自动化上线更新