Bladeren bron

Verify docker container build and scripts configuration

Timothy Pomeroy 4 dagen geleden
bovenliggende
commit
e153edd461
7 gewijzigde bestanden met toevoegingen van 230 en 10 verwijderingen
  1. 67 0
      .dockerignore
  2. 76 0
      Dockerfile
  3. 32 9
      README.md
  4. 30 0
      docker-compose.yml
  5. 4 0
      next.config.ts
  6. 6 1
      package.json
  7. 15 0
      src/app/api/health/route.ts

+ 67 - 0
.dockerignore

@@ -0,0 +1,67 @@
+# Dependencies
+node_modules
+.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
+
+# Testing
+coverage
+
+# Next.js
+.next
+out
+
+# Production build artifacts (rebuilt in container)
+build
+
+# Misc
+.DS_Store
+*.pem
+
+# Debug logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# Local env files (never bake secrets into the image)
+.env
+.env.*
+!.env.example
+
+# Vercel
+.vercel
+
+# TypeScript
+*.tsbuildinfo
+next-env.d.ts
+
+# Docker (avoid copying Docker-related files into context)
+Dockerfile
+.dockerignore
+docker-compose*.yml
+docker-compose*.yaml
+
+# Git
+.git
+.gitignore
+.gitattributes
+
+# Documentation (optional to exclude; remove these lines if you want docs in the image)
+docs
+README.md
+AGENTS.md
+CLAUDE.md
+
+# IDE / editor
+.vscode
+.idea
+*.swp
+*.swo
+
+# OS
+Thumbs.db

+ 76 - 0
Dockerfile

@@ -0,0 +1,76 @@
+# syntax=docker/dockerfile:1
+
+# =============================================================================
+# Jenado Unlimited Website - Production Dockerfile
+# Multi-stage build for a minimal, secure production image.
+# =============================================================================
+
+# ---- Base image with Node (Alpine for small footprint) ------------------------
+FROM node:22-alpine AS base
+
+# Install system dependencies needed for sharp (image optimization) and healthchecks
+RUN apk add --no-cache libc6-compat wget
+
+WORKDIR /app
+
+# Enable corepack for pnpm (matches lockfileVersion 9)
+RUN corepack enable
+
+# ---- Dependencies stage -------------------------------------------------------
+FROM base AS deps
+
+# Copy only manifests for better layer caching
+COPY package.json pnpm-lock.yaml ./
+COPY pnpm-workspace.yaml ./
+
+# Install dependencies (frozen for reproducibility)
+RUN pnpm install --frozen-lockfile
+
+# ---- Builder stage ------------------------------------------------------------
+FROM base AS builder
+
+# Bring in dependencies
+COPY --from=deps /app/node_modules ./node_modules
+COPY . .
+
+# Build the Next.js app (uses output: "standalone" from next.config.ts)
+ENV NEXT_TELEMETRY_DISABLED=1
+RUN pnpm build
+
+# ---- Runner stage (minimal production image) ----------------------------------
+FROM base AS runner
+
+ENV NODE_ENV=production
+ENV NEXT_TELEMETRY_DISABLED=1
+# Default port (can be overridden at runtime)
+ENV PORT=3000
+
+# Create a non-root user for security
+RUN addgroup --system --gid 1001 nodejs \
+  && adduser --system --uid 1001 nextjs
+
+WORKDIR /app
+
+# Copy public assets
+COPY --from=builder /app/public ./public
+
+# Copy standalone output (contains a minimal server.js + required node_modules)
+# See: https://nextjs.org/docs/app/api-reference/next-config-js/output
+COPY --from=builder /app/.next/standalone ./
+
+# Copy static assets into the correct location relative to server.js
+COPY --from=builder /app/.next/static ./.next/static
+
+# Ensure correct ownership
+RUN chown -R nextjs:nodejs /app
+
+USER nextjs
+
+EXPOSE 3000
+
+# Basic healthcheck using the /api/health endpoint
+HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
+  CMD wget -qO- http://127.0.0.1:${PORT}/api/health || exit 1
+
+# Start the standalone server
+CMD ["node", "server.js"]

