Crafting multi-stage builds with Docker in Node.js
Tags: showdev, webdev, devops, docker
Published: 2019-10-05 12:21:07

---
title: Crafting multi-stage builds with Docker in Node.js
published: true
description: Crafting multi-stage builds with Docker in Node.js
tags: showdev,webdev,devops,docker
canonical_url : https://cloudnweb.dev/2019/10/crafting-multi-stage-builds-with-docker-in-node-js/
---
<!-- wp:paragraph -->
<p>Docker has became an inevitable tool for development. Everyday developers face new challenges for containerizing their applications.One of the important problems are containerizing the application for different enviroments. Crafting multi-stage builds with Docker in Node.js.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>you can ask me, why do we need multi-stage build in node.js applications.why can't we just build a single stage image and deploy it to server ?. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>we are in a development era where Compiler and transpiler plays a vital role. especially, in javascript development environment. For Example, <strong><a href="https://cloudnweb.dev/2019/09/building-a-production-ready-node-js-app-with-typescript-and-docker/">TypeScript </a></strong>and <strong><a href="https://babeljs.io">Babel</a></strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Before multi-stage builds</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Before the concept of multi-stage builds,  application will have two <strong>Dockerfile</strong>. one is for <strong>development </strong>and another one is for <strong>production</strong>. this  has been referred as  a <strong><a href="https://matthiasnoback.nl/2017/04/docker-build-patterns/">builder pattern</a></strong>. But maintaining two Dockerfiles is not ideal.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Dockerfile.dev</strong></p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10.15.2-alpine
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
RUN npm run dev</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p><strong>Dockerfile</strong></p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10.15.2-alpine
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY /usr/src/app/dist ./dist
EXPOSE 4002
CMD npm start</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Although, it solves the problem of development and production image builds. this will be expensive in the long run.it will take lots of spaces in local disk as well.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Using multi-stage builds</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>multi-stage build combines different environment <strong>Dockerfile </strong>into one to create a production build. For example, Staging build creates a compiled version of application source code and final build contains the compiled version deployed in the image container.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let's see with an example of building muti-stage for Node.js with babel and MongoDB. Complete Source is available in this <a href="https://github.com/ganeshmani/node-multistage-docker">repository</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a directory and initialize the Application with Express and <a href="https://cloudnweb.dev/2019/07/configuring-babel-for-node-js-express-server/">Babel</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Staging Build</h4>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10.15.2-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY .babelrc ./
RUN npm install
COPY ./src ./src
RUN npm run build</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Above command, takes the <strong>node:10.15.2-alpine</strong> as base image and copies all the source code along with babel config. it builds the compiled code and stores it in <strong>dist </strong>folder in a container.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Final Build</h4>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10.15.2-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY .babelrc ./
RUN npm install
COPY --from=0 /usr/src/app/dist ./dist
EXPOSE 4002
CMD npm start</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>This command, takes the compiled version from previous staging build and stores it in a new image container. the magic happens in line <strong>COPY --from=0</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>COPY --from=0</strong> line copies just the build artifacts from previous stage into the new stage.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Naming build stages</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Instead of referring build stages with a Number, you can name them and use it  for reference. For Example, we specify the stage build with the name <strong>appbuild</strong></p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Staging Docker Build</h4>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10.15.2-alpine AS appbuild
WORKDIR /usr/src/app
COPY package.json ./
COPY .babelrc ./
RUN npm install
COPY ./src ./src
RUN npm run build</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":4} -->
<h4>Final docker Build</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>we refer the previous build with <strong>COPY --from=appbuild</strong></p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10.15.2-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY .babelrc ./
RUN npm install
COPY --from=appbuild /usr/src/app/dist ./dist
EXPOSE 4002
CMD npm start</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":3} -->
<h3>Complete Dockerfile</h3>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code># Build Stage 1
# This build created a staging docker image 
#
FROM node:10.15.2-alpine AS appbuild
WORKDIR /usr/src/app
COPY package.json ./
COPY .babelrc ./
RUN npm install
COPY ./src ./src
RUN npm run build

# Build Stage 2
# This build takes the production build from staging build
#
FROM node:10.15.2-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY .babelrc ./
RUN npm install
COPY --from=appbuild /usr/src/app/dist ./dist
EXPOSE 4002
CMD npm start</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Once, we complete the dockerfile. create docker compose to link multiple containers together.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a docker-compose.yml file and add the following,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>version: "3"

services: 
  app:
    container_name: app
    restart: always
    build: .
    environment: 
      - PORT=4002
    ports: 
      - "4002:4002"
    links:
      - mongo
  mongo:
    container_name: mongo
    image : mongo
    volumes: 
      - ./data:/data/db
    ports: 
      - "27017:27017"        </code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>After that, Run the docker compose with the command,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>docker-compose up</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>you can see the docker builds an intermediate image and use it to build a final one. Once it builds a final one,Docker deletes the intermediate images.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":1484} -->
<figure class="wp-block-image"><img src="https://cloudnweb.dev/wp-content/uploads/2019/10/Screenshot-2019-10-05-at-3.48.11-PM-1024x792.png" alt="" class="wp-image-1484"/></figure>
<!-- /wp:image -->

<!-- wp:image {"id":1483} -->
<figure class="wp-block-image"><img src="https://cloudnweb.dev/wp-content/uploads/2019/10/Screenshot-2019-10-05-at-3.48.36-PM-1024x237.png" alt="" class="wp-image-1483"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Complete Source code is available in this <a href="https://github.com/ganeshmani/node-multistage-docker">repository</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->