This guide covers integrating Docker with various CI/CD platforms including Jenkins, GitHub Actions, and GitLab CI/CD for automated building, testing, and deployment of containerized applications.
- Docker installed on the CI/CD server or runner
- A Git repository with your application's code and a Dockerfile
- Docker Hub or container registry account
- Appropriate permissions to push/pull images
# Pull Jenkins LTS image
docker pull jenkins/jenkins:lts
# Run Jenkins container with Docker socket mounted
docker run -d \
--name jenkins \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
jenkins/jenkins:ltsAccess Jenkins at http://localhost:8080 and follow the setup wizard.
- Go to Manage Jenkins > Manage Plugins
- Install:
- Pipeline
- Git
- Docker Pipeline
- Docker Build Step
pipeline {
agent any
environment {
DOCKER_IMAGE = "your-dockerhub-username/your-app"
DOCKER_TAG = "${env.BUILD_NUMBER}"
REGISTRY = 'https://index.docker.io/v1/'
CREDENTIALS_ID = 'dockerhub-credentials'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Docker Image') {
steps {
script {
docker.build("${DOCKER_IMAGE}:${DOCKER_TAG}")
docker.build("${DOCKER_IMAGE}:latest")
}
}
}
stage('Run Tests') {
steps {
script {
docker.image("${DOCKER_IMAGE}:${DOCKER_TAG}").inside {
sh '''
echo "Running tests..."
npm test || pytest || go test
'''
}
}
}
}
stage('Security Scan') {
steps {
script {
sh 'docker scout quickview ${DOCKER_IMAGE}:${DOCKER_TAG} || echo "Scout not available, skipping"'
sh 'trivy image ${DOCKER_IMAGE}:${DOCKER_TAG} || echo "Trivy not available, skipping"'
}
}
}
stage('Push to Registry') {
steps {
script {
docker.withRegistry(REGISTRY, CREDENTIALS_ID) {
docker.image("${DOCKER_IMAGE}:${DOCKER_TAG}").push()
docker.image("${DOCKER_IMAGE}:latest").push()
}
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
script {
sh '''
docker stop myapp || true
docker rm myapp || true
docker run -d --name myapp -p 8080:8080 ${DOCKER_IMAGE}:latest
'''
}
}
}
}
post {
always {
echo 'Cleaning up...'
sh 'docker system prune -f'
}
success {
echo 'Pipeline completed successfully!'
}
failure {
echo 'Pipeline failed. Check logs for details.'
}
}
}- Go to Manage Jenkins > Manage Credentials
- Add credentials:
- Kind: Username with password
- Scope: Global
- ID:
dockerhub-credentials - Username: Your Docker Hub username
- Password: Your Docker Hub password or access token
Create .github/workflows/docker.yml:
name: Docker Build and Push
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
DOCKER_IMAGE: your-dockerhub-username/your-app
REGISTRY: docker.io
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.DOCKER_IMAGE }}:buildcache
cache-to: type=registry,ref=${{ env.DOCKER_IMAGE }}:buildcache,mode=max
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.DOCKER_IMAGE }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'- Go to your repository Settings > Secrets and variables > Actions
- Add the following secrets:
DOCKER_USERNAME: Your Docker Hub usernameDOCKER_PASSWORD: Your Docker Hub password or access token
name: Multi-Platform Docker Build
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [linux/amd64, linux/arm64]
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in 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:
context: .
platforms: ${{ matrix.platform }}
push: true
tags: your-dockerhub-username/your-app:latestCreate .gitlab-ci.yml:
stages:
- build
- test
- security
- deploy
variables:
DOCKER_IMAGE: your-dockerhub-username/your-app
DOCKER_TAG: $CI_COMMIT_SHORT_SHA
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $DOCKER_IMAGE:$DOCKER_TAG .
- docker build -t $DOCKER_IMAGE:latest .
- docker push $DOCKER_IMAGE:$DOCKER_TAG
- docker push $DOCKER_IMAGE:latest
only:
- main
- develop
test:
stage: test
image: $DOCKER_IMAGE:$DOCKER_TAG
script:
- echo "Running tests..."
- npm test || pytest || go test
needs:
- build
security:
stage: security
image: aquasec/trivy:latest
script:
- trivy image --severity HIGH,CRITICAL $DOCKER_IMAGE:$DOCKER_TAG
needs:
- build
allow_failure: true
deploy:
stage: deploy
image: docker:latest
services:
- docker:dind
script:
- docker pull $DOCKER_IMAGE:latest
- docker stop myapp || true
- docker rm myapp || true
- docker run -d --name myapp -p 8080:8080 $DOCKER_IMAGE:latest
only:
- main
when: manual- Go to Settings > CI/CD > Variables
- Add the following variables:
CI_REGISTRY_USER: Your Docker Hub usernameCI_REGISTRY_PASSWORD: Your Docker Hub password or access token- Mark them as Masked and Protected
variables:
IMAGE_TAG: $CI_COMMIT_SHORT_SHA
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .
- docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG# Scan local image
trivy image your-image:tag
# Scan with severity threshold
trivy image --severity HIGH,CRITICAL your-image:tag
# Generate SARIF report
trivy image --format sarif --output trivy-results.sarif your-image:tag# Quick view of vulnerabilities
docker scout quickview your-image:tag
# CVEs report
docker scout cves your-image:tag
# Compare two images
docker scout compare your-image:v1.0 your-image:v2.0# Install Snyk
npm install -g snyk
# Authenticate
snyk auth YOUR_TOKEN
# Scan Docker image
snyk container test your-image:tag- Use semantic versioning:
v1.0.0,v1.0.1 - Use Git commit SHA for reproducibility:
abc1234 - Use
latesttag for the most recent stable build - Use branch names for development builds:
develop,feature-xyz
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/main.js"]- Use BuildKit cache mounts
- Implement layer caching in CI/CD
- Use
.dockerignoreto exclude unnecessary files
- Scan images for vulnerabilities before deployment
- Use non-root users in containers
- Minimize image size (use alpine variants)
- Keep base images updated
- Don't include secrets in images
- Use specific image versions, not
latestin production
- Run tests before building images
- Use parallel stages for faster builds
- Implement rollback strategies
- Monitor pipeline performance
- Use infrastructure as code for deployment
- Implement proper notification systems
Solution:
- Check Docker daemon is running
- Verify build context is correct
- Check for syntax errors in Dockerfile
- Ensure all required files are included in build context
Solution:
- Verify credentials are correctly configured
- Check if credentials have expired
- Use access tokens instead of passwords
- Ensure registry URL is correct
Solution:
- Check registry permissions
- Verify image name format
- Ensure sufficient disk space
- Check network connectivity
- Docker Build Documentation
- GitHub Actions Documentation
- GitLab CI/CD Documentation
- Jenkins Pipeline Documentation
- Trivy Documentation
Note
Join Our Telegram Community // Follow me for more DevOps & Cloud content.

