Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Github Copilot in Practice: DevOps

The main purpose of this repo is to demonstrate how to use GitHub Copilot to support DevOps activities using custom agents, repository skills, and the Azure MCP Server.

You get:

  • Two pre-built custom agents (DevOps Engineer + Security Reviewer)
  • Four repository skills covering Terraform, Docker, GitHub Actions, and runbooks
  • A small two-service Node.js app (a task API and a web UI) ready to run locally and deploy to Azure Container Apps
  • Intentionally messy / broken artefacts to use as input for Copilot review and hardening exercises
  • A walkthrough of four Copilot-driven DevOps demos you can run end to end in your own subscription

Everything is designed to be opened in VS Code with GitHub Copilot Chat enabled.


Table of contents


Key learning points

Concept What it does Where to look
Custom agents Encode a role and a tool/skill policy. Switch agents in the chat picker. .github/agents/
Repository skills Versioned team and project conventions, automatically loaded by the agent when the task matches. .github/skills/
Agent plan The DevOps agent outlines its intended changes up front, then proceeds to implement them — giving you an early chance to course-correct. Used in Demo 1
Azure MCP Server Live Azure context: best practices, resource health, monitor logs, Advisor. .vscode/mcp.json
terraform plan Reviews the infrastructure delta before you apply. Pairs with the agent's upfront plan. Demo 1
Generate → use loop Copilot generates docs (a runbook) from real config, then reads them back as diagnostic context. Demo 3

The high-level mental model:

Agents describe who is doing the work and which skills/tools they use. Skills describe what good looks like for a particular kind of artefact. Azure MCP brings live Azure facts into the conversation.


Repo tour

.
├── app/
│   ├── api/                # Express + TypeScript task API (in-memory store)
│   └── web/                # Express + TypeScript web UI (single-page, vanilla JS)
├── infra/
│   ├── main.tf             # Monolithic Terraform — refactored in Demo 1
│   ├── variables.tf
│   ├── terraform.tfvars.example
│   └── backend.hcl.example
├── broken/                 # Intentionally broken artefacts for review demos
│   ├── main.tf             # Wrong resource type
│   ├── deploy.yml          # Bad indentation, missing OIDC perms
│   ├── Dockerfile          # Insecure Dockerfile (no USER, no multi-stage…)
│   └── README.md
├── scripts/
│   ├── setup.ps1           # Provision RG + Terraform state storage, write tfvars + backend.hcl
│   ├── setup.sh            # Bash equivalent
│   └── run-local.ps1       # Run API + web locally in two terminals
├── .github/
│   ├── agents/             # DevOps Engineer + Security Reviewer
│   └── skills/             # terraform / docker / github-actions / runbook conventions
├── .devcontainer/          # Optional dev container with Node 20 + Terraform + Azure CLI
├── .vscode/
│   └── mcp.json            # Azure MCP Server configuration
├── .env.example
└── .gitignore

What is not here, and is generated during the demos:

  • infra/modules/, infra/outputs.tf, infra/providers.tf (Demo 1)
  • app/api/Dockerfile, app/web/Dockerfile, */.dockerignore (Demo 2)
  • .github/workflows/deploy.yml (Demo 2)
  • docs/runbook.md (Demo 2)

This is intentional — the point is to use Copilot to produce them.


Prerequisites

  • Node.js 20+
  • Azure CLI (az) on PATH, signed in via az login
  • Terraform 1.5+
  • Docker (Docker Desktop or equivalent) — only needed if you want to build images locally; the demos use az acr build so this is optional
  • VS Code with the GitHub Copilot and GitHub Copilot Chat extensions
  • An Azure subscription you can deploy resources into

Optional: open the repo in the included .devcontainer/ for a pre-configured environment with all of the above.


Quick start: run the app locally

You can explore the app without any Azure setup.

  1. Install dependencies:
    cd app/api;  npm install;  cd ../..
    cd app/web;  npm install;  cd ../..
  2. Start both services in separate windows:
    pwsh ./scripts/run-local.ps1
  3. Open the UI:

Add a task in the browser, toggle it complete, and delete it — that exercises all four CRUD endpoints on the API.


Custom agents

Agents live in .github/agents/ and appear in the chat agent picker once VS Code recognises the workspace.

Agent Role When to use
DevOps-Engineer-Agent Senior DevOps engineer. Orchestrates Terraform, Docker, pipelines, and Azure best practices via repo skills + Azure MCP. Building, refactoring, generating, troubleshooting.
Security-Reviewer-Agent Senior security engineer. Reviews Dockerfiles, Terraform, and pipeline YAML against CIS / OWASP / Azure baselines and Advisor recommendations. Hardening, audit, security review.

