Friday, 5 April 2024

Loop Jobs based on Parameter Value in Azure DevOps Pipelines

 Consider a situation where we want to perform same set of steps in a pipeline, multiple times. A good example would be building or deloying multiple apps, using same set of steps. Let's explore this example to understand how we can loop through set of pipeline steps, to build multiple apps using a list of app names provided as a parameter in the pipeline.

The app name list can be provided as a parameter as shown below.

parameters:
  - nameapps
    displayName'Apps to deploy'
    typeobject
    default: [
      'customer_api',
      'invoice_api',
      'order_api',
      'payment_api',
      'order_eventhandler',
      'invoice_eventhandler',
      'customer_eventhandler'
      ]

We can then call a template for build and push docker images for the apps. Here, the each app in the parameter allows to loop through and create job for each app.

      # Build and push docker images for each app
      - ${{ each app in parameters.apps }}:
        - template../jobs/build_and_push_app.yml
          parameters:
            app${{ app }}


The template for job is as below.

parameters:
  - nameapp
    typestring

jobs:
  - jobbuild_and_push_${{ parameters.app }}
    workspace:
      cleanall
    displayNameBuild and push ${{ parameters.app }}
    variables:
      # Get app variables for the app
      - template../vars/app_vars.yml
        parameters:
          app${{ parameters.app }}
      # Get app OS specific variables from os_vars for the app, based on app buildos received 
# from app_vars
      - template../vars/os_vars.yml
        parameters:
          buildos${{ variables.buildos }}
    # Set agent VM image based on app OS received from os_vars
    pool:
      vmImage${{ variables.agentvmimage }}
    steps:
        # - script: |
        #     echo $(agentvmimage)
        #     echo $(buildos)
        #     echo $(aksappname)

        - checkoutself
          fetchDepth1
          lfstrue
          cleantrue
          submodulestrue
          persistCredentialstrue

        - taskDocker@2
          displayName'Build docker image'
          inputs:
            containerRegistry'$(aks_shared_container_registry)'
            repository'demo/$(aksappname)'
            commandbuild
            Dockerfile'**/$(projectname)/Dockerfile'
            buildContext'$(Build.Repository.LocalPath)'
            tags'$(Build.BuildId)'
            arguments'--no-cache'
          retryCountOnTaskFailure2
        
        - taskDocker@2
          displayName'Push docker image'
          inputs:
            containerRegistry'$(aks_shared_container_registry)'
            repository'demo/$(aksappname)'
            commandpush
            tags'$(Build.BuildId)'
          retryCountOnTaskFailure3

Variables for apps are setup as below.

parameters:
  - nameapp
    typestring
    
variables:
  - nameaksappname
    value$[replace('${{ parameters.app }}', '_', '-')]

  - ${{ if eq(parameters.app, 'customer_api') }}:
    - nameprojectname
      valueCustomer.API
    - namebuildos
      valuewindows
    - nameaksappcontainerrequestscpu
      value500m
    - nameaksappcontainermemorylimit
      value1Gi
    - nameaksapppriorityclassname
      valuedemo-medium-priority-win
    - namedeploymentyaml
      valuek8s_api.yaml
  - ${{ elseif eq(parameters.app, 'invoice_api') }}:
    - nameprojectname
      valueInvoice.API
    - namebuildos
      valuelinux
    - nameaksappcontainerrequestscpu
      value200m
    - nameaksappcontainermemorylimit
      value512Mi
    - nameaksapppriorityclassname
      valuedemo-highest-priority-linux
    - namedeploymentyaml
      valuek8s_api.yaml
  - ${{ elseif eq(parameters.app, 'order_api') }}:
    - nameprojectname
      valueOrder.API
    - namebuildos
      valuewindows
    - nameaksappcontainerrequestscpu
      value500m
    - nameaksappcontainermemorylimit
      value1Gi
    - nameaksapppriorityclassname
      valuedemo-highest-priority-win
    - namedeploymentyaml
      valuek8s_api.yaml
  - ${{ elseif eq(parameters.app, 'payment_api') }}:
    - nameprojectname
      valuePayment.API
    - namebuildos
      valuelinux
    - nameaksappcontainerrequestscpu
      value200m
    - nameaksappcontainermemorylimit
      value512Mi
    - nameaksapppriorityclassname
      valuedemo-highest-priority-linux
    - namedeploymentyaml
      valuek8s_api.yaml
  - ${{ elseif eq(parameters.app, 'order_eventhandler') }}:
    - nameprojectname
      valueOrder.EventHandler
    - namebuildos
      valuelinux
    - nameaksappcontainerrequestscpu
      value200m
    - nameaksappcontainermemorylimit
      value512Mi
    - nameaksapppriorityclassname
      valuedemo-medium-priority-linux
    - namedeploymentyaml
      valuek8s_eh.yaml
  - ${{ elseif eq(parameters.app, 'invoice_eventhandler') }}:
    - nameprojectname
      valueInvoice.EventHandler
    - namebuildos
      valuewindows
    - nameaksappcontainerrequestscpu
      value500m
    - nameaksappcontainermemorylimit
      value1Gi
    - nameaksapppriorityclassname
      valuedemo-medium-priority-win
    - namedeploymentyaml
      valuek8s_eh.yaml
  - ${{ elseif eq(parameters.app, 'customer_eventhandler') }}:
    - nameprojectname
      valueCustomer.EventHandler
    - namebuildos
      valuelinux
    - nameaksappcontainerrequestscpu
      value200m
    - nameaksappcontainermemorylimit
      value512Mi
    - nameaksapppriorityclassname
      valuedemo-medium-priority-linux
    - namedeploymentyaml
      valuek8s_eh.yaml

The OS varables are as in below template.

parameters:
  - namebuildos
    typestring
    # default: linux
    # values:
    #   - linux
    #   - windows
    
variables:
  - ${{ if eq(parameters.buildos, 'windows') }}:
    - namecontainersleepcommand
      value'"powershell.exe","-c","sleep"'
    - nameagentvmimage
      valuewindows-2022
  - ${{ else }}:
    - namecontainersleepcommand
      value'"sleep"'
    - nameagentvmimage
      valueubuntu-22.04

The expectation is to create multiple build and push jobs as shown below. The full pipline code is avaialble in the public repo in Azure DevOps here.





No comments:

Popular Posts