CI/CD Interview Questions
CI/CD Interview Questions & Answers (1–50)
Section titled “CI/CD Interview Questions & Answers (1–50)”Section 1: CI/CD Fundamentals
Section titled “Section 1: CI/CD Fundamentals”Q1: What is CI/CD and why is it important?
Section titled “Q1: What is CI/CD and why is it important?”Answer:
| Term | What it means | Deployment trigger |
|---|---|---|
| CI (Continuous Integration) | Auto build + test on every commit | Never (just tests) |
| CD (Continuous Delivery) | Auto deliver to staging; human approves prod | Manual approval |
| CD (Continuous Deployment) | Auto deploy to production if tests pass | Fully automatic |
CI/CD Pipeline flow:
Developer commits ↓ [Source Control] ↓ [CI Pipeline] ├── Build (compile, package) ├── Unit Tests ├── Integration Tests ├── Security Scan (SAST, dependency check) ├── Build Docker image └── Push to registry ↓ [CD Pipeline] ├── Deploy to Staging ├── Run E2E / smoke tests ├── [Manual approval gate] ← Continuous Delivery stops here └── Deploy to Production ← Continuous Deployment continues here ↓ [Monitor] Alerts, dashboards, rollback if neededBenefits:
- Faster feedback: bug found in minutes not weeks
- Smaller releases = lower risk per deployment
- Repeatable: same process every time, no snowflake deployments
- Audit trail: every change is tracked
DORA Metrics (measure CI/CD maturity):
1. Deployment Frequency → Elite: multiple/day | Low: monthly2. Lead Time for Changes → Elite: < 1 hour | Low: > 6 months3. Change Failure Rate → Elite: 0-15% | Low: 46-60%4. MTTR (Mean Time to Recovery) → Elite: < 1 hour | Low: > 6 monthsInterview tip: Always mention DORA metrics when asked about CI/CD maturity. Interviewers love when you know how to measure CI/CD success, not just implement it.
Q2: What is the difference between Continuous Delivery and Continuous Deployment?
Section titled “Q2: What is the difference between Continuous Delivery and Continuous Deployment?”Answer:
| Aspect | Continuous Delivery | Continuous Deployment |
|---|---|---|
| Deployment to prod | Manual approval required | Fully automated |
| Gate | Human decision | Only automated tests |
| Risk | Lower (human safety net) | Higher (fully automated) |
| Speed | Slightly slower | Fastest possible |
| Best for | Regulated industries (finance, healthcare) | High-velocity SaaS teams |
| Example | Engineer clicks “Deploy” button | Merging PR triggers prod deploy |
Example workflow difference:
Continuous Delivery:commit → test → staging deploy → [HUMAN APPROVES] → prod deploy
Continuous Deployment:commit → test → staging deploy → [AUTO after 30min soak] → prod deployInterview tip: Most companies practice Continuous Delivery, not Deployment. Even Netflix and Google use approval gates for their most critical services. Continuous Deployment works best with feature flags so you can deploy dark code and enable it later.
Section 2: GitHub Actions
Section titled “Section 2: GitHub Actions”Q3: How does GitHub Actions work?
Section titled “Q3: How does GitHub Actions work?”Answer: GitHub Actions is an event-driven automation platform. Workflows are defined in .github/workflows/*.yml.
name: CI Pipeline
on: push: branches: [main, develop] pull_request: branches: [main]
env: IMAGE_NAME: myapp
jobs: test: name: Test runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm'
- name: Install dependencies run: npm ci
- name: Run tests run: npm test
- name: Upload coverage uses: codecov/codecov-action@v3
build: name: Build & Push Docker Image needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4
- name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push uses: docker/build-push-action@v5 with: push: true tags: | ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}Q4: How do you use GitHub Actions secrets and environments?
Section titled “Q4: How do you use GitHub Actions secrets and environments?”Answer:
Secrets hierarchy (where they can be set):
Organization Secrets → shared across reposRepository Secrets → specific to one repoEnvironment Secrets → only available in specific environment# Using secrets in workflowjobs: deploy: runs-on: ubuntu-latest environment: production # Links to GitHub Environment (can require approval) steps: - name: Deploy to production env: API_KEY: ${{ secrets.PROD_API_KEY }} # From environment secrets DB_URL: ${{ secrets.DATABASE_URL }} # From repo secrets REGION: us-east-1 # Non-secret, just env var run: ./scripts/deploy.sh
- name: Notify Slack if: always() # Run even if deploy fails uses: slackapi/slack-github-action@v1 with: payload: '{"text": "Deploy ${{ job.status }}: ${{ github.ref }}"}' env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}# Set secrets via CLIgh secret set DOCKER_PASSWORD --body "mypassword"gh secret set DOCKER_PASSWORD < ./password.txt # from file (more secure)gh secret list # list all secret names
# Environment-specific secrets# GitHub UI: Settings → Environments → production → Add secret# These secrets ONLY become available when environment: production is set in workflow
# Required reviewers for environment (approval gate)# Settings → Environments → production → Required reviewers → add team/userUsing OIDC instead of stored secrets (most secure):
permissions: id-token: write # Needed for OIDC contents: read
steps:- uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789:role/github-actions aws-region: us-east-1 # No AWS_SECRET_ACCESS_KEY needed! OIDC token used insteadInterview tip: Use OIDC (OpenID Connect) instead of storing cloud credentials as secrets. With OIDC, GitHub gets a short-lived token from AWS/Azure/GCP directly — no long-lived credentials to rotate or leak.
Q5: How do you implement matrix builds in GitHub Actions?
Section titled “Q5: How do you implement matrix builds in GitHub Actions?”Answer: Matrix builds run the same job with different combinations of variables in parallel — great for cross-platform and multi-version testing.
jobs: test: name: Test (Node ${{ matrix.node }} on ${{ matrix.os }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false # Continue other matrix jobs even if one fails matrix: os: [ubuntu-latest, windows-latest, macos-latest] node: [16, 18, 20] exclude: - os: windows-latest node: 16 # Skip this combination include: - os: ubuntu-latest node: 20 experimental: true # Custom variable for this combination steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - run: npm ci && npm test - name: Experimental only step if: matrix.experimental == true run: npm run test:experimentalMatrix outputs:
Matrix creates 3 × 3 = 9 jobs (minus 1 excluded = 8 jobs), running in parallel:┌────────────────────────────────────────┐│ ubuntu+node16 ubuntu+node18 ubuntu+node20 ││ windows+node18 windows+node20 ││ macos+node16 macos+node18 macos+node20 │└────────────────────────────────────────┘Interview tip: Use
fail-fast: falsefor test matrices so you see ALL failures across versions, not just the first one. Usefail-fast: true(default) when early failure matters (e.g., build matrix).
Q6: How do you cache dependencies in GitHub Actions?
Section titled “Q6: How do you cache dependencies in GitHub Actions?”Answer: Caching avoids re-downloading dependencies on every run — can save 2-5 minutes per job.
How cache works:
First run: MISS → install deps → save to cacheNext run: HIT → restore from cache → skip installCache key changes: MISS → reinstall → save new cache# Node.js (npm)- name: Cache npm packages uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} # ↑ cache bust when lockfile changes restore-keys: | ${{ runner.os }}-npm- # fallback: use any npm cache for this OS
# Python (pip)- uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }} restore-keys: | ${{ runner.os }}-pip-
# Go- uses: actions/cache@v4 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
# Docker layer caching (most impactful for image builds)- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Build and push with cache uses: docker/build-push-action@v5 with: context: . push: true tags: myapp:latest cache-from: type=gha # Restore from GitHub Actions cache cache-to: type=gha,mode=max # Save all layers to cacheMeasuring cache effectiveness:
# In workflow, check if cache was hit- name: Cache npm id: cache-npm uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
- name: Install deps (skip if cache hit) if: steps.cache-npm.outputs.cache-hit != 'true' run: npm ciInterview tip: Cache key strategy is critical. Use
hashFiles()on lockfiles — NOT onpackage.json.package-lock.jsonchanges only when dependencies actually change, giving better cache hit rates.
Section 3: Jenkins
Section titled “Section 3: Jenkins”Q7: What is a Jenkinsfile and how does it work?
Section titled “Q7: What is a Jenkinsfile and how does it work?”Answer: A Jenkinsfile defines a Jenkins pipeline as code using Groovy DSL.
// Declarative Pipelinepipeline { agent any
environment { DOCKER_IMAGE = 'myapp' DOCKER_TAG = "${env.BUILD_NUMBER}" REGISTRY = 'registry.example.com' }
stages { stage('Checkout') { steps { git branch: 'main', url: 'https://github.com/org/repo.git' } }
stage('Test') { steps { sh 'npm ci' sh 'npm test' } post { always { junit 'test-results/*.xml' } } }
stage('Build Docker Image') { steps { script { docker.build("${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}") } } }
stage('Push Image') { steps { withCredentials([usernamePassword( credentialsId: 'registry-creds', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD' )]) { sh "docker login -u $USERNAME -p $PASSWORD ${REGISTRY}" sh "docker push ${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}" } } }
stage('Deploy to Staging') { steps { sh """ kubectl set image deployment/myapp \ myapp=${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG} \ -n staging """ } }
stage('Deploy to Production') { when { branch 'main' } input { message "Deploy to production?" ok "Yes, deploy!" } steps { sh """ kubectl set image deployment/myapp \ myapp=${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG} \ -n production """ } } }
post { failure { slackSend channel: '#deploys', message: "Build FAILED: ${env.JOB_NAME} ${env.BUILD_NUMBER}" } success { slackSend channel: '#deploys', message: "Build SUCCESS: ${env.JOB_NAME} ${env.BUILD_NUMBER}" } }}Q8: How do you set up Jenkins agents?
Section titled “Q8: How do you set up Jenkins agents?”Answer:
// Specify agent for the whole pipelinepipeline { agent { label 'docker-agent' // Node with 'docker-agent' label }}
// Different agents per stagepipeline { agent none stages { stage('Build') { agent { label 'linux' } steps { sh 'make build' } } stage('Test Windows') { agent { label 'windows' } steps { bat 'test.bat' } } }}
// Docker agentpipeline { agent { docker { image 'node:18-alpine' args '-v /tmp:/tmp' } }}Q9: How do you use Jenkins shared libraries?
Section titled “Q9: How do you use Jenkins shared libraries?”Answer:
// vars/deployApp.groovy (shared library function)def call(String environment, String image) { sh """ kubectl set image deployment/app \ app=${image} -n ${environment} kubectl rollout status deployment/app -n ${environment} """}
// Jenkinsfile using shared library@Library('my-shared-library') _
pipeline { agent any stages { stage('Deploy') { steps { deployApp('staging', "myapp:${BUILD_NUMBER}") } } }}Section 4: GitLab CI/CD
Section titled “Section 4: GitLab CI/CD”Q10: How does GitLab CI/CD work?
Section titled “Q10: How does GitLab CI/CD work?”Answer:
stages: - test - build - deploy
variables: DOCKER_DRIVER: overlay2 IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
test: stage: test image: node:18 cache: key: "$CI_COMMIT_REF_SLUG" paths: - node_modules/ script: - npm ci - npm test coverage: '/Lines\s*:\s*(\d+\.?\d*)%/' artifacts: reports: junit: test-results.xml coverage_report: coverage_format: cobertura path: coverage/cobertura-coverage.xml
build: stage: build image: docker:24 services: - docker:24-dind before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - docker build -t $IMAGE_TAG . - docker push $IMAGE_TAG only: - main - develop
deploy-staging: stage: deploy script: - kubectl set image deployment/app app=$IMAGE_TAG -n staging environment: name: staging url: https://staging.myapp.com only: - develop
deploy-production: stage: deploy script: - kubectl set image deployment/app app=$IMAGE_TAG -n production environment: name: production url: https://myapp.com when: manual # Require manual trigger only: - mainSection 5: ArgoCD & GitOps
Section titled “Section 5: ArgoCD & GitOps”Q11: What is GitOps and how does ArgoCD implement it?
Section titled “Q11: What is GitOps and how does ArgoCD implement it?”Answer: GitOps: Git is the single source of truth for infrastructure and application configuration. Changes happen via Git commits/PRs.
ArgoCD continuously watches a Git repo and syncs cluster state.
# Install ArgoCDkubectl create namespace argocdkubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Get admin passwordkubectl get secret argocd-initial-admin-secret -n argocd \ -o jsonpath="{.data.password}" | base64 -d
# Port forward UIkubectl port-forward svc/argocd-server -n argocd 8080:443# ArgoCD ApplicationapiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: myapp namespace: argocdspec: project: default source: repoURL: https://github.com/org/k8s-configs targetRevision: main path: apps/myapp/overlays/production destination: server: https://kubernetes.default.svc namespace: production syncPolicy: automated: prune: true # Delete resources removed from Git selfHeal: true # Fix manual changes syncOptions: - CreateNamespace=true# Sync manuallyargocd app sync myapp
# Check app statusargocd app get myapp
# Roll backargocd app rollback myapp --revision=5Q12: What is Kustomize and how does it work with CI/CD?
Section titled “Q12: What is Kustomize and how does it work with CI/CD?”Answer:
k8s-configs/├── base/│ ├── deployment.yaml│ ├── service.yaml│ └── kustomization.yaml└── overlays/ ├── staging/ │ ├── kustomization.yaml # Patches for staging │ └── replica-patch.yaml └── production/ ├── kustomization.yaml └── replica-patch.yamlapiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationnamespace: productionresources:- ../../baseimages:- name: myapp newTag: "1.5.0" # Update via CI: kustomize edit set imagepatches:- path: replica-patch.yaml# Update image tag in CI pipelinecd k8s-configs/overlays/productionkustomize edit set image myapp=myapp:$NEW_TAGgit commit -am "chore: update image to $NEW_TAG"git push# ArgoCD detects change and syncsSection 6: Deployment Strategies
Section titled “Section 6: Deployment Strategies”Q13: What are the different deployment strategies?
Section titled “Q13: What are the different deployment strategies?”Answer:
1. Rolling Update (Default in K8s)
strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25% maxSurge: 25%✅ Zero downtime | ❌ Mixed versions briefly
2. Blue-Green Deployment
# Switch traffic by changing service selectorkubectl patch service myapp-service \ -p '{"spec":{"selector":{"version":"green"}}}'✅ Instant rollback | ❌ Double infrastructure cost
3. Canary Deployment
# 90% traffic to stable, 10% to canary# Using Argo Rolloutsspec: strategy: canary: steps: - setWeight: 10 # 10% traffic - pause: {duration: 5m} - setWeight: 50 # 50% traffic - pause: {duration: 10m} - setWeight: 100 # Full rollout✅ Test with real traffic | ❌ Complex setup
4. Recreate
strategy: type: Recreate✅ Simple | ❌ Downtime during deployment
Q14: How do you implement feature flags in CI/CD?
Section titled “Q14: How do you implement feature flags in CI/CD?”Answer:
// Application code uses feature flagconst featureFlags = require('./flags');
if (featureFlags.isEnabled('new-checkout-flow', userId)) { return newCheckout();} else { return oldCheckout();}# Environment-based flagsenv:- name: FEATURE_NEW_CHECKOUT value: "true" # Toggle per environment
# External flag services: LaunchDarkly, Unleash, FlagsmithSection 7: Testing in CI/CD
Section titled “Section 7: Testing in CI/CD”Q15: How do you structure testing in a CI pipeline?
Section titled “Q15: How do you structure testing in a CI pipeline?”Answer:
# GitHub Actions — Test pyramid approachjobs: unit-tests: runs-on: ubuntu-latest steps: - run: npm run test:unit - uses: actions/upload-artifact@v3 with: name: unit-results path: coverage/
integration-tests: needs: unit-tests services: postgres: image: postgres:15 env: POSTGRES_PASSWORD: test steps: - run: npm run test:integration
e2e-tests: needs: integration-tests steps: - name: Run Cypress uses: cypress-io/github-action@v6 with: start: npm start wait-on: 'http://localhost:3000'
security-scan: steps: - uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
performance-test: steps: - run: | k6 run --vus 50 --duration 30s load-test.jsQ16: What is SAST and DAST in a DevSecOps pipeline?
Section titled “Q16: What is SAST and DAST in a DevSecOps pipeline?”Answer:
| Type | When | Tools |
|---|---|---|
| SAST (Static) | During build — analyze source code | SonarQube, Semgrep, CodeQL |
| DAST (Dynamic) | Against running app | OWASP ZAP, Burp Suite |
| SCA (Dependencies) | Build time | Snyk, OWASP Dependency Check |
| Container Scan | Image build | Trivy, Grype, Clair |
# GitHub Actions: SAST with CodeQL- name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: javascript, python
- name: Run CodeQL Analysis uses: github/codeql-action/analyze@v2
# Container scanning- name: Scan image with Trivy uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} exit-code: '1' severity: 'CRITICAL,HIGH'Section 8: Pipeline Optimization
Section titled “Section 8: Pipeline Optimization”Q17: How do you speed up CI/CD pipelines?
Section titled “Q17: How do you speed up CI/CD pipelines?”Answer:
# 1. Parallel jobsjobs: test-unit: runs-on: ubuntu-latest steps: [...]
test-e2e: runs-on: ubuntu-latest steps: [...]
# Both run simultaneously! lint: runs-on: ubuntu-latest steps: [...]
# 2. Fail-fast — stop all on first failurestrategy: fail-fast: true
# 3. Path-based triggerson: push: paths: - 'src/**' - '!docs/**' # Skip if only docs changed
# 4. Conditional jobsdeploy: if: github.ref == 'refs/heads/main' && github.event_name == 'push'
# 5. Reuse Docker layers via cache- uses: docker/build-push-action@v5 with: cache-from: type=gha cache-to: type=gha,mode=maxQ18: How do you implement infrastructure as code in CI/CD?
Section titled “Q18: How do you implement infrastructure as code in CI/CD?”Answer:
# Terraform in CI/CD (GitHub Actions)- name: Terraform Init working-directory: ./infrastructure run: terraform init
- name: Terraform Plan run: terraform plan -out=tfplan env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Comment plan on PR uses: actions/github-script@v6 with: script: | const plan = fs.readFileSync('tfplan.txt', 'utf8') github.rest.issues.createComment({ issue_number: context.issue.number, body: `\`\`\`terraform\n${plan}\n\`\`\`` })
- name: Terraform Apply if: github.ref == 'refs/heads/main' run: terraform apply -auto-approve tfplanQ19: How do you handle database migrations in CI/CD?
Section titled “Q19: How do you handle database migrations in CI/CD?”Answer:
# Strategy: Run migrations before new code is live
# Option 1: K8s Init ContainerinitContainers:- name: db-migrate image: myapp:$NEW_TAG command: ["python", "manage.py", "migrate"] env: - name: DATABASE_URL valueFrom: secretKeyRef: name: db-secret key: url
# Option 2: Kubernetes Job before deploymentjobs: migrate: runs-on: ubuntu-latest steps: - name: Run migration run: | kubectl apply -f migration-job.yaml kubectl wait --for=condition=complete job/db-migration --timeout=5m
deploy: needs: migrate runs-on: ubuntu-latest steps: - name: Deploy application run: kubectl apply -f deployment.yamlQ20: What is trunk-based development and how does it affect CI/CD?
Section titled “Q20: What is trunk-based development and how does it affect CI/CD?”Answer:
Trunk-Based Development: - All developers commit to 'main' (trunk) at least daily - Feature branches are short-lived (< 2 days) - Feature flags used to hide incomplete features - CI triggers on every commit
vs. GitFlow: - Long-lived branches (feature/*, release/*) - PRs to develop → merge to main - More complex, slower feedback# Trunk-based CI — run on every commit to mainon: push: branches: [main]
jobs: build-test-deploy: steps: - run: npm ci - run: npm test - run: npm run build - run: ./deploy.sh staging # Automatic staging deployment - run: ./deploy.sh prod --canary 10% # 10% canary to prodBack to DevOps Q&A Index
Section 9: Advanced CI/CD Questions
Section titled “Section 9: Advanced CI/CD Questions”Q21: What is the difference between CI and CD?
Section titled “Q21: What is the difference between CI and CD?”Answer (Simple):
- CI (Continuous Integration) = Automatically build and test every commit. Catch bugs early.
- CD (Continuous Delivery) = Every passing commit is deployable. Deploy button is always ready.
- CD (Continuous Deployment) = Every passing commit AUTO-deploys to production. No human needed.
Developer pushes code ↓ [CI Pipeline] - Build code - Run unit tests - Run integration tests - Security scan - Build Docker image ↓ [CD Pipeline] - Deploy to staging (automatic) - Run smoke tests - Deploy to production (manual approval = Delivery) OR (automatic = Deployment)Q22: How do you prevent secrets from being exposed in CI/CD logs?
Section titled “Q22: How do you prevent secrets from being exposed in CI/CD logs?”Answer:
# GitHub Actions — use secrets, never hardcode# BAD ❌env: API_KEY: "sk-prod-abc123secretkey"
# GOOD ✅ — Use GitHub Secretsenv: API_KEY: ${{ secrets.PROD_API_KEY }}
# Mask custom values in logs- name: Mask token run: echo "::add-mask::${{ steps.get-token.outputs.token }}"
# Jenkins — use credentials bindingwithCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) { sh 'curl -H "Authorization: $API_KEY" https://api.example.com'}# Jenkins automatically masks the value in logs
# GitLab — masked variables# Settings → CI/CD → Variables → check "Masked"Q23: What is the difference between a CI runner and an agent?
Section titled “Q23: What is the difference between a CI runner and an agent?”Answer:
| Platform | Term | Description |
|---|---|---|
| GitHub Actions | Runner | VM/container that executes workflow jobs |
| Jenkins | Agent | Node that executes pipeline stages |
| GitLab CI | Runner | Process registered to execute jobs |
| Azure DevOps | Agent | Service that runs pipeline jobs |
# GitHub Actions — GitHub-hosted runner (free)runs-on: ubuntu-latest # GitHub manages this
# GitHub Actions — Self-hosted runner (your own server)runs-on: [self-hosted, linux, gpu] # Your server
# Jenkins — define agentpipeline { agent { label 'linux-agent' # Named Jenkins agent }}
# GitLab — register runnergitlab-runner register \ --url https://gitlab.com \ --token <token> \ --executor docker \ --docker-image node:18Q24: What is semantic versioning in CI/CD?
Section titled “Q24: What is semantic versioning in CI/CD?”Answer: MAJOR.MINOR.PATCH — e.g., 2.1.3
| Version Part | When to bump | Example |
|---|---|---|
MAJOR | Breaking change | API removed, incompatible |
MINOR | New feature, backward compatible | New endpoint added |
PATCH | Bug fix, backward compatible | Fixed null pointer exception |
# Auto-generate version in CI from git tagsgit tag v1.2.3git push --tags
# In CI pipeline:VERSION=$(git describe --tags --abbrev=0) # v1.2.3FULL_VERSION=$(git describe --tags) # v1.2.3-5-gabcd123
# Conventional Commits → auto bump version# feat: add login button → MINOR bump# fix: correct null check → PATCH bump# feat!: change auth API → MAJOR bump (breaking)
# Tools: semantic-release, standard-versionnpx semantic-release # Auto-tags + changelog generationQ25: How do you implement multi-environment CI/CD (dev/staging/prod)?
Section titled “Q25: How do you implement multi-environment CI/CD (dev/staging/prod)?”Answer:
# GitHub Actions — environment-based deploymentname: Deploy
on: push: branches: [main, develop]
jobs: deploy-staging: if: github.ref == 'refs/heads/develop' environment: name: staging url: https://staging.myapp.com runs-on: ubuntu-latest steps: - name: Deploy to staging run: | kubectl config use-context staging-cluster kubectl apply -f k8s/overlays/staging/
deploy-production: if: github.ref == 'refs/heads/main' environment: name: production # Requires approval in GitHub settings url: https://myapp.com needs: [test] runs-on: ubuntu-latest steps: - name: Deploy to production run: | kubectl config use-context prod-cluster kubectl apply -f k8s/overlays/production/Q26: What is a Pipeline as Code?
Section titled “Q26: What is a Pipeline as Code?”Answer: Pipeline as Code means CI/CD pipeline is defined in a file stored in the repository (version controlled), not configured through a UI.
# GitHub Actions (.github/workflows/ci.yml)# GitLab CI (.gitlab-ci.yml)# Jenkins (Jenkinsfile)# Azure Pipelines (azure-pipelines.yml)# CircleCI (.circleci/config.yml)
# Benefits:# ✅ Version controlled (git history)# ✅ Code reviewed (PR reviews)# ✅ Reproducible# ✅ Self-documenting
# Example — complete pipeline as codename: Full Pipelineon: [push]jobs: pipeline: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run lint - run: npm test - run: docker build -t myapp:${{ github.sha }} . - run: trivy image myapp:${{ github.sha }} - run: docker push myapp:${{ github.sha }} - run: kubectl set image deployment/myapp app=myapp:${{ github.sha }}Q27: How do you implement approval gates in CI/CD?
Section titled “Q27: How do you implement approval gates in CI/CD?”Answer:
# GitHub Actions — environment protection rules# 1. Go to Settings → Environments → production# 2. Add required reviewers# 3. Workflow will pause and notify reviewers
jobs: deploy-prod: environment: production # Pauses here for approval steps: - run: kubectl apply -f production/
# Jenkins — input stepstage('Deploy to Production') { input { message "Deploy to production?" ok "Yes, deploy!" submitter "devops-lead,cto" # Only these users can approve } steps { sh './deploy-prod.sh' }}
# GitLab — when: manualdeploy-production: stage: deploy script: - ./deploy.sh production when: manual # Requires clicking "Play" in GitLab UI only: - mainQ28: What is artifact management in CI/CD?
Section titled “Q28: What is artifact management in CI/CD?”Answer: Artifacts are the build outputs (binaries, Docker images, test reports) passed between pipeline stages.
# GitHub Actions — upload/download artifacts between jobsjobs: build: runs-on: ubuntu-latest steps: - run: npm run build
- name: Upload build artifacts uses: actions/upload-artifact@v3 with: name: build-output path: ./dist/ retention-days: 7
deploy: needs: build runs-on: ubuntu-latest steps: - name: Download build artifacts uses: actions/download-artifact@v3 with: name: build-output path: ./dist/
- run: aws s3 sync ./dist/ s3://my-bucket/
# GitLab — artifactsbuild: script: npm run build artifacts: paths: - dist/ expire_in: 1 week reports: junit: test-results.xmlQ29: How do you implement rollback in CI/CD?
Section titled “Q29: How do you implement rollback in CI/CD?”Answer:
# Strategy 1: Re-run previous pipeline# In GitHub Actions: Actions → Find last good run → Re-run
# Strategy 2: Git revertgit revert HEAD # Reverts last commit, creates new commitgit push # Triggers new pipeline with old code
# Strategy 3: Kubernetes rollbackkubectl rollout undo deployment/myappkubectl rollout undo deployment/myapp --to-revision=3kubectl rollout history deployment/myapp # View history
# Strategy 4: ArgoCD rollbackargocd app rollback myapp --revision=5argocd app history myapp # See previous versions
# Strategy 5: Helm rollbackhelm rollback myapp 3 # Rollback to release 3helm history myapp # View helm release history
# Strategy 6: Feature flag (instant, no redeployment)# Toggle flag off in LaunchDarkly/Unleash# No code deployment needed!Q30: What is a monorepo and how does CI/CD work with it?
Section titled “Q30: What is a monorepo and how does CI/CD work with it?”Answer: Monorepo = All projects in one repository.
# Monorepo structuremyorg/├── services/│ ├── api/│ ├── worker/│ └── auth/├── packages/│ ├── ui-components/│ └── utils/└── infrastructure/
# GitHub Actions — only run for changed servicejobs: changes: runs-on: ubuntu-latest outputs: api: ${{ steps.filter.outputs.api }} worker: ${{ steps.filter.outputs.worker }} steps: - uses: dorny/paths-filter@v2 id: filter with: filters: | api: - 'services/api/**' worker: - 'services/worker/**'
deploy-api: needs: changes if: ${{ needs.changes.outputs.api == 'true' }} runs-on: ubuntu-latest steps: - run: cd services/api && ./deploy.sh
deploy-worker: needs: changes if: ${{ needs.changes.outputs.worker == 'true' }} runs-on: ubuntu-latest steps: - run: cd services/worker && ./deploy.shQ31: What is continuous testing and shift-left testing?
Section titled “Q31: What is continuous testing and shift-left testing?”Answer:
Shift-Left = Move testing earlier in the development cycle (to the “left” on the timeline).
Traditional (Shift-Right):Dev → Build → QA Testing → Security Review → Deploy ↑ Problems found late, expensive to fix
Shift-Left:Dev → [Unit tests] → [Integration tests] → [Security scan] → Build → Deploy ↑ Problems found early (in dev phase), cheap to fix# Test pyramid in CIjobs: # Level 1: Unit tests (fast, many) unit-tests: runs-on: ubuntu-latest timeout-minutes: 5 steps: - run: npm run test:unit -- --coverage
# Level 2: Integration tests (medium) integration-tests: needs: unit-tests timeout-minutes: 15 services: postgres: image: postgres:15 steps: - run: npm run test:integration
# Level 3: E2E tests (slow, few) e2e-tests: needs: integration-tests timeout-minutes: 30 steps: - run: npx playwright test
# Security shift-left sast-scan: runs-on: ubuntu-latest steps: - uses: github/codeql-action/analyze@v2Q32: What is blue-green deployment in CI/CD?
Section titled “Q32: What is blue-green deployment in CI/CD?”Answer:
Current State: Load Balancer → Blue (v1.0, LIVE, 100% traffic) Green (v2.0, IDLE, 0% traffic)
Deploy new version: Step 1: Deploy v2.0 to Green, test it Step 2: Switch load balancer: Blue=0%, Green=100% Step 3: Keep Blue running (instant rollback if needed) Step 4: After confidence, decommission Blue
Benefits: ✅ Zero downtime ✅ Instant rollback (just switch back) ✅ Test in production-like environment before switching# GitHub Actions — Blue-Green with ECS- name: Deploy to Green run: | aws ecs update-service \ --cluster production \ --service myapp-green \ --task-definition myapp:${{ env.NEW_REVISION }} aws ecs wait services-stable --cluster production --services myapp-green
- name: Run smoke tests against Green run: curl -f https://green.myapp.com/health
- name: Switch traffic to Green run: | aws elbv2 modify-listener \ --listener-arn $LISTENER_ARN \ --default-actions Type=forward,TargetGroupArn=$GREEN_TG_ARNQ33: What is a canary release and how does it differ from blue-green?
Section titled “Q33: What is a canary release and how does it differ from blue-green?”Answer:
| Feature | Blue-Green | Canary |
|---|---|---|
| Traffic split | 0% or 100% | Gradual (5% → 25% → 100%) |
| Risk | All users switch at once | Small % exposed first |
| Rollback | Instant | Gradual or instant |
| Cost | 2x infrastructure | Minimal extra |
| Test with real traffic | ❌ | ✅ |
# GitHub Actions — Canary with weighted routing- name: Deploy canary (10% traffic) run: | kubectl apply -f canary-deployment.yaml # Service routes: 90% stable, 10% canary # Monitor error rates, latency for 30 mins
- name: Monitor metrics run: | ERROR_RATE=$(curl -s prometheus/api/v1/query?query=error_rate | jq .data.result[0].value[1]) if (( $(echo "$ERROR_RATE > 0.01" | bc) )); then echo "Error rate too high: $ERROR_RATE" kubectl delete -f canary-deployment.yaml exit 1 fi
- name: Promote to 100% if: success() run: | kubectl set image deployment/myapp-stable app=myapp:$NEW_TAG kubectl delete -f canary-deployment.yamlQ34: How do you implement compliance checks in CI/CD?
Section titled “Q34: How do you implement compliance checks in CI/CD?”Answer:
# DevSecOps pipeline with compliance checksjobs: compliance: runs-on: ubuntu-latest steps: # 1. License compliance - name: Check licenses uses: pivotal/licensed@v3 with: command: status
# 2. SAST — Static code analysis - name: SonarQube scan uses: SonarSource/sonarcloud-github-action@master env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: args: -Dsonar.qualitygate.wait=true # Fail if quality gate fails
# 3. Dependency vulnerabilities - name: Check dependencies run: | npm audit --audit-level=high # or: pip-audit, safety check, bundler-audit
# 4. Container compliance - name: CIS benchmark check uses: docker://aquasec/kube-bench:latest with: args: --benchmark cis-1.6
# 5. Infrastructure compliance - name: Checkov IaC scan uses: bridgecrewio/checkov-action@master with: directory: infrastructure/ framework: terraformQ35: What is a pipeline timeout and why is it important?
Section titled “Q35: What is a pipeline timeout and why is it important?”Answer:
# Without timeouts, a stuck job runs forever and blocks other jobs
# GitHub Actions — set timeoutsjobs: build: timeout-minutes: 30 # Job-level timeout
steps: - name: Run tests timeout-minutes: 15 # Step-level timeout run: npm test
- name: Deploy timeout-minutes: 10 run: ./deploy.sh
# Jenkins — timeoutstage('Tests') { timeout(time: 20, unit: 'MINUTES') { sh 'npm test' }}
# Common timeout scenarios:# - Tests hang (infinite loop, deadlock)# - Deployment stuck (waiting for approval)# - External service not responding# - Resource contention (no runners available)Q36: What is GitOps and how is it different from traditional CI/CD?
Section titled “Q36: What is GitOps and how is it different from traditional CI/CD?”Answer:
| Aspect | Traditional CI/CD | GitOps |
|---|---|---|
| Trigger | Code push → deploy | Git commit → reconcile |
| Source of truth | CI/CD pipeline config | Git repository |
| Deployment | Pipeline pushes to cluster | Operator pulls from Git |
| Security | Pipeline has cluster access | Cluster pulls (safer) |
| Rollback | Re-run pipeline | git revert |
| Tools | Jenkins, GitHub Actions | ArgoCD, Flux |
# GitOps flow with ArgoCD:# 1. Dev pushes code → CI builds image → CI updates image tag in K8s config repo# 2. ArgoCD detects config change in Git# 3. ArgoCD syncs cluster to match Git state
# In CI pipeline (updates Git config repo):- name: Update image tag in GitOps repo run: | git clone https://github.com/org/k8s-configs cd k8s-configs kustomize edit set image myapp=myapp:${{ github.sha }} git commit -am "chore: update myapp to ${{ github.sha }}" git push# ArgoCD then auto-syncs the clusterQ37: How do you handle flaky tests in CI/CD?
Section titled “Q37: How do you handle flaky tests in CI/CD?”Answer:
# Strategy 1: Retry failed tests- name: Run tests with retry uses: nick-fields/retry@v2 with: timeout_minutes: 10 max_attempts: 3 command: npm test
# Strategy 2: Quarantine flaky tests# Mark flaky test with special tag# jest --testPathPattern="stable" (skip flaky)# Run flaky tests separately on a schedule, not blocking
# Strategy 3: Identify and report flaky tests- name: Run tests and track flakiness run: | for i in 1 2 3; do npm test; done | tee test-results.txt # Check if same test fails inconsistently grep -E "FAIL|PASS" test-results.txt | sort | uniq -c
# Strategy 4: Fix root causes# - Use deterministic test data# - Mock external APIs# - Use fake timers for time-dependent tests# - Fix race conditions# - Use proper test isolation (cleanup DB after each test)Q38: What is a release pipeline vs a build pipeline?
Section titled “Q38: What is a release pipeline vs a build pipeline?”Answer:
Build Pipeline (triggered per commit): Code → Test → Build → Package → Artifact Registry Fast, runs many times per day Purpose: Validate code quality
Release Pipeline (triggered per release): Artifact → Deploy to Staging → Test → Approve → Deploy to Production Slower, runs less frequently Purpose: Safely deliver to production
Example: PR merged to main ↓ [Build Pipeline] - Run tests - Build Docker image - Push to ECR as myapp:abc123 ↓ Image is ready but NOT deployed yet ↓ [Release Pipeline] (triggered manually or on tag) - Pull myapp:abc123 - Deploy to staging - Run E2E tests - Manual approval - Deploy to productionQ39: What is DRY (Don’t Repeat Yourself) in CI/CD?
Section titled “Q39: What is DRY (Don’t Repeat Yourself) in CI/CD?”Answer:
# GitHub Actions — reusable workflowsname: Deploy Templateon: workflow_call: inputs: environment: required: true type: string image-tag: required: true type: string
jobs: deploy: environment: ${{ inputs.environment }} runs-on: ubuntu-latest steps: - name: Deploy run: | kubectl set image deployment/myapp \ app=myapp:${{ inputs.image-tag }} \ -n ${{ inputs.environment }}
---# Use the reusable workflowname: CI/CDjobs: deploy-staging: uses: ./.github/workflows/deploy-template.yml with: environment: staging image-tag: ${{ github.sha }}
deploy-production: needs: deploy-staging uses: ./.github/workflows/deploy-template.yml with: environment: production image-tag: ${{ github.sha }}Q40: How do you monitor CI/CD pipeline health?
Section titled “Q40: How do you monitor CI/CD pipeline health?”Answer:
# Key CI/CD metrics to track:# - DORA metrics (DevOps Research and Assessment)
# 1. Deployment Frequency# How often do you deploy? (daily, weekly, monthly)# Elite: Multiple times/day# Low: Less than once/month
# 2. Lead Time for Changes# Code commit → Production deployment time# Elite: < 1 hour# Low: > 6 months
# 3. Mean Time to Recovery (MTTR)# How fast do you recover from failure?# Elite: < 1 hour
# 4. Change Failure Rate# % of deployments causing production failure# Elite: < 5%# GitHub Actions — track build times- name: Record metrics run: | START=$(cat /tmp/start_time) END=$(date +%s) DURATION=$((END - START)) echo "Pipeline duration: ${DURATION}s"
# Send to monitoring curl -X POST https://metrics.internal/ci \ -d "pipeline=$GITHUB_WORKFLOW&duration=$DURATION&status=success"
# Tools for pipeline monitoring:# - Grafana + Prometheus (self-hosted)# - Datadog CI Visibility# - GitHub Insights# - Jenkins AnalyticsQ41: What is a staging environment and how should it differ from production?
Section titled “Q41: What is a staging environment and how should it differ from production?”Answer:
Staging should mirror Production as closely as possible:
Production: Staging:- 3 replicas - 1-2 replicas (cost savings OK)- Production DB - Copy of production DB (with PII masked)- Real cloud resources - Same cloud region/services- Real external APIs - Sandbox/test versions of external APIs- Production secrets - Separate set of secrets- SSL certificate - Staging SSL certificate- CDN enabled - CDN optional- Real traffic - Synthetic/test traffic
Common staging mistakes:❌ Staging uses SQLite, production uses PostgreSQL❌ Staging has different env vars set to "test"❌ Staging skips external service calls❌ Staging runs single container vs production's 3 replicas→ These make staging tests meaningless!Q42: How do you implement ChatOps for deployments?
Section titled “Q42: How do you implement ChatOps for deployments?”Answer:
# ChatOps = Trigger deployments from Slack/Teams commands# "Hey bot, deploy myapp:v1.5 to staging"
# GitHub Actions — triggered by Slack slash commandon: repository_dispatch: types: [slack-deploy]
jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy run: | ENV=${{ github.event.client_payload.environment }} TAG=${{ github.event.client_payload.image_tag }} kubectl set image deployment/myapp app=myapp:$TAG -n $ENV
# Slack bot → GitHub webhook → Trigger workflow# Response: Post deployment status back to Slack channel
# Tools:# - Slack + GitHub Actions# - PagerDuty + Slack for incident response# - Rundeck for operational tasks# - Hubot + custom scriptsQ43: What are self-hosted vs cloud-hosted CI runners?
Section titled “Q43: What are self-hosted vs cloud-hosted CI runners?”Answer:
| Feature | Cloud-Hosted (GitHub-managed) | Self-Hosted |
|---|---|---|
| Cost | Minutes-based billing | Infrastructure cost |
| Maintenance | ❌ Zero | ✅ You manage |
| Security | Ephemeral, isolated | Your responsibility |
| Performance | Standard specs | Custom hardware (GPU etc.) |
| Network access | Public internet | Your VPC/network |
| Docker support | ✅ Built-in | ✅ If configured |
| Best for | Most use cases | GPU jobs, air-gapped, cost savings |
# GitHub Actions — self-hosted runnerruns-on: self-hosted
# Register self-hosted runner# Settings → Actions → Runners → New self-hosted runner# Download runner script, configure, and start
./config.sh --url https://github.com/org/repo \ --token <TOKEN> \ --name my-server \ --labels linux,gpu,high-memory./run.sh # Start listening for jobsQ44: How do you handle database migrations safely in CI/CD?
Section titled “Q44: How do you handle database migrations safely in CI/CD?”Answer:
# Pattern: Run migrations BEFORE deploying new code# Why: New code may expect new schema; old code must still work with new schema
jobs: # Step 1: Migrate DB first migrate-database: runs-on: ubuntu-latest environment: production steps: - name: Run migrations run: | # Run as K8s Job cat <<EOF | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: name: migrate-${{ github.sha }} namespace: production spec: template: spec: containers: - name: migrate image: myapp:${{ github.sha }} command: ["python", "manage.py", "migrate", "--no-input"] env: - name: DATABASE_URL valueFrom: secretKeyRef: name: db-secret key: url restartPolicy: Never EOF kubectl wait --for=condition=complete \ job/migrate-${{ github.sha }} \ -n production \ --timeout=5m
# Step 2: Only deploy after successful migration deploy-app: needs: migrate-database runs-on: ubuntu-latest steps: - run: kubectl apply -f k8s/production/Q45: What is the difference between push-based and pull-based deployment?
Section titled “Q45: What is the difference between push-based and pull-based deployment?”Answer:
| Model | Description | Tools | Security |
|---|---|---|---|
| Push-based | CI pipeline pushes changes to target | Jenkins, GitHub Actions | CI needs cluster credentials |
| Pull-based | Operator in cluster pulls from Git | ArgoCD, Flux | No external credentials needed |
Push-based: GitHub Actions → (has kubectl credentials) → Deploy to K8s cluster Risk: CI system has production access (wider blast radius)
Pull-based (GitOps): GitHub Actions → Update config in Git repo ArgoCD (inside cluster) → Detects change → Applies to cluster Safer: Cluster connects out, not inbound# Push-based (GitHub Actions)- name: Deploy env: KUBECONFIG: ${{ secrets.KUBECONFIG }} run: kubectl apply -f k8s/
# Pull-based (ArgoCD)# ArgoCD application auto-syncs when Git changes# No cluster credentials needed in CIQ46: How do you version APIs in a CI/CD pipeline?
Section titled “Q46: How do you version APIs in a CI/CD pipeline?”Answer:
# API versioning strategies:# 1. URL versioning: /api/v1/users, /api/v2/users# 2. Header versioning: Accept: application/vnd.myapi.v2+json# 3. Query param: /api/users?version=2
# In CI/CD — deploy multiple API versions simultaneously# Blue deployment = v1 API# Green deployment = v2 API# Both run simultaneously during transition period
jobs: deploy-api-v2: runs-on: ubuntu-latest steps: - name: Deploy v2 API (alongside v1) run: | kubectl apply -f k8s/api-v2/deployment.yaml kubectl apply -f k8s/api-v2/service.yaml # Update Ingress to route /api/v2/* to new service kubectl apply -f k8s/ingress-v2.yaml
- name: Test v2 API run: | curl -f https://api.myapp.com/api/v2/health
- name: Update documentation run: | # Auto-generate API docs from code npx swagger-cli validate api-spec.yaml aws s3 cp api-spec.yaml s3://docs-bucket/v2/Q47: What is a Chaos Engineering experiment in CI/CD?
Section titled “Q47: What is a Chaos Engineering experiment in CI/CD?”Answer: Chaos Engineering = Intentionally inject failures to test system resilience.
# Run chaos tests as part of staging pipelinejobs: chaos-tests: needs: deploy-staging runs-on: ubuntu-latest steps: - name: Install chaos tools run: | pip install chaostoolkit pip install chaostoolkit-kubernetes
- name: Run chaos experiment — kill random pod run: | chaos run experiments/kill-pod.json
- name: Verify service is still up run: | sleep 30 # Wait for recovery curl -f https://staging.myapp.com/health # If this fails, system doesn't self-heal!{ "title": "Kill random API pod", "steady-state-hypothesis": { "title": "Service responds to requests", "probes": [{ "name": "service-healthy", "type": "probe", "provider": { "type": "http", "url": "https://staging.myapp.com/health", "timeout": 10 } }] }, "method": [{ "name": "kill-api-pod", "type": "action", "provider": { "type": "python", "module": "chaosk8s.pod.actions", "func": "terminate_pods", "arguments": { "label_selector": "app=api", "ns": "staging" } } }]}Q48: How do you implement dependency updates automation?
Section titled “Q48: How do you implement dependency updates automation?”Answer:
# Dependabot — auto-create PRs for dependency updatesversion: 2updates: - package-ecosystem: npm directory: "/" schedule: interval: weekly # weekly or daily labels: - dependencies open-pull-requests-limit: 10 groups: minor-updates: patterns: ["*"] update-types: ["minor", "patch"]
- package-ecosystem: docker directory: "/" schedule: interval: weekly commit-message: prefix: "chore(docker)"
- package-ecosystem: github-actions directory: "/" schedule: interval: monthly# Auto-merge safe dependency updateson: pull_request: types: [opened, synchronize]
jobs: auto-merge-deps: if: github.actor == 'dependabot[bot]' runs-on: ubuntu-latest steps: - name: Check if minor/patch update id: metadata uses: dependabot/fetch-metadata@v1
- name: Auto-merge if minor/patch if: steps.metadata.outputs.update-type != 'version-update:semver-major' run: gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Q49: How do you implement progressive delivery?
Section titled “Q49: How do you implement progressive delivery?”Answer: Progressive Delivery = Controlled, gradual rollout with automated analysis.
# Flagger — automatic canary analysis and promotionapiVersion: flagger.app/v1beta1kind: Canarymetadata: name: myappspec: targetRef: apiVersion: apps/v1 kind: Deployment name: myapp progressDeadlineSeconds: 120 service: port: 80 analysis: interval: 1m # Check metrics every minute threshold: 5 # Max failed checks before rollback maxWeight: 50 # Max canary traffic % stepWeight: 10 # Increase by 10% each interval metrics: - name: request-success-rate thresholdRange: min: 99 # Must be > 99% success rate interval: 1m - name: request-duration thresholdRange: max: 500 # Must be < 500ms p99 latency interval: 1m webhooks: - name: load-test url: http://flagger-loadtester.test/ timeout: 5s metadata: cmd: "hey -z 1m -q 10 -c 2 http://myapp-canary/"Q50: What are the DORA metrics and how do you measure them?
Section titled “Q50: What are the DORA metrics and how do you measure them?”Answer: DORA (DevOps Research and Assessment) metrics are the 4 key indicators of DevOps performance.
| Metric | Measures | Elite | Low |
|---|---|---|---|
| Deployment Frequency | How often you deploy | Multiple/day | < 1/month |
| Lead Time for Changes | Commit → Production | < 1 hour | > 6 months |
| Change Failure Rate | % failing deployments | < 5% | > 46% |
| MTTR | Time to recover from failure | < 1 hour | > 1 week |
# Measure Deployment Frequency# Count deployments per day from CI/CD tool
# Measure Lead Timegit log --format="%H %ci" HEAD | head -1 # Get commit time# Compare with deployment time in pipeline logs
# Measure Change Failure Rate# (Failed deployments / Total deployments) × 100# Track incidents that were deployment-related
# Measure MTTR# Time from incident created → incident resolved# Track in PagerDuty, OpsGenie, or similar
# Tools that auto-calculate DORA metrics:# - Faros (open-source)# - LinearB# - Cortex# - DORA Team's Four Keys project (GitHub)Back to DevOps Q&A Index