Files

379 lines
8.2 KiB
Markdown
Raw Permalink Normal View History

2025-10-25 22:29:06 +02:00
# Docker Deployment Guide
This guide covers building and deploying sexy.pivoine.art using Docker.
## Overview
The Dockerfile uses a multi-stage build process:
1. **Base stage**: Sets up Node.js and pnpm
2. **Builder stage**: Installs Rust, compiles WASM, builds all packages
3. **Runner stage**: Minimal production image with only runtime dependencies
## Prerequisites
- Docker 20.10+ with BuildKit support
- Docker Compose 2.0+ (optional, for orchestration)
## Building the Image
### Basic Build
```bash
docker build -t sexy.pivoine.art:latest .
```
### Build with Build Arguments
```bash
docker build \
--build-arg NODE_ENV=production \
-t sexy.pivoine.art:latest \
.
```
### Multi-platform Build (for ARM64 and AMD64)
```bash
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t sexy.pivoine.art:latest \
--push \
.
```
## Running the Container
### Run with Environment Variables
```bash
docker run -d \
--name sexy-pivoine-frontend \
-p 3000:3000 \
-e PUBLIC_API_URL=https://api.pivoine.art \
-e PUBLIC_URL=https://sexy.pivoine.art \
-e PUBLIC_UMAMI_ID=your-umami-id \
-e LETTERSPACE_API_URL=https://api.letterspace.com/v1 \
-e LETTERSPACE_API_KEY=your-api-key \
-e LETTERSPACE_LIST_ID=your-list-id \
sexy.pivoine.art:latest
```
### Run with Environment File
```bash
# Create .env.production from template
cp .env.production.example .env.production
# Edit .env.production with your values
nano .env.production
# Run container
docker run -d \
--name sexy-pivoine-frontend \
-p 3000:3000 \
--env-file .env.production \
sexy.pivoine.art:latest
```
## Docker Compose Deployment
### Using docker-compose.production.yml
```bash
# 1. Create environment file
cp .env.production.example .env.production
# 2. Edit environment variables
nano .env.production
# 3. Build and start
docker-compose -f docker-compose.production.yml up -d --build
# 4. View logs
docker-compose -f docker-compose.production.yml logs -f frontend
# 5. Stop services
docker-compose -f docker-compose.production.yml down
```
### Scale the Application
```bash
docker-compose -f docker-compose.production.yml up -d --scale frontend=3
```
## Environment Variables Reference
### Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `PUBLIC_API_URL` | Directus API backend URL | `https://api.pivoine.art` |
| `PUBLIC_URL` | Frontend application URL | `https://sexy.pivoine.art` |
### Optional Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `PUBLIC_UMAMI_ID` | Umami analytics tracking ID | `abc123def-456` |
| `LETTERSPACE_API_URL` | Letterspace API endpoint | `https://api.letterspace.com/v1` |
| `LETTERSPACE_API_KEY` | Letterspace authentication key | `sk_live_...` |
| `LETTERSPACE_LIST_ID` | Mailing list identifier | `list_abc123` |
| `PORT` | Application port (inside container) | `3000` |
| `HOST` | Host binding | `0.0.0.0` |
| `NODE_ENV` | Node environment | `production` |
## Health Checks
The container includes a built-in health check that pings the HTTP server every 30 seconds:
```bash
# Check container health
docker inspect --format='{{.State.Health.Status}}' sexy-pivoine-frontend
# View health check logs
docker inspect --format='{{json .State.Health}}' sexy-pivoine-frontend | jq
```
## Logs and Debugging
### View Container Logs
```bash
# Follow logs
docker logs -f sexy-pivoine-frontend
# Last 100 lines
docker logs --tail 100 sexy-pivoine-frontend
# With timestamps
docker logs -f --timestamps sexy-pivoine-frontend
```
### Execute Commands in Running Container
```bash
# Open shell
docker exec -it sexy-pivoine-frontend sh
# Check Node.js version
docker exec sexy-pivoine-frontend node --version
# Check environment variables
docker exec sexy-pivoine-frontend env
```
### Debug Build Issues
```bash
# Build with no cache
docker build --no-cache -t sexy.pivoine.art:latest .
# Build specific stage for debugging
docker build --target builder -t sexy.pivoine.art:builder .
# Inspect builder stage
docker run -it --rm sexy.pivoine.art:builder sh
```
## Production Best Practices
### 1. Use Specific Tags
```bash
# Tag with version
docker build -t sexy.pivoine.art:1.0.0 .
docker tag sexy.pivoine.art:1.0.0 sexy.pivoine.art:latest
```
### 2. Image Scanning
```bash
# Scan for vulnerabilities (requires Docker Scout or Trivy)
docker scout cves sexy.pivoine.art:latest
# Or with Trivy
trivy image sexy.pivoine.art:latest
```
### 3. Resource Limits
```bash
docker run -d \
--name sexy-pivoine-frontend \
-p 3000:3000 \
--memory="2g" \
--cpus="2" \
--env-file .env.production \
sexy.pivoine.art:latest
```
### 4. Restart Policies
```bash
docker run -d \
--name sexy-pivoine-frontend \
--restart=unless-stopped \
-p 3000:3000 \
--env-file .env.production \
sexy.pivoine.art:latest
```
### 5. Use Docker Secrets (Docker Swarm)
```bash
# Create secrets
echo "your-api-key" | docker secret create letterspace_api_key -
# Deploy with secrets
docker service create \
--name sexy-pivoine-frontend \
--secret letterspace_api_key \
-p 3000:3000 \
sexy.pivoine.art:latest
```
## Optimization Tips
### Reduce Build Time
1. **Use BuildKit cache mounts** (already enabled in Dockerfile)
2. **Leverage layer caching** - structure Dockerfile to cache dependencies
3. **Use `.dockerignore`** - exclude unnecessary files from build context
### Reduce Image Size
Current optimizations:
- Multi-stage build (builder artifacts not in final image)
- Production-only dependencies (`pnpm install --prod`)
- Minimal base image (`node:20.19.1-slim`)
- Only necessary build artifacts copied to runner
Image size breakdown:
```bash
docker images sexy.pivoine.art:latest
```
## CI/CD Integration
### GitHub Actions (Automated)
This repository includes automated GitHub Actions workflows for building, scanning, and managing Docker images.
**Pre-configured workflows:**
- **Build & Push** (`.github/workflows/docker-build-push.yml`)
- Automatically builds and pushes to `ghcr.io/valknarxxx/sexy`
- Triggers on push to main/develop, version tags, and PRs
- Multi-platform builds (AMD64 + ARM64)
- Smart tagging: latest, branch names, semver, commit SHAs
- **Security Scan** (`.github/workflows/docker-scan.yml`)
- Daily vulnerability scans with Trivy
- Reports to GitHub Security tab
- Scans on every release
- **Cleanup** (`.github/workflows/cleanup-images.yml`)
- Weekly cleanup of old untagged images
- Keeps last 10 versions
**Using pre-built images:**
```bash
# Pull latest from GitHub Container Registry
docker pull ghcr.io/valknarxxx/sexy:latest
# Pull specific version
docker pull ghcr.io/valknarxxx/sexy:v1.0.0
# Run the image
docker run -d -p 3000:3000 --env-file .env.production ghcr.io/valknarxxx/sexy:latest
```
**Triggering builds:**
```bash
# Push to main → builds 'latest' tag
git push origin main
# Create version tag → builds semver tags
git tag v1.0.0 && git push origin v1.0.0
# Pull request → builds but doesn't push
```
See `.github/workflows/README.md` for detailed workflow documentation.
## Troubleshooting
### Build Fails at Rust Installation
**Problem**: Rust installation fails or times out
**Solution**:
- Check internet connectivity
- Use a Rust mirror if in restricted network
- Increase build timeout
### WASM Build Fails
**Problem**: `wasm-bindgen-cli` version mismatch
**Solution**:
```dockerfile
# In Dockerfile, pin wasm-bindgen-cli version
RUN cargo install wasm-bindgen-cli --version 0.2.103
```
### Container Exits Immediately
**Problem**: Container starts then exits
**Solution**: Check logs and verify:
```bash
docker logs sexy-pivoine-frontend
# Verify build output exists
docker run -it --rm sexy.pivoine.art:latest ls -la packages/frontend/build
```
### Port Already in Use
**Problem**: Port 3000 already bound
**Solution**:
```bash
# Use different host port
docker run -d -p 8080:3000 sexy.pivoine.art:latest
```
## Maintenance
### Clean Up
```bash
# Remove stopped containers
docker container prune
# Remove unused images
docker image prune -a
# Remove build cache
docker builder prune
# Complete cleanup (use with caution)
docker system prune -a --volumes
```
### Update Base Image
Regularly update the base Node.js image:
```bash
# Pull latest Node 20 LTS
docker pull node:20.19.1-slim
# Rebuild
docker build --pull -t sexy.pivoine.art:latest .
```