mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
Add GHCR container image support with multi-arch builds and security scanning
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
99
.dockerignore
Normal file
99
.dockerignore
Normal file
@@ -0,0 +1,99 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Testing
|
||||
coverage
|
||||
.nyc_output
|
||||
*.test.ts
|
||||
*.test.tsx
|
||||
*.spec.ts
|
||||
*.spec.tsx
|
||||
__tests__
|
||||
__mocks__
|
||||
.vitest
|
||||
|
||||
# Next.js
|
||||
.next
|
||||
out
|
||||
dist
|
||||
build
|
||||
|
||||
# Production
|
||||
/build
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# Debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env*.local
|
||||
.env.development
|
||||
.env.test
|
||||
.env.production
|
||||
|
||||
# Vercel
|
||||
.vercel
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# IDE
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
docs
|
||||
README*
|
||||
CHANGELOG*
|
||||
LICENSE
|
||||
|
||||
# CI/CD
|
||||
.github
|
||||
.gitlab-ci.yml
|
||||
azure-pipelines.yml
|
||||
|
||||
# Docker
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
.dockerignore
|
||||
|
||||
# Development
|
||||
.editorconfig
|
||||
.prettierrc*
|
||||
.eslintrc*
|
||||
.eslintignore
|
||||
|
||||
# Storybook
|
||||
.storybook
|
||||
storybook-static
|
||||
|
||||
# E2E
|
||||
e2e
|
||||
playwright-report
|
||||
test-results
|
||||
|
||||
# Temporary files
|
||||
tmp
|
||||
temp
|
||||
.tmp
|
||||
.cache
|
||||
138
.github/workflows/container-build.yml
vendored
Normal file
138
.github/workflows/container-build.yml
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
name: Build and Push GHCR Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build and Push Docker Images
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- image: nextjs-app
|
||||
context: .
|
||||
dockerfile: ./frontends/nextjs/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- image: dbal-daemon
|
||||
context: ./dbal/production
|
||||
dockerfile: ./dbal/production/build-config/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha,prefix={{branch}}-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ${{ matrix.context }}
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: ${{ matrix.platforms }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
||||
VCS_REF=${{ github.sha }}
|
||||
VERSION=${{ steps.meta.outputs.version }}
|
||||
|
||||
- name: Generate artifact attestation
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}
|
||||
subject-digest: ${{ steps.build.outputs.digest }}
|
||||
push-to-registry: true
|
||||
|
||||
security-scan:
|
||||
name: Security Scan Images
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-and-push
|
||||
if: github.event_name != 'pull_request'
|
||||
strategy:
|
||||
matrix:
|
||||
image: [nextjs-app, dbal-daemon]
|
||||
steps:
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}
|
||||
format: 'sarif'
|
||||
output: 'trivy-results-${{ matrix.image }}.sarif'
|
||||
|
||||
- name: Upload Trivy results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results-${{ matrix.image }}.sarif'
|
||||
category: container-${{ matrix.image }}
|
||||
|
||||
publish-manifest:
|
||||
name: Create Multi-Arch Manifest
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-and-push
|
||||
if: github.event_name != 'pull_request'
|
||||
steps:
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifest for all images
|
||||
run: |
|
||||
for image in nextjs-app dbal-daemon; do
|
||||
docker manifest create \
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$image:${{ github.ref_name }} \
|
||||
--amend ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$image:${{ github.ref_name }}-amd64 \
|
||||
--amend ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$image:${{ github.ref_name }}-arm64
|
||||
docker manifest push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/$image:${{ github.ref_name }}
|
||||
done
|
||||
110
docker-compose.ghcr.yml
Normal file
110
docker-compose.ghcr.yml
Normal file
@@ -0,0 +1,110 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
# MetaBuilder Next.js App
|
||||
nextjs-app:
|
||||
image: ghcr.io/${GITHUB_REPOSITORY:-johndoe6345789/metabuilder}/nextjs-app:${IMAGE_TAG:-latest}
|
||||
container_name: metabuilder-nextjs
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=file:/app/data/metabuilder.db
|
||||
- DBAL_API_URL=http://dbal-daemon:8080
|
||||
- DBAL_WS_URL=ws://dbal-daemon:50051
|
||||
- NEXTAUTH_URL=http://localhost:3000
|
||||
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-change-me-in-production}
|
||||
volumes:
|
||||
- metabuilder-data:/app/data
|
||||
depends_on:
|
||||
- dbal-daemon
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
networks:
|
||||
- metabuilder-network
|
||||
|
||||
# DBAL Daemon (Production)
|
||||
dbal-daemon:
|
||||
image: ghcr.io/${GITHUB_REPOSITORY:-johndoe6345789/metabuilder}/dbal-daemon:${IMAGE_TAG:-latest}
|
||||
container_name: metabuilder-dbal
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "50051:50051"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=file:/app/data/metabuilder.db
|
||||
- LOG_LEVEL=info
|
||||
- ENABLE_METRICS=true
|
||||
volumes:
|
||||
- metabuilder-data:/app/data
|
||||
- dbal-logs:/app/logs
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
networks:
|
||||
- metabuilder-network
|
||||
|
||||
# Prometheus for metrics (optional)
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: metabuilder-prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./deployment/docker/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus-data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
|
||||
- '--web.console.templates=/usr/share/prometheus/consoles'
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- metabuilder-network
|
||||
profiles:
|
||||
- monitoring
|
||||
|
||||
# Grafana for visualization (optional)
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: metabuilder-grafana
|
||||
ports:
|
||||
- "3001:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
|
||||
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
- ./deployment/docker/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
|
||||
- ./deployment/docker/grafana/datasources:/etc/grafana/provisioning/datasources:ro
|
||||
depends_on:
|
||||
- prometheus
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- metabuilder-network
|
||||
profiles:
|
||||
- monitoring
|
||||
|
||||
volumes:
|
||||
metabuilder-data:
|
||||
driver: local
|
||||
dbal-logs:
|
||||
driver: local
|
||||
prometheus-data:
|
||||
driver: local
|
||||
grafana-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
metabuilder-network:
|
||||
driver: bridge
|
||||
189
docs/CONTAINER_IMAGES.md
Normal file
189
docs/CONTAINER_IMAGES.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# MetaBuilder Container Images
|
||||
|
||||
MetaBuilder provides official container images hosted on GitHub Container Registry (GHCR) for easy deployment.
|
||||
|
||||
## Available Images
|
||||
|
||||
### 1. Next.js App (`ghcr.io/johndoe6345789/metabuilder/nextjs-app`)
|
||||
The main MetaBuilder web application built with Next.js.
|
||||
|
||||
**Features:**
|
||||
- Multi-architecture support (amd64, arm64)
|
||||
- Standalone output for minimal image size
|
||||
- Built-in health checks
|
||||
- Non-root user for security
|
||||
- DBAL types pre-generated
|
||||
|
||||
**Tags:**
|
||||
- `latest` - Latest stable build from main branch
|
||||
- `develop` - Latest development build
|
||||
- `v*.*.*` - Semantic version tags
|
||||
- `main-<sha>` - Specific commit from main branch
|
||||
|
||||
### 2. DBAL Daemon (`ghcr.io/johndoe6345789/metabuilder/dbal-daemon`)
|
||||
The secure C++ DBAL daemon for production deployments.
|
||||
|
||||
**Features:**
|
||||
- Multi-architecture support (amd64, arm64)
|
||||
- Process isolation for security
|
||||
- Connection pooling
|
||||
- Row-level security enforcement
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using Docker Compose with GHCR Images
|
||||
|
||||
```bash
|
||||
# Pull and start all services
|
||||
docker compose -f docker-compose.ghcr.yml up -d
|
||||
|
||||
# With monitoring stack
|
||||
docker compose -f docker-compose.ghcr.yml --profile monitoring up -d
|
||||
|
||||
# Stop services
|
||||
docker compose -f docker-compose.ghcr.yml down
|
||||
|
||||
# View logs
|
||||
docker compose -f docker-compose.ghcr.yml logs -f
|
||||
```
|
||||
|
||||
### Running Individual Containers
|
||||
|
||||
```bash
|
||||
# Run Next.js app
|
||||
docker run -d \
|
||||
--name metabuilder-nextjs \
|
||||
-p 3000:3000 \
|
||||
-e DATABASE_URL=file:/app/data/metabuilder.db \
|
||||
-v metabuilder-data:/app/data \
|
||||
ghcr.io/johndoe6345789/metabuilder/nextjs-app:latest
|
||||
|
||||
# Run DBAL daemon
|
||||
docker run -d \
|
||||
--name metabuilder-dbal \
|
||||
-p 8080:8080 \
|
||||
-p 50051:50051 \
|
||||
-e DATABASE_URL=file:/app/data/metabuilder.db \
|
||||
-v metabuilder-data:/app/data \
|
||||
ghcr.io/johndoe6345789/metabuilder/dbal-daemon:latest
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
To pull images from GHCR, you need a GitHub Personal Access Token with `read:packages` scope:
|
||||
|
||||
```bash
|
||||
# Login to GHCR
|
||||
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
|
||||
|
||||
# Pull an image
|
||||
docker pull ghcr.io/johndoe6345789/metabuilder/nextjs-app:latest
|
||||
```
|
||||
|
||||
## Building Images Locally
|
||||
|
||||
```bash
|
||||
# Build Next.js app
|
||||
docker build -f frontends/nextjs/Dockerfile -t metabuilder/nextjs-app:local .
|
||||
|
||||
# Build with specific platform
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-f frontends/nextjs/Dockerfile \
|
||||
-t metabuilder/nextjs-app:local .
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Next.js App
|
||||
- `DATABASE_URL` - Database connection string
|
||||
- `DBAL_API_URL` - DBAL daemon API URL (default: `http://localhost:8080`)
|
||||
- `DBAL_WS_URL` - DBAL daemon WebSocket URL (default: `ws://localhost:50051`)
|
||||
- `NEXTAUTH_SECRET` - NextAuth secret for session encryption
|
||||
- `NODE_ENV` - Environment mode (production/development)
|
||||
|
||||
### DBAL Daemon
|
||||
- `DATABASE_URL` - Database connection string
|
||||
- `LOG_LEVEL` - Logging level (debug/info/warn/error)
|
||||
- `ENABLE_METRICS` - Enable Prometheus metrics (true/false)
|
||||
- `MAX_CONNECTIONS` - Maximum database connections
|
||||
|
||||
## Health Checks
|
||||
|
||||
Both images include health checks:
|
||||
|
||||
```bash
|
||||
# Check Next.js app health
|
||||
curl http://localhost:3000/api/health
|
||||
|
||||
# Check DBAL daemon health
|
||||
curl http://localhost:8080/health
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### Image Scanning
|
||||
All images are automatically scanned for vulnerabilities using Trivy during the CI/CD pipeline. Results are available in the GitHub Security tab.
|
||||
|
||||
### Attestations
|
||||
Build provenance attestations are generated for all images pushed to GHCR, ensuring supply chain security.
|
||||
|
||||
### Non-Root Users
|
||||
All containers run as non-root users:
|
||||
- Next.js app runs as user `nextjs` (UID 1001)
|
||||
- DBAL daemon runs as user `dbal` (UID 1000)
|
||||
|
||||
## Monitoring
|
||||
|
||||
When using the monitoring profile:
|
||||
- **Prometheus**: http://localhost:9090
|
||||
- **Grafana**: http://localhost:3001 (admin/admin)
|
||||
|
||||
## Volumes
|
||||
|
||||
- `metabuilder-data` - Persistent database and application data
|
||||
- `dbal-logs` - DBAL daemon logs
|
||||
- `prometheus-data` - Prometheus metrics storage
|
||||
- `grafana-data` - Grafana dashboards and settings
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container won't start
|
||||
```bash
|
||||
# Check logs
|
||||
docker logs metabuilder-nextjs
|
||||
docker logs metabuilder-dbal
|
||||
|
||||
# Check health status
|
||||
docker inspect --format='{{json .State.Health}}' metabuilder-nextjs
|
||||
```
|
||||
|
||||
### Permission issues
|
||||
```bash
|
||||
# Ensure volumes have correct permissions
|
||||
docker volume inspect metabuilder-data
|
||||
```
|
||||
|
||||
### Network connectivity
|
||||
```bash
|
||||
# Test network connectivity between containers
|
||||
docker compose -f docker-compose.ghcr.yml exec nextjs-app curl http://dbal-daemon:8080/health
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
Images are automatically built and pushed on:
|
||||
- Push to `main` or `develop` branches
|
||||
- New version tags (`v*.*.*`)
|
||||
- Manual workflow dispatch
|
||||
|
||||
See `.github/workflows/container-build.yml` for the complete workflow.
|
||||
|
||||
## Support
|
||||
|
||||
For issues related to container images, please open an issue in the MetaBuilder repository with:
|
||||
- Image tag being used
|
||||
- Docker/Podman version
|
||||
- Platform (amd64/arm64)
|
||||
- Container logs
|
||||
- docker-compose.yml configuration (if applicable)
|
||||
89
frontends/nextjs/Dockerfile
Normal file
89
frontends/nextjs/Dockerfile
Normal file
@@ -0,0 +1,89 @@
|
||||
# Multi-stage Dockerfile for MetaBuilder Next.js App
|
||||
# Optimized for production deployment with GHCR
|
||||
|
||||
# Stage 1: Dependencies
|
||||
FROM node:20-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk add --no-cache libc6-compat
|
||||
|
||||
# Copy package files for all workspaces
|
||||
COPY package*.json ./
|
||||
COPY frontends/nextjs/package*.json ./frontends/nextjs/
|
||||
COPY dbal/development/package*.json ./dbal/development/
|
||||
COPY config/package*.json ./config/ 2>/dev/null || true
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Stage 2: Builder
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Copy dependencies from deps stage
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY --from=deps /app/frontends/nextjs/node_modules ./frontends/nextjs/node_modules
|
||||
COPY --from=deps /app/dbal/development/node_modules ./dbal/development/node_modules
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Generate DBAL types from YAML schemas
|
||||
WORKDIR /app/dbal/development
|
||||
RUN npx tsx ../shared/tools/codegen/generate-types.ts
|
||||
|
||||
# Generate Prisma Client
|
||||
WORKDIR /app/frontends/nextjs
|
||||
RUN npm run db:generate
|
||||
|
||||
# Build Next.js app
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_ENV=production
|
||||
RUN npm run build
|
||||
|
||||
# Stage 3: Production runner
|
||||
FROM node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
tini \
|
||||
curl \
|
||||
dumb-init
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copy necessary files from builder
|
||||
COPY --from=builder /app/frontends/nextjs/public ./public
|
||||
COPY --from=builder /app/frontends/nextjs/.next/standalone ./
|
||||
COPY --from=builder /app/frontends/nextjs/.next/static ./.next/static
|
||||
|
||||
# Copy Prisma schema and generated client
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma
|
||||
|
||||
# Set proper permissions
|
||||
RUN chown -R nextjs:nodejs /app
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
|
||||
CMD curl -f http://localhost:3000/api/health || exit 1
|
||||
|
||||
# Use dumb-init to handle signals
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
Reference in New Issue
Block a user