How ammobin.ca reduced its Nuxt docker container image size by 60% using multi stage builds
To run a nuxt.js server in production mode, one needs to ‘build’ it first using
nuxt build. This generates a node server to host the app and serve the assets as well as generating a ‘production’ build of the clientside assets.
These build time dependencies are not needed for running the server in production and contribute a lot to the final docker image size.
In order to both build and run the nuxt server within the same Dockerfile, the below sample will make use of Docker’s multi stage build feature
In the below case, the nuxt client for ammobin.ca will used.
Old dockerfile (src)
FROM node:12-alpine RUN apk --no-cache add wget git g++ make python WORKDIR /build COPY package*.json /build/ RUN npm install #--production RUN apk --no-cache del git g++ make python COPY . /build EXPOSE 3000 RUN npm run build HEALTHCHECK --interval=30s --timeout=1s CMD wget localhost:3000/ping -q -O/dev/null || exit 1 CMD npm start
build size 732MB (304MB compressed)
New dockerfile (src)
#### # build: pull in + install everything to run nuxt build #### FROM node:12-alpine as build RUN apk --no-cache add wget git g++ make python WORKDIR /build COPY package*.json /build/ RUN npm install RUN apk --no-cache del git g++ make python COPY . /build RUN npm run build ######## # run: do production install + copy build output of build container and run the node server ######## FROM node:12-alpine as main WORKDIR /build COPY --from=build /build/package*.json /build/ RUN npm install --production # copy min needed to run (built) app COPY --from=build /build/nuxt.config.ts /build COPY --from=build /build/.nuxt /build/.nuxt COPY --from=build /build/static /build/static RUN apk --no-cache add wget EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=1s CMD wget localhost:3000/ping -q -O/dev/null || exit 1 USER node CMD npm start
build size 295MB (110MB compressed)
By isolating the build dependencies from the server dependencies, the final image size was reduced by 60% (64% compressed). While the old build size was not a blocking issue, the reduced size speeds up updates, reduces downtime, and saves some disk space (ammobin.ca runs on a single 20GB VPS using docker-compose).