Skip to content

Docker_ci_cd

Chapter 15: Docker in CI/CD - Building, Testing, and Deploying Containers

Section titled “Chapter 15: Docker in CI/CD - Building, Testing, and Deploying Containers”
  1. Introduction to CI/CD with Docker
  2. Why Use Docker in CI/CD
  3. CI/CD Pipeline Overview
  4. Building Docker Images in CI/CD
  5. Testing Containers
  6. Docker Registry Integration
  7. Image Tagging Strategies
  8. Deployment Strategies
  9. Security Scanning in CI/CD
  10. GitOps with Docker
  11. Hands-on Lab
  12. Summary

Continuous Integration and Continuous Deployment (CI/CD) is a methodology that automates the building, testing, and deployment of applications. Docker plays a crucial role in modern CI/CD pipelines.

┌─────────────────────────────────────────────────────────────────────────────┐
│ CI/CD PIPELINE OVERVIEW │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Code │───▶│ Build │───▶│ Test │───▶│ Deploy │ │
│ │ Commit │ │ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ CI (Continuous Integration): │
│ ─────────────────────────── │
│ • Automated builds on code commit │
│ • Automated testing │
│ • Code quality checks │
│ │
│ CD (Continuous Delivery/Deployment): │
│ ─────────────────────────────────── │
│ • Automated deployment to staging │
│ • Automated deployment to production │
│ • Rollback capabilities │
│ │
│ Where Docker Fits: │
│ ────────────────── │
│ • Build: Package application in containers │
│ • Test: Run tests in isolated containers │
│ • Deploy: Deploy containerized applications │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ DOCKER IN CI/CD │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CI/CD Pipeline with Docker │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Code │ │ Build │ │ Test │ │ Stage │ │ Deploy │ │ │
│ │ │ Commit │ │ Image │ │ │ │ Image │ │ to Prod │ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ │ │ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ ▼ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ GitHub │ │ Docker │ │ Container│ │Registry │ │ K8s/ │ │ │
│ │ │Actions │ │ Build │ │ Testing │ │ (ECR, │ │ Docker │ │ │
│ │ │Jenkins │ │ │ │ │ │DockerHub)│ │ Swarm │ │ │
│ │ │GitLab CI│ │ │ │ │ │ │ │ │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ │ Benefits: │ │
│ │ • Consistent build environment │ │
│ │ • Isolated testing │ │
│ │ • Same artifacts from dev to production │ │
│ │ • Fast rollbacks │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│ BENEFITS OF DOCKER IN CI/CD │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. CONSISTENCY │
│ ────────────── │
│ • Same environment from local dev to production │
│ • Eliminates "works on my machine" issues │
│ • Reproducible builds │
│ │
│ 2. ISOLATION │
│ ────────── │
│ • Tests run in clean containers │
│ • No dependency conflicts │
│ • Parallel test execution │
│ │
│ 3. SPEED │
│ ────── │
│ • Faster provisioning of test environments │
│ • Cached layers speed up builds │
│ • Parallel execution │
│ │
│ 4. SCALABILITY │
│ ─────────── │
│ • Easy to scale up test runners │
│ • Container-based parallelization │
│ • Resource isolation │
│ │
│ 5. PORTABILITY │
│ ─────────── │
│ • Works on any CI/CD platform │
│ • Cloud-agnostic │
│ • Same workflow everywhere │
│ │
│ 6. REPRODUCIBILITY │
│ ───────────────── │
│ • Exact same artifacts │
│ • Version-controlled infrastructure │
│ • Audit trails │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│ COMPLETE CI/CD PIPELINE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ STAGE 1: SOURCE │ │
│ │ ───────────────── │ │
│ │ • Code checkout │ │
│ │ • Dependency resolution │ │
│ │ • Secret injection │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ STAGE 2: BUILD │ │ │
│ │ │ ─────────────── │ │ │
│ │ │ • Build application code │ │ │
│ │ │ • Build Docker image │ │ │
│ │ │ • Run linters │ │ │
│ │ │ • Security scan │ │ │
│ │ │ • Push to registry │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ STAGE 3: TEST │ │ │
│ │ │ ─────────────── │ │ │
│ │ │ • Unit tests │ │ │
│ │ │ • Integration tests │ │ │
│ │ │ • End-to-end tests │ │ │
│ │ │ • Performance tests │ │ │
│ │ │ • Security tests │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ STAGE 4: DEPLOY │ │ │
│ │ │ ─────────────── │ │ │
│ │ │ • Deploy to staging │ │ │
│ │ │ • Integration tests │ │ │
│ │ │ • Deploy to production │ │ │
│ │ │ • Health checks │ │ │
│ │ │ • Smoke tests │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

