Seeking the thrill of transformative tech? Explore the art of designing and implementing DevOps solutions on Azure. Master the shift towards CI/CD, testing, and delivery, while preparing for the Designing and Implementing Microsoft DevOps Solutions exam!
Choosing between GitHub Actions and Azure Pipelines depends on your team's existing tools and needs. Both automate building, testing, and deploying code, which is called CI/CD. GitHub Actions works directly inside GitHub repositories, scaling automatically and offering a free tier with usage limits. Azure Pipelines is part of the Azure DevOps ecosystem and offers more flexibility, including the choice between Microsoft-hosted agents and self-hosted agents you run on your own hardware. This control over the build environment is important for meeting strict security or compliance rules.
The decision often comes down to a few key areas. For orchestration, GitHub Actions uses event-driven triggers, while Azure Pipelines uses multi-stage YAML pipelines. If your team needs to run pipelines on your own servers, Azure Pipelines is more flexible. Both tools handle security with encrypted secrets, but Azure Pipelines adds more enterprise controls like detailed role-based access. Pricing models differ: GitHub Actions charges for runner minutes, and Azure Pipelines charges for parallel jobs and agent minutes. Finally, if your organization already uses many Azure services, Azure Pipelines integrates with them directly, making deployments simpler.
You must decide where to host your pipeline workers, called runners in GitHub and agents in Azure DevOps. You can use Microsoft's cloud, your own servers, or a mix. Each option has different costs and management overhead. Understanding pricing plans, like the different tiers for API Management, helps fit the model to your budget. The goal is to get the features and control you need without overspending.
Your CI/CD tools must work together smoothly. This means comparing features of Azure Repos, GitHub Actions, and other tools to find the best fit for your workflow. Once selected, you must set up secure network connections so agents can talk to code repositories and other services. This involves configuring permissions and security practices like multi-factor authentication to ensure a stable and secure link for continuous synchronization.
A good agent infrastructure is easy to keep running. Key strategies include automated updates for the runner or agent software to reduce manual work and security risks. Scalability policies automatically add or remove agents based on pipeline demand, which helps control costs. Implementing monitoring lets you track agent health and performance, so you can fix problems before they disrupt builds. These practices ensure long-term reliability.
To connect GitHub to Azure Pipelines, you create a secure service connection. This bridge can use a personal access token (PAT) from GitHub or an OAuth app for better organizational permission management. Once set up, this connection lets Azure Pipelines read code and report status. Webhooks are configurations in GitHub that send a notification to Azure Pipelines when an event happens, like a code push. Azure Pipelines receives this message and starts the appropriate pipeline.
A system architecture diagram showing how GitHub repositories connect to Azure Pipelines using service connections and webhooks to trigger YAML pipelines based on branch and event filters, secured by branch protection policies.
You can control when pipelines run to avoid unnecessary builds. Branch triggers let you specify which branches (like main or release/*) should start a pipeline. Event triggers determine what kind of GitHub activity causes the run, such as code pushes or pull requests. When both the branch and event conditions match, the pipeline runs automatically.
Keeping the integration secure involves managing permissions. The service connection should have only the minimum permissions needed, like read access to code. Branch protection policies add another layer by requiring pull request reviews or successful pipeline runs before code can be merged. Pipeline status checks ensure builds must pass before merging, preventing broken code from reaching protected branches.
A continuous integration trigger automatically starts a pipeline run every time a developer pushes code changes. This provides immediate feedback if new code breaks the build. In a YAML pipeline, you configure this with the trigger keyword, specifying which branches to monitor.
Scheduled triggers run pipelines at specific times, like nightly, for routine tasks such as security scans or cleanup. You configure these in YAML using the schedules keyword with cron syntax, so the system manages the timing automatically.
A pull request trigger runs a pipeline to validate code changes before they merge into a target branch. This acts as a quality gate. You configure it with the pr keyword in YAML, and teams can require a successful run before a merge is allowed.
Pipeline resource triggers chain pipelines together. One pipeline can start automatically after another finishes. You set this up by declaring a resource dependency under resources.pipelines in your YAML. When the upstream pipeline reaches a completed state, the downstream pipeline begins.
Branch and path filters give granular control to prevent unnecessary runs and save costs. You add branches and paths attributes under your trigger definitions. For example, a pipeline can run only when files in a specific folder on the main branch are changed.
YAML Pipelines in Azure DevOps automate CI/CD workflows. A pipeline is defined in a YAML file and controls building, testing, and deploying. The structure has three layers: Steps are individual tasks or scripts. Jobs are sequences of steps that run on a single agent. Stages are high-level phases like "Build" or "Deploy," and can contain multiple jobs. Variables hold values that change between environments, and templates let you reuse common pipeline logic.
To create a pipeline, you sign into Azure DevOps, select "New pipeline," and choose your code repository. You can then use a template or write your own YAML file, which is stored in your repository and version-controlled with your code.
A typical build pipeline for a .NET app shows the layers. The trigger field runs the pipeline on pushes to main. The pool field selects a Windows agent. The steps section lists tasks in order: restore packages, build the solution, and publish artifacts for later use.
To deploy, you add tasks targeting Azure services. For example, the AzureWebApp task deploys to an Azure App Service. It needs an azureSubscription connection and the target appName, and uses the artifact published in the build stage.
You control the flow between jobs using if conditions. These let you decide the next step based on whether a previous step succeeded or failed. For example, you can run an error-handling step only when a prior activity fails.
Stages are major checkpoints. You connect them using conditions like Upon Completion, so the next stage only runs if the previous one finishes as expected. This ensures the pipeline stops early if something critical fails, saving time and resources.
Running multiple jobs at the same time, called parallel task execution, reduces total pipeline time. You can use job matrices and resource limits to run activities on different agents simultaneously. Patterns like Try-Catch-Proceed let the pipeline handle errors without stopping everything. Steps that must always run, like cleanup, can be connected via UponFailure paths.
Building robust pipelines means planning for errors. Place generic error-handling jobs at the end to catch unexpected issues. When a task fails, a logging or cleanup job should run automatically to record details and clean up resources. Connecting failure paths directly to error-handling jobs keeps the process reliable and maintainable.
Hybrid pipelines create a single workflow using both Azure resources and your own on-premises computers. You write YAML definitions that run tasks in both places. This lets you keep sensitive tasks on your local network while using Azure cloud services for other parts, maintaining consistent CI/CD across different environments.
You can use Azure DevTest Labs to create virtual machines (VMs) that act as build agents. These VMs are made from preconfigured ARM templates that install all necessary software. This gives teams a private, production-like environment for safe testing and parallel builds. The lab manages the VM lifecycle, starting them for builds and shutting them down to save costs.
A self-hosted agent is software you install on your own VM, in Azure or on-premises. You register these agents to an agent pool in Azure Pipelines. To secure them, you connect them to Azure using a service connection backed by a service principal or managed identity. This lets the agent authenticate and follow your organization's security rules (RBAC) when accessing Azure resources.
To create a hybrid pipeline, you write YAML with tasks that use tools like the Azure CLI. A task might create a new VM to act as a self-hosted agent and add it to a pool. Another task might use an Azure Resource Manager connection to deploy infrastructure from an ARM template. This builds a pipeline that scales agent capacity and operates securely across cloud and on-premises boundaries.
YAML templates let you define reusable pieces of pipeline configuration. When you add parameters to a template, you can adapt it for different scenarios without copying code. This provides modularity by breaking large pipelines into smaller sections, consistency by ensuring every pipeline follows the same standards, and maintainability because you update the template in one place and all referencing pipelines get the change.
Task groups are collections of tasks that perform a specific function, like running tests and publishing artifacts. By grouping related tasks, you can reuse the entire group as a single step across many pipelines. This encapsulates logic, promotes reuse, and simplifies maintenance by reducing repetitive configurations.
Variables and variable groups store values that change, like secrets, connection strings, or version numbers. They enable secure data management by keeping sensitive information out of the pipeline code. They allow dynamic configuration so the pipeline uses different settings for development versus production. They provide consistency by using the same variable names and values across multiple pipelines.
You use these components by referencing YAML templates in your pipeline definitions, calling task groups within stages, and linking variables and variable groups to environments. This combination ensures modular, consistent, and maintainable workflows across Azure DevOps.
To control deployments, YAML pipelines use environments and approvals. A pipeline needs a service connection (like an Azure Resource Manager connection) to authenticate with Azure. Environments define where code is deployed (like Sandbox or WebApp) and are linked to specific Azure subscriptions and permissions, creating clear security boundaries.
Pipelines use automated pre-deployment and post-deployment gates to validate application health and compliance. These gates run scripts or tools within the pipeline steps. For example, a script might check a web endpoint's health and fail the deployment if the response is not Healthy.
Beyond automated checks, pipelines can require manual approval. Teams configure reviewers within an environment's checks, halting the deployment until authorized users sign off. This creates a control boundary where code cannot flow to sensitive environments without explicit, logged approval from stakeholders.
Prepare and test your skills

Prepare and test your skills

GitHub Actions uses event-driven triggers and scales automatically within GitHub repositories, whereas Azure Pipelines uses multi-stage YAML pipelines. Azure Pipelines also provides greater hosting flexibility by allowing teams to choose between Microsoft-hosted agents and self-hosted agents running on their own hardware.
A YAML pipeline in Azure DevOps is structured into steps, jobs, and stages. Steps represent individual tasks or scripts, jobs are sequences of steps that execute on a single agent, and stages are high-level phases like Build or Deploy that can hold multiple jobs.
A continuous integration trigger automatically executes a pipeline whenever a developer pushes code changes to monitored branches configured with the trigger keyword. In contrast, scheduled triggers run pipelines at designated times using cron syntax under the schedules keyword for routine tasks like cleanup or security scans.