In the previous post "Create Multi Stage Pipeline Structure with GitHub Actions - The Layout - Mapping Azure DevOps Multi-Stage Pipelines to GitHub Actions - Part 2" we have dicussed the GitHub action workflow layout mapping to the Azure pipeline structure. The code for workflows can be structured as shown below for the pipeline requirement discussed in "Mapping Azure DevOps Multi-Stage Pipelines to GitHub Actions - Part 1". Note that we have seperated folder structure for job actions and step actions to organize the code properly in a manageable way. However, both are really composite actions in GitHub. Each action name is setup using a folder name as it must be action.yml or action.yaml for actions.

The main workflow is defined as eck_on_aks.yml. All others are reusable workflows to form the structure of the workflow. However, it is not possible to organize them into seprate stage folder etc. as organized in Azure pipeline templates due to limitation of GitHub reusable workflows must be in .github\workflows path. The above GitHub worflow structure represents below, pipeline structure of Azure pipelines (of course with limitations of GitHub actions), to achive pipeline as shown in "Mapping Azure DevOps Multi-Stage Pipelines to GitHub Actions - Part 1".
Now that we have understanding on the layout of the GitHub workflow as described in "Create Multi Stage Pipeline Structure with GitHub Actions - The Layout - Mapping Azure DevOps Multi-Stage Pipelines to GitHub Actions - Part 2" , we can explore how the code is defined in the workflow, to achive the structure.
THE ROOT WORKFLOW
The entrypoint is the root workflow .github\workflows\eck_on_aks.yml. Here we have deined the workflow name. Then we have set the trigger as manual by setting worflow_dispatch. The important thing here is the environment input. Asin Azure pipelines it is not feasible to define multi environemnt wrkflow layout in the GitHub actions workflow, which would not a neat implementation. Instead in the GitHub workflow we can create workflow by selecting the environment at the start of workflow, so that the workflow instance would ran targeting the given environment. Then we pass this environment input to the reusable workflow, env_blue_green_stages.
name: ECK on AKS
on:
workflow_dispatch:
inputs:
environment:
description: "Environment to deploy"
required: true
default: "dev"
type: choice
options:
- dev
- qa
- prd-eus-001
jobs:
deploy:
name: "${{ inputs.environment }}"
uses: ./.github/workflows/env_blue_green_stages.yml
with:
environment: ${{ inputs.environment }}
BLUE GREEN STAGES
.github\workflows\env_blue_green_stages.yml defines the stage layout of the blue green structure below for a given environment.
The reusable workflow works with a workflow call from the root workflow .github\workflows\eck_on_aks and takes in the environment as input. Then it defines the stages below with stage input varaible set according to the stage.
- stage_deploy
- stage_switch
- stage_heath_checks
- stage_destroy
on:
workflow_call:
inputs:
environment:
required: true
type: string
jobs:
stage_deploy:
name: "${{ inputs.environment }}: deploy"
uses: ./.github/workflows/stage_deploy_iac.yml
with:
environment: ${{ inputs.environment }}
stage: deploy
stage_switch:
name: "${{ inputs.environment }}: switch"
needs: stage_deploy
uses: ./.github/workflows/stage_deploy_services.yml
with:
environment: ${{ inputs.environment }}
stage: switch
stage_health_checks:
name: "${{ inputs.environment }}: health_checks"
needs: stage_switch
uses: ./.github/workflows/stage_run_health_checks.yml
with:
environment: ${{ inputs.environment }}
stage: switch
stage_destroy:
name: "${{ inputs.environment }}: destroy"
needs: stage_health_checks
uses: ./.github/workflows/stage_deploy_iac.yml
with:
environment: ${{ inputs.environment }}
stage: destroy
JOBS IN STAGES
Each stage described below has one or more jobs. Each job starts with a first action checkout which is required to checkout the repo in the job scope (to checkout the repo in the job runner).
stage_deploy & stage destroy.github\workflows\stage_deploy_iac.yml is reused in both stage_deploy and stage_destroy above. This stage_deploy_iac contains two jobs. The jobs run bound to the environment so it could use the approvals and variables defined for the environment.
The plan_iac uses two job level actions, each having the steps for the job.
- setup_blue_green_control
- plan_iac
The deploy_iac job has two job level actions as well
- deploy_iac
- run_aks_nodepool_validation (this would only run if the stage is deploy, so the destroy stage skips this job action)
The seperation of plan_iac and deploy_iac to two jobs and binding them to the environment allows approval before each job runs so the plan can be validated before applying it. Then we run the node pool validation only in the deploy stage.
on:
workflow_call:
inputs:
environment:
required: true
type: string
stage:
required: true
type: string
jobs:
plan_iac:
name: "${{ inputs.stage }}: plan_iac"
runs-on: ubuntu-24.04
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v6.0.3
- uses: ./.github/actions/job/setup_blue_green_control
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- uses: ./.github/actions/job/plan_iac
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
deploy_iac:
name: "${{ inputs.stage }}: deploy_iac"
runs-on: ubuntu-24.04
needs: plan_iac
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v6.0.3
- uses: ./.github/actions/job/deploy_iac
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- if: ${{ inputs.stage == 'deploy' }}
uses: ./.github/actions/job/run_aks_nodepool_validation
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
stage_switch
This stage uses the .github\workflows\stage_deploy_services.yml to define its job deploy_services. It has two job level actions. Note that we reuse the same setup_blue_green_control here, which used in above stage_deploy and stage_destroy jobs as well. This let us manage the workflow code in more structural and clear way.
- setup_blue_green_control
- deploy_service
on:
workflow_call:
inputs:
environment:
required: true
type: string
stage:
required: true
type: string
jobs:
deploy_services:
name: "${{ inputs.stage }}: deploy_services"
runs-on: ubuntu-24.04
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v6.0.3
- uses: ./.github/actions/job/setup_blue_green_control
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- uses: ./.github/actions/job/deploy_services
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
stage_health_check
The health checks stage is defined in the .github\workflows\stage_run_health_checks.yml. This stage has a single job run_health_checks which has a single job level action run_health_checks.
on:
workflow_call:
inputs:
environment:
required: true
type: string
stage:
required: true
type: string
jobs:
run_health_check:
name: "${{ inputs.stage }}: run_health_check"
runs-on: ubuntu-24.04
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v6.0.3
- uses: ./.github/actions/job/run_health_checks
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
JOB LEVEL ACTIONS
Job level actions map to Azure pipeline jobs scope. The contain multiple steps grouped together to make a meaningful job functionality.
setup_blue_green_control
.github\actions\job\setup_blue_green_control\action.yml defines the setup_blue_green_control job level action, which takes input variables environment and stage (there may be more in actual implementation, the current two inputs are suffcient to setup the structure of the workflow). This job level action reuses shared log_blue_green_parameters steps level action.
name: setup_blue_green_control
description: Setup blue-green control
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- uses: ./.github/actions/step/log_blue_green_parameters
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- name: "${{ inputs.stage }}: setup_blue_green_control"
shell: bash
run: |
echo "Run setup blue-green control for environment: ${{ inputs.environment }}"
echo "stage: ${{ inputs.stage }}"
plan_iac
.github\actions\job\plan_iac\action.yml defines the job level actions for plan_iac. It reuses log_blue_green_parameters step level action and then it will define the plan_iac step (there can be multiple steps requirement in actual implementation).
name: plan_iac
description: Plan IaC
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- uses: ./.github/actions/step/log_blue_green_parameters
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- name: "${{ inputs.stage }}: plan_iac"
shell: bash
run: |
echo "Run plan IaC for environment: ${{ inputs.environment }}"
echo "stage: ${{ inputs.stage }}"
deploy_iac
github\actions\job\deploy_iac\action.yml defines the job level actions for plan_iac. This is similar to plan_iac job level action.
name: deploy_iac
description: Deploy IaC
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- uses: ./.github/actions/step/log_blue_green_parameters
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- name: "${{ inputs.stage }}: deploy_iac"
shell: bash
run: |
echo "Run deploy IaC for environment: ${{ inputs.environment }}"
echo "stage: ${{ inputs.stage }}"
run_aks_nodepool_validation
This job level action is defined in the .github\actions\job\run_aks_nodepool_validation\action.yml.
name: run_aks_nodepool_validation
description: Run AKS nodepool validation
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- uses: ./.github/actions/step/log_blue_green_parameters
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- name: "${{ inputs.stage }}: run_aks_nodepool_validation"
shell: bash
run: |
echo "Run aks nodepool validation for environment: ${{ inputs.environment }}"
echo "stage: ${{ inputs.stage }}"
deploy_services
.github\actions\job\deploy_services\action.yml defines the job levels actions for deploy services.
name: deploy_services
description: Deploy services
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- uses: ./.github/actions/step/log_blue_green_parameters
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- name: "${{ inputs.stage }}: deploy_services"
shell: bash
run: |
echo "Run deploy services for environment: ${{ inputs.environment }}"
echo "stage: ${{ inputs.stage }}"
run_health_checks
This job level action is defined in .github\actions\job\run_health_checks\action.yml.
name: run_health_checks
description: Run health checks
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- uses: ./.github/actions/step/log_blue_green_parameters
with:
environment: ${{ inputs.environment }}
stage: ${{ inputs.stage }}
- name: "${{ inputs.stage }}: run_health_checks"
shell: bash
run: |
echo "Run health checks for environment: ${{ inputs.environment }}"
echo "stage: ${{ inputs.stage }}"
STEP LEVEL ACTIONS
Step level actions contain shared steps that can be shared to multiple jobs (or job level actions). Such examples would be install terraform, install helm etc. this allows to keep terraform version defined only once in the workflow step and reuse it across all jobs.
log_blue_green_parameters
.github\actions\step\log_blue_green_parameters\action.yml has the step level actions defined.
name: log_blue_green_parameters
description: Logs blue-green paramters
inputs:
environment:
description: Environment name
required: true
stage:
description: Stage name
required: true
runs:
using: composite
steps:
- name: "${{ inputs.stage }}: log_blue_green_parameters"
shell: bash
run: |
echo "Environment: ${{ inputs.environment }}"
echo "Stage: ${{ inputs.stage }}"
echo "Live AKS nodepool: just me yet"
The workflow and actions code is available here in GitHub.
No comments:
Post a Comment