'Swap slots in Azure devops (angular+api), how to change Angular configuration for the target slot?
The configuration of the Angular app is the challenging part. During our publishing Job in Azure Yaml pipeline, we execute a "token" replacement to match the target environment on this configuration on a tokenized-artifact.
Later we deploy this tokenized-artifact (tokens already replaced) to the especific environment:
- task: AzureWebApp@1
inputs:
azureSubscription: 'xxxx'
appType: 'webApp'
appName: [depends on $(environment)]
package: '$(Pipeline.Workspace)/xxx'
This way, we can have specific configuration for DEV, TEST, and STAGING (staging is a Production slot).
At some point, we need to swap STAGING to PROD. As result, we have the Angular app in PROD but with values are still for STAGING, which is incorrect, and here we are stuck on what to do. I would like to get advice on a good way to continue.
Some ideas:
During the STAGING deployment, generate also the PROD files, using different name (i.e. main.*.js.PROD). Then, after PROD swap, rename the files, but..
- The files may be in use and, therefore, cannot be renamed.
- During rename a little downtime is added (I am not even sure if there is a way, for yaml, to rename the already deployed files).
When deploy to PROD is triggered, first deploy to STAGING with PROD variables, then execute the swap, but...
- It will have a longer deployment time, because STAGING will have to be deployed first, even if it is already deployed.
- It is taking little advantage of slots.
Do not swap from STAGING and do a complete deployment to PROD, but...
- It will have the longest deployment time.
- It will not take any advantage of slots.
Edit: Thanks to @prawin advice, I'll add another one:
- Provide configuration dinamically, from the server side
- Looks promising since the frontend shares a host with the server side. But still, what in the case of being decoupled from the backend part? This means that the backend url will also need to be configured somewhere, by environment.
After some reading, trial and error, I have some more:
Deploy only the changing file using FTP or Kudu API
Generate and copy PROD config to STAGING, then perform the swap task. I really like this option the most.
Is there anything else to consider? What is the "standard" way to perform this?
Solution 1:[1]
EDIT (17/05/2022): I keep the original proposal just as reference (below), but I must warn that it will fail silently if the file to replace is in use. This could happen most of the time.
Due to this problem, we have changed the strategy:
- we deploy STAGING with STAGING variables to do a proper testing (automated E2E).
- After we are happy with the outcome, we deploy STAGING again, but with PROD variables. We call this Job step: "PRE-PROD".
- When PRE-PROD is ready, we swap STAGING to PROD.
- stage: STAGING
jobs:
- template: release-to.yml
parameters:
environment: staging
variables: staging
- stage: Release_PRE_PROD
dependsOn: Release_STAGING
jobs:
- template: release-to.yml
parameters:
environment: staging
variables: production
- stage: Swap_PROD
dependsOn: Release_PRE_PROD
#Your swap steps
Inside release-to.yml, we perform the proper variable loads and replacements.
Hope it helps!
Before 17/05/2022 just as reference After testing different approaches, we found the following way:
- Produce a PROD specific file during build stage. This file will be put as a separate artifact. The idea is to have the "build" and the "PROD angular configuration" artifacts, for example:
- publish: $(Build.artifactstagingdirectory)/Config
displayName: 'Publish config'
artifact: ConfigPROD
- publish: $(Build.artifactstagingdirectory)/Build
displayName: 'Publish build'
artifact: BUILD
- After the BUILD artifact is deployed in STAGING, download the ConfigPROD artifact to STAGING using FTP. This will overwrite the existing (STAGING) configuration.
- task: DownloadPipelineArtifact@2
displayName: 'Download config artifact'
inputs:
buildType: 'specific'
project: [your devops project name]
definition: [your build definition name]
artifactName: 'ConfigPROD'
path: '$(Pipeline.Workspace)/config'
- task: FtpUpload@2
displayName: 'Deploy configPROD'
inputs:
credentialsOption: 'inputs'
serverUrl: [your ftp server url]
username: [your ftp username]
password: [your ftp password]
rootDirectory: '$(Pipeline.Workspace)/config'
filePatterns: '**'
remoteDirectory: [your remote directory]
clean: false
cleanContents: false
- Swap STAGING to PROD
- task: AzureAppServiceManage@0
displayName: 'Swap STAGING and PROD'
inputs:
azureSubscription: [your azure subscription]
Action: 'Swap Slots'
WebAppName: [your app name]
ResourceGroupName: [your rg name]
SourceSlot: 'staging'
If you wonder how to find your ftp credentials in Azure, here is the path: [AzurePortal]/[AppServicePage]/Deployment Center/Deployment Credentials
[your remote directory] can be checked using Kudu or the console in "Advanced Tools". In this case, the Angular wwwroot is inside site/wwwroot, therefore my remote directory is '/site/wwwroot/wwwroot'
Not a silver bullet, but is working 100% and there is absolutely not extra downtime.
Thanks for sugestions
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |