Continuous Integration and Continuous Deployment (CI/CD) pipelines are essential for delivering software faster, with better quality, and at scale. Integrating Docker and Kubernetes into your CI/CD workflows ensures consistent build environments, seamless containerization, and streamlined deployments to production.
This guide explores how to use Docker in a CI pipeline, steps to build Docker images with GitHub Actions or Jenkins, deploy to Kubernetes, and automate rolling updates for no-downtime deployments.
Table of Contents
- Using Docker in a CI Pipeline
- Building Docker Images with GitHub Actions or Jenkins
- Deploying to Kubernetes
- Automating Rolling Updates
- Final Thoughts
Using Docker in a CI Pipeline
Docker ensures that your CI builds are reproducible by isolating applications and their dependencies within containers.
Why Use Docker in CI?
- Environment Consistency: Builds run the same on local environments, build servers, and production.
- Reproducibility: The same Docker image version can be tested and deployed.
- Speed: Docker caches layers during builds, reducing build times for incremental changes.
- Portability: Docker images can run on any platform where Docker is installed.
Workflow Overview
- Developers push their code to a Git repository.
- CI tools like GitHub Actions or Jenkins build a Docker image directly from the source.
- The image is pushed to a container registry (e.g., Docker Hub, Amazon ECR, or Google Artifact Registry) for distribution.
- The image is deployed to a Kubernetes cluster.
Building Docker Images with GitHub Actions or Jenkins
Using GitHub Actions
GitHub Actions is a native CI/CD solution for automating workflows directly from your GitHub repository.
Sample GitHub Actions Workflow for Building Images:
Create a .github/workflows/docker-image.yml
file:
name: Build and Push Docker Image
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Log in to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: Build Docker Image
run: docker build -t my-docker-image:${{ github.sha }} .
- name: Push Docker Image
run: docker push my-docker-image:${{ github.sha }}
Workflow Explanation:
- Trigger on Push: Runs the pipeline on pushes to the
main
branch. - Docker Login: Uses GitHub Secrets to store Docker credentials securely.
- Build and Push Image: Builds and pushes the Docker image, tagging it with the Git commit SHA.
Using Jenkins
Jenkins is a robust and flexible CI/CD tool with excellent Docker integration.
Sample Jenkins Pipeline for Building Docker Images:
Create a Jenkinsfile
:
pipeline {
agent {
docker {
image 'docker:dind'
}
}
environment {
DOCKER_CREDENTIALS_ID = 'docker-hub-credentials'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Docker Image') {
steps {
script {
sh 'docker build -t my-docker-image:${env.BUILD_ID} .'
}
}
}
stage('Push to Docker Registry') {
steps {
withCredentials([usernamePassword(credentialsId: "${DOCKER_CREDENTIALS_ID}", usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
script {
sh 'echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin'
sh 'docker push my-docker-image:${env.BUILD_ID}'
}
}
}
}
}
}
Workflow Explanation:
- Docker-in-Docker (DinD): Runs Docker within the Jenkins agent.
- Credentials Management: Uses a Jenkins credential ID (
DOCKER_CREDENTIALS_ID
) to protect secrets. - Build and Push: Builds a Docker image and pushes it to Docker Hub.
Deploying to Kubernetes
Once the Docker image is built and pushed to a registry, it needs to be deployed to a Kubernetes cluster.
Creating a Kubernetes Deployment
Below is an example Deployment YAML that pulls the Docker image and deploys it to the cluster.
deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app-container
image: my-docker-image:<TAG>
ports:
- containerPort: 8080
Deploying the Application
To deploy the application to Kubernetes, use kubectl
:
kubectl apply -f deployment.yaml
Monitor the deployment:
kubectl get pods
kubectl describe deployment my-app
Automating Deployment in CI/CD
To deploy automatically after image builds, integrate a kubectl
step into your CI pipeline:
kubectl rollout restart deployment my-app
Diagram of Workflow:
Below is a simplified representation of the CI/CD flow:
Automating Rolling Updates
Rolling updates allow Kubernetes to incrementally update application deployments without causing downtime.
Rolling Update Configuration
Configure the Deployment strategy to use RollingUpdate:
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
This ensures that during an update:
- MaxSurge: A maximum of one extra Pod is allowed temporarily.
- MaxUnavailable: At most, one Pod can be unavailable during the update.
Automating Updates with Image Tags
To trigger an automatic rolling update, update the image version in the Deployment YAML:
spec:
containers:
- name: app-container
image: my-docker-image:new-tag
Use kubectl apply
to initiate the update:
kubectl apply -f deployment.yaml
To check the rollout status:
kubectl rollout status deployment my-app
Rollback to a previous revision in case of failure:
kubectl rollout undo deployment my-app
Final Thoughts
Integrating Docker and Kubernetes into a CI/CD pipeline simplifies the building, testing, and deployment of containerized applications. By automating every stage, from image builds using GitHub Actions or Jenkins to Kubernetes rolling updates, teams can ensure efficient, reproducible, and downtime-free deployments.
Use this guide to start implementing robust CI/CD pipelines tailored to your containerized workloads, and streamline application delivery with Docker and Kubernetes. Bookmark this guide for future reference and deep-dive into automation!
Your detailed article on “CI/CD with Docker and Kubernetes” is ready, covering Docker in CI pipelines, building images with GitHub Actions or Jenkins, deploying to Kubernetes, and automating rolling updates, along with a helpful diagram. Let me know if there’s anything else you’d like to refine or add!