Terminal window
# Simple build
docker build -t myapp:latest .
# Build with specific Dockerfile
docker build -f Dockerfile.prod -t myapp:latest .
# Build with build arguments
docker build --build-arg VERSION=1.0.0 -t myapp:latest .
# Build with labels
docker build --label version=1.0.0 --label environment=ci -t myapp:latest .
# Dockerfile - Multi-stage build
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]
name: Build and Push Docker Image
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
Set up Docker Buildx
uses - name:: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: myregistry/myapp
tags: |
type=ref,event=branch
type=sha,prefix=
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
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=gha
cache-to: type=gha,mode=max
.gitlab-ci.yml
stages:
- build
- test
- deploy
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build:
stage: build
image: docker:24-dind
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
test:
stage: test
image: $IMAGE_TAG
script:
- npm test
- npm run test:integration
deploy:
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- kubectl set image deployment/myapp myapp=$IMAGE_TAG
only:
- main
// Jenkinsfile
pipeline {
agent any
environment {
REGISTRY = 'docker.io'
IMAGE_NAME = 'myapp'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
script {
def tag = "${env.BUILD_NUMBER}"
env.IMAGE_TAG = "${IMAGE_NAME}:${tag}"
}
sh "docker build -t ${env.IMAGE_TAG} ."
}
}
stage('Test') {
steps {
sh "docker run --rm ${env.IMAGE_TAG} npm test"
}
}
stage('Push') {
steps {
withCredentials([usernamePassword(credentialsId: 'docker-hub', usernameVariable: 'USER', passwordVariable: 'PASS')]) {
sh """
docker login -u ${USER} -p ${PASS} ${REGISTRY}
docker tag ${env.IMAGE_TAG} ${REGISTRY}/${IMAGE_NAME}:latest
docker push ${REGISTRY}/${IMAGE_NAME}:latest
"""
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh "kubectl set image deployment/myapp myapp=${env.IMAGE_TAG}"
}
}
}
}

Dockerfile.test
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "test", "--", "--coverage"]
Terminal window
# Run tests in container
docker run --rm myapp:test npm test
docker-compose.test.yml
version: '3.8'
services:
app:
build: .
environment:
- DB_HOST=db
- DB_PORT=5432
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=test
- POSTGRES_DB=test
test:
build: .
command: npm run test:integration
depends_on:
- app
- db
# Cypress configuration for container testing
# cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://web:80',
video: false,
screenshotOnRunFailure: true,
supportFile: false,
},
})
docker-compose.e2e.yml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
cypress:
image: cypress/included:12.0.0
working_dir: /e2e
volumes:
- ./e2e:/e2e
depends_on:
- web
command: --config-file cypress.config.js

┌─────────────────────────────────────────────────────────────────────────────┐
│ DOCKER REGISTRY OPTIONS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Public Registries │
│ ─────────────── │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ Docker Hub │ │ GitHub │ │
│ │ Official │ │ Packages │ │
│ │ Images │ │ │ │
│ └────────────────┘ └────────────────┘ │
│ │
│ Private/Cloud Registries │
│ ────────────────────── │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ AWS ECR │ │ Azure ACR │ │ GCP GCR │ │
│ │ │ │ │ │ │ │
│ │ Pay per use │ │ Pay per use │ │ Pay per use │ │
│ │ IAM control │ │ RBAC │ │ IAM control │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ Self-Hosted │
│ ─────────── │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Harbor │ │ GitLab │ │ Distribution │ │
│ │ Enterprise │ │ Registry │ │ (OSS) │ │
│ │ │ │ │ │ │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Terminal window
# Login to registry
docker login myregistry.io
# Or using credentials
docker login -u USER -p PASS myregistry.io
# Tag image for registry
docker tag myapp:latest myregistry.io/myapp:latest
# Push image
docker push myregistry.io/myapp:latest
# Pull image
docker pull myregistry.io/myapp:latest
Terminal window
# Get ECR login password
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin account.dkr.ecr.us-east-1.amazonaws.com
# Build and tag
docker build -t myapp .
docker tag myapp:latest account.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
# Push
docker push account.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

