Sample Applications
This guide provides complete, working Docker applications that demonstrate real-world scenarios.
Node.js Web Application
Application Structure
nodejs-app/
├── app/
│ ├── package.json
│ ├── app.js
│ └── Dockerfile
├── docker-compose.yml
└── nginx.conf
Application Code
app/package.json
{
"name": "docker-nodejs-app",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.17.1",
"cors": "^2.8.5"
}
}
app/app.js
const express = require('express');
const cors = require('cors');
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
app.get('/', (req, res) => {
res.json({
message: 'Hello from Docker!',
timestamp: new Date().toISOString(),
hostname: require('os').hostname()
});
});
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
uptime: process.uptime(),
environment: process.env.NODE_ENV
});
});
app.get('/api/users', (req, res) => {
res.json([
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
]);
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
app/Dockerfile
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
RUN chown -R nodejs:nodejs /app
USER nodejs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"
CMD ["npm", "start"]
docker-compose.yml
version: '3.8'
services:
web:
build:
context: ./app
dockerfile: Dockerfile
image: nodejs-app:latest
ports:
- "3000:3000"
environment:
- NODE_ENV=production
volumes:
- app-logs:/app/logs
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"]
interval: 30s
timeout: 10s
retries: 3
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
networks:
- app-network
restart: unless-stopped
volumes:
app-logs:
networks:
app-network:
driver: bridge
nginx.conf
events {
worker_connections 1024;
}
http {
upstream app {
server web:3000;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Running the Application
# Build and start
docker-compose up -d
# Test the application
curl http://localhost/health
# View logs
docker-compose logs -f
# Stop
docker-compose down
Python Flask Application with Database
Application Structure
python-flask-app/
├── app/
│ ├── requirements.txt
│ ├── app.py
│ └── Dockerfile
├── docker-compose.yml
└── README.md
Application Code
app/requirements.txt
Flask==2.0.1
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.9.1
gunicorn==20.1.0
app/app.py
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import os
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
@app.route('/')
def home():
return jsonify({
'message': 'Hello from Flask Docker App!',
'timestamp': datetime.utcnow().isoformat()
})
@app.route('/health')
def health():
return jsonify({
'status': 'healthy',
'database': 'connected' if db.engine.execute('SELECT 1').scalar() else 'disconnected'
})
@app.route('/api/users', methods=['GET'])
def get_users():
users = User.query.all()
return jsonify([{
'id': user.id,
'name': user.name,
'email': user.email,
'created_at': user.created_at.isoformat()
} for user in users])
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json()
if not data or not data.get('name') or not data.get('email'):
return jsonify({'error': 'Name and email are required'}), 400
user = User(name=data['name'], email=data['email'])
db.session.add(user)
db.session.commit()
return jsonify({
'id': user.id,
'name': user.name,
'email': user.email,
'created_at': user.created_at.isoformat()
}), 201
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(host='0.0.0.0', port=5000)
app/Dockerfile
FROM python:3.9-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd --create-home --shell /bin/bash app && \
chown -R app:app /app
USER app
EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:5000/health')" || exit 1
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
docker-compose.yml
version: '3.8'
services:
web:
build:
context: ./app
dockerfile: Dockerfile
image: flask-app:latest
ports:
- "5000:5000"
environment:
- FLASK_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/flaskapp
volumes:
- app-logs:/app/logs
depends_on:
db:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:5000/health')"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:13-alpine
environment:
- POSTGRES_DB=flaskapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d flaskapp"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres-data:
app-logs:
networks:
app-network:
driver: bridge
Multi-Service Application
Application Structure
microservices-app/
├── frontend/
│ ├── package.json
│ ├── index.js
│ └── Dockerfile
├── backend/
│ ├── requirements.txt
│ ├── app.py
│ └── Dockerfile
├── docker-compose.yml
└── README.md
Frontend Service
frontend/index.js
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
app.get('/api/users', async (req, res) => {
try {
const response = await axios.get('http://backend:5000/api/users');
res.json(response.data);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch users' });
}
});
app.get('/health', (req, res) => {
res.json({ status: 'healthy', service: 'frontend' });
});
app.listen(port, () => {
console.log(`Frontend service running on port ${port}`);
});
Backend Service
backend/app.py
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import os
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
@app.route('/api/users', methods=['GET'])
def get_users():
users = User.query.all()
return jsonify([{
'id': user.id,
'name': user.name,
'email': user.email,
'created_at': user.created_at.isoformat()
} for user in users])
@app.route('/health')
def health():
return jsonify({
'status': 'healthy',
'service': 'backend',
'database': 'connected' if db.engine.execute('SELECT 1').scalar() else 'disconnected'
})
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(host='0.0.0.0', port=5000)
docker-compose.yml
version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
image: microservices-frontend:latest
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
backend:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
backend:
build:
context: ./backend
dockerfile: Dockerfile
image: microservices-backend:latest
ports:
- "5000:5000"
environment:
- FLASK_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/microservices
depends_on:
db:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
db:
image: postgres:13-alpine
environment:
- POSTGRES_DB=microservices
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d microservices"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres-data:
networks:
app-network:
driver: bridge
Testing the Applications
API Testing
# Test Node.js application
curl http://localhost:3000/health
curl http://localhost:3000/api/users
# Test Flask application
curl http://localhost:5000/health
curl http://localhost:5000/api/users
# Test microservices application
curl http://localhost:3000/api/users
Database Testing
# Connect to PostgreSQL
docker-compose exec db psql -U user -d myapp
# Check database tables
\dt
SELECT * FROM users;
Running the Applications
Development Mode
# Start the application
docker-compose up -d
# View logs
docker-compose logs -f
# Test the application
curl http://localhost/health
# Stop the application
docker-compose down
Production Mode
# Build images
docker-compose build
# Start in production mode
docker-compose up -d
# Scale services
docker-compose up --scale backend=3
# Monitor services
docker-compose ps
Best Practices Demonstrated
- Security: Non-root users, read-only filesystems
- Health Checks: Proper health check implementations
- Resource Limits: Memory and CPU constraints
- Logging: Structured logging
- Database: Proper database initialization
- Networking: Isolated networks and service discovery
- Monitoring: Health checks and metrics collection
Next Steps
These sample applications demonstrate:
- Single-service applications
- Multi-service microservices
- Database integration
- Load balancing
- Health monitoring
- Production deployments
You can extend these examples by:
- Adding authentication and authorization
- Implementing API versioning
- Adding message queues
- Implementing service mesh
- Adding monitoring and alerting
- Implementing CI/CD pipelines
- Adding automated testing
Summary
These sample applications provide practical examples of:
- Containerizing different types of applications
- Managing multi-service architectures
- Implementing proper health checks and monitoring
- Using volumes for data persistence
- Setting up networking between services
- Following Docker best practices
You can use these examples as starting points for your own Docker applications!