General Structure of the azure-pipelines.yml File
The contents of the azure-pipelines.yml file drive the selection of CI/CD pipeline logic to be executed and the configuration and customization of the pipeline and its actions. As a YAML structure, the data elements of the azure-pipelines.yml file are part of a hierarchy of complex objects, as follows:
| Top-Level YAML Object | Purpose / Function of the Object | Default |
|---|---|---|
| name | Name of the pipeline, generally composed of built-in strings | $(SourceBranchName)_$(BuildID) |
| trigger | Definition of conditions to trigger the pipeline | triggered by git branch update |
| pr | Pull Request filter | none |
| resources | List of respositories defininng the V3 pipeline & containers on which to run it | N/A |
| extends | A set of complex YAML objects passed to the V3 pipeline code to drive the pipeline behavior | N/A |
Base pipeline settings
The first 3 YAML objects generally should not require modification from how they are originally generated. The typical settings for each of these are as follows:
name:
trigger:
trigger:
batch: true
branches:
include:
- feature/*
exclude:
- master
pr:
Pipeline Resources
The resources YAML object lists the resources used by the pipeline. In the case of a V3.5 pipeline, this section should be defined as follows and should not require modification:
resources:
repositories:
- { repository: templates, type: git, name: devexp-engg/automation, ref: release/v3.5 }
The repositories object points to the V3 CI/CD pipeline logic and the containers defines the Docker container that will be used to run the pipeline logic.
Pipeline Configuration Details
Most of the configuration detail in the azure-pipelines.yml file will be found in the extends YAML object which is a complex object consisting of additional complex YAML objects ("complex" here simply means objects composed of multiple elements of various data types, including other complex objects). This object is used to extend the v4.0 pipeline logic (referenced by the repositories defined in the resources object) by (a) referencing the correct application stack pipeline entry point (devops/<<appstack>>.yml for the application stack referenced by <<appstack>>) and (b) passing a set of YAML objects as parameters to influence the behavior of the pipeline to meet an application's specific needs or the procedural needs of that application's team.
The extends YAML object consists of 2 objects beneath it:
- template
- parameters
The template YAML object is a single value set to the initial entry point for the v4.0 pipeline for the particular application stack, so it should always be defined as follows:
extends:
> template: devops/<<appstack>>.yml@spaces
where <<appstack>> is the name of the application stack.
The parameters YAML object is defined immediately following the template object and at the same indentation level. This is the object that requires the most attention and definition to be set up.
The parameters YAML object includes application stack-specific YAML variables and objects with parameters used for the build of the application, followed by additional YAML objects that are common across all application stacks. The following is a list of these YAML objects used in all application stacks that are a part of the parameters YAML object:
| extends YAML Object | Purpose / Function of the Object |
|---|---|
| system | general pipeline configuration settings - this is where Helm charts vs another template method would be specified (but only helm2 is currently supported), for example |
| spaces | configuration settings for generating the Kubernetes objects - this is where the location of the Kubernetes configuration files is specified if not using the default location and is also where specific versions of tools can be set to override defaults |
| workspace | defines some details required for deploying the application into the workspace for unit testing |
| hostspaces | defines all of the target hostspaces to deploy the application to with associated details for deployment |
Parameters that can be set in the system YAML object are the following:
| system parameter | Purpose / Function of the parameter | Default |
|---|---|---|
| template | Indicates which templating technology will be used to generate Kubernetes objects (currently only Helm is supported) | helm2 |
| kubectlVersion | Sets the version of kubectl used to interact with the Kubernetes API | |
| helmVersion | Sets the version of Helm to use to generate Kubernetes deployment objects from Helm charts | |
| smtpServer | Sets the name of the SMTP server used for email messages sent from the pipeline - used to communicate results of XRay security scans | smtp.netapp.com |
NOTE: All of the -----Version parameters in the system YAML object are NOT passed from wrapper.yml to orcehstrate.yml indicating that these settings will have no effect
Parameters that can be set in the build YAML object are the following:
| build parameter | Purpose / Function of the parameter | Default |
|---|---|---|
| chartDir | When using Helm charts, defines the name of the subdirectory containing the Helm chart files | Same as serviceName, i.e. $(appCode)-$(serviceName) |
Defining hostspaces for application deployment
Pipeline 4.0 simplifies the structure of azure-pipelines.yml to define all spaces(workspace,devint,db/hostspaces) as a single list. Older format is still supported but to continue using old format ref and k8s must be removed from spaces. It's strongly recommended to follow newer format. acceptanceSpace must be specified in the file. For example:
parameters:
acceptanceSpace: devexp-stg-1
spaces:
workspace:
helm:
overrideFiles: |
devexp-app/values.workspace.yaml
devexp-stg-2:
helm:
overrideFiles: |
devexp-app/values.hostspace.yaml
devexp-stg-1:
helm:
overrideFiles: |
devexp-app/values.hostspace.yaml
dependsOn:
- devexp-stg-2
devexp-prd-1:
helm:
overrideFiles: |
devexp-app/values.hostspace.yaml
workspace-specific Parameters
Within the workspace YAML object, the following parameters can be defined:
| workspace parameters | Purpose / Function of the parameter | Default |
|---|---|---|
| dockerRepo | Internal name of the Artifactory repo used for Docker images | docker-<<appCode>> |
| k8s | Name of the workspace namespace (Azure service connection name that references the Kubernetes namespace) | <<appCode>>-workspace |
hostspace-specific Parameters
Within the hostspaces YAML object, hostspaces are listed under the following YAML objects:
| hostspace object | Purpose / Function of the object |
|---|---|
| devint | Lists the hostspaces to deploy to for DevInt environments - Unlike workspaces where deployments get cleaned up automatically, devint deployments will be persistent |
| stage | Lists the hostspaces to deploy to for Stage environments - these deployments occur following successful Unit Tests |
| preprod | Lists the hostspaces to deploy to for Pre-Production environments - these deployments occur pending approval following User Acceptance Testing |
| prod | Lists the hostspaces to deploy to for Production environments - these deployments occur pending approval and depend on quality checks having passed |
Within each hostspace object (stage, preprod or prod) is a YAML list of hostspaces, each as a spacename object consisting of the following optional parameters:
| spacename parameters | Purpose / Function of the object |
|---|---|
| ref | Simple string to be identified by the CI/CD pipeline during execution (namespace naming conventions are not legal Azure pipeline stage names; thus requiring a simpler string to be used here) and referenced for dependencies |
| dependsOn | YAML list of previously defined stages (in the form of the ref values) that a given hostspace must wait upon for completion before proceeding |
Additional values within each spacename object are common parameters for all hostspaces as well as the workspace and are described below.
Parameters Common to all Workspace and Hostspace objects
Within each workspace and hostspace list object, the following parameters can be defined:
| workspace/hostspace parameter | Purpose / Function of the parameter |
|---|---|
| manifestSupportSteps | YAML list of pipeline tasks (e.g. powershell or bash tasks) to be executed prior to the generation of the Kubernetes deployment objects based on the Helm V2 charts (example usage is to download secret files from the Azure vault) |
| helm: | |
| overrideFiles | String list of files (file paths are relative to the top of the source repository) that will be added to the Helm chart files (when Helm charts are used) for inclusion when generating Kubernetes deployment objects |
| overrideValues | String list of key-value pairs in the format of key-name:key-value (when Helm charts are used) to assign additional values to be evaluated by Helm when generating deployment objects |
Working with Passing Additional Files to Deployment Objects
There are two types of files that can contain additional deployment objects and be passed to Kubernetes as generated deployment objects (through Helm):
- Files contained within the source code repository (containing non-sensitive data that can be viewed)
- Files downloaded from Azure Vault (containing secrets that should not be visible)
In the case of files contained within the source code repository, no additional actions need to be executed prior to referencing these files, and they simply need to be referenced as (Helm) overrideFiles.
In the case of secret files downloaded from Azure Vault, additional tasks must be defined to retrieve these files from the vault first. This would typically be done by defining manifestSupportSteps that consist of calls to DownloadSecureFile@1 tasks. The names of these tasks would then become a part of the reference to the retrieved files, along with the fixed sub-element name secureFilePath. So if a manifestSupportSteps object is defined for an environment, for example, as follows:
.
.
.
- spacename: sample-stg-2
ref: stage2
manifestSupportSteps:
- task: DownloadSecureFile@1
name: mySecureFile
inputs:
secureFile: values.sample-credentials.secret.yaml
then the name of that download task, mySecureFile, would be used to refer to the retrieved file in the overrideFiles lists later, as follows:
helm:
overrideFiles: |
$(mySecureFile.secureFilePath)
The following is a more complete example of what a portion of the hostspace YAML structure could look like in the case of using Helm charts and passing a non-sensitive file and secret values from a Vault file into the deployment and also having the second hostspace proceed only after successfully completing the deployment to the first hostspace:
hostspaces:
stage:
- spacename: sample-stg-1
ref: stage1
manifestSupportSteps:
- task: DownloadSecureFile@1
name: mySecureFile
inputs:
secureFile: values.sample-credentials.secret.yaml
helm:
overrideFiles: |
devexp-caas/values.hostspace.yaml
$(mySecureFile.secureFilePath)
overrideValues: |
key1:value1
key2:value2
- spacename: sample-stg-2
ref: stage2
manifestSupportSteps:
- task: DownloadSecureFile@1
name: mySecureFile
inputs:
secureFile: values.sample-credentials.secret.yaml
helm:
overrideFiles: |
devexp-caas/values.hostspace.yaml
$(mySecureFile.secureFilePath)
overrideValues: |
key1:value1
key2:value2
dependsOn:
- stage1