DEV Community

Rafael Magalhaes
Rafael Magalhaes

Posted on • Edited on

Docker and Nuxt 3

Lets start by creating a Dockerfile in the root of the project

Dockerfile



# use node 16 alpine image
FROM node:16-alpine

# create work directory in app folder
WORKDIR /app

# install required packages for node image
RUN apk --no-cache add openssh g++ make python3 git

# copy over package.json files
COPY package.json /app/
COPY package-lock.json /app/

# install all depencies
RUN npm ci && npm cache clean --force

# copy over all files to the work directory
ADD . /app

# build the project
RUN npm run build

# expose the host and port 3000 to the server
ENV HOST 0.0.0.0
EXPOSE 3000

# run the build project with node
ENTRYPOINT ["node", ".output/server/index.mjs"]


Enter fullscreen mode Exit fullscreen mode

now lets make a docker-compose file

docker-compose.yml



version: "3"

services:
  nuxt-docker-example:
    container_name: nuxt-docker-example
    build:
      context: .
      dockerfile: DockerFile
    ports:
      - "3000:3000"


Enter fullscreen mode Exit fullscreen mode

build the docker image

docker compose up --build you can add -d at the end to run it in the background

if everything went alright, open localhost:3000 and we can see the project running.

Docker image size

If we look over at the docker desktop and see the image size its over 850MB

Image description

We can reduce the size of the image by adjusting the Dockerfile using multi-stage builds

Docker multi stage

Multistage builds make use of one Dockerfile with multiple FROM instructions. Each of these FROM instructions is a new build stage that can COPY artifacts from the previous stages. By going and copying the build artifact from the build stage, you get rid of all the unnecessary packages and files. All these steps create additional layers, and you want to eliminate them from the final image. thus reducing the size of the final image

lets adjust the dockerfile



# use node 16 alpine image as build image
FROM node:16-alpine as builder

# create work directory in app folder
WORKDIR /app

# install required packages for node image
RUN apk --no-cache add openssh g++ make python3 git

# copy over package.json files
COPY package.json /app/
COPY package-lock.json /app/

# install all depencies
RUN npm ci && npm cache clean --force

# copy over all files to the work directory
ADD . /app

# build the project
RUN npm run build

# start final image
FROM node:16-alpine


WORKDIR /app

# copy over build files from builder step
COPY --from=builder /app/.output  app/.output
COPY --from=builder /app/.nuxt  app/.nuxt

# expose the host and port 3000 to the server
ENV HOST 0.0.0.0
EXPOSE 3000

# run the build project with node
ENTRYPOINT ["node", ".output/server/index.mjs"]


Enter fullscreen mode Exit fullscreen mode

the first line of code in the file changed to

FROM node:16-alpine as builder

this tells docker that this stage is just for building our application

after npm run build command we added another FROM command
FROM node:16-alpine because this is a new stage we specified a WORKDIR again, then we copied over the files from the build stage to the final stage.

And that's it, the image size is now 364MB! A big difference from the previous 886MB

Image description
)

Top comments (5)

Collapse
 
aleksandrkrokis profile image
Aleksandr

just want to notice. you don't need copy all files of project from first stage. it is enough to copy only .output directory. so then your image will be much smaller)

Collapse
 
rafaelmagalhaes profile image
Rafael Magalhaes

nice one, thank you

I will update the article with these changes

Collapse
 
freecoderx profile image
FreeCoderX

Is that what you're saying?
...
ADD ./output /app

build the project

RUN npm run build
...

Sorry, I'm new to this, I don't quite understand what you mean, could you explain it in detail

Collapse
 
willsilvano profile image
Willian • Edited

Thanks!
I've changed the Dockerfile:
COPY --from=builder /app/.output /app/.output

Collapse
 
jackhuynh95 profile image
Jack Huynh

very helpful and insightful