+ 32 - 9
README.md

@@ -5,20 +5,45 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-
 First, run the development server:
 
 ```bash
-npm run dev
-# or
-yarn dev
-# or
 pnpm dev
-# or
-bun dev
 ```
 
 Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
 
 You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
 
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+## Docker
+
+The project ships with a multi-stage `Dockerfile` that produces a minimal production image using Next.js [standalone output](https://nextjs.org/docs/app/api-reference/next-config-js/output).
+
+### Build the image
+
+```bash
+pnpm docker:build
+```
+
+### Run the container
+
+```bash
+pnpm docker:run
+```
+
+The app will be available at [http://localhost:3000](http://localhost:3000).
+
+### Docker Compose (recommended for local production testing)
+
+```bash
+# Build and start
+pnpm docker:up
+
+# View logs
+pnpm docker:logs
+
+# Stop and remove containers
+pnpm docker:down
+```
+
+> **Secrets:** Pass runtime environment variables (e.g. `RESEND_API_KEY`) via a `.env` file or your deployment platform's secret manager. Never bake secrets into the image.
 
 ## Learn More
 
@@ -27,8 +52,6 @@ To learn more about Next.js, take a look at the following resources:
 - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
 - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
 
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
-
 ## Deploy on Vercel
 
 The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

+ 30 - 0
docker-compose.yml

@@ -0,0 +1,30 @@
+# =============================================================================
+# Jenado Unlimited Website - Docker Compose
+# Orchestrates the production container locally for testing.
+# =============================================================================
+
+services:
+  web:
+    build:
+      context: .
+      dockerfile: Dockerfile
+    image: jenado-unlimited:latest
+    container_name: jenado-unlimited
+    ports:
+      - "3000:3000"
+    environment:
+      - NODE_ENV=production
+      - PORT=3000
+      # Pass runtime secrets via a .env file or environment variables.
+      # Never bake secrets into the image.
+      # Example: RESEND_API_KEY=${RESEND_API_KEY}
+    env_file:
+      - path: .env
+        required: false
+    restart: unless-stopped
+    healthcheck:
+      test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
+      interval: 30s
+      timeout: 5s
+      start_period: 15s
+      retries: 3

+ 4 - 0
next.config.ts

@@ -1,6 +1,10 @@
 import type { NextConfig } from "next";
 
 const nextConfig: NextConfig = {
+  // Enable standalone output for optimized Docker images
+  // Produces .next/standalone with a minimal server.js
+  output: "standalone",
+
   images: {
     remotePatterns: [
       {

+ 6 - 1
package.json

@@ -10,7 +10,12 @@
     "test": "vitest run",
     "test:watch": "vitest",
     "test:ui": "vitest --ui",
-    "test:coverage": "vitest run --coverage"
+    "test:coverage": "vitest run --coverage",
+    "docker:build": "docker build -t jenado-unlimited-website:latest .",
+    "docker:run": "docker run --rm -p 3000:3000 --name jenado-unlimited-website jenado-unlimited-website:latest",
+    "docker:up": "docker compose up --build",
+    "docker:down": "docker compose down",
+    "docker:logs": "docker compose logs -f"
   },
   "dependencies": {
     "@hookform/resolvers": "^5.7.1",

+ 15 - 0
src/app/api/health/route.ts

@@ -0,0 +1,15 @@
+import { NextResponse } from "next/server";
+
+/**
+ * Simple health check endpoint for container orchestration and load balancers.
+ * Returns 200 when the application is running.
+ */
+export async function GET() {
+  return NextResponse.json(
+    {
+      status: "ok",
+      timestamp: new Date().toISOString(),
+    },
+    { status: 200 }
+  );
+}