To switch between them in VS Code, use the agent picker at the top of the Copilot Chat panel.

See: Use custom agents in VS Code.

Agent or skill?

Agents and skills solve different problems, and it's easy to reach for the wrong one:

  • Reach for a custom agent when the role changes. Agents encode a persona, a default toolset, and a policy for which skills to load. Use one when the same person would wear a different hat for the task — e.g. a DevOps engineer building infra vs. a security engineer auditing it. An agent is a long-lived configuration you switch into.
  • Reach for a skill when the artefact has team conventions. Skills describe "what good looks like" for a specific kind of file or workflow (Terraform modules, Dockerfiles, GitHub Actions, runbooks). They load automatically based on the task and are shared across agents — the DevOps and Security Reviewer agents both consult docker-conventions when Dockerfiles are in scope.

Rule of thumb: if you find yourself writing "act as a …" you probably want an agent; if you're writing "when editing X, always …" you probably want a skill.


Repository skills

Skills live in .github/skills/. Copilot loads them automatically when the task matches the skill's description.

Skill What it covers
terraform-conventions Naming, tagging, module structure, Container Apps patterns, validation flow
docker-conventions Pinned base images, multi-stage builds, non-root user, HEALTHCHECK, .dockerignore, deploy script
github-actions-conventions Pipeline structure, OIDC auth, image scanning, environment gates
runbook-conventions Architecture overview, deploy steps, rollback, troubleshooting, monitoring queries

The docker-conventions skill bundles a working scripts/deploy-apps.ps1 helper that the agent uses in Demo 2 to build images in ACR and update both Container Apps.

See: Customize chat with skills.


Azure MCP Server

.vscode/mcp.json wires up the Azure MCP Server with the scopes used by the demos:

  • azureterraformbestpractices — Terraform best practices for Azure (Demo 1)
  • resourcehealth, monitor, applicationinsights — live diagnostics (Demo 3)
  • advisor — security/cost/reliability recommendations (Demo 4)
  • group, subscription — context

Make sure you are signed into Azure in VS Code (az login) so the MCP server can pick up your credentials.

See: Azure MCP Server documentation.


Demo walkthroughs

The four demos take you from a messy monolith to a deployed, hardened, fully observable workload. They use the prompts shown verbatim — copy them straight into Copilot Chat.

Before you start:

  1. Copy .env.example to .env and fill in your subscription, resource group, location, and Terraform state storage account names.
  2. Run pwsh ./scripts/setup.ps1 (or bash ./scripts/setup.sh) to provision the resource group, the state storage account/container, and to generate infra/terraform.tfvars and infra/backend.hcl.
  3. From infra/, run terraform init -backend-config=backend.hcl.
  4. Open Copilot Chat and switch to DevOps-Engineer-Agent.

