Containerization with Docker Assignment#
Assignment Metadata#
Field |
Description |
|---|---|
Assignment Name |
Containerizing a Python Application with Best Practices |
Course |
Basic DevOps Essentials for Developer |
Project Name |
docker-python-app |
Estimated Time |
120 minutes |
Framework |
Docker 24+, Python 3.11+ |
Learning Objectives#
After completing this assignment, you will be able to:
Create optimized Dockerfiles for Python applications
Implement multi-stage builds to reduce image size
Configure proper layer caching for faster builds
Apply security best practices (non-root users, secrets management)
Utilize .dockerignore to exclude unnecessary files
Verify image security using vulnerability scanning tools
Prerequisites#
Docker installed locally (Docker Desktop or Docker Engine)
Basic understanding of Python application structure
Familiarity with command line operations
Tasks#
Task 1: Create a Basic Dockerfile (20 points)#
Create a simple Python web application (FastAPI or Flask):
Create
app.pywith a basic health endpoint (/health)Create
pyproject.tomlorrequirements.txtwith dependencies
Write an initial Dockerfile that:
Uses
python:3.11-slimas base imageSets appropriate environment variables (
PYTHONDONTWRITEBYTECODE,PYTHONUNBUFFERED)Copies and installs dependencies
Exposes the application port
Sets the default command to run the application
Build and test the image:
docker build -t myapp:v1 . docker run -d -p 8000:8000 myapp:v1
Task 2: Optimize Layer Caching (20 points)#
Analyze the current Dockerfile for caching issues
Refactor to optimize caching:
Copy dependency files before application code
Combine RUN commands to reduce layers
Order instructions from least to most frequently changed
Document the changes and explain why each optimization improves build time
Task 3: Implement Multi-stage Build (25 points)#
Create a multi-stage Dockerfile with:
Builder stage: Install build dependencies and compile/install packages
Runtime stage: Copy only necessary artifacts from builder
Compare image sizes:
Stage
Image Size
Single-stage
? MB
Multi-stage
? MB
Implement build targets for different environments:
development: Include dev tools (pytest, ruff)production: Minimal runtime only
Build specific targets:
docker build --target development -t myapp:dev . docker build --target production -t myapp:prod .
Task 4: Implement Security Best Practices (25 points)#
Create a non-root user and run the container as that user
Create a
.dockerignorefile excluding:.git,__pycache__,.venvTest files and documentation
Environment files (
.env)
Add a HEALTHCHECK instruction to monitor application health
Scan the image for vulnerabilities using Docker Scout or Trivy:
docker scout cves myapp:prod # or trivy image myapp:prod
Document any vulnerabilities found and mitigation strategies
Task 5: Volume and Port Configuration (10 points)#
Configure volumes for:
Persistent data storage
Configuration files (read-only)
Document port mapping requirements
Create a
docker-compose.ymlfor local development that includes:Volume mounts for hot-reload
Environment variable configuration
Health check configuration
Submission Requirements#
Required Deliverables#
Source code for Python application
Optimized multi-stage
Dockerfile.dockerignorefiledocker-compose.ymlfor developmentREADME.mdwith build and run instructionsScreenshots of running container and vulnerability scan results
Submission Checklist#
Docker image builds without errors
Application runs correctly in container
Multi-stage build implemented with measurable size reduction
Non-root user configured
Health check working
Vulnerability scan completed
Evaluation Criteria#
Criteria |
Points |
|---|---|
Basic Dockerfile creation |
20 |
Layer caching optimization |
20 |
Multi-stage build implementation |
25 |
Security best practices |
25 |
Volume and port configuration |
10 |
Total |
100 |
Hints#
Use
docker history <image>to inspect layer sizesUse
docker imagesto compare image sizes before and after optimizationStart with the official Python slim images for smaller base size
Always specify exact version tags for reproducibility
Test your health check with
docker inspect --format='{{.State.Health.Status}}' <container>