K8s nextjs deploy
Personal collection of agent skills for use with Claude Code and other LLM agents.
npx -y skills add andreab67/agent-skills --skill k8s-nextjs-deployAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Kubernetes deployment patterns for Next.js applications — Deployment/Service/Ingress manifests, Harbor image pull secrets, Traefik ingress with cert-manager TLS, Linkerd service mesh, multi-app namespaces, and K8s secret rotation. Use this skill whenever the user mentions deploying a Next.js app to Kubernetes, ImagePullBackOff, CrashLoopBackOff, Harbor pull secret, Traefik ingress, cert-manager, a missing secretKeyRef, or namespace recovery — even if they just say "the pod won't start" or "deploy this to k8s" without further detail.
SKILL.md
8.4 KB, as published. Nobody here has run it
k8s-nextjs-deploy
Kubernetes deployment patterns for containerized Next.js apps: Harbor registry auth, Traefik ingress with automatic TLS, Linkerd sidecar injection, and multi-app namespace management.
When to use
- Deploying a new Next.js app (Deployment + Service + Ingress rule)
- Diagnosing
ImagePullBackOff,ErrImagePull,CreateContainerConfigError - Rotating Harbor pull secret credentials
- Adding a subdomain to an existing Traefik ingress with cert-manager
- Applying K8s manifests after a namespace was deleted
- Troubleshooting pods stuck because of missing
secretKeyRefsecrets
Do NOT use for:
- Non-Kubernetes deployments (Docker Compose, bare-metal, Vercel)
- Database deployments (stateful sets require separate skill)
Deploying a new Next.js app — step by step
- Create the namespace (if it doesn't exist yet):
kubectl create namespace <ns>. Success:kubectl get ns <ns>showsActive. - Create the Harbor pull secret using the single-quoted
docker-registrycommand below. Success:kubectl -n <ns> get secret harbor-pull-secretexists anddescribeshows typekubernetes.io/dockerconfigjson. - Apply the Deployment manifest (with
imagePullSecrets, resource requests/limits, and readiness/liveness probes set). Success:kubectl -n <ns> get podsshows the podRunningand1/1 Ready. - Apply the Service. Success:
kubectl -n <ns> get svc <name>shows a ClusterIP with the expected port mapping. - Apply/extend the Ingress, adding the new host to both
tls.hostsandrules. Success:kubectl -n <ns> get ingresslists the host, andkubectl -n <ns> get certificatereachesREADY: Truewithin a couple of minutes as cert-manager issues the cert. - Verify end-to-end:
curl -I https://<host>returns200/3xxwith a trusted TLS chain (no cert warning). If it doesn't, work through Common failure diagnosis below.
Deployment manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: cloudreviewer-web
namespace: cloudreviewer
spec:
replicas: 1
selector:
matchLabels:
app: cloudreviewer-web
template:
metadata:
labels:
app: cloudreviewer-web
spec:
imagePullSecrets:
- name: harbor-pull-secret
containers:
- name: web
image: harbor.example.com/project/app:latest
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
ports:
- containerPort: 3000
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
env:
- name: HOSTNAME
value: "0.0.0.0"
- name: NODE_ENV
value: "production"
- name: NEXT_TELEMETRY_DISABLED
value: "1"
- name: OTEL_SERVICE_NAME
value: "my-app"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://tempo.tempo.svc.cluster.local:4318"
readinessProbe:
httpGet:
path: /
port: 3000
livenessProbe:
httpGet:
path: /
port: 3000
Service
apiVersion: v1
kind: Service
metadata:
name: cloudreviewer-web
namespace: cloudreviewer
spec:
selector:
app: cloudreviewer-web
ports:
- name: http
port: 80
targetPort: 3000
Ingress (Traefik + cert-manager)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cloudreviewer
namespace: cloudreviewer
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: traefik
tls:
- hosts:
- www.example.com
- buy.example.com
- kb.example.com
secretName: cloudreviewer-tls
rules:
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: cloudreviewer-web
port:
number: 80
Add new subdomains to both tls.hosts and rules.
Harbor pull secret
kubectl -n <namespace> create secret docker-registry harbor-pull-secret \
--docker-server=harbor.example.com \
--docker-username='robot$project+robot' \
--docker-password='TOKEN'
Single quotes are mandatory — robot account usernames contain $ which the shell would expand. Never use double quotes.
Rotating credentials
kubectl -n <namespace> delete secret harbor-pull-secret
kubectl -n <namespace> create secret docker-registry harbor-pull-secret \
--docker-server=harbor.example.com \
--docker-username='robot$project+robot' \
--docker-password='NEW_TOKEN'
kubectl -n <namespace> rollout restart deployment/<name>
Pods scheduled before the secret existed cache the auth failure. Always rollout restart after recreating the secret.
Common failure diagnosis
ImagePullBackOff / ErrImagePull
kubectl -n <ns> describe pod <pod> | grep -A 10 "Events:"
| Error message | Cause | Fix |
|---|---|---|
401 Unauthorized | Stale or missing pull secret | Rotate pull secret → rollout restart |
repository does not exist | Wrong image name or project | Check Harbor project name matches image path |
no basic auth credentials | Pod scheduled before secret created | rollout restart after creating secret |
CreateContainerConfigError
Pod image pulled successfully but container won't start — usually a missing secretKeyRef:
kubectl -n <ns> describe pod <pod> | grep -i "secret\|error" | head -20
The referenced secret (e.g., cloudreviewer-buy-secrets) was lost when the namespace was deleted. Recreate it:
kubectl -n <ns> create secret generic my-app-secrets \
--from-literal=key1=value1 \
--from-literal=key2=value2
Namespace deleted — full apply order
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/web-deployment.yaml -f k8s/web-service.yaml
kubectl apply -f k8s/buy-deployment.yaml -f k8s/buy-service.yaml
kubectl apply -f k8s/kb-deployment.yaml -f k8s/kb-service.yaml
kubectl apply -f k8s/ingress.yaml
# Then recreate pull secret and app secrets
Environment variables for Next.js
Required env vars for a standalone Next.js container:
| Variable | Value | Purpose |
|---|---|---|
HOSTNAME | 0.0.0.0 | Bind to all interfaces |
NODE_ENV | production | Enables prod optimisations |
NEXT_TELEMETRY_DISABLED | 1 | Disable Next.js telemetry |
OTEL_SERVICE_NAME | app name | OTel trace attribution |
OTEL_EXPORTER_OTLP_ENDPOINT | Tempo/Grafana URL | Trace export |
NEXT_PUBLIC_SITE_URL | https://www.example.com | Metadata base URL |
Multiple kubectl contexts
When managing multiple clusters:
kubectl config get-contexts # list
kubectl config use-context sr-k8s # switch
kubectl config current-context # verify
Always verify context before applying manifests or rotating secrets.
Example prompts
- "Our pods are stuck in
ImagePullBackOff. How do I diagnose and fix this?" - "I rotated the Harbor robot account token. How do I update the pull secret without downtime?"
- "Add subdomain
kb.example.comto the existing Traefik ingress." - "The namespace got accidentally deleted. Walk me through restoring everything in order."
- "A pod is in
CreateContainerConfigError. What does that mean and how do I fix it?" - "Show me a production-ready Next.js Deployment manifest with resource limits and probes."
Related skills
nextjs-monorepo-ci— CI pipeline that builds and pushes the images this skill deploysarcgis-enterprise-k8s— deploying a more complex stateful app on Kubernetes