This document describes the architecture of the Next.js portfolio application and how Docker and Kubernetes are orchestrated to build, run, and scale it.
- Architecture Overview
- Docker Multi-Stage Build
- Kubernetes Manifests
- Local Debugging with Docker
- Deploying to Kubernetes
- Environment Variables
- Troubleshooting
- Support
The portfolio application is a Next.js 14 project (App Router, TypeScript, React 18) styled with TailwindCSS and animated via Framer Motion and Radix UI. At build time, Next.js outputs:
- A standalone server bundle (
.next/standalone) - Static assets (
.next/static,public)
At runtime, a minimal Node.js container serves the application on port 3000.
In Kubernetes, traffic flows as:
Client → Ingress → Service → Deployment → Pod (Node.js + Next.js)
To optimize image size and security, the Dockerfile uses two stages:
FROM node:24-slim AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml* ./
RUN npm install --legacy-peer-deps
COPY . .
RUN npm run build- Installs dependencies and builds the Next.js application into a standalone server bundle.
FROM node:24-slim AS runner
WORKDIR /app
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
ENV RESEND_API_KEY=
EXPOSE 3000
CMD ["node", "server.js"]- Copies only the production bundle and static assets into a fresh image.
- Defines a default environment variable for the Resend API key.
- Exposes port 3000 and launches the standalone Next.js server.
All Kubernetes manifests are stored in the k8s/ directory:
- deployment.yml: Defines a Deployment with 3 replicas, CPU/memory requests and limits, and health probes (
livenessProbe,readinessProbe). - service.yml: Creates a ClusterIP Service exposing port 80, forwarding to container port 3000.
- ingress.yml: Configures an NGINX Ingress to route
portfolio.localhost traffic to the Service.
Apply all manifests:
kubectl apply -f k8s/Build and run the container locally for development:
docker build -t portfolio:local .
docker run --rm -p 3000:3000 `
-e RESEND_API_KEY=$env:RESEND_API_KEY `
portfolio:localBrowse http://localhost:3000 to verify functionality.
-
Build, tag, and push your image:
docker build -t portfolio:prod . docker tag portfolio:prod yourrepo/portfolio:latest docker push yourrepo/portfolio:latest -
Update
image:ink8s/deployment.yml:containers: - name: portfolio image: yourrepo/portfolio:latest
-
Apply or update manifests:
kubectl apply -f k8s/
| Variable | Description | Required |
|---|---|---|
| RESEND_API_KEY | API key for Resend email service | Yes |
Override at runtime in Docker or via Kubernetes Secrets/ConfigMaps.
Container exits immediately
- Inspect logs:
docker logs <container-id> - Verify
RESEND_API_KEYis set correctly
Port conflicts
- Map to a different host port:
-p 8080:3000
Ingress routing fails
- Ensure
portfolio.localis added to your/etc/hostsor DNS - Check Ingress details:
kubectl describe ingress portfolio-ingress
If you encounter issues with containerization or Kubernetes deployment, please open an issue at the GitHub repository or contact the maintainer at abpriyanshu085@gmail.com.