┌─────────────────────────────────────────────────────────────────────────────┐
│ IMAGE TAGGING STRATEGIES │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Semantic Versioning (SemVer) │
│ ───────────────────────────────────── │
│ myapp:1.0.0 - Major version │
│ myapp:1.0.1 - Patch version │
│ myapp:1.1.0 - Minor version │
│ │
│ 2. Git-based Tagging │
│ ───────────────────── │
│ myapp:abc123 - First 7 characters of commit SHA │
│ myapp:sha-abc123 - Full SHA │
│ myapp:branch-main - Branch name │
│ │
│ 3. Dynamic Tags │
│ ──────────────── │
│ myapp:latest - Latest stable build │
│ myapp:stable - Stable release │
│ myapp:develop - Development branch │
│ │
│ 4. Date-based Tags │
│ ───────────────── │
│ myapp:2024.01.15 - Date of build │
│ myapp:2024-01-15 - ISO date │
│ │
│ Recommended Strategy: │
│ ─────────────────── │
│ Always tag with: │
│ • SHA (myapp:sha-abc123) - Immutable, traceable │
│ • SemVer (myapp:1.2.3) - Human readable │
│ • Latest (myapp:latest) - Convenience (not for production) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Terminal window
# Tag with git SHA
IMAGE_TAG=$(git rev-parse --short HEAD)
docker build -t myapp:${IMAGE_TAG} .
# Tag with branch name
BRANCH_NAME=${CI_COMMIT_BRANCH:-$(git branch --show-current)}
docker build -t myapp:${BRANCH_NAME} .
# Tag with semver (from git tag)
VERSION=$(git describe --tags --abbrev=0)
docker build -t myapp:${VERSION} .
# Multiple tags
docker build -t myapp:latest -t myapp:${VERSION} -t myapp:${SHA} .

┌─────────────────────────────────────────────────────────────────────────────┐
│ BLUE-GREEN DEPLOYMENT │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Before Switch: │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ BLUE (v1.0) │ │ GREEN (v2.0) │ │ │
│ │ │ │ │ │ │ │
│ │ │ Active ◄──────┼────────┼── Inactive │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ │ Load Balancer: 100% traffic → Blue │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ After Switch: │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ BLUE (v1.0) │ │ GREEN (v2.0) │ │ │
│ │ │ │ │ │ │ │
│ │ │ Inactive │◄───────┼── Active ► │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ │ Load Balancer: 100% traffic → Green │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Rollback: Switch traffic back to Blue │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ CANARY DEPLOYMENT │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: 10% Traffic │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ v1.0 (90%) │██│██│██│██│██│██│██│██│██│ │ │ │
│ │ v2.0 (10%) │█│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Phase 2: 50% Traffic │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ v1.0 (50%) │██│██│██│██│ │ │ │
│ │ v2.0 (50%) │██│██│██│██│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Phase 3: 100% Traffic │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ v2.0 (100%) │██│██│██│██│██│██│██│██│██│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Benefits: │
│ • Test with real traffic │
│ • Easy rollback │
│ • Gradual rollout │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ ROLLING DEPLOYMENT │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Initial: 3 replicas v1.0 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ v1.0 ✓ │ │ v1.0 ✓ │ │ v1.0 ✓ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Step 1: Replace 1st replica │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ v2.0 ⏳ │ │ v1.0 ✓ │ │ v1.0 ✓ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Step 2: Replace 2nd replica │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ v2.0 ✓ │ │ v2.0 ⏳ │ │ v1.0 ✓ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Step 3: Replace 3rd replica │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ v2.0 ✓ │ │ v2.0 ✓ │ │ v2.0 ⏳ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Complete: All replicas v2.0 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ v2.0 ✓ │ │ v2.0 ✓ │ │ v2.0 ✓ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

