This guide will set you on the path to mastering Continuous Integration and Continuous Delivery/Deployment (CI/CD), covering key concepts, best practices, and real-world examples using popular tools such as Azure DevOps, Jenkins, and GitHub Actions. For more insights and to explore my other repositories or access this post in Portuguese, be sure to visit my GitHub profile at my GitHub.
What is CI/CD?
CI/CD (Continuous Integration / Continuous Delivery or Deployment) is a set of practices that automates software delivery, ensuring every code change is built, tested, and delivered quickly and reliably.
Analogy: Think of a car factory **production line or an automated pizzeria:
- CI: Assembly + quality inspection (build and tests).
- CD: Delivering the product to the customer (deployment to staging or production).
Common Structure of a YAML Pipeline File
A pipeline.yml
file describes, as code, the steps to build, test, and deploy your application. Key components shared by Azure DevOps, Jenkins (Declarative Pipeline), and GitHub Actions:
1. Trigger / Events
Define when the pipeline runs.
- Azure DevOps
trigger:
- main
- GitHub Actions
on:
push:
branches:
- main
pull_request:
branches:
- develop
- Jenkins usually relies on webhooks in the SCM or cron jobs in the
Jenkinsfile
.
2. Agents / Runners / Nodes
Specify where the jobs run (VM, container, physical agent).
- Azure DevOps
pool:
vmImage: 'ubuntu-latest'
- GitHub Actions
runs-on: ubuntu-latest
- Jenkins
agent any
3. Stages / Jobs / Workflows
Split the pipeline into logical phases.
- Azure DevOps:
stages
→jobs
→steps
- GitHub Actions
jobs
→steps
- Jenkins:
stages
→steps
Azure example
stages:
- stage: Build
jobs:
- job: Compile
steps:
- script: npm install && npm run build
Jenkins example
pipeline {
stages {
stage('Build') {
steps {
sh 'npm install && npm run build'
}
}
}
}
GitHub Actions example
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install && npm run build
4. Steps / Tasks / Actions
Actual commands or tasks.
- Scripts (
script
,run
) or predefined tasks (build, deploy, lint). - Azure DevOps: tasks like
UseNode@1
,PublishPipelineArtifact@1
. - GitHub Actions: reusable actions (
actions/checkout@v3
,actions/setup-node@v3
). - Jenkins: steps with
sh
,bat
, or plugins (Maven, Docker, etc.).
GitHub Actions example
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install && npm test
5. Environment Variables / Secrets
Configure env vars and credentials.
- Azure DevOps: inline under
variables:
or via Variable Groups / Key Vault. - GitHub Actions:
env:
or repository secrets (secrets.MY_TOKEN
). - Jenkins:
environment {}
or Jenkins Credentials.
Azure example:
variables:
NODE_ENV: production
6. Artifacts & Caching
Store build outputs or dependencies between stages.
- Azure DevOps:
PublishPipelineArtifact@1
,Cache@2
. - GitHub Actions:
actions/cache@v3
. - Jenkins:
stash/unstash
or cache plugins.
7. Deployments & Approvals
Handle continuous delivery with optional approvals.
- Azure DevOps:
deployment
jobs withenvironment:
and approvals. - GitHub Actions:
environments:
with protection rules and reviewers. - Jenkins: manual stages or integration with release tools.
Azure example:
- stage: Deploy
dependsOn: Build
jobs:
- deployment: DeployToProd
environment: Production
strategy:
runOnce:
deploy:
steps:
- script: ./deploy.sh
General YAML Pipeline Best Practices
- Version the pipeline file in your repo.
- Fail fast (run tests early).
- Keep pipelines short (ideally < 10–15 minutes).
- Use dependency caching.
- Protect secrets and credentials.
- Add gates/approvals for production.
- Reuse templates to avoid duplication.
- Monitor failures and execution times.
Simple Example (Node.js)
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseNode@1
inputs:
version: '18.x'
displayName: 'Install Node.js'
- script: npm install
displayName: 'Install dependencies'
- script: npm run build
displayName: 'Build application'
- script: npm test
displayName: 'Run tests'
- task: PublishPipelineArtifact@1
inputs:
artifactName: 'node-app'
targetPath: '$(Build.ArtifactStagingDirectory)'
displayName: 'Publish artifact'
Simple Example (Python)
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.10'
displayName: 'Use Python 3.10'
- script: |
python -m pip install --upgrade pip
pip install -r requirements.txt
displayName: 'Install dependencies'
- script: pytest
displayName: 'Run tests'
- task: PublishPipelineArtifact@1
inputs:
artifactName: 'python-app'
targetPath: '$(Build.ArtifactStagingDirectory)'
displayName: 'Publish artifact'
Multi-Stage Pipeline (Build → Test → Deploy)
stages:
- stage: Build
jobs:
- job: BuildAndTest
pool: ubuntu-latest
steps:
- script: npm install && npm run build && npm test
- task: PublishPipelineArtifact@1
inputs:
artifactName: 'app-build'
targetPath: '$(Build.ArtifactStagingDirectory)'
- stage: Staging
dependsOn: Build
jobs:
- deployment: DeployToStaging
environment: Staging
strategy:
runOnce:
deploy:
steps:
- download: current
- script: echo "Deploying to Staging..."
- stage: Production
dependsOn: Staging
jobs:
- deployment: DeployToProd
environment: Production
strategy:
runOnce:
deploy:
steps:
- download: current
- script: echo "Deploying to Production..."
(Configure manual or automatic approvals on the environments before deploying to Production.)
Conclusion
CI/CD underpins fast, reliable software delivery. Using YAML pipelines in Azure DevOps (or Jenkins / GitHub Actions) automates the entire development lifecycle, reduces manual errors, and speeds up value delivery.
“A well-tuned pipeline is like a refined production line: fast, safe, and always ready to deliver value to the user.”
Note: This documentation brings together my personal notes and study materials used in my daily work, organized into a single document to share concepts and make them easier to understand for anyone interested.
I hope you find it helpful and valuable for your learning or projects!
Top comments (0)