379 lines
8.2 KiB
Markdown
379 lines
8.2 KiB
Markdown
|
|
# 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 .
|
||
|
|
```
|