# GitHub Actions with security scanning
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Build image
- name: Build
run: docker build -t myapp:test .
# Run Trivy scanner
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
# Upload results
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
# Fail on critical vulnerabilities
- name: Check for critical vulnerabilities
run: |
docker run --rm -v $(pwd):/workspace aquasecurity/trivy:0.44.0 \
image --exit-code 1 --severity CRITICAL myapp:test || \
(echo "Critical vulnerabilities found!" && exit 1)
Terminal window
# Enable Docker Scout
docker scout cves myapp:latest
# In CI/CD
docker build -t myapp:latest .
docker scout cves --exit-code --policy /policy.yaml myapp:latest

┌─────────────────────────────────────────────────────────────────────────────┐
│ GITOPS WORKFLOW │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Traditional CI/CD: GitOps: │
│ ─────────────────── ───────: │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Code │───▶│ Build │───▶ │ Code │───▶│ Sync │ │
│ │ Commit │ │ & Deploy │ │ Commit │ │ State │ │
│ └──────────┘ └──────────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Git │ │ Cluster │ │
│ │ Repo │ │ State │ │
│ │ (Desired) │ │ (Actual) │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ Key Principles: │
│ • Git as single source of truth │
│ • Declarative infrastructure │
│ • Automated synchronization │
│ • Drift detection │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp.git
targetRevision: main
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true

In this hands-on lab, we’ll build a complete CI/CD pipeline with Docker.

  • Docker installed
  • GitHub account (or use GitLab/Jenkins)
Terminal window
# Step 1: Create a simple Node.js application
mkdir myapp && cd myapp
npm init -y
npm install express
# Step 2: Create the application
cat > index.js << 'EOF'
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({
message: 'Hello from Docker CI/CD!',
version: process.env.VERSION || 'dev'
});
});
app.listen(port, () => {
console.log(`App listening on port ${port}`);
});
EOF
# Step 3: Create Dockerfile
cat > Dockerfile << 'EOF'
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
EOF
# Step 4: Create package.json
cat > package.json << 'EOF'
{
"name": "myapp",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"No tests specified\""
},
"dependencies": {
"express": "^4.18.2"
}
}
EOF
# Step 5: Create GitHub Actions workflow
mkdir -p .github/workflows
cat > .github/workflows/docker.yml << 'EOF'
name: Docker Build and Push
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build
run: docker build -t myapp:test .
- name: Test
run: docker run --rm myapp:test node -e "console.log('Container works!')"
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
if: github.event_name != 'pull_request'
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKER_USERNAME }}/myapp
- name: Push
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v5
with:
push: true
tags: ${{ steps.meta.outputs.tags }}
EOF
# Step 6: Commit and push
git init
git add .
git commit -m "Initial commit with Docker CI/CD"
# git remote add origin <your-repo-url>
# git push -u origin main
# Step 7: Test locally
docker build -t myapp:local .
docker run -p 3000:3000 myapp:local
# Step 8: Verify with curl
curl http://localhost:3000

  1. CI/CD with Docker - Consistent builds, tests, and deployments
  2. Multi-stage Builds - Smaller, optimized images
  3. Security Scanning - Scan images in CI/CD pipeline
  4. Image Tagging - Use SHA-based tags for production
  5. Deployment Strategies - Blue-green, canary, rolling
  6. GitOps - Git as source of truth for deployments
Terminal window
# Build image
docker build -t myapp:latest .
# Tag for registry
docker tag myapp:latest registry.io/myapp:latest
# Push to registry
docker push registry.io/myapp:latest
# Pull in deployment
docker pull registry.io/myapp:latest
# Security scan
trivy image myapp:latest
docker scout cves myapp:latest

This concludes the Docker Advanced section. You now have comprehensive knowledge of:

  • Docker Swarm (Chapter 11)
  • Docker Security (Chapter 12)
  • Docker Monitoring (Chapter 13)
  • Docker Networking (Chapter 14)
  • Docker CI/CD (Chapter 15)
  • Kubernetes Fundamentals (Chapter 16-25)
  • Kubernetes Advanced (Chapter 26-32)
  • Terraform & IaC (Chapter 33-40)
  • Ansible (Chapter 41-45)
  • CI/CD Tools (Chapter 46-50)