Docker Compose Applications¶
milkcrate supports deploying multi-container applications using Docker Compose. This allows you to deploy complex applications with databases, caches, message queues, and other supporting services.
Overview¶
Docker Compose applications in milkcrate:
- Deploy entire application stacks with multiple services
- Automatically integrate with Traefik for routing
- Support health checks and status monitoring
Creating a Docker Compose Application¶
1. Application Structure¶
Your application should have this structure:
my-compose-app/
├── app.py # Your main application (not confined to Python)
├── requirements.txt # Dependencies (not confined to Python)
├── Dockerfile # Build instructions for main service
├── docker-compose.yml # Multi-service configuration
└── README.md # Documentation
2. Required docker-compose.yml Configuration¶
Your docker-compose.yml must include these essential elements:
version: '3.8'
services:
app: # Main service (name can be anything)
build: . # Build from local Dockerfile
ports:
- "8000:8000" # Expose the port your app runs on
labels:
- milkcrate.main_service=true # REQUIRED: Mark as main service
environment:
- FLASK_ENV=production
- FLASK_APP=app.py
3. Main Service Requirements¶
The service marked with milkcrate.main_service=true must:
- Expose a port: Use
portsmapping (e.g.,"8000:8000") - Be accessible: Respond to HTTP requests on the exposed port
- Have a health endpoint: Respond to health check requests
4. Complete Example¶
Here's a complete example with a web app and database:
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- FLASK_ENV=production
- FLASK_APP=app.py
- DATABASE_URL=postgresql://user:password@db:5432/myapp
labels:
- milkcrate.main_service=true
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
postgres_data:
redis_data:
Health Check Endpoints¶
milkcrate automatically checks these endpoints to determine if your application is healthy:
/health- Primary health check endpoint/status- Alternative status endpoint/api/health- API health endpoint/api/status- API status endpoint/- Fallback to main page
Health Check Response¶
Your application should respond with a 200 status code. For JSON endpoints, include status information:
@app.route("/health")
def health():
return jsonify({
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"version": "1.0.0"
})
Advanced Configuration¶
Environment Variables¶
Pass configuration through environment variables:
services:
app:
build: .
ports:
- "8000:8000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
labels:
- milkcrate.main_service=true
Volume Mounts¶
Docker Compose Volumes¶
Use volumes defined in your docker-compose.yml for persistent data:
services:
app:
build: .
ports:
- "8000:8000"
volumes:
- ./uploads:/app/uploads
- app_data:/app/data
labels:
- milkcrate.main_service=true
volumes:
app_data:
Milkcrate-Managed Volumes¶
You can also mount volumes created through Milkcrate's volume management interface during deployment.
To use Milkcrate-managed volumes:
- Create and populate volumes through the Milkcrate UI (Admin → Manage Volumes)
- During deployment, select volumes to mount and specify paths
- Volumes will be mounted to your main service container
See Volume Management for detailed instructions on creating and managing volumes.
Service Dependencies¶
Define service startup order:
services:
app:
build: .
ports:
- "8000:8000"
depends_on:
- db
- redis
labels:
- milkcrate.main_service=true
Deployment Process¶
- Package your application:
cd my-compose-app
zip -r my-app.zip . -x "*.git*" "*.pyc" "__pycache__/*"
# Or, run:
milkcrate package --output my-app.zip
-
Upload via milkcrate UI:
- Go to Admin Dashboard
- Click "Deploy New App"
- Upload your ZIP file
- Set app name and public route
-
milkcrate will:
- Extract the ZIP file
- Detect it's a Docker Compose application
- Add Traefik labels to the main service
- Deploy the entire stack
- Monitor health and status
Network Integration¶
Traefik Labels (Auto-generated)¶
milkcrate adds these labels to your main service:
labels:
- traefik.enable=true
- traefik.http.routers.myapp.rule=PathPrefix(`/myapp`)
- traefik.http.routers.myapp.entrypoints=web
- traefik.http.services.myapp.loadbalancer.server.port=8000
- traefik.http.middlewares.myapp_stripprefix.stripprefix.prefixes=/myapp
- traefik.http.routers.myapp.middlewares=myapp_stripprefix
Note: These rules accept requests from any hostname. To restrict to specific domains, use Host(yourdomain.com) && PathPrefix(/myapp) instead.
Troubleshooting¶
Common Issues¶
-
"No main service found":
- Ensure one service has
milkcrate.main_service=truelabel
- Ensure one service has
-
"Service refers to undefined network":
- milkcrate automatically adds the Traefik network
- Don't manually define external networks
-
Health check failures:
- Ensure your app responds to health endpoints
- Check that the exposed port is correct
-
Service startup order:
- Use
depends_onfor service dependencies - Consider using health checks in your services
- Use
Debugging¶
Check application logs:
# View compose stack logs
docker compose -p milkcrate-myapp logs
# View specific service logs
docker compose -p milkcrate-myapp logs app
When to Use Docker Compose vs Dockerfile¶
Use Docker Compose apps when:
- Multiple containers are required
- Need databases, caches, or other supporting services
- Complex service dependencies
- Services need to communicate with each other
Use Dockerfile apps when:
- Single-container application
- No external services required
- Simple deployment and configuration
See Dockerfile Applications for single-container deployments.
Best Practices¶
- Use named volumes for persistent data
- Set restart policies (
restart: unless-stopped) - Include health endpoints in your main service
- Use environment variables for configuration
- Document dependencies with
depends_on - Use specific image tags for reproducibility
Example Applications¶
Simple Web App with Database¶
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/myapp
labels:
- milkcrate.main_service=true
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Microservices Application¶
version: '3.8'
services:
api:
build: ./api
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
labels:
- milkcrate.main_service=true
depends_on:
- db
- redis
worker:
build: ./worker
environment:
- DATABASE_URL=postgresql://user:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
Next Steps¶
- See Volume Management for persistent data
- See Docker Compose Apps for multi-container applications
- See Deployment for production setup