【DevOps】使用Azure DevOps为Azure静态网站配置多阶段部署
推荐超级课程:
@TOC
Azure静态网站可以自动配置Azure DevOps Pipeline来构建和部署您的应用程序。这是快速启动和运行您的应用程序的好方法。
对于生产应用程序,通常首先将应用程序部署到暂存环境,然后再部署到生产环境。在本文中,我们将引导您如何配置一个健壮的Azure DevOpsPipeline,该Pipeline将执行以下操作:
- 构建应用程序、Azure Functions API和Playwright测试
- 将应用程序部署到暂存环境
- 自动使用Playwright测试验证暂存应用程序
- 等待手动批准
- 将您的应用程序部署到生产环境
示例应用程序
我们将使用一个.NET6全栈应用程序。源代码可以在CSDN下载。
- 前端:Blazor WebAssembly
- 后端:Azure Functions
- 测试:Playwright
要跟随本教程,请将存储库导入您的Azure DevOps项目。
您可以使用类似的步骤来处理Node.js等其他应用程序。
创建静态网站和部署Pipeline
Azure静态网站生成Azure DevOpsPipeline 的功能,以部署您的应用程序。
您可以在一步中创建静态网站和部署Pipeline。
在Azure门户中,搜索并创建一个新的静态网站。
在创建过程中,选择“Azure DevOps”作为部署源,并选择包含应用程序的DevOps存储库和分支。
在构建预设中,选择“Blazor”。这将自动填充应用程序和API文件夹位置。
创建应用程序时,将在存储库中创建一个新的PipelineYAML文件。它将自动运行。构建和部署应用程序需要几分钟时间。
在浏览器或本地编辑器中打开PipelineYAML文件,查看其内容。它包含一个AzureStaticWebApp
任务,可以自动构建和部署应用程序。
创建AzurePipeline环境
AzurePipeline允许您定义环境。环境对于添加手动批准到您的Pipeline非常有用。
我们将创建两个环境——暂存和生产。它们将对应我们部署到的两个Azure静态网站环境。
要创建Pipeline环境,请在“Pipeline”下选择“环境”。
创建一个名为“Staging”的环境。因为您不需要对这个阶段的 manual approval,所以不需要配置其他内容。
接下来,创建一个名为“Production”的新环境。因为我们希望在部署到生产之前需要手动批准,所以您可以配置环境以要求手动批准。
在环境的“Approvals and checks”中,选择“Approvals”。
添加自己作为批准者并创建批准策略。
168910157-d32f767f-c608-4047-b0f5-66b7e4beb2f2
为Azure静态网站环境添加密码保护
Azure静态网站提供了预览环境,允许您在部署到生产之前测试您的应用程序。最初,预览环境仅适用于GitHub的拉取请求。最近,静态网站引入了任意定义命名预览环境
的功能。例如,我们可以创建一个名为“Staging”的环境。
预览环境默认是公开的。这对于开源项目来说很棒,但有时我们希望保护它们免受公共访问。
您可以为您的应用程序的预览环境添加密码保护。
- 在Azure门户中,打开您的静态网站。
- 在“配置”中,选择“常规设置”选项卡。
- 选择“仅保护暂存环境”并输入密码。
您还可以选择保护所有环境。但在这个应用程序中,我们希望生产环境对公众开放。
配置多阶段 Pipeline
现在我们已经配置了Azure Pipeline环境和密码保护,我们可以配置 Pipeline了。
在浏览器或本地编辑器中打开 PipelineYAML文件。用 azure-pipelines.yml 的内容替换它。
我们将逐一介绍 Pipeline的不同部分。它有三个主要阶段:构建、部署到暂存和生产。
第1阶段:构建应用程序
trigger:
- main
pool:
vmImage: ubuntu-latest
stages:
- stage: Build
jobs:
- job: build
displayName: Build app
steps:
- task: UseDotNet@2
displayName: Install .NET SDK
inputs:
packageType: 'sdk'
version: '6.0.x'
- script: |
dotnet publish -c Release -o "$(Build.ArtifactStagingDirectory)/frontend"
displayName: Build Blazor frontend
workingDirectory: $(System.DefaultWorkingDirectory)/Client
- script: |
dotnet publish -c Release -o "$(Build.ArtifactStagingDirectory)/api"
displayName: Build Azure Functions API
workingDirectory: $(System.DefaultWorkingDirectory)/Api
- script: |
dotnet build -c Release -o "$(Build.ArtifactStagingDirectory)/tests"
displayName: Build Playwright tests
workingDirectory: $(System.DefaultWorkingDirectory)/PlaywrightTests
- task: PublishBuildArtifacts@1
displayName: Publish artifacts
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
Pipeline在main
分支有任何更改时触发。如果您的应用程序使用不同的分支,您可以更改它。
Pipeline然后构建应用程序、Azure Functions API和Playwright测试。然后输出工件。所有环境的相同构建工件被部署,确保您在其他环境中测试的应用程序与部署到生产的相同。
第2阶段:部署到暂存并运行Playwright测试
- stage: deploy_staging
displayName: Deploy to staging
jobs:
- deployment: deploy
displayName: Deploy and test
environment: Staging
variables:
# Change the variable group name to match the one in the generated pipeline
- group: Azure-Static-Web-Apps-calm-coast-0df39b910-variable-group
strategy:
runOnce:
deploy:
steps:
- download: none
- checkout: none
- task: DownloadBuildArtifacts@1
displayName: Download artifacts
inputs:
buildType: current
downloadType: single
artifactName: drop
downloadPath: $(System.ArtifactsDirectory)
- task: AzureStaticWebApp@0
displayName: Deploy to staging environment
inputs:
app_location: frontend/wwwroot
api_location: api
skip_app_build: true
skip_api_build: true
verbose: true
azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN_CALM_COAST_0DF39B910)
deployment_environment: staging
workingDirectory: $(System.ArtifactsDirectory)/drop
- task: UseDotNet@2
displayName: Install .NET SDK
inputs:
packageType: 'sdk'
version: '6.0.x'
- script: |
chmod -R a+x $(System.ArtifactsDirectory)/drop/tests
sudo --preserve-env=PLAYWRIGHT_BROWSERS_PATH pwsh $(System.ArtifactsDirectory)/drop/tests/playwright.ps1 install --with-deps chromium
dotnet test $(System.ArtifactsDirectory)/drop/tests/PlaywrightTests.dll --logger trx
displayName: Run Playwright tests on staging app
env:
PLAYWRIGHT_BROWSERS_PATH: $(Build.SourcesDirectory)/browsers
LOGIN_PASSWORD: $(LOGIN_PASSWORD)
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
第3阶段:部署到生产
- stage: deploy_production
displayName: Deploy to production
jobs:
- deployment: deploy
displayName: Deploy
environment: Production
variables:
# Change the variable group name to match the one in the generated pipeline
- group: Azure-Static-Web-Apps-calm-coast-0df39b910-variable-group
strategy:
runOnce:
deploy:
steps:
- download: none
- checkout: none
- task: DownloadBuildArtifacts@1
displayName: Download artifacts
inputs:
buildType: current
downloadType: single
artifactName: drop
downloadPath: $(System.ArtifactsDirectory)
- task: AzureStaticWebApp@0
displayName: Deploy to production environment
inputs:
app_location: frontend/wwwroot
api_location: api
skip_app_build: true
skip_api_build: true
verbose: true
azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN_CALM_COAST_0DF39B910)
workingDirectory: $(System.ArtifactsDirectory)/drop
这个阶段引用了Azure Pipeline中的“生产”环境。因为我们配置了这个环境以要求批准,所以这将触发在运行此阶段之前的手动批准步骤。
与上一个阶段类似,这个阶段下载工件并使用AzureStaticWebApp任务进行部署。这次,没有设置deployment_environment,因为我们希望部署到静态网站的生产环境。
运行多阶段 Pipeline
现在 Pipeline已经设置好,您可以通过保存文件来运行它。如果您在本地编辑了它,不要忘记将其推送到您的Azure DevOps存储库。
在“部署到暂存”阶段运行后,您应该会看到Playwright测试已经运行以验证暂存环境,并且结果已经发布。
Pipeline运行被暂停,因为“部署到生产”阶段需要批准。
当您批准 Pipeline时, Pipeline将再次运行。
批准后,应用程序将部署到生产环境。
深入了解
在我们结束本文之前,我们想更深入地探讨静态网站环境和Playwright测试。
Azure静态网站环境
要查看您创建的环境,请在Azure门户中点击您的静态网站的“环境”选项卡。您应该会看到生产环境和暂存环境。
Playwright测试
Playwright测试位于PlaywrightTests
项目中,它们是用C#编写的。
Playwright
可以用来使用真实浏览器自动化测试Web应用程序。示例中的测试使用Chrome(Chromium),但Playwright也支持Firefox、WebKit和Microsoft Edge。
这是一个C#中的Playwright测试示例。它导航浏览器到应用程序的主页,点击“获取数据”链接,并确认数据从后端API获取并成功渲染。
[Test]
public async Task ShouldLoadWeather()
{
await using var browser = await Playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await GoToHomePage(page);
await page.ClickAsync("a[href='fetchdata']");
var h1 = await page.QuerySelectorAsync("div#app main h1");
var h1Text = h1 == null ? "" : await h1.TextContentAsync();
Assert.AreEqual("Weather forecast", h1Text);
var rowsSelector = "div#app main table tbody tr";
// wait for table to have rows
await page.WaitForFunctionAsync($"document.querySelectorAll('{rowsSelector}').length");
var rows = await page.QuerySelectorAllAsync(rowsSelector);
Assert.AreEqual(5, rows.Count);
}
测试使用AZURESTATICWEBAPP_STATIC_WEB_APP_URL环境变量来确定要测试的应用程序URL。在Azure Pipeline中,这个变量在成功部署后由Azure静态网站任务设置。因为测试在部署到暂存环境后运行,所以变量包含暂存静态网站环境的URL。
测试的另一个有趣方面是以下代码,用于导航到主页:
private async Task GoToHomePage(IPage page)
{
await page.GotoAsync($"{siteBaseUrl}/");
var homePageLocatorTask = page.Locator("text=Hello, world!").WaitForAsync();
var passwordPageLocatorTask = page.Locator("text=Password protected").WaitForAsync();
var isPasswordPage = (await Task.WhenAny(homePageLocatorTask, passwordPageLocatorTask)) == passwordPageLocatorTask;
if (isPasswordPage)
{
System.Console.WriteLine("Found password page, logging in...");
var passwordInput = await page.QuerySelectorAsync("input[type=password]");
if (passwordInput == null)
{
throw new Exception("Could not find password input");
}
await passwordInput.TypeAsync(sitePassword);
await page.ClickAsync("button");
await page.Locator("text=Hello, world!").WaitForAsync();
}
}
这段代码在浏览器会话未认证时自动登录到暂存环境。在运行时,sitePassword变量设置为LOGIN_PASSWORD秘密变量的值。
总结
随着命名预览环境和自动 Pipeline生成等功能的增加,现在可以配置复杂、健壮的 Pipeline,从Azure DevOps构建和部署到Azure静态网站。