太好了——你准备“手撸一个 .NET Core(.NET)CI/CD”(从编译、测试、打包到部署)——下面我给你一份开箱即可用的实战方案:包含方案选择、版本/兼容性注意、推荐工具、完整的 GitHub Actions 工作流(YAML)、Dockerfile、部署脚本、以及可直接拿去改的 Jenkinsfile 示例。所有关键点我都标注了来源,方便你验证与后续扩展。
先行提示:如果你目标是长期维护,优先以 LTS .NET 版本 + 容器化部署 + GitHub Actions(或 Jenkins 自托管) 为主线;下面以 GitHub Actions + Docker 部署到自托管 Linux 服务器为主示例(你也可以替换为 Azure App Service / AKS / ECR 等)。关于 .NET 当前 LTS/版本信息请以官方页面为准。(Microsoft)
1)高层架构(快速看图)
- 开发者 push → GitHub repo
- GitHub Actions CI:restore → build → test → publish artifact / build Docker image → push registry(Docker Hub / ACR)
- CD:在成功推镜像后,Actions 通过 SSH 在目标服务器上 pull 镜像并重启容器(或触发 k8s rollout)
可选:使用 Jenkins 自托管 + Webhook 触发(更适合复杂私有 infra)。(Jenkins)
2)选型建议(为什么这样选)
- GitHub Actions:原生于 GitHub,容易配置、社区 Action 丰富、适合快速上手并托管在 GitHub。官方也有 .NET 指南。(Microsoft Learn)
- Dockerize:容器化保证环境一致性,部署脚本更简单;支持从单机到 k8s 的迁移路径。
- Jenkins(可选):如果你需要完全自管,复杂 CI 流水线、代理池、内网构建,Jenkins 是成熟方案。文档/教程齐全。(Jenkins)
3)必须先做的准备(环境)
- 在
csproj根 repo(或 monorepo)中保证dotnet test可运行并通过。 - 创建 Docker Hub / 私有镜像仓库凭据(或 Azure Container Registry)。
- 在目标服务器(Linux)上安装 Docker(以及 docker-compose 可选)。
- 在 GitHub 仓库设置 Secrets:
DOCKERHUB_USERNAME,DOCKERHUB_TOKEN,SSH_HOST,SSH_USER,SSH_PRIVATE_KEY(私钥),CONTAINER_NAME等。
4)关键文件:多阶段 Dockerfile(推荐 .NET 8/10 LTS,根据你项目改)
把这个放到 Web 项目根目录(例如 src/MyApp/)内作为 Dockerfile。
# syntax=docker/dockerfile:1
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "./"]
RUN dotnet restore "MyApp.csproj"
COPY . .
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish
# Runtime stage (smaller)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
ENV DOTNET_URLS=http://+:80
COPY --from=build /app/publish .
EXPOSE 80
ENTRYPOINT ["dotnet", "MyApp.dll"]
如果你选择 self-contained 或不同 .NET 版本,把镜像 tag 换成相应版本(参考官方下载页)。(Microsoft)
5)GitHub Actions 工作流(.github/workflows/ci-cd.yml)
下面示例会:checkout → setup-dotnet → restore → build → test → publish Docker image → push 到 Docker Hub → SSH 到目标服务器拉镜像并重启容器(使用 appleboy/ssh-action)。
name: CI-CD .NET Docker
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
IMAGE_NAME: myorg/myapp
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x' # or 10.0.x LTS if you choose .NET 10
- name: Restore
run: dotnet restore ./src/MyApp/MyApp.csproj
- name: Build
run: dotnet build ./src/MyApp/MyApp.csproj --configuration Release --no-restore
- name: Test
run: dotnet test ./tests/MyApp.Tests/MyApp.Tests.csproj --no-build --verbosity normal
- name: Publish
run: dotnet publish ./src/MyApp/MyApp.csproj -c Release -o ./publish
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
run: |
IMAGE=${{ env.IMAGE_NAME }}:${{ github.sha }}
docker build -t $IMAGE ./src/MyApp
docker push $IMAGE
# Also update "latest" tag
docker tag $IMAGE ${{ env.IMAGE_NAME }}:latest
docker push ${{ env.IMAGE_NAME }}:latest
deploy:
needs: build-and-test
runs-on: ubuntu-latest
steps:
- name: Deploy to server via SSH - pull & restart
uses: appleboy/ssh-action@v0.1.7
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: 22
script: |
docker pull ${{ env.IMAGE_NAME }}:${{ github.sha }}
docker stop ${{ secrets.CONTAINER_NAME }} || true
docker rm ${{ secrets.CONTAINER_NAME }} || true
docker run -d --name ${{ secrets.CONTAINER_NAME }} -p 80:80 ${{ env.IMAGE_NAME }}:${{ github.sha }}
- 你可以把
docker run换成docker-compose pull && docker-compose up -d(如果使用 compose 管理多容器)。 - 若你用 Registry 是 ACR/GCR/ECR,换成相应登录 action。
- 要把
ssh-action版本替换为你信任的最新版本。
(参考:GitHub Actions + .NET 教程与社区示例)。(Microsoft Learn)
6)目标服务器上的部署脚本(可选:deploy.sh 放到服务器)
如果你不想用 SSH action 的 inline 脚本,可以在 server 上维护:
#!/bin/bash
IMAGE=$1
CONTAINER=myapp
docker pull $IMAGE
docker stop $CONTAINER || true
docker rm $CONTAINER || true
docker run -d --name $CONTAINER -p 80:80 $IMAGE
在 Actions 中只需 ssh 并调用 ./deploy.sh myorg/myapp:sha.
7)Jenkinsfile(简洁版)—— 如果你想自托管 Jenkins
把 Jenkins agent 配置好(带 Docker),然后在 repo 里放 Jenkinsfile:
pipeline {
agent any
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Build') {
steps {
sh 'dotnet restore src/MyApp/MyApp.csproj'
sh 'dotnet build src/MyApp/MyApp.csproj -c Release --no-restore'
}
}
stage('Test') {
steps {
sh 'dotnet test tests/MyApp.Tests/MyApp.Tests.csproj --no-build'
}
}
stage('Docker Build & Push') {
steps {
withCredentials([usernamePassword(credentialsId: 'dockerhub', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) {
sh '''
docker login -u $DOCKER_USER -p $DOCKER_PASS
docker build -t myorg/myapp:${GIT_COMMIT} src/MyApp
docker push myorg/myapp:${GIT_COMMIT}
'''
}
}
}
stage('Deploy') {
steps {
// Run ssh to server and pull+restart
sh "ssh ubuntu@your.server 'docker pull myorg/myapp:${GIT_COMMIT} && ./deploy.sh myorg/myapp:${GIT_COMMIT}'"
}
}
}
}
Jenkins 文档有更多 .NET 支持、插件、report 集成示例。(Jenkins)
8)测试报告 / 代码覆盖 / 安全扫描(可选增强)
- 测试报告:将
dotnet test结果导出为 TRX 或 junit(--logger "trx;LogFileName=test_results.trx"),再用 Actions 上传 artifact 或用插件解析。 - 代码覆盖:使用
coverlet+reportgenerator,把结果发布到 cobertura/junit 格式,集成 SonarQube 或 Codecov。 - 安全扫描:在 CI 阶段加
dotnet list package --vulnerable或 Dependabot / Snyk。
9)实操小贴士(经验)
- 把敏感凭据放在 GitHub Secrets / Jenkins Credentials。
- 把 CI job 分成
build/test(快速且频繁)和release/deploy(需要权限的步骤)。 - 用
github.sha或git tag做镜像版本号,方便回滚。 - 在生产部署前,在 staging 分支跑一套相同流程到 staging 环境进行 smoke test。
- 对于数据库迁移,避免在自动 deploy 时直接运行可能不可逆的脚本;最好先手动或在可回滚的 migration 工具里执行。
10)快速清单(你可以照着做)
- 在 repo 建
Dockerfile、dockerignore、publish脚本。 - 配置 GitHub Secrets(DOCKERHUB_, SSH_)。
- 把上面的
ci-cd.yml放.github/workflows/并 push 到main。 - 在目标 Linux server 上准备 docker、deploy.sh、开放端口(80/443)。
- push commit,观察 Actions(build → push → deploy)是否通过;若失败,先修 CI(单元测试/restore 出错最常见)。