State expectations before Demo 1: the repo is exactly as cloned, with no infra/modules/, no app/*/Dockerfile, no .github/workflows/, and no docs/runbook.md. The infra/main.tf monolith uses placeholder MCR images so it can deploy successfully before any real images exist.

Heads up: setup.ps1 writes a few extra keys into infra/terraform.tfvars (project, environment, owner, api_external_enabled) that the monolithic infra/variables.tf does not declare yet. Terraform will warn about undeclared variables on the first plan/apply — that is expected. Demo 1 wires those variables up properly during the refactor.

Demo 1 — Refactor the monolithic Terraform

Agent: DevOps Engineer. Skills used: terraform-conventions, plus Azure MCP azureterraformbestpractices.

  1. Open infra/main.tf. Note the smell: hardcoded values, inconsistent naming (mycontainerapp vs acrprodregistry), no tags, no outputs, no modules.

  2. In Copilot Chat (DevOps Engineer), run:

    Prepare this repo for Azure Container Apps. Refactor the Terraform in infra/ into modules following our team conventions, and validate the structure before making changes.

  3. The agent outlines its plan first — proposed file structure (modules, variables, outputs, naming changes, tags) — then proceeds to implement it, restructuring infra/ and running terraform fmt, terraform validate, and terraform plan. Read the plan as it streams so you can interrupt early if the direction is wrong.

  4. Review the terraform plan output, then run:

    cd infra
    terraform apply -auto-approve

    Leave it running — you can move on to Demo 2 while Azure provisions.

Why two layers of review? The agent's upfront plan tells you what it intends to change in the repo. terraform plan tells you what those changes will do to your environment. One protects the codebase, the other protects the infrastructure.

Demo 2 — Generate Dockerfiles, pipeline, runbook, and deploy

Agent: DevOps Engineer. Skills used: docker-conventions, github-actions-conventions, runbook-conventions.

Each step is one prompt:

  1. Dockerfiles for both services:

    Generate production-ready Dockerfiles for both the API in app/api/ and the web app in app/web/.

    The docker-conventions skill already enforces multi-stage builds, non-root user, a HEALTHCHECK, a pinned MCR base image, and a .dockerignore — so a single prompt should produce compliant Dockerfiles on the first pass. Check the output against the skill's review checklist before moving on.

  2. CI/CD pipeline:

    Generate a GitHub Actions CI/CD workflow for this repo. Build and test both services, push both images to ACR, then deploy to staging followed by production approval.

    This produces .github/workflows/deploy.yml.

  3. Runbook:

    Generate an operational runbook for our Container Apps deployment. Include: architecture overview, deployment steps, rollback procedure, health check troubleshooting, common issues and fixes, monitoring queries to run. Use the Terraform and pipeline we just created.

    This produces docs/runbook.md.

  4. Build and deploy real images (waits for the Demo 1 terraform apply to complete first):

    Build and deploy both apps to our running Container Apps for testing.

    The agent picks up the docker-conventions skill, finds deploy-apps.ps1, and runs it. The script does an az acr build for both images, updates each Container App, and syncs infra/terraform.tfvars so subsequent terraform apply runs preserve your real images.

Demo 3 — Troubleshooting a failing deployment

Agent: DevOps Engineer. Skills + tools: Azure MCP resourcehealth, monitor, applicationinsights, plus the runbook generated in Demo 2.

  1. Fix broken/main.tf — pretend a colleague pushed it and the pipeline is failing. In Copilot Chat (DevOps Engineer), run:

    A colleague pushed broken/main.tf and the pipeline is failing. Take a look, work out what's wrong, and fix it.

    The agent picks up the terraform-conventions skill, runs terraform init / validate / plan itself, and identifies the wrong resource type (azurerm_container_group, which is Azure Container Instances, not Azure Container Apps) along with the missing container_app_environment_id.

  2. Fix broken/deploy.yml:

    Review this GitHub Actions workflow for issues. Check for: correct syntax, up-to-date action versions, security best practices, and missing configurations.

    Watch it catch the indentation, the outdated actions/checkout@v2, and the missing OIDC permissions: block.

  3. Live diagnostics — the web app cannot reach the API. With the real apps deployed from Demo 2, the web app loads but tasks do not appear. The API's ingress is internal-only while the web app is calling its FQDN — a classic Container Apps networking trap.

    The web app is running but can't load any data from the API. Check the health of both Container Apps and query Application Insights for any connection errors in the last 10 minutes.

    Then bring in your runbook as diagnostic context:

    Use our runbook at docs/runbook.md to diagnose why the web app can't connect to the API.

    Apply the suggested fix (enable external ingress on the API, or switch to internal-only on both with proper service-to-service DNS) and redeploy.

Demo 4 — Security review and Dockerfile hardening

Agent: Security Reviewer. Tools: Azure MCP advisor.

  1. Switch agent to Security-Reviewer-Agent.

  2. Harden broken/Dockerfile:

    Review this Dockerfile for security issues and container best practices.

    Then:

    Fix all findings. Generate a hardened Dockerfile and a .dockerignore file.

    Compare the result with the Dockerfiles produced in Demo 2 — the docker-conventions skill already enforces the same standards by default.

  3. Full-stack audit:

    Now review our Terraform in infra/ and the CI/CD pipeline for security issues. Also get Azure Advisor recommendations for our deployed resources.

    Expect findings on the Terraform side (HTTPS-only enforcement, VNET integration, diagnostic settings, image digests vs tags, resource locks) and an Advisor cross-reference for the live resources.


Configuration

Sample file Copy to Purpose
.env.example .env Subscription, resource group, location, state storage account
infra/terraform.tfvars.example infra/terraform.tfvars Terraform input variables (auto-generated by setup.ps1)
infra/backend.hcl.example infra/backend.hcl Azure Storage backend config (auto-generated by setup.ps1)

.env, terraform.tfvars, and backend.hcl are all listed in .gitignore and will not be committed.


Cleanup

When you are finished, tear down everything you provisioned:

cd infra
terraform destroy -auto-approve

Then delete the resource group if you want a completely clean slate:

az group delete --name <your-resource-group> --yes

You can also delete any generated demo artefacts (infra/modules/, app/*/Dockerfile, .github/workflows/, docs/runbook.md) to return the repo to its starting state.


References


License

MIT — see LICENSE (add your preferred license file before publishing).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages