mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Update documentation
This commit is contained in:
510
docs/docker.md
Normal file
510
docs/docker.md
Normal file
@@ -0,0 +1,510 @@
|
||||
# Docker Guide
|
||||
|
||||
This document covers Docker deployment, configuration, and troubleshooting for The Biergarten App.
|
||||
|
||||
## Overview
|
||||
|
||||
The project uses Docker Compose to orchestrate multiple services:
|
||||
- SQL Server 2022 database
|
||||
- Database migrations runner (DbUp)
|
||||
- Database seeder
|
||||
- .NET API
|
||||
- Test runners
|
||||
|
||||
See the [deployment diagram](diagrams/pdf/deployment.pdf) for visual representation.
|
||||
|
||||
## Docker Compose Environments
|
||||
|
||||
### 1. Development (`docker-compose.dev.yaml`)
|
||||
|
||||
**Purpose**: Local development with persistent data
|
||||
|
||||
**Features**:
|
||||
- Persistent SQL Server volume
|
||||
- Hot reload support
|
||||
- Swagger UI enabled
|
||||
- Seed data included
|
||||
- `CLEAR_DATABASE=true` (drops and recreates schema)
|
||||
|
||||
**Services**:
|
||||
```yaml
|
||||
sqlserver # SQL Server 2022 (port 1433)
|
||||
database.migrations # DbUp migrations
|
||||
database.seed # Seed initial data
|
||||
api.core # Web API (ports 8080, 8081)
|
||||
```
|
||||
|
||||
**Start Development Environment**:
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yaml up -d
|
||||
```
|
||||
|
||||
**Access**:
|
||||
- API Swagger: http://localhost:8080/swagger
|
||||
- Health Check: http://localhost:8080/health
|
||||
- SQL Server: localhost:1433 (sa credentials from .env.dev)
|
||||
|
||||
**Stop Environment**:
|
||||
```bash
|
||||
# Stop services (keep volumes)
|
||||
docker compose -f docker-compose.dev.yaml down
|
||||
|
||||
# Stop and remove volumes (fresh start)
|
||||
docker compose -f docker-compose.dev.yaml down -v
|
||||
```
|
||||
|
||||
### 2. Testing (`docker-compose.test.yaml`)
|
||||
|
||||
**Purpose**: Automated CI/CD testing in isolated environment
|
||||
|
||||
**Features**:
|
||||
- Fresh database each run
|
||||
- All test suites execute in parallel
|
||||
- Test results exported to `./test-results/`
|
||||
- Containers auto-exit after completion
|
||||
- Fully isolated testnet network
|
||||
|
||||
**Services**:
|
||||
```yaml
|
||||
sqlserver # Test database
|
||||
database.migrations # Fresh schema
|
||||
database.seed # Test data
|
||||
api.specs # Reqnroll BDD tests
|
||||
repository.tests # Repository unit tests
|
||||
service.auth.tests # Service unit tests
|
||||
```
|
||||
|
||||
**Run Tests**:
|
||||
```bash
|
||||
# Run all tests
|
||||
docker compose -f docker-compose.test.yaml up --abort-on-container-exit
|
||||
|
||||
# View results
|
||||
ls -la test-results/
|
||||
cat test-results/api-specs/results.trx
|
||||
cat test-results/repository-tests/results.trx
|
||||
cat test-results/service-auth-tests/results.trx
|
||||
|
||||
# Clean up
|
||||
docker compose -f docker-compose.test.yaml down -v
|
||||
```
|
||||
|
||||
### 3. Production (`docker-compose.prod.yaml`)
|
||||
|
||||
**Purpose**: Production-ready deployment
|
||||
|
||||
**Features**:
|
||||
- Production logging levels
|
||||
- No database clearing
|
||||
- Optimized build configurations
|
||||
- Health checks enabled
|
||||
- Restart policies (unless-stopped)
|
||||
- Security hardening
|
||||
|
||||
**Services**:
|
||||
```yaml
|
||||
sqlserver # Production SQL Server
|
||||
database.migrations # Schema updates only
|
||||
api.core # Production API
|
||||
```
|
||||
|
||||
**Deploy Production**:
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yaml up -d
|
||||
```
|
||||
|
||||
**Note**: In real production, use orchestration platforms (Kubernetes, ECS, etc.).
|
||||
|
||||
## Service Dependencies
|
||||
|
||||
Docker Compose manages startup order using health checks:
|
||||
|
||||
```mermaid
|
||||
sqlserver (health check)
|
||||
↓
|
||||
database.migrations (completes successfully)
|
||||
↓
|
||||
database.seed (completes successfully)
|
||||
↓
|
||||
api.core / tests (start when ready)
|
||||
```
|
||||
|
||||
**Health Check Example** (SQL Server):
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 30s
|
||||
```
|
||||
|
||||
**Dependency Configuration**:
|
||||
```yaml
|
||||
api.core:
|
||||
depends_on:
|
||||
database.seed:
|
||||
condition: service_completed_successfully
|
||||
```
|
||||
|
||||
## Volumes
|
||||
|
||||
### Persistent Volumes
|
||||
|
||||
**Development**:
|
||||
- `sqlserverdata-dev` - Database files persist between restarts
|
||||
- `nuget-cache-dev` - NuGet package cache (speeds up builds)
|
||||
|
||||
**Testing**:
|
||||
- `sqlserverdata-test` - Temporary, typically removed after tests
|
||||
|
||||
**Production**:
|
||||
- `sqlserverdata-prod` - Production database files
|
||||
- `nuget-cache-prod` - Production NuGet cache
|
||||
|
||||
### Mounted Volumes
|
||||
|
||||
**Test Results**:
|
||||
```yaml
|
||||
volumes:
|
||||
- ./test-results:/app/test-results
|
||||
```
|
||||
Test results are written to host filesystem for CI/CD integration.
|
||||
|
||||
**Code Volumes** (development only):
|
||||
```yaml
|
||||
volumes:
|
||||
- ./src:/app/src # Hot reload for development
|
||||
```
|
||||
|
||||
## Networks
|
||||
|
||||
Each environment uses isolated bridge networks:
|
||||
|
||||
- `devnet` - Development network
|
||||
- `testnet` - Testing network (fully isolated)
|
||||
- `prodnet` - Production network
|
||||
|
||||
This prevents cross-environment communication and improves security.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All containers are configured via environment variables from `.env` files:
|
||||
|
||||
```yaml
|
||||
env_file: ".env.dev" # or .env.test, .env.prod
|
||||
|
||||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: "Development"
|
||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||
DB_SERVER: "${DB_SERVER}"
|
||||
DB_NAME: "${DB_NAME}"
|
||||
DB_USER: "${DB_USER}"
|
||||
DB_PASSWORD: "${DB_PASSWORD}"
|
||||
JWT_SECRET: "${JWT_SECRET}"
|
||||
```
|
||||
|
||||
For complete list, see [Environment Variables](environment-variables.md).
|
||||
|
||||
## Common Commands
|
||||
|
||||
### View Services
|
||||
|
||||
```bash
|
||||
# Running services
|
||||
docker compose -f docker-compose.dev.yaml ps
|
||||
|
||||
# All containers (including stopped)
|
||||
docker ps -a
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All services
|
||||
docker compose -f docker-compose.dev.yaml logs -f
|
||||
|
||||
# Specific service
|
||||
docker compose -f docker-compose.dev.yaml logs -f api.core
|
||||
|
||||
# Last 100 lines
|
||||
docker compose -f docker-compose.dev.yaml logs --tail=100 api.core
|
||||
```
|
||||
|
||||
### Execute Commands in Container
|
||||
|
||||
```bash
|
||||
# Interactive shell
|
||||
docker exec -it dev-env-api-core bash
|
||||
|
||||
# Run command
|
||||
docker exec dev-env-sqlserver /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'password' -C
|
||||
```
|
||||
|
||||
### Restart Services
|
||||
|
||||
```bash
|
||||
# Restart all services
|
||||
docker compose -f docker-compose.dev.yaml restart
|
||||
|
||||
# Restart specific service
|
||||
docker compose -f docker-compose.dev.yaml restart api.core
|
||||
|
||||
# Rebuild and restart
|
||||
docker compose -f docker-compose.dev.yaml up -d --build api.core
|
||||
```
|
||||
|
||||
### Build Images
|
||||
|
||||
```bash
|
||||
# Build all images
|
||||
docker compose -f docker-compose.dev.yaml build
|
||||
|
||||
# Build specific service
|
||||
docker compose -f docker-compose.dev.yaml build api.core
|
||||
|
||||
# Build without cache
|
||||
docker compose -f docker-compose.dev.yaml build --no-cache
|
||||
```
|
||||
|
||||
### Clean Up
|
||||
|
||||
```bash
|
||||
# Stop and remove containers
|
||||
docker compose -f docker-compose.dev.yaml down
|
||||
|
||||
# Remove containers and volumes
|
||||
docker compose -f docker-compose.dev.yaml down -v
|
||||
|
||||
# Remove containers, volumes, and images
|
||||
docker compose -f docker-compose.dev.yaml down -v --rmi all
|
||||
|
||||
# System-wide cleanup
|
||||
docker system prune -af --volumes
|
||||
```
|
||||
|
||||
## Dockerfile Structure
|
||||
|
||||
### Multi-Stage Build
|
||||
|
||||
All service Dockerfiles use multi-stage builds:
|
||||
|
||||
```dockerfile
|
||||
# Stage 1: Build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["Project/Project.csproj", "Project/"]
|
||||
RUN dotnet restore
|
||||
COPY . .
|
||||
RUN dotnet build -c Release
|
||||
|
||||
# Stage 2: Runtime
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/build .
|
||||
ENTRYPOINT ["dotnet", "Project.dll"]
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Smaller final images (no SDK)
|
||||
- Cached layers speed up builds
|
||||
- Separation of build and runtime dependencies
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
**Problem**: Port 8080 or 1433 already bound
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Find process using port
|
||||
lsof -ti:8080
|
||||
lsof -ti:1433
|
||||
|
||||
# Kill process
|
||||
kill -9 $(lsof -ti:8080)
|
||||
|
||||
# Or change port in docker-compose.yaml
|
||||
ports:
|
||||
- "8081:8080" # Map to different host port
|
||||
```
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
**Problem**: Container exits immediately
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# View logs
|
||||
docker compose -f docker-compose.dev.yaml logs <service-name>
|
||||
|
||||
# Check container status
|
||||
docker compose -f docker-compose.dev.yaml ps
|
||||
|
||||
# Inspect container
|
||||
docker inspect <container-name>
|
||||
```
|
||||
|
||||
### Database Connection Failed
|
||||
|
||||
**Problem**: API can't connect to SQL Server
|
||||
|
||||
**Check**:
|
||||
1. SQL Server container is running:
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yaml ps sqlserver
|
||||
```
|
||||
|
||||
2. Health check is passing:
|
||||
```bash
|
||||
docker inspect dev-env-sqlserver | grep -A 10 Health
|
||||
```
|
||||
|
||||
3. Connection string is correct in `.env` file
|
||||
|
||||
4. SQL Server is accepting connections:
|
||||
```bash
|
||||
docker exec dev-env-sqlserver /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'password' -C -Q "SELECT 1"
|
||||
```
|
||||
|
||||
### Out of Disk Space
|
||||
|
||||
**Problem**: No space left on device
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check Docker disk usage
|
||||
docker system df
|
||||
|
||||
# Remove unused data
|
||||
docker system prune -af --volumes
|
||||
|
||||
# Remove specific volumes
|
||||
docker volume ls
|
||||
docker volume rm <volume-name>
|
||||
```
|
||||
|
||||
### SQL Server Container Unhealthy
|
||||
|
||||
**Problem**: Health check failing
|
||||
|
||||
**Reasons**:
|
||||
- Incorrect password
|
||||
- Container still starting up
|
||||
- Insufficient memory
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check logs
|
||||
docker compose -f docker-compose.dev.yaml logs sqlserver
|
||||
|
||||
# Verify password matches .env file
|
||||
grep DB_PASSWORD .env.dev
|
||||
|
||||
# Increase memory in Docker Desktop settings (min 4GB recommended)
|
||||
```
|
||||
|
||||
### Build Failures
|
||||
|
||||
**Problem**: Docker build fails
|
||||
|
||||
**Common Causes**:
|
||||
- Missing project references
|
||||
- Incorrect COPY paths
|
||||
- Network issues during restore
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Build without cache
|
||||
docker compose -f docker-compose.dev.yaml build --no-cache
|
||||
|
||||
# Check Dockerfile COPY paths match project structure
|
||||
# Ensure all .csproj files are in correct locations
|
||||
```
|
||||
|
||||
### Test Results Not Appearing
|
||||
|
||||
**Problem**: `test-results/` folder is empty
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Ensure folder has write permissions
|
||||
chmod -R 755 test-results/
|
||||
|
||||
# Check test container logs
|
||||
docker compose -f docker-compose.test.yaml logs api.specs
|
||||
|
||||
# Verify volume mount
|
||||
docker compose -f docker-compose.test.yaml config | grep -A 5 volumes
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Build Cache
|
||||
|
||||
Leverage Docker layer caching:
|
||||
1. Copy `.csproj` files first
|
||||
2. Run `dotnet restore`
|
||||
3. Copy source code
|
||||
4. Build application
|
||||
|
||||
This allows dependency layer caching when only source changes.
|
||||
|
||||
### Volume Mounts for Development
|
||||
|
||||
Use NuGet cache volume for faster rebuilds:
|
||||
```yaml
|
||||
volumes:
|
||||
- nuget-cache-dev:/root/.nuget/packages
|
||||
```
|
||||
|
||||
### Resource Limits
|
||||
|
||||
Set memory/CPU limits for containers:
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2GB
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
### GitHub Actions Example
|
||||
|
||||
```yaml
|
||||
name: Run Tests
|
||||
on: [push]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run tests
|
||||
run: |
|
||||
docker compose -f docker-compose.test.yaml build
|
||||
docker compose -f docker-compose.test.yaml up --abort-on-container-exit
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results/
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Don't commit `.env` files** - Use `.env.example` as template
|
||||
2. **Use secrets management** - For production credentials
|
||||
3. **Run as non-root user** - Configure USER in Dockerfile
|
||||
4. **Scan images** - Use `docker scan` or Trivy
|
||||
5. **Keep base images updated** - Regularly update FROM images
|
||||
6. **Minimize installed packages** - Only install what's needed
|
||||
7. **Use specific tags** - Avoid `latest` tag
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||
- [.NET Docker Images](https://hub.docker.com/_/microsoft-dotnet)
|
||||
- [SQL Server Docker Images](https://hub.docker.com/_/microsoft-mssql-server)
|
||||
Reference in New Issue
Block a user