feat: Next 16 + Payload 3 scaffold with Kaniko CI and Swarm deploy (#1)
Some checks failed
ci/woodpecker/push/web Pipeline failed
Some checks failed
ci/woodpecker/push/web Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #1.
This commit is contained in:
110
docker-compose.swarm.yml
Normal file
110
docker-compose.swarm.yml
Normal file
@@ -0,0 +1,110 @@
|
||||
# =============================================================================
|
||||
# jasonwoltje.com — Docker Swarm / Portainer stack
|
||||
# =============================================================================
|
||||
#
|
||||
# Deploy target: w-docker0 (10.1.1.45), Portainer endpoint 7.
|
||||
# Routing:
|
||||
# jasonwoltje.com / www.jasonwoltje.com -> web (Next.js + Payload CMS)
|
||||
#
|
||||
# Ingress pattern (mirrors MosaicStack):
|
||||
# Edge Traefik (10.1.1.43) terminates TLS
|
||||
# -> per-swarm Traefik on w-docker0 on entrypoint "web" (HTTP)
|
||||
# -> web:3000
|
||||
#
|
||||
# Usage (Portainer):
|
||||
# Stacks -> Add Stack -> Git repository
|
||||
# URL: https://git.mosaicstack.dev/jason.woltje/professional-website
|
||||
# Compose path: docker-compose.swarm.yml
|
||||
# Env vars: see .env.example (all required unless marked optional)
|
||||
# Deploy
|
||||
#
|
||||
# Image tag rule: WEB_IMAGE_TAG MUST be an immutable tag (sha-<8> or vX.Y.Z).
|
||||
# Never point this stack at `latest`.
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
web:
|
||||
image: git.mosaicstack.dev/jason.woltje/professional-website:${WEB_IMAGE_TAG}
|
||||
environment:
|
||||
DATABASE_URI: postgresql://${PAYLOAD_POSTGRES_USER}:${PAYLOAD_POSTGRES_PASSWORD}@jasonwoltje_postgres:5432/${PAYLOAD_POSTGRES_DB}
|
||||
PAYLOAD_SECRET: ${PAYLOAD_SECRET}
|
||||
PAYLOAD_PUBLIC_SERVER_URL: https://${SITE_DOMAIN:-jasonwoltje.com}
|
||||
NEXT_PUBLIC_SITE_URL: https://${SITE_DOMAIN:-jasonwoltje.com}
|
||||
NEXT_PUBLIC_BUILD_SHA: ${WEB_IMAGE_TAG}
|
||||
NEXT_PUBLIC_BUILD_REV: ${WEB_IMAGE_TAG}
|
||||
TURNSTILE_SITE_KEY: ${TURNSTILE_SITE_KEY:-}
|
||||
TURNSTILE_SECRET_KEY: ${TURNSTILE_SECRET_KEY:-}
|
||||
NEXT_PUBLIC_UMAMI_SRC: ${NEXT_PUBLIC_UMAMI_SRC:-}
|
||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${NEXT_PUBLIC_UMAMI_WEBSITE_ID:-}
|
||||
RESEND_API_KEY: ${RESEND_API_KEY:-}
|
||||
RESEND_FROM: ${RESEND_FROM:-no-reply@jasonwoltje.com}
|
||||
RESEND_TO: ${RESEND_TO:-jason@diversecanvas.com}
|
||||
MAUTIC_FORM_URL: ${MAUTIC_FORM_URL:-}
|
||||
volumes:
|
||||
- media:/app/media
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
networks:
|
||||
- internal
|
||||
- traefik-public
|
||||
deploy:
|
||||
replicas: 1
|
||||
update_config:
|
||||
parallelism: 1
|
||||
delay: 30s
|
||||
order: start-first
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 5
|
||||
window: 120s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jasonwoltje.rule=Host(`${SITE_DOMAIN:-jasonwoltje.com}`) || Host(`www.${SITE_DOMAIN:-jasonwoltje.com}`)"
|
||||
- "traefik.http.routers.jasonwoltje.entrypoints=web"
|
||||
- "traefik.http.services.jasonwoltje.loadbalancer.server.port=3000"
|
||||
# www -> apex 301
|
||||
- "traefik.http.middlewares.jasonwoltje-www-redirect.redirectregex.regex=^https?://www\\.${SITE_DOMAIN:-jasonwoltje.com}/(.*)"
|
||||
- "traefik.http.middlewares.jasonwoltje-www-redirect.redirectregex.replacement=https://${SITE_DOMAIN:-jasonwoltje.com}/$${1}"
|
||||
- "traefik.http.middlewares.jasonwoltje-www-redirect.redirectregex.permanent=true"
|
||||
- "traefik.http.routers.jasonwoltje.middlewares=jasonwoltje-www-redirect"
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_DB: ${PAYLOAD_POSTGRES_DB:-payload}
|
||||
POSTGRES_USER: ${PAYLOAD_POSTGRES_USER:-payload}
|
||||
POSTGRES_PASSWORD: ${PAYLOAD_POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks:
|
||||
- internal
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 5
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
media:
|
||||
|
||||
networks:
|
||||
internal:
|
||||
driver: overlay
|
||||
traefik-public:
|
||||
external: true
|
||||
Reference in New Issue
Block a user