Introduction#
GitHub this note shows how to deploy a simple next.js app in eks
- nextjs and grid of books
- build docker image
- build yaml file
Setup Project#
Let create a new next.js project
npx create-next-app@latest
Project structure
|--app|--page.tsx|--layout.css|--global.css|--Dockerfile|--.dockerignore|--build.py|--tailwind.config.js|--next.config.js|--package.json
Dark Theme#
Update the tailwind.config.js to enable dark theme
module.exports = {darkMode: "class",content: ["./pages/**/*.{js,ts,jsx,tsx,mdx}","./components/**/*.{js,ts,jsx,tsx,mdx}","./app/**/*.{js,ts,jsx,tsx,mdx}",],theme: {extend: {backgroundImage: {},fontFamily: {mplus: ["'M PLUS Rounded 1c'", "Verdana", "sans-serif"],},},},plugins: [],};
Add the mplus theme to global.css also
@import url("https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@300;500;700&display=swap");@tailwind base;@tailwind components;@tailwind utilities;
Hero Section#
Let create a nice hero section with image background or loop video (TODO)
<div className="relative h-80 dark:bg-slate-800 flex items-center justify-center"><imgsrc="/singapore.jpg"className="absolute w-full h-full object-cover opacity-30"></img><h1 className="dark:text-white font-mplus font-semibold text-3xl z-10">Web Development on AWS</h1></div>
and simple footer
<footer className="dark:text-white dark:bg-slate-900 bg-gray-200 text-gray-00 py-4"><div className="mx-auto max-w-5xl text-center text-base">Copyright © 2023 entest, Inc</div></footer>
Tailwind Grid#
Let create the home page with a grid of all books in two columns
<divclassName="mx-automax-w-5xldark:bg-slate-800px-5mt-5mb-5"><div className="grid grid-cols-2 gap-5">{books.map((book) => {return (<div key={book.order}><divclassName="ml-4bg-white p-3dark:bg-slate-900dark:text-white"><h4 className="font-bold mb-8">{book.title}</h4><div><imgsrc={book.image}className="float-left h-auto w-64 mr-6"alt="book-image"/></div><p className="text-sm">{book.description}</p><a href="#" target="_blank"><buttonclassName="bg-orange-300px-14 py-3rounded-mdshadow-mdhover:bg-orange-400mt-2">Amazon</button></a></div></div>);})}</div></div>
Docker Image#
Let build a docker image to deploy the next.js app. Here is the dockerfile
# layer 1FROM node:lts as dependenciesWORKDIR /appCOPY package.json package-lock.json ./RUN npm install --frozen-lockfile# layer 2FROM node:lts as builderWORKDIR /appCOPY . .COPY --from=dependencies /app/node_modules ./node_modulesRUN npm run build# layer 3FROM node:lts as runnerWORKDIR /appENV NODE_ENV productionCOPY --from=builder /app/public ./publicCOPY --from=builder /app/.next ./.nextCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package.json ./package.json# runEXPOSE 3000CMD ["npm", "start"]
The .dockerignore file
node_modules**/node_modules/.next.git
Let write a python script to automate build and push to aws ecr
import osimport subprocess# parametersREGION = "ap-southeast-1"ACCOUNT = "227135398356"# delete all docker imagesos.system("sudo docker system prune -a")# build next-app imageos.system("sudo docker build -t next-app . ")# aws ecr loginos.system(f"aws ecr get-login-password --region {REGION} | sudo docker login --username AWS --password-stdin {ACCOUNT}.dkr.ecr.{REGION}.amazonaws.com")# get image idIMAGE_ID=os.popen("sudo docker images -q next-app:latest").read()# tag next-app imageos.system(f"sudo docker tag {IMAGE_ID.strip()} {ACCOUNT}.dkr.ecr.{REGION}.amazonaws.com/next-app:latest")# create ecr repositoryos.system(f"aws ecr create-repository --registry-id {ACCOUNT} --repository-name next-app")# push image to ecros.system(f"sudo docker push {ACCOUNT}.dkr.ecr.{REGION}.amazonaws.com/next-app:latest")# run locally to testos.system(f"sudo docker run -d -p 3000:3000 next-app:latest")
Run the container image locally to test it
sudo docker run -d -p 3000:3000 next-app:latest"
Deploy in EKS#
Let deploy the next.js app in EKS, here is the yaml file. Please replace the ecr image path
apiVersion: v1kind: Servicemetadata:name: next-app-servicespec:ports:- port: 80targetPort: 3000selector:app: next-apptype: LoadBalancer---apiVersion: apps/v1kind: Deploymentmetadata:name: next-app-deploymentspec:replicas: 2selector:matchLabels:app: next-apptemplate:metadata:labels:app: next-appspec:containers:- image: 227135398356.dkr.ecr.ap-southeast-1.amazonaws.com/next-app:latestname: next-appports:- containerPort: 3000resources:limits:cpu: 500mrequests:cpu: 500m---apiVersion: autoscaling/v2beta2kind: HorizontalPodAutoscalermetadata:name: next-app-hpaspec:maxReplicas: 1000metrics:- resource:name: cputarget:averageUtilization: 5type: Utilizationtype: ResourceminReplicas: 2scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: next-app-deployment