initial commit
This commit is contained in:
215
docs/architecture/14-deployment-architecture.md
Normal file
215
docs/architecture/14-deployment-architecture.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# 14. Deployment Architecture
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
```dockerfile
|
||||
# docker/Dockerfile
|
||||
|
||||
# Build stage
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Copy package files
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source and build
|
||||
COPY . .
|
||||
RUN pnpm prisma generate
|
||||
RUN pnpm build
|
||||
|
||||
# Production stage
|
||||
FROM node:20-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 app
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder --chown=app:nodejs /app/.output ./.output
|
||||
COPY --from=builder --chown=app:nodejs /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=app:nodejs /app/package.json ./package.json
|
||||
COPY --from=builder --chown=app:nodejs /app/prisma ./prisma
|
||||
|
||||
USER app
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
|
||||
CMD ["node", ".output/server/index.mjs"]
|
||||
```
|
||||
|
||||
## Docker Compose (Production)
|
||||
|
||||
```yaml
|
||||
# docker/docker-compose.yml
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/dofus_manager
|
||||
- SESSION_SECRET=${SESSION_SECRET}
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- internal
|
||||
- traefik
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dofus.rule=Host(`dofus.example.com`)"
|
||||
- "traefik.http.routers.dofus.entrypoints=websecure"
|
||||
- "traefik.http.routers.dofus.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.dofus.loadbalancer.server.port=3000"
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- POSTGRES_DB=dofus_manager
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- internal
|
||||
|
||||
traefik:
|
||||
image: traefik:v3.0
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- "--api.dashboard=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- letsencrypt:/letsencrypt
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
letsencrypt:
|
||||
|
||||
networks:
|
||||
internal:
|
||||
traefik:
|
||||
external: true
|
||||
```
|
||||
|
||||
## GitLab CI/CD Pipeline
|
||||
|
||||
```yaml
|
||||
# .gitlab-ci.yml
|
||||
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
|
||||
# Test stage
|
||||
test:
|
||||
stage: test
|
||||
image: node:20-alpine
|
||||
before_script:
|
||||
- corepack enable
|
||||
- pnpm install --frozen-lockfile
|
||||
script:
|
||||
- pnpm lint
|
||||
- pnpm typecheck
|
||||
- pnpm test
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- node_modules/
|
||||
|
||||
# Build stage
|
||||
build:
|
||||
stage: build
|
||||
image: docker:24
|
||||
services:
|
||||
- docker:24-dind
|
||||
before_script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
script:
|
||||
- docker build -t $DOCKER_IMAGE -f docker/Dockerfile .
|
||||
- docker push $DOCKER_IMAGE
|
||||
- docker tag $DOCKER_IMAGE $CI_REGISTRY_IMAGE:latest
|
||||
- docker push $CI_REGISTRY_IMAGE:latest
|
||||
only:
|
||||
- main
|
||||
- develop
|
||||
|
||||
# Deploy staging
|
||||
deploy_staging:
|
||||
stage: deploy
|
||||
image: alpine:latest
|
||||
before_script:
|
||||
- apk add --no-cache openssh-client
|
||||
- eval $(ssh-agent -s)
|
||||
- echo "$SSH_PRIVATE_KEY" | ssh-add -
|
||||
- mkdir -p ~/.ssh
|
||||
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
|
||||
script:
|
||||
- ssh $STAGING_USER@$STAGING_HOST "cd /opt/dofus-manager && docker compose pull && docker compose up -d"
|
||||
environment:
|
||||
name: staging
|
||||
url: https://staging.dofus.example.com
|
||||
only:
|
||||
- develop
|
||||
|
||||
# Deploy production
|
||||
deploy_production:
|
||||
stage: deploy
|
||||
image: alpine:latest
|
||||
before_script:
|
||||
- apk add --no-cache openssh-client
|
||||
- eval $(ssh-agent -s)
|
||||
- echo "$SSH_PRIVATE_KEY" | ssh-add -
|
||||
- mkdir -p ~/.ssh
|
||||
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
|
||||
script:
|
||||
- ssh $PROD_USER@$PROD_HOST "cd /opt/dofus-manager && docker compose pull && docker compose up -d && docker compose exec app pnpm prisma migrate deploy"
|
||||
environment:
|
||||
name: production
|
||||
url: https://dofus.example.com
|
||||
only:
|
||||
- main
|
||||
when: manual
|
||||
```
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user