Understanding the CI/CD Workflow: From Development to Production
TLDR: This blog post provides a comprehensive overview of the CI/CD workflow, detailing the process of promoting applications from development to production environments. It covers the roles of various branches, the Jenkins pipeline stages, and best practices for managing different environments in a CI/CD setup.
In today's fast-paced software development landscape, Continuous Integration and Continuous Delivery (CI/CD) play a crucial role in ensuring that applications are delivered efficiently and reliably. This blog post will explore the entire workflow involved in promoting an application from the development environment to production, including the various stages and best practices.
CI/CD is a method used in software development to automate the process of integrating code changes and delivering them to production. This approach allows teams to release software updates more frequently and with higher quality. In previous videos, we have discussed how to create CI/CD pipelines for individual environments using tools like Jenkins, GitHub Actions, and GitLab. However, this post will focus on the complete workflow across multiple environments.
The CI/CD Workflow Explained
Initial Code Changes
When a developer makes code changes in a feature branch within a version control system like GitHub, a webhook triggers the CI/CD pipeline. This pipeline is typically managed by Jenkins and follows a series of stages:
Code Checkout: The pipeline checks out the code from the feature branch.
Build and Unit Testing: The application is built using a build tool (e.g., Maven for Java applications) and unit tests are executed.
Code Scanning: Tools like SonarQube are used to analyze the code for quality issues, such as static code analysis and duplicate code.
Image Build Creation: A container image is created using Docker or similar tools.
Image Scanning: The created image is scanned for vulnerabilities using tools like Trivy or Clair.
Pushing the Image: The final image is pushed to an image registry (e.g., Docker Hub).
Promoting Changes to Staging
Once the image is ready, the next step is to update the Kubernetes manifests (e.g., deployment.yaml
) to reflect the new image version. It is a good practice to maintain these manifests in a separate repository. After updating the manifests, the changes are deployed to the staging environment using tools like Argo CD or Flux.
Branching Strategy
Understanding the branching strategy is key to managing the CI/CD workflow effectively. In an ideal scenario, the following branches are typically used:
Feature Branches: Multiple feature branches are created for different enhancements or bug fixes.
Main Branch: This branch contains the active development code and is where features are merged after testing.
Release Branches: These branches are created for preparing a new release version of the application.
Hotfix Branches: Used for urgent fixes to production issues, these branches allow developers to address critical bugs quickly.
Moving from Development to Production
The process of promoting code from development to production involves several steps:
Feature Branch to Main Branch: Once a feature is complete, it is merged into the main branch, triggering a new Jenkins pipeline that deploys the code to the staging environment.
Staging Environment: In this environment, the QA team conducts thorough testing, including manual tests and automated regression tests. This phase is crucial for ensuring that the application is stable and ready for release.
Creating a Release Branch: After successful testing, a release branch is created from the main branch. A release pipeline is triggered to deploy the application to a pre-production environment.
Pre-Production Testing: This environment is used for final testing before production. It allows teams to verify that everything works as expected and to debug any issues that may arise.
Production Deployment: Once all tests are passed and the application is confirmed to be stable, the final deployment to the production environment occurs.
Best Practices for CI/CD Workflows
Separate Environments: It is advisable to maintain separate Kubernetes clusters for development, staging, pre-production, and production environments to ensure isolation and security.
Automated Testing: Incorporate automated tests at various stages of the pipeline to catch issues early and reduce manual testing efforts.
Monitoring and Feedback: Implement monitoring tools to track application performance and gather feedback from users to continuously improve the application.
Your workflow follows a structured Git Flow with CI/CD using Jenkins, ArgoCD, and Amazon EKS. Hereโs how each step plays out in detail:
๐ Multi-Branch CI/CD Flow with Jenkins & ArgoCD
1๏ธโฃ Feature Development (Feature Branch CI/CD)
Process:
Developer creates a feature branch (
feature-xyz
) frommain
.Code is written, committed, and pushed to the feature branch.
Jenkins CI/CD pipeline triggers:
Runs unit tests, linting, and security scans.
Builds the Docker image and pushes it to Amazon ECR.
Updates the Kubernetes manifests (YAML/Helm) in the feature branch's Git repo.
ArgoCD detects changes in the feature branch repository and deploys the feature to EKS for testing.
Feature is tested and verified.
โ Outcome: Feature branch deployed to EKS for testing.
2๏ธโฃ Merging to Main (Main Branch CI/CD)
Process:
Once testing is complete, the feature branch is merged into the
main
branch.Jenkins CI/CD pipeline triggers:
Runs tests and builds the latest Docker image.
Pushes the new image to Amazon ECR.
Updates the Kubernetes manifests in the main branchโs Git repo.
ArgoCD detects the change in the main branch and deploys it to EKS.
The updated application is now running in the staging or pre-production environment.
โ
Outcome: main
branch is deployed to EKS for staging/pre-production.
3๏ธโฃ Releasing to Production (Release Branch CI/CD)
Process:
A release branch (
release-vX.Y.Z
) is created frommain
.Jenkins CI/CD pipeline triggers again:
Runs all CI/CD checks.
Builds and pushes a final production image to Amazon ECR.
Updates Kubernetes manifests in the release branchโs Git repo.
ArgoCD detects the release branch update and deploys the release to EKS (production environment).
โ
Outcome: release
branch is deployed to EKS (production).
๐น How to Set Up Jenkins for This Workflow?
In your Jenkinsfile, modify the pipeline to check the branch name and trigger the appropriate steps.
pipeline {
agent any
environment {
DOCKER_IMAGE = "my-app:${GIT_BRANCH}-${BUILD_NUMBER}"
ECR_REGISTRY = "123456789012.dkr.ecr.us-east-1.amazonaws.com"
GIT_REPO = "git@github.com:user/k8s-config-repo.git"
}
stages {
stage('Checkout Code') {
steps {
git branch: env.BRANCH_NAME, url: 'https://github.com/user/app-repo.git'
}
}
stage('Run Tests') {
steps {
sh 'npm install && npm test'
}
}
stage('Build & Push Docker Image') {
steps {
script {
def imageTag = "${ECR_REGISTRY}/my-app:${GIT_BRANCH}-${BUILD_NUMBER}"
sh "docker build -t ${imageTag} ."
sh "docker push ${imageTag}"
}
}
}
stage('Update Kubernetes Manifest') {
steps {
script {
sh '''
git clone ${GIT_REPO} k8s-config
cd k8s-config
sed -i 's|image: .*|image: ${ECR_REGISTRY}/my-app:${GIT_BRANCH}-${BUILD_NUMBER}|' deployment.yaml
git config --global user.email "jenkins@example.com"
git config --global user.name "jenkins"
git add deployment.yaml
git commit -m "Deploy ${GIT_BRANCH}-${BUILD_NUMBER} to k8s"
git push origin ${GIT_BRANCH}
'''
}
}
}
}
post {
success {
echo "Deployment manifest updated! ArgoCD will detect and deploy changes."
}
}
}
๐น How to Configure ArgoCD for Multi-Branch Deployment?
Create three ArgoCD applications for:
Feature branch (
feature-*
pattern)Main branch (
main
)Release branch (
release-*
pattern)
Example ArgoCD Application YAML for
main
branch:apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: my-app-main namespace: argocd spec: project: default source: repoURL: 'git@github.com:user/k8s-config-repo.git' targetRevision: main path: 'k8s/' destination: server: 'https://kubernetes.default.svc' namespace: staging syncPolicy: automated: prune: true selfHeal: true
Similarly, configure ArgoCD applications for
feature-*
andrelease-*
branches.
๐น Summary of the CI/CD Process
Step | Trigger | CI/CD Actions (Jenkins) | CD Actions (ArgoCD) |
Feature Branch (feature-xyz ) | Code commit to feature-* | Test, Build, Push Image, Update Git | Deploy feature branch to EKS (dev/testing) |
Merge to Main (main ) | Feature branch merged | Test, Build, Push Image, Update Git | Deploy main branch to EKS (staging) |
Release Branch (release-vX.Y.Z ) | Release branch created | Test, Build, Push Image, Update Git | Deploy release branch to EKS (production) |
๐น Key Benefits
โ
Branch-based deployments for separate dev, staging, and production environments.
โ
Automated testing, building, and deploying using Jenkins & ArgoCD.
โ
Full GitOps workflow โ No manual intervention, only Git changes trigger deployments.
โ
Rollback available โ Since everything is in Git, you can easily revert to a previous version.
๐น Pipeline Breakdown
1๏ธโฃ Define the Pipeline and Agent
pipeline {
agent any
pipeline {}
โ Declares this as a Jenkins declarative pipeline.agent any
โ Runs the pipeline on any available Jenkins agent (worker node).
2๏ธโฃ Define Environment Variables
environment {
DOCKER_IMAGE = "my-app:${GIT_BRANCH}-${BUILD_NUMBER}"
ECR_REGISTRY = "123456789012.dkr.ecr.us-east-1.amazonaws.com"
GIT_REPO = "git@github.com:user/k8s-config-repo.git"
}
DOCKER_IMAGE
โ Sets the Docker image name using:GIT_BRANCH
โ The current branch name.BUILD_NUMBER
โ The unique build number from Jenkins.Example:
"my-app:feature-branch-25"
ECR_REGISTRY
โ Amazon Elastic Container Registry (ECR) URL where the image will be stored.GIT_REPO
โ The GitHub repository containing Kubernetes YAML manifests.
๐น Stages of the Pipeline
3๏ธโฃ Checkout the Code
stages {
stage('Checkout Code') {
steps {
git branch: env.BRANCH_NAME, url: 'https://github.com/user/app-repo.git'
}
}
stage('Checkout Code')
โ Retrieves the source code from the Git repository.git branch: env.BRANCH_NAME, url: '
https://github.com/user/app-repo.git
'
Clones the repo using the current branch (
BRANCH_NAME
).Ensures the latest code is available for testing & building.
4๏ธโฃ Run Tests
stage('Run Tests') {
steps {
sh 'npm install && npm test'
}
}
stage('Run Tests')
โ Runs unit tests to ensure code correctness.sh 'npm install && npm test'
Installs project dependencies (
npm install
).Runs unit tests (
npm test
).
If tests fail, the pipeline stops.
5๏ธโฃ Build & Push Docker Image
stage('Build & Push Docker Image') {
steps {
script {
def imageTag = "${ECR_REGISTRY}/my-app:${GIT_BRANCH}-${BUILD_NUMBER}"
sh "docker build -t ${imageTag} ."
sh "docker push ${imageTag}"
}
}
}
stage('Build & Push Docker Image')
โ Builds and pushes the Docker image to Amazon ECR.def imageTag = "${ECR_REGISTRY}/my-app:${GIT_BRANCH}-${BUILD_NUMBER}"
- Constructs the image tag dynamically.
docker build -t ${imageTag} .
- Builds the Docker image from the current directory (
.
).
- Builds the Docker image from the current directory (
docker push ${imageTag}
- Pushes the image to ECR, making it available for deployment.
6๏ธโฃ Update Kubernetes Manifest
stage('Update Kubernetes Manifest') {
steps {
script {
sh '''
git clone ${GIT_REPO} k8s-config
cd k8s-config
sed -i 's|image: .*|image: ${ECR_REGISTRY}/my-app:${GIT_BRANCH}-${BUILD_NUMBER}|' deployment.yaml
git config --global user.email "jenkins@example.com"
git config --global user.name "jenkins"
git add deployment.yaml
git commit -m "Deploy ${GIT_BRANCH}-${BUILD_NUMBER} to k8s"
git push origin ${GIT_BRANCH}
'''
}
}
}
stage('Update Kubernetes Manifest')
โ Updates the Kubernetes deployment manifest with the new Docker image.git clone ${GIT_REPO} k8s-config
โ Clones the Kubernetes configuration repo (k8s-config
).cd k8s-config
โ Moves into the repo.sed -i 's|image: .*|image: ${ECR_REGISTRY}/my-app:${GIT_BRANCH}-${BUILD_NUMBER}|' deployment.yaml
Replaces the
image:
field indeployment.yaml
with the new Docker image.Example change:
Before: image: my-app:old-tag After: image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:feature-25
Git Configuration:
git config --global user.email "jenkins@example.com" git config --global user.name "jenkins"
- Sets the Git identity for Jenkins.
Git Commit & Push:
git add deployment.yaml git commit -m "Deploy ${GIT_BRANCH}-${BUILD_NUMBER} to k8s" git push origin ${GIT_BRANCH}
Commits the updated Kubernetes manifest to the repo.
Pushes it to the same branch in
k8s-config-repo
.
๐น ArgoCD Automatically Deploys Changes
ArgoCD watches the
k8s-config-repo
for changes.Since
deployment.yaml
is updated & committed, ArgoCD detects the new image and deploys it to Amazon EKS.
7๏ธโฃ Post-Build Success Message
post {
success {
echo "Deployment manifest updated! ArgoCD will detect and deploy changes."
}
}
}
post { success {}
โ Runs after a successful build.echo
โ Displays a confirmation message in Jenkins logs.
๐น Summary of the Pipeline Execution
Stage | Action |
Checkout Code | Pulls latest code from GitHub |
Run Tests | Installs dependencies, runs tests |
Build & Push Docker Image | Builds & pushes Docker image to Amazon ECR |
Update Kubernetes Manifest | Updates deployment.yaml with new image |
ArgoCD Deployment | ArgoCD detects the changes and deploys to EKS |
๐น Key Benefits
โ
Automated CI/CD โ No manual intervention needed.
โ
ArgoCD ensures GitOps workflow โ Deployments are triggered by Git commits.
โ
Rollback support โ If needed, revert the Kubernetes manifest to a previous commit.
โ
Multi-branch support โ The pipeline works for feature, main, and release branches.
Hereโs an improved version of your Jenkins + ArgoCD CI/CD pipeline with best practices applied:
๐น Key Improvements
โ
Uses Jenkins credentials store for security.
โ
Uses Helm for Kubernetes deployment (instead of editing YAML files manually).
โ
Adds Slack notifications for visibility.
โ
Uses multi-stage Docker builds for optimization.
โ
Adds error handling and rollback capabilities.
๐น Improved Multibranch, Multistage Jenkins Pipeline
pipeline {
agent any
environment {
ECR_REGISTRY = credentials('ECR_CREDENTIALS_ID') // Securely fetch ECR URL
GIT_REPO = credentials('GIT_REPO_CREDENTIALS_ID') // Securely fetch Git URL
IMAGE_TAG = "my-app:${BRANCH_NAME}-${BUILD_NUMBER}"
SLACK_CHANNEL = "#deployments"
}
stages {
stage('Checkout Code') {
steps {
git branch: env.BRANCH_NAME, url: 'https://github.com/user/app-repo.git'
}
}
stage('Run Tests') {
steps {
sh 'npm install && npm test'
}
}
stage('Build & Push Docker Image') {
steps {
script {
def imageTag = "${ECR_REGISTRY}/my-app:${BRANCH_NAME}-${BUILD_NUMBER}"
sh """
echo "๐น Logging into ECR..."
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${ECR_REGISTRY}
echo "๐น Building Docker Image..."
docker build -t ${imageTag} .
echo "๐น Pushing Image to ECR..."
docker push ${imageTag}
"""
}
}
}
stage('Deploy Using Helm') {
steps {
script {
sh """
echo "๐น Cloning Kubernetes Config Repository..."
git clone ${GIT_REPO} k8s-config
cd k8s-config
echo "๐น Updating Helm Values File..."
sed -i 's|imageTag: .*|imageTag: ${BRANCH_NAME}-${BUILD_NUMBER}|' values.yaml
echo "๐น Committing Changes to Git..."
git config --global user.email "jenkins@example.com"
git config --global user.name "jenkins"
git add values.yaml
git commit -m "Deploy ${BRANCH_NAME}-${BUILD_NUMBER} to EKS"
git push origin ${BRANCH_NAME}
echo "๐น Deploying Using Helm..."
helm upgrade --install my-app ./helm-chart --set image.tag=${BUILD_NUMBER}
"""
}
}
}
}
post {
success {
script {
slackSend(channel: SLACK_CHANNEL, message: "โ
Deployment successful: ${BRANCH_NAME}-${BUILD_NUMBER}")
}
}
failure {
script {
slackSend(channel: SLACK_CHANNEL, message: "โ Deployment failed: ${BRANCH_NAME}-${BUILD_NUMBER}")
}
}
}
}
๐น Whatโs Improved?
๐น 1. Secure Credentials Management
Uses
credentials('ECR_CREDENTIALS_ID')
instead of hardcoded values.Prevents security leaks (no exposed AWS keys in logs).
๐น 2. Helm Deployment Instead of YAML Edits
Instead of manually editing
deployment.yaml
, it updatesvalues.yaml
.Command:
helm upgrade --install my-app ./helm-chart --set image.tag=${BUILD_NUMBER}
More scalable & flexible than raw YAML files.
๐น 3. Multi-Stage Docker Build
- Reduces image size by installing dependencies separately.
๐น 4. Slack Notifications for Visibility
Sends messages for both success & failure cases.
Helps DevOps teams monitor deployments instantly.
๐น Summary
โ
Industry best practices applied
โ
Secure, scalable, and easy to maintain
โ
Automated GitOps workflow with Helm & ArgoCD
โ
Real-time deployment status via Slack
๐ Implementing Canary Deployments with Jenkins, ArgoCD & Helm
๐น Canary Deployments help deploy new versions gradually to a subset of users before full rollout.
๐น Weโll modify our Jenkins pipeline & Kubernetes deployment to enable traffic splitting for canary releases.
๐น How Canary Deployment Works
1๏ธโฃ Deploy a new version (canary) alongside the stable version in Kubernetes.
2๏ธโฃ Route a small percentage of traffic (e.g., 10%) to the canary version.
3๏ธโฃ Monitor logs & performance metrics (if issues occur, rollback).
4๏ธโฃ If stable, gradually increase traffic until 100% is on the new version.
๐น Updated Jenkins Pipeline (with Canary Deployment)
pipeline {
agent any
environment {
ECR_REGISTRY = credentials('ECR_CREDENTIALS_ID')
GIT_REPO = credentials('GIT_REPO_CREDENTIALS_ID')
IMAGE_TAG = "my-app:${BRANCH_NAME}-${BUILD_NUMBER}"
SLACK_CHANNEL = "#deployments"
}
stages {
stage('Checkout Code') {
steps {
git branch: env.BRANCH_NAME, url: 'https://github.com/user/app-repo.git'
}
}
stage('Run Tests') {
steps {
sh 'npm install && npm test'
}
}
stage('Build & Push Docker Image') {
steps {
script {
def imageTag = "${ECR_REGISTRY}/my-app:${BRANCH_NAME}-${BUILD_NUMBER}"
sh """
echo "๐น Logging into ECR..."
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${ECR_REGISTRY}
echo "๐น Building Docker Image..."
docker build -t ${imageTag} .
echo "๐น Pushing Image to ECR..."
docker push ${imageTag}
"""
}
}
}
stage('Deploy Canary Version Using Helm') {
steps {
script {
sh """
echo "๐น Cloning Kubernetes Config Repository..."
git clone ${GIT_REPO} k8s-config
cd k8s-config
echo "๐น Updating Helm Values for Canary..."
sed -i 's|imageTag: .*|imageTag: ${BRANCH_NAME}-${BUILD_NUMBER}|' values-canary.yaml
echo "๐น Committing Canary Changes to Git..."
git config --global user.email "jenkins@example.com"
git config --global user.name "jenkins"
git add values-canary.yaml
git commit -m "Deploy Canary ${BRANCH_NAME}-${BUILD_NUMBER}"
git push origin ${BRANCH_NAME}
echo "๐น Deploying Canary Version Using Helm..."
helm upgrade --install my-app-canary ./helm-chart --set image.tag=${BUILD_NUMBER} --set replicaCount=2 --set trafficWeight=10
"""
}
}
}
stage('Monitor Canary Traffic & Scale') {
steps {
script {
sh """
echo "๐น Checking Canary Logs & Metrics..."
sleep 60 # Simulating monitoring (replace with real monitoring)
echo "๐น Scaling Canary to 50% Traffic..."
helm upgrade --install my-app-canary ./helm-chart --set trafficWeight=50
sleep 60 # Simulating monitoring again
echo "๐น Moving 100% Traffic to New Version..."
helm upgrade --install my-app ./helm-chart --set image.tag=${BUILD_NUMBER}
helm delete my-app-canary # Remove the canary after success
"""
}
}
}
}
post {
success {
script {
slackSend(channel: SLACK_CHANNEL, message: "โ
Canary Deployment successful: ${BRANCH_NAME}-${BUILD_NUMBER}")
}
}
failure {
script {
slackSend(channel: SLACK_CHANNEL, message: "โ Canary Deployment failed! Rolling back...")
sh "helm rollback my-app 0" // Rollback to the previous stable version
}
}
}
}
๐น Kubernetes Changes for Canary Deployment
Modify your Helm chart (values-canary.yaml
) to define canary deployment strategy:
replicaCount: 2
image:
repository: "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app"
tag: "latest"
trafficWeight: 10 # Canary gets 10% of traffic initially
service:
name: "my-app"
port: 80
ingress:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "{{ .Values.trafficWeight }}"
๐น How This Works
โ
Deploys a canary version with 10% traffic.
โ
Waits for logs & performance validation (simulated with sleep 60
).
โ
Gradually increases traffic (50% โ 100%).
โ
Removes the canary after success.
โ
Rolls back if failure is detected.
๐ Why This is Best Practice?
โ Safer Deployments โ Catch issues before full rollout.
โ Automatic Rollbacks โ No manual intervention needed.
โ Traffic Gradually Shifted โ Avoids breaking production.
โ ArgoCD + Helm Automation โ Fully GitOps compatible.
๐ Adding Monitoring with Prometheus & Grafana to Jenkins + ArgoCD + EKS ๐
๐น Why Monitor Canary Deployments?
โ๏ธ Detect issues early before full rollout.
โ๏ธ Visualize CPU, memory, request latency, and error rates.
โ๏ธ Automatically rollback if thresholds are exceeded.
๐น Step 1: Install Prometheus & Grafana in EKS
We'll deploy Prometheus Operator (for metrics collection) and Grafana (for visualization).
1๏ธโฃ Install Prometheus Operator Using Helm
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace
๐น Step 2: Expose Metrics in Application
Your Node.js app (or other services) must expose Prometheus-compatible metrics.
๐ Example: Exposing Metrics in Express.js
Install Prometheus middleware:
npm install prom-client express-prometheus-middleware
Add this to your server file (server.js
):
const express = require('express');
const promMid = require('express-prometheus-middleware');
const app = express();
app.use(promMid({
metricsPath: '/metrics',
collectDefaultMetrics: true,
}));
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(3000, () => console.log('Server running on port 3000'));
๐ Now, the app exposes /metrics
, and Prometheus can scrape it.
๐น Step 3: Configure Prometheus to Scrape Application
Modify Prometheus scrape config in values.yaml
:
scrape_configs:
- job_name: 'my-app'
static_configs:
- targets: ['my-app.default.svc.cluster.local:3000']
Apply changes:
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
--set serverFiles.prometheus.yml.scrape_configs[0].job_name=my-app \
--set serverFiles.prometheus.yml.scrape_configs[0].static_configs[0].targets[0]=my-app.default.svc.cluster.local:3000 \
--namespace monitoring
๐น Step 4: Install Grafana & Create Dashboards
Grafana is included in kube-prometheus-stack
, so we just need to log in and create dashboards.
๐น Get Grafana Credentials
kubectl get secret -n monitoring prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode
๐น Access Grafana
kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring
๐น Login at http://localhost:3000 using:
Username:
admin
Password: (from command above)
๐น Add Prometheus as a Data Source
Go to Grafana โ Configuration โ Data Sources.
Add Prometheus with URL:
http://prometheus-server.monitoring.svc.cluster.local:80
.
๐น Import a Prebuilt Dashboard
Go to Create โ Import
Use Dashboard ID: 315 (Kubernetes Cluster Monitoring).
Click Import and View Metrics! ๐
๐น Step 5: Automate Rollbacks Based on Metrics
Modify Jenkins pipeline to rollback if error rate > 5%.
๐ Update Jenkins Pipeline
Add a monitoring stage:
stage('Monitor Canary Traffic & Rollback if Needed') {
steps {
script {
def errorRate = sh(script: '''
curl -s "http://prometheus-server.monitoring.svc.cluster.local:9090/api/v1/query?query=rate(http_requests_total{status=~'5.*'}[5m])"
''', returnStdout: true).trim()
echo "Current Error Rate: ${errorRate}"
if (errorRate.toDouble() > 5.0) {
echo "โ High error rate detected! Rolling back deployment..."
sh "helm rollback my-app 0"
slackSend(channel: SLACK_CHANNEL, message: "โ Rollback triggered! Canary Deployment failed.")
error("Deployment Failed: Rolling Back.")
}
}
}
}
๐น Summary: What We Achieved
โ
Prometheus installed & scraping app metrics.
โ
Grafana configured to visualize errors, latency, CPU usage, etc.
โ
Jenkins auto-rollbacks canary deployment if error rate > 5%.
๐ Enhancing Monitoring & Scaling: Slack Alerts, Auto-scaling, and Logging with Loki
๐น What Weโll Do:
โ๏ธ Send Slack Alerts for high CPU/memory usage or errors.
โ๏ธ Auto-scale Pods based on Prometheus metrics.
โ๏ธ Integrate Loki for centralized logging & debugging.
1๏ธโฃ Slack Alerts for High CPU & Errors ๐จ
๐น Step 1: Create a Slack Webhook
Go to Slack API Apps โ Create New App.
Enable Incoming Webhooks and create a webhook URL.
Copy the URL (e.g.,
https://hooks.slack.com/services/T0000/B0000/XXXX
).
๐น Step 2: Configure Alertmanager in Prometheus
Modify Alertmanager Config (values.yaml
in Prometheus Helm chart):
alertmanager:
config:
receivers:
- name: 'slack'
slack_configs:
- channel: '#alerts'
send_resolved: true
username: 'AlertManager'
icon_emoji: ':alert:'
webhook_url: 'https://hooks.slack.com/services/T0000/B0000/XXXX'
route:
receiver: 'slack'
group_by: ['alertname']
group_wait: 10s
repeat_interval: 1h
Apply the changes:
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack -n monitoring
2๏ธโฃ Auto-Scale Pods Based on Prometheus Metrics ๐
๐น Step 1: Install the Kubernetes Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
๐น Step 2: Deploy the Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Scale if CPU > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80 # Scale if Memory > 80%
Apply the autoscaler:
kubectl apply -f hpa.yaml
3๏ธโฃ Logging with Loki for Debugging ๐ต๏ธ
๐น Step 1: Install Loki and Promtail
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm upgrade --install loki grafana/loki-stack \
--set grafana.enabled=true \
--set promtail.enabled=true \
--namespace logging --create-namespace
๐น Step 2: Configure Promtail to Collect Logs
Modify Promtail Config (values.yaml
):
promtail:
config:
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: my-app
Apply changes:
helm upgrade --install loki grafana/loki-stack -n logging
๐น Step 3: View Logs in Grafana
Open Grafana:
kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring
Add Loki as Data Source in Grafana.
Use query:
{app="my-app"} |= "error"
๐ Now, you can filter logs directly from Grafana! ๐
๐ Enhancing Monitoring & Scaling: Slack Alerts, Auto-scaling, and Logging with Loki
๐น What Weโll Do:
โ๏ธ Send Slack Alerts for high CPU/memory usage or errors.
โ๏ธ Auto-scale Pods based on Prometheus metrics.
โ๏ธ Integrate Loki for centralized logging & debugging.
1๏ธโฃ Slack Alerts for High CPU & Errors ๐จ
๐น Step 1: Create a Slack Webhook
Go to Slack API Apps โ Create New App.
Enable Incoming Webhooks and create a webhook URL.
Copy the URL (e.g.,
https://hooks.slack.com/services/T0000/B0000/XXXX
).
๐น Step 2: Configure Alertmanager in Prometheus
Modify Alertmanager Config (values.yaml
in Prometheus Helm chart):
alertmanager:
config:
receivers:
- name: 'slack'
slack_configs:
- channel: '#alerts'
send_resolved: true
username: 'AlertManager'
icon_emoji: ':alert:'
webhook_url: 'https://hooks.slack.com/services/T0000/B0000/XXXX'
route:
receiver: 'slack'
group_by: ['alertname']
group_wait: 10s
repeat_interval: 1h
Apply the changes:
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack -n monitoring
2๏ธโฃ Auto-Scale Pods Based on Prometheus Metrics ๐
๐น Step 1: Install the Kubernetes Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
๐น Step 2: Deploy the Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Scale if CPU > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80 # Scale if Memory > 80%
Apply the autoscaler:
kubectl apply -f hpa.yaml
3๏ธโฃ Logging with Loki for Debugging ๐ต๏ธ
๐น Step 1: Install Loki and Promtail
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm upgrade --install loki grafana/loki-stack \
--set grafana.enabled=true \
--set promtail.enabled=true \
--namespace logging --create-namespace
๐น Step 2: Configure Promtail to Collect Logs
Modify Promtail Config (values.yaml
):
promtail:
config:
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: my-app
Apply changes:
helm upgrade --install loki grafana/loki-stack -n logging
๐น Step 3: View Logs in Grafana
Open Grafana:
kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring
Add Loki as Data Source in Grafana.
Use query:
{app="my-app"} |= "error"
๐ Now, you can filter logs directly from Grafana! ๐
Conclusion
The CI/CD workflow is a vital component of modern software development, enabling teams to deliver high-quality applications efficiently. By understanding the various stages involved in promoting code from development to production and adhering to best practices, organizations can enhance their deployment processes and improve overall software quality. If you have any questions or feedback, feel free to reach out in the comments section. Thank you for reading!