Creating a Docker Image with Next.js Build and send to GitHub Container Registry
Today, I'll guide you through a simple process to create a Docker Image with Next.js app build and host in GitHub Container Registry. In another day i'll show you how to deploy this image in Digital Ocean. Follow me folks! 🧙♂️
Start your Next.js App
1º STEP: Create a simple application with Next.js for your test. In your terminal in your app folder, please type this command line below:
npx create-next-app@latest
Creating a Dockerfile
2º STEP: After you have developed your application, let's create a file called Dockerfile and place the lines below inside it. Please create this file without any extension at root folder together with package.json.
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js
Building a Docker Image
3º STEP: Now let's build the Docker Image using this command line:
docker . -t ghcr.io/<your-git-user-here>/name-my-docker-image:latest
ATENTION: For better organization I advise you to use the domain ghcr.io along with the name of your image. And this is REQUIRED to send your image to GitHub, ok?
4º STEP: Please verify if your Docker Image was created correctly by running the following command below. The terminal will display a list of Docker Images stored on your local machine. Can you see your Docker image listed there?
docker images
Running a Docker Image
5º STEP: Now let's run the Docker Image and test if everything is running perfectly, and if we can access the application developed in the browser. Please run the following command line in your terminal.
docker run -p 3000:3000 ghcr.io/<your-git-user-here>/name-my-docker-image:latest
ATENTION: In the docker run -p 3000:3000 command, the first 3000 refers to the host port (your local machine) to which you want to map the Docker container port. This means that you will access your Docker application on port 3000 on your local computer. The second 3000 refers to the port inside the Docker container. If your Next.js application is configured to listen on port 3000, then yes, that is the port your Next.js application will be running on inside the container. If you define a different port for your application inside the container, then you would replace the second 3000 with that specific port.
5º STEP: Now please, go to your browser and try to access localhost:3000. In my case, the boilerplate from Next.js App.
6º STEP: We need to send this Docker Image to Github Container Registry. We need to create our Access Token in GitHub. Let's go guys! 😎
Creating Access Token in GitHub
7º STEP: Connect in your GitHub account in your browser, then click on your AVATAR at the right side above, and then click on SETTINGS. In the menu on the left side, at the end of this menu, click on DEVELOPER SETTINGS. Now, in the left menu, click on PERSONAL ACCESS TOKEN and then click on TOKEN CLASSIC. Click on the GENERATE NEW TOKEN button and then GENERATE NEW TOKEN CLASSIC. Now you can choose the name of this token, expiration date, and then please mark these options below.
8º STEP: Click the 'GENERATE TOKEN' button. Now GitHub will display your token. Please copy this token and save it in a safe place. We will use it later for Docker Login.
9º STEP: In the terminal, we are now going to connect to the GitHub Container Repository using the command line below. The terminal will prompt you to enter your username and password. Please COPY and PASTE your ACCESS TOKEN from GitHub. You should see a message in the terminal saying 'Login Succeeded'. 😀
docker login ghcr.io
Sending our Docker Image to GitHub
10º STEP: We will send our Docker Image to GitHub Container Repository using the command line bellow:
docker push ghcr.io/<your-git-user-here>/name-my-docker-image
11º STEP: When this process is finished, go to your GitHub account, click on the 'Packages' menu, and you will see your Docker Image.
If you've made it this far and done all the steps correctly, congratulations. 🏆 You've just pushed your first Docker Image to the GitHub Container Repository. 🤩
In my next post I will teach you how to use this image and deploy it to a VPS on Digital Ocean.
Follow me for more tips and see you next time Folks.
Eduardo Burko - Senior Front-End Developer