8.2 KiB
Docker Deployment Guide
This guide covers building and deploying sexy.pivoine.art using Docker.
Overview
The Dockerfile uses a multi-stage build process:
- Base stage: Sets up Node.js and pnpm
- Builder stage: Installs Rust, compiles WASM, builds all packages
- 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
docker build -t sexy.pivoine.art:latest .
Build with Build Arguments
docker build \
--build-arg NODE_ENV=production \
-t sexy.pivoine.art:latest \
.
Multi-platform Build (for ARM64 and AMD64)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t sexy.pivoine.art:latest \
--push \
.
Running the Container
Run with Environment Variables
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
# 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
# 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
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:
# 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
# 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
# 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
# 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
# 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
# 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
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
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)
# 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
- Use BuildKit cache mounts (already enabled in Dockerfile)
- Leverage layer caching - structure Dockerfile to cache dependencies
- 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:
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
- Automatically builds and pushes to
-
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:
# 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:
# 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:
# 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:
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:
# Use different host port
docker run -d -p 8080:3000 sexy.pivoine.art:latest
Maintenance
Clean Up
# 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:
# Pull latest Node 20 LTS
docker pull node:20.19.1-slim
# Rebuild
docker build --pull -t sexy.pivoine.art:latest .