如何在Azure中为NextJS应用的每个PR创建预览部署实例
Azure DevOps PR预览Pipeline配置(NextJS + Docker)
我们已在Azure上通过Docker部署NextJS应用,现有三个分支:
- Dev(开发分支)
- Staging(预生产分支)
- Main(生产分支)
开发新功能时会创建feature分支并推送变更,希望在合并至Dev分支前,让利益相关者能查看功能的实时预览(类似Vercel与GitHub的预览功能),同时需要在PR合并后自动删除对应的预览部署实例。
已有的Dev分支合并Pipeline参考:
trigger: - dev variables: dockerRegistryServiceConnection: "xxx" imageRepository: "xxx" containerRegistry: "xxx" dockerfilePath: "$(Build.SourcesDirectory)/Dockerfile.prod" tag: "$(Build.BuildId)" vmImageName: "ubuntu-latest" pool: vmImage: ubuntu-latest stages: - stage: Install displayName: "Install" jobs: - job: InstallJob displayName: "Install Node.js and Dependencies" steps: - task: NodeTool@0 inputs: versionSpec: "20.x" displayName: "Install Node.js" - script: | npm install displayName: "Install Node.js and Dependencies" - stage: UnitComponentTests displayName: "Run Unit and Component Tests" jobs: - job: UnitComponnentTestsJob displayName: "Run Unit and Component Tests" steps: - script: | npm install npm run test displayName: "Run Unit and Component Tests" - stage: E2ETests displayName: "Run E2E Tests" jobs: - job: E2ETestsJob displayName: "Run E2E Tests" steps: - script: | npm install npx playwright install npm run test-e2e displayName: "Run E2E Tests" - stage: Build displayName: Build jobs: - job: Build displayName: Build pool: vmImage: $(vmImageName) steps: - task: Docker@2 displayName: Build and push an image to container registry inputs: command: buildAndPush repository: $(imageRepository) dockerfile: $(dockerfilePath) buildContext: "./" containerRegistry: $(dockerRegistryServiceConnection) tags: | $(tag) latest
完整PR预览Pipeline配置
# 仅针对目标为dev分支的PR触发,合并后自动执行清理 trigger: none pr: branches: include: - dev paths: exclude: - README.md # 按需排除无需触发的文件 variables: # 通用配置(替换为你的实际值) dockerRegistryServiceConnection: "xxx" imageRepository: "xxx" containerRegistry: "xxx" dockerfilePath: "$(Build.SourcesDirectory)/Dockerfile.prod" vmImageName: "ubuntu-latest" # PR专属标识:用PR编号确保资源唯一 prNumber: $(System.PullRequest.PullRequestNumber) previewImageTag: "pr-$(prNumber)" # Azure App Service预览资源配置(替换为你的资源组和服务名称规则) appServiceName: "nextjs-preview-pr-$(prNumber)" resourceGroupName: "your-resource-group-name" azureServiceConnection: "your-azure-service-connection" pool: vmImage: $(vmImageName) stages: # 1. 统一安装依赖并执行所有测试 - stage: Test displayName: "执行测试用例" jobs: - job: TestJob displayName: "安装依赖并运行测试" steps: - task: NodeTool@0 inputs: versionSpec: "20.x" displayName: "安装Node.js" - script: | npm install displayName: "安装项目依赖" - script: | npm run test displayName: "运行单元与组件测试" - script: | npx playwright install npm run test-e2e displayName: "运行E2E测试" # 2. 构建PR专属Docker镜像 - stage: BuildPreviewImage displayName: "构建PR预览镜像" dependsOn: Test condition: succeeded() jobs: - job: BuildJob displayName: "构建并推送预览镜像" steps: - task: Docker@2 displayName: "构建并推送镜像至容器注册表" inputs: command: buildAndPush repository: $(imageRepository) dockerfile: $(dockerfilePath) buildContext: "./" containerRegistry: $(dockerRegistryServiceConnection) tags: | $(previewImageTag) # 3. 部署PR预览实例(仅当PR处于打开状态时执行) - stage: DeployPreview displayName: "部署PR预览实例" dependsOn: BuildPreviewImage condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) jobs: - job: DeployJob displayName: "部署至Azure App Service" steps: - task: AzureWebAppContainer@1 displayName: "部署预览App Service" inputs: azureSubscription: $(azureServiceConnection) appName: $(appServiceName) containers: $(containerRegistry)/$(imageRepository):$(previewImageTag) resourceGroupName: $(resourceGroupName) - script: | echo "✅ 预览部署完成,访问地址:https://$(appServiceName).azurewebsites.net" displayName: "输出预览链接" # 4. 清理PR预览资源(仅当PR合并完成后执行) - stage: CleanupPreview displayName: "清理PR预览实例" condition: and(succeeded(), eq(variables['System.PullRequest.Status'], 'completed')) jobs: - job: CleanupJob displayName: "删除预览资源" steps: # 删除预览App Service实例 - task: AzureCLI@2 displayName: "删除预览App Service" inputs: azureSubscription: $(azureServiceConnection) scriptType: bash scriptLocation: inlineScript inlineScript: | az webapp delete --name $(appServiceName) --resource-group $(resourceGroupName) --yes # 删除容器注册表中的预览镜像(可选,避免镜像堆积) - task: AzureCLI@2 displayName: "删除预览Docker镜像" inputs: azureSubscription: $(azureServiceConnection) scriptType: bash scriptLocation: inlineScript inlineScript: | az acr repository delete --name $(containerRegistry) --repository $(imageRepository) --tag $(previewImageTag) --yes
关键配置说明
- 触发逻辑:仅监听目标为
dev分支的PR,合并后自动触发清理阶段,避免不必要的资源消耗 - 资源隔离:用PR编号作为镜像标签和App Service名称的后缀,确保每个PR的预览资源独立,不会互相干扰
- 阶段控制:通过条件判断实现:
- PR打开时自动构建、部署预览实例
- PR合并完成后自动删除对应的预览资源
- 效率优化:将原Pipeline中重复的
npm install步骤合并到一个测试阶段,减少冗余操作 - 可选扩展:可以添加PR评论任务,自动将预览链接评论到PR中,方便利益相关者直接查看
内容的提问来源于stack exchange,提问作者Ala Eddine Menai
相关产品推荐
相关产品推荐

