✅ Repository forked and cloned locally
- ✅ Latest Python version: Using
python:3.13-slim(Python 3.13.5 - latest stable) - ✅ Smallest tag possible:
-slimvariant reduces image size by ~70% vs standard - ✅ Optimized image: Multi-layer optimization and build cache strategies
- ✅ Security best practices: Non-root user, minimal dependencies, health checks
Base Image Selection:
FROM python:3.13-slim- Python 3.13.5: Latest stable version (Released June 11, 2025)
slimtag: Minimal Debian-based image (~45MB vs ~165MB for standard)
Environment Optimization:
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PYTHONPATH=/appPYTHONDONTWRITEBYTECODE=1: Prevents .pyc file generationPYTHONUNBUFFERED=1: Ensures real-time log outputPIP_NO_CACHE_DIR=1: Reduces image size by not caching pip downloadsPIP_DISABLE_PIP_VERSION_CHECK=1: Speeds up pip operations
Security Measures:
RUN groupadd -r appuser && useradd -r -g appuser appuser
# ... later in file ...
RUN chown -R appuser:appuser /app
USER appuser- Creates and switches to non-root user
- Follows principle of least privilege
Build Optimization Strategies:
- Layer Caching: Dependencies copied before application code
- Single RUN Commands: Reduces layer count
- Cleanup: Removes package lists and temporary files
- .dockerignore: Excludes unnecessary files from build context
Health Check Implementation:
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:5000/books')" || exit 1- Uses Python's built-in urllib (no external dependencies)
- Tests actual API endpoint functionality
.dockerignore File:
- Excludes development files, caches, and documentation
- Reduces build context size significantly
- Improves build performance
Application Modification:
- Modified
app/main.pyto bind to0.0.0.0:5000 - Enables external access to containerized application
Build Command:
docker build -t myapp:1 .Run Command:
docker run -d -p 8080:5000 --name myapp_container myapp:1Status Check Command
docker psFile: docker-compose.yaml
version: '3.8'
services:
myapp:
image: myapp:1
container_name: myapp_compose_container
ports:
- "8080:5000"
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/books')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5sService Definition:
services:- Defines all services in this compose filemyapp:- Service name as required
Image and Container:
image: myapp:1- Uses the Docker image built in step 3container_name: myapp_compose_container- Custom container name for identification
Port Mapping:
ports: - "8080:5000"- Maps host port 8080 to container port 5000
Restart Policy:
restart: unless-stopped- Automatically restarts if crashes (unless manually stopped)
Health Check:
- Tests API endpoint every 30 seconds
- Helps monitor service health
- Automatic restart if health checks fail
Image Selection:
image: postgres:17- PostgreSQL 17: Latest stable version (released September 26, 2024)
- Avoids
latesttag to prevent automatic upgrades - Production-ready with all latest features
Security Implementation - Docker Secrets:
secrets:
postgres_password:
file: ./secrets/postgres_password.txt- Password stored in separate file, not environment variables
- File permissions set to 600 (owner read-only)
- Excluded from version control via
.gitignore
Data Persistence:
volumes:
- postgres_data:/var/lib/postgresql/data- Named volume for PostgreSQL data persistence
- Data survives container restarts and recreations
- Automatic backup and restore capability
Database Configuration:
environment:
POSTGRES_DB: myapp_db
POSTGRES_USER: myapp_user
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_passwordEnhanced depends_on with Health Check Condition:
myapp:
depends_on:
postgres:
condition: service_healthyWhy This Works:
depends_onwithcondition: service_healthywaits for PostgreSQL health check to pass- PostgreSQL health check verifies database accepts connections:
pg_isready -U myapp_user -d myapp_db - Application container only starts after database is confirmed ready
- Prevents connection errors and application crashes
Start Command:
docker-compose up -dThis project implements two GitHub Actions workflows following DevOps best practices:
docker-build-push.yml- Builds and pushes Docker images to GitHub Container Registrytest.yml- Runs comprehensive testing and security scans
Builds and pushes Docker images to GitHub Container Registry (ghcr.io) only when code is pushed to the main branch.
Security Best Practices:
- ✅ Uses
GITHUB_TOKENfor authentication (no manual secrets needed) - ✅ Implements proper permissions (
contents: read,packages: write) - ✅ Only pushes images on main branch, not on pull requests
- ✅ Includes vulnerability scanning with Trivy
Performance Optimization:
- ✅ Docker Buildx for advanced building features
- ✅ Multi-platform builds (linux/amd64, linux/arm64)
- ✅ GitHub Actions cache for Docker layers (
cache-from: type=gha) - ✅ Cache maximization with
cache-to: type=gha,mode=max
Image Tagging Strategy:
- ✅ Branch-based tags for development
- ✅ SHA-based tags for traceability
- ✅
latesttag only for main branch - ✅ PR-specific tags for pull requests
Security Scanning:
- ✅ Trivy vulnerability scanner integration
- ✅ SARIF format output for GitHub Security tab
- ✅ Automated security reporting
on:
push:
branches: [main] # Builds and pushes on main
pull_request:
branches: [main] # Only builds on PRs (no push)Comprehensive testing pipeline that validates code quality, functionality, and security.
Multi-Python Version Testing:
- ✅ Matrix strategy testing Python 3.10.x through 3.13.x
- ✅ Ensures compatibility across Python versions
- ✅ Parallel execution for faster feedback
Comprehensive Testing Pipeline: Three distinct job types:
-
Unit Testing (
testjob)- Python syntax validation with flake8
- Unit tests with pytest
- Code coverage reporting
- Codecov integration
-
Docker Integration Testing (
docker-testjob)- Builds Docker image
- Tests container functionality
- API endpoint validation
- Dependency on unit tests passing
Performance Optimizations:
- ✅ Pip cache for faster dependency installation
- ✅ Docker layer caching
- ✅ Parallel job execution
- ✅ Strategic job dependencies
Quality Gates:
- ✅ Code linting enforcement
- ✅ Test coverage tracking
- ✅ Docker functionality validation
- ✅ Security vulnerability detection
The project includes comprehensive unit tests (app/test_main.py) covering:
- ✅ All CRUD operations (Create, Read, Update, Delete)
- ✅ Error handling scenarios
- ✅ API endpoint validation
- ✅ Integration testing workflows
class TestBooksAPI:
def test_get_all_books(self, client)
def test_get_book_by_id(self, client)
def test_get_book_not_found(self, client)
def test_add_new_book(self, client, sample_book)
def test_add_book_missing_data(self, client)
def test_update_book(self, client)
def test_update_book_not_found(self, client)
def test_delete_book(self, client)
def test_delete_book_not_found(self, client)
def test_api_integration(self, client, sample_book)- Push code to
mainbranch to trigger Docker image build - Create pull requests to trigger testing workflow
- View results in GitHub Actions tab
Images are available at: ghcr.io/[username]/[repository]:tag
Example:
docker pull ghcr.io/yourusername/docker-gha-training:latest# Install test dependencies
pip install pytest pytest-cov flask-testing requests
# Run tests
pytest app/ -v --cov=appCompleting this Docker final exam presented several learning opportunities. The most frustrating challenge was initially having my GitHub Actions workflows stuck in a queued state and never executing. After troubleshooting, I discovered this was due to a typo in my workflow configuration where I had mistakenly used main instead of master as the branch name, preventing the workflows from triggering properly. However even after fixing that there was still a problem on github side as my workflows were in queue for 10min before starting and I had to rerun the docker-build-push multiple times as I got timeout error when trying to log in ghcr. Other challenges included setting up proper Docker Compose service dependencies with health checks and implementing comprehensive unit tests for the Flask API. Through systematic debugging and documentation review, I successfully resolved these issues and implemented a working CI/CD pipeline with proper testing and security scanning.
To make this Docker stack production-ready, several critical improvements would be necessary:
- Secrets Management: Implement proper secrets management using Kubernetes secrets or HashiCorp Vault instead of file-based secrets
- Image Scanning: Integrate continuous vulnerability scanning in production registries
- Network Security: Implement proper network policies and service mesh (Istio/Linkerd)
- RBAC: Configure role-based access control for container orchestration
- Non-root Containers: Ensure all containers run as non-root users with minimal privileges
- Orchestration: Deploy using Kubernetes or Docker Swarm for auto-scaling and high availability
- Load Balancing: Implement proper load balancers (NGINX, HAProxy, or cloud-native solutions)
- Database Clustering: Set up PostgreSQL in high-availability mode with read replicas
- Caching Layer: Add Redis for session management and application caching
- CDN Integration: Implement content delivery networks for static assets
- Application Monitoring: Integrate Prometheus, Grafana, and AlertManager
- Centralized Logging: Implement ELK stack (Elasticsearch, Logstash, Kibana) or equivalent
- Distributed Tracing: Add OpenTelemetry for microservices communication tracking
- Health Checks: Implement comprehensive liveness and readiness probes
- SLI/SLO Monitoring: Define and monitor Service Level Indicators/Objectives
- Infrastructure as Code: Use Terraform or Pulumi for infrastructure provisioning
- GitOps: Implement ArgoCD or Flux for declarative deployments
- Blue-Green Deployments: Zero-downtime deployment strategies
- Disaster Recovery: Automated backup and recovery procedures
- Multi-Environment: Separate development, staging, and production environments




