<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Node.JS Practices</title>
    <description>The latest articles on DEV Community by Node.JS Practices (@nodepractices).</description>
    <link>https://dev.to/nodepractices</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F453541%2Fcce603b8-271d-4bfc-8bc5-9f8bc3872349.jpg</url>
      <title>DEV Community: Node.JS Practices</title>
      <link>https://dev.to/nodepractices</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nodepractices"/>
    <language>en</language>
    <item>
      <title>Docker best practices with Node.js</title>
      <dc:creator>Node.JS Practices</dc:creator>
      <pubDate>Sun, 16 Aug 2020 15:48:42 +0000</pubDate>
      <link>https://dev.to/nodepractices/docker-best-practices-with-node-js-4ln4</link>
      <guid>https://dev.to/nodepractices/docker-best-practices-with-node-js-4ln4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Collected, curated and written by:&lt;/strong&gt; &lt;a href="https://testjavascript.com/" rel="noopener noreferrer"&gt;Yoni Goldberg&lt;/a&gt;, &lt;a href="https://brunoscheufler.com" rel="noopener noreferrer"&gt;Bruno Scheufler&lt;/a&gt;, Kevyn Bruyere and Kyle Martin&lt;/p&gt;

&lt;h2&gt;
  
  
  Welcome to our comprehensive list of Docker best practices that are exemplified under the realm of Node.js.
&lt;/h2&gt;

&lt;p&gt;Note that each and every bullet has a link to detailed information and code examples. The entire list can be found in our repository &lt;a href="https://github.com/goldbergyoni/nodebestpractices" rel="noopener noreferrer"&gt;Node.js Best Practices&lt;/a&gt;. It covers the basics but goes all the way to strategic decisions like how much and where to limit the container's memory, how to prevent secrets from sticking to the image, is a process manager needed as the top process or can Node act as PID1?&lt;/p&gt;

&lt;p&gt;🏅 Many thanks to &lt;a href="https://github.com/BretFisher" rel="noopener noreferrer"&gt;Bret Fisher&lt;/a&gt; from whom we learned many insightful Docker best practices&lt;/p&gt;



&lt;h2&gt;
  
  
  ✅ 1 Use multi-stage builds for leaner and more secure Docker images
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Use multi-stage build to copy only necessary production artifacts. A lot of build-time dependencies and files are not needed for running your application. With multi-stage builds these resources can be used during build while the runtime environment contains only what's necessary. Multi-stage builds are an easy way to get rid of overweight and security threats&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Larger images will take longer to build and ship, build-only tools might contain vulnerabilities and secrets only meant for the build phase might be leaked.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍🏽 Code Example - Dockerfile for multi-stage builds
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:14.4.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:slim-14.4.0&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "node", "dist/app.js" ]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/multi_stage_builds.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 2. Bootstrap using 'node' command, avoid npm start
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; use &lt;code&gt;CMD ['node','server.js']&lt;/code&gt; to start your app, avoid using npm scripts which don't pass OS signals to the code. This prevents problems with child-process, signal handling, graceful shutdown and having processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code example - Bootstrapping using Node
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;


&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:12-slim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;


&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--production&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm cache clean &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "server.js"]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/bootstrap-using-node.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 3. Let the Docker runtime handle replication and uptime
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; When using a Docker run time orchestrator (e.g., Kubernetes), invoke the Node.js process directly without intermediate process managers or custom code that replicate the process (e.g. PM2, Cluster module). The runtime platform has the highest amount of data and visibility for making placement decision - It knows best how many processes are needed, how to spread them and what to do in case of crashes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Container keeps crashing due to lack of resources will get restarted indefinitely by the process manager. Should Kubernetes be aware of that, it could relocate it to a different roomy instance&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Invoking Node.js directly without intermediate tools
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

FROM node:12-slim

# The build logic comes here

CMD ["node", "index.js"]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/restart-and-replicate-processes.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 4. Use .dockerignore to prevent leaking secrets
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Include a .dockerignore file that filters out common secret files and development artifacts. By doing so, you might prevent secrets from leaking into the image. As a bonus the build time will significantly decrease. Also, ensure not to copy all files recursively rather explicitly choose what should be copied to Docker&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Otherwise&lt;/strong&gt;: Common personal secret files like .env, .aws and .npmrc will be shared with anybody with access to the image (e.g. Docker repository)&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – A good default .dockerignore for Node.js
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

**/node_modules/
**/.git
**/README.md
**/LICENSE
**/.vscode
**/npm-debug.log
**/coverage
**/.env
**/.editorconfig
**/.aws
**/dist


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/docker-ignore.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 5. Clean-up dependencies before production
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Although DevDependencies are sometimes needed during the build and test life-cycle, eventually the image that is shipped to production should be minimal and clean from development dependencies. Doing so guarantees that only necessary code is shipped and the amount of potential attacks (i.e. attack surface) is minimized. When using multi stage build (see dedicated bullet) this can be achieved by installing all dependencies first and finally running 'npm ci --production'&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Many of the infamous npm security breaches were found within development packages (e.g. &lt;a href="https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes" rel="noopener noreferrer"&gt;eslint-scope&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Installing for production
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:12-slim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json package-lock.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--production&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm clean cache &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="c"&gt;# The rest comes here&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/install-for-production.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 6. Shutdown smartly and gracefully
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Dying immediately means not responding to thousands of disappointed users&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Placing Node.js as the root process allows passing signals to the code
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;


&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12-slim&lt;/span&gt;

&lt;span class="c"&gt;# Build logic comes here&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "index.js"]&lt;/span&gt;
&lt;span class="c"&gt;#This line above will make Node.js the root process (PID1)&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✍🏽 Code Example – Using Tiny process manager to forward signals to Node
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;


&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12-slim&lt;/span&gt;

&lt;span class="c"&gt;# Build logic comes here&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; TINI_VERSION v0.19.0&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /tini
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/tini", "--"]&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "index.js"]&lt;/span&gt;
&lt;span class="c"&gt;#Now Node will run a sub-process of TINI which acts as PID1&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/graceful-shutdown.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 7. Set memory limits using both Docker and v8
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Always configure a memory limit using both Docker and the JavaScript runtime flags. The Docker limit is needed to make thoughtful container placement decision, the --v8's flag max-old-space is needed to kick off the GC on time and prevent under utilization of memory. Practically, set the v8's old space memory to be a just bit less than the container limit&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; The docker definition is needed to perform thoughtful scaling decisions and prevent starving other citizens. Without also defining the v8's limits, it will underutilize the container resources - Without explicit instructions, it crashes when utilizing ~50-60% of its host resources&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Memory limit with Docker
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker run --memory 512m my-node-app


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✍🏽 Code Example – Memory limit with Kubernetes and v8
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

apiVersion: v1
kind: Pod
metadata:
  name: my-node-app
spec:
  containers:
  - name: my-node-app
    image: my-node-app
    resources:
      requests:
        memory: "400Mi"
      limits:
        memory: "500Mi"
    command: ["node index.js --max-old-space-size=450"]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/memory-limit.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 8. Plan for efficient caching
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly. The less updated instructions should be at the top of your Dockerfile and the ones constantly changing (like app code) should be at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Docker build will be very long and consume a lot of resources even when making tiny changes&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Dependencies install first, then code
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; "package.json" "package-lock.json" "./"&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./app ./app"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  ✍🏽 Anti-pattern – Dynamic labels
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="c"&gt;#Beginning of the file&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:10.22.0-alpine3.11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="c"&gt;# Don't do that here!&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; build_number="483"&lt;/span&gt;

&lt;span class="c"&gt;#... Rest of the Dockerfile&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Install "system" packages first
&lt;/h3&gt;

&lt;p&gt;It is recommended to create a base docker image that has all the system packages you use. If you &lt;strong&gt;really&lt;/strong&gt; need to install packages using &lt;code&gt;apt&lt;/code&gt;,&lt;code&gt;yum&lt;/code&gt;,&lt;code&gt;apk&lt;/code&gt; or the likes, this should be one of the first instructions. You don't want to reinstall make,gcc or g++ every time you build your node app.&lt;br&gt;
&lt;strong&gt;Do not install package only for convenience, this is a production app.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:10.22.0-alpine3.11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    build-base &lt;span class="se"&gt;\
&lt;/span&gt;    gcc &lt;span class="se"&gt;\
&lt;/span&gt;    g++ &lt;span class="se"&gt;\
&lt;/span&gt;    make

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; "package.json" "package-lock.json" "./"&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . "./"&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/ "./"&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm prune &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/server.js"]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/use-cache-for-shorter-build-time.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 9. Use explicit image reference, avoid &lt;code&gt;latest&lt;/code&gt; tag
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Specify an explicit image digest or versioned label, never refer to 'latest'. Developers are often led to believe that specifying the &lt;code&gt;latest&lt;/code&gt; tag will provide them with the most recent image in the repository however this is not the case. Using a digest guarantees that every instance of the service is running exactly the same code.&lt;/p&gt;

&lt;p&gt;In addition, referring to an image tag means that the base image is subject to change, as image tags cannot be relied upon for a deterministic install. Instead, if a deterministic install is expected, a SHA256 digest can be used to reference an exact image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; A new version of a base image could be deployed into production with breaking changes, causing unintended application behavior.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code example - Right vs wrong
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; company/image_name:0.1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# 👍🏼 Immutable&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; company/image_name
&lt;span class="c"&gt;# 👎 Mutable&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; company/image_name:0.2 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# 👍🏼 Immutable&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; company/image_name:latest &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# 👎 Mutable&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker pull ubuntu@sha256:45b23dee
&lt;span class="c"&gt;# 👍🏼 Immutable&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/image-tags.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 10. Prefer smaller Docker base images
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Large images lead to higher exposure to vulnerabilities and increased resource consumption. Using leaner Docker images, such as Slim and Alpine Linux variants, mitigates this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Building, pushing, and pulling images will take longer, unknown attack vectors can be used by malicious actors and more resources are consumed.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/smaller_base_images.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ✅ 11. Clean-out build-time secrets, avoid secrets in args
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Avoid secrets leaking from the Docker build environment. A Docker image is typically shared in multiple environment like CI and a registry that are not as sanitized as production. A typical example is an npm token which is usually passed to a Dockerfile as argument. This token stays within the image long after it is needed and allows the attacker indefinite access to a private npm registry. This can be avoided by coping a secret file like &lt;code&gt;.npmrc&lt;/code&gt; and then removing it using multi-stage build (beware, build history should be deleted as well) or by using Docker build-kit secret feature which leaves zero traces&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Everyone with access to the CI and docker registry will also get access to some precious organization secrets as a bonus&lt;/p&gt;
&lt;h3&gt;
  
  
  ✍🏽 Code Example – Using Docker mounted secrets (experimental but stable)
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# syntax = docker/dockerfile:1.0-experimental

FROM node:12-slim
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci

# The rest comes here


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✍🏽 Code Example – Building securely using multi-stage build
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;FROM node:12-slim AS build&lt;br&gt;
ARG NPM_TOKEN&lt;br&gt;
WORKDIR /usr/src/app&lt;br&gt;
COPY . /dist&lt;br&gt;
RUN echo "//registry.npmjs.org/:_authToken=\$NPM_TOKEN" &amp;gt; .npmrc &amp;amp;&amp;amp; \&lt;br&gt;
 npm ci --production &amp;amp;&amp;amp; \&lt;br&gt;
 rm -f .npmrc&lt;/p&gt;

&lt;p&gt;FROM build as prod&lt;br&gt;
COPY --from=build /dist /dist&lt;br&gt;
CMD ["node","index.js"]&lt;/p&gt;
&lt;h1&gt;
  
  
  The ARG and .npmrc won't appear in the final image but can be found in the Docker daemon un-tagged images list - make sure to delete those
&lt;/h1&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/avoid-build-time-secrets.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ 12. Scan images for multi-layers of vulnerabilities
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Besides checking code dependencies vulnerabilities also scan the final image that is shipped to production. Docker image scanners check the code dependencies but also the OS binaries. This E2E security scan covers more ground and verifies that no bad guy injected bad things during the build. Consequently, it is recommended to run this as the last step before deployment. There are a handful of free and commercial scanners that also provide CI/CD plugins&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Your code might be entirely free from vulnerabilities. However, it might still get hacked due to vulnerable version of OS-level binaries (e.g. OpenSSL, TarBall) that are commonly being used by applications&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍🏽 Code Example – Scanning with Trivvy
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;sudo apt-get install rpm&lt;br&gt;
$ wget &lt;a href="https://github.com/aquasecurity/trivy/releases/download/%7BTRIVY_VERSION%7D/trivy_%7BTRIVY_VERSION%7D_Linux-64bit.deb" rel="noopener noreferrer"&gt;https://github.com/aquasecurity/trivy/releases/download/{TRIVY_VERSION}/trivy_{TRIVY_VERSION}_Linux-64bit.deb&lt;/a&gt;&lt;br&gt;
$ sudo dpkg -i trivy_{TRIVY_VERSION}_Linux-64bit.deb&lt;br&gt;
trivy image [YOUR_IMAGE_NAME]&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/scan-images.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ 13 Clean NODE_MODULE cache
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; After installing dependencies in a container remove the local cache. It doesn't make any sense to duplicate the dependencies for faster future installs since there won't be any further installs - A Docker image is immutable. Using a single line of code tens of MB (typically 10-50% of the image size) are shaved off&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; The image that will get shipped to production will weigh 30% more due to files that will never get used&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍🏽 Code Example – Clean cache
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;FROM node:12-slim AS build&lt;br&gt;
WORKDIR /usr/src/app&lt;br&gt;
COPY package.json package-lock.json ./&lt;br&gt;
RUN npm ci --production &amp;amp;&amp;amp; npm cache clean --force&lt;/p&gt;
&lt;h1&gt;
  
  
  The rest comes here
&lt;/h1&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/clean-cache.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ 14. Generic Docker practices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; This is a collection of Docker advice that is not related directly to Node.js - the Node implementation is not much different than any other language:&lt;/p&gt;

&lt;h2&gt;
  
  
  ✓ Prefer COPY over ADD command
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; COPY is safer as it copies local files only while ADD supports fancier fetches like downloading binaries from remote sites&lt;/p&gt;

&lt;h2&gt;
  
  
  ✓ Avoid updating the base OS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Updating the local binaries during build (e.g. apt-get update) creates inconsistent images every time it runs and also demands elevated privileges. Instead use base images that are updated frequently&lt;/p&gt;

&lt;h2&gt;
  
  
  ✓ Classify images using labels
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Providing metadata for each image might help Ops professionals treat it adequately. For example, include the maintainer name, build date and other information that might prove useful when someone needs to reason about an image&lt;/p&gt;

&lt;h2&gt;
  
  
  ✓ Use unprivileged containers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Privileged container have the same permissions and capabilities as the root user over the host machine. This is rarely needed and as a rule of thumb one should use the 'node' user that is created within official Node images&lt;/p&gt;

&lt;h2&gt;
  
  
  ✓ Inspect and verify the final result
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Sometimes it's easy to overlook side effects in the build process like leaked secrets or unnecessary files. Inspecting the produced image using tools like &lt;a href="https://github.com/wagoodman/dive" rel="noopener noreferrer"&gt;Dive&lt;/a&gt; can easily help to identify such issues&lt;/p&gt;

&lt;h2&gt;
  
  
  ✓ Perform integrity check
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; While pulling base or final images, the network might be mislead and redirected to download malicious images. Nothing in the standard Docker protocol prevents this unless signing and verifying the content. &lt;a href="https://docs.docker.com/notary/getting_started/" rel="noopener noreferrer"&gt;Docker Notary&lt;/a&gt; is one of the tools to achieve this&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/generic-tips.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ 15. Lint your Dockerfile
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📘 TL;DR:&lt;/strong&gt; Linting your Dockerfile is an important step to identify issues in your Dockerfile which differ from best practices. By checking for potential flaws using a specialized Docker linter, performance and security improvements can be easily identified, saving countless hours of wasted time or security issues in production code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚩 Otherwise:&lt;/strong&gt; Mistakenely the Dockerfile creator left Root as the production user and also used an image from an unknown source repository. This could be avoided with just a simple linter.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍🏽 Code example - Inspecting a Dockerfile using hadolint
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;hadolint production.Dockerfile&lt;br&gt;
hadolint &lt;span class="nt"&gt;--ignore&lt;/span&gt; DL3003 &lt;span class="nt"&gt;--ignore&lt;/span&gt; DL3006 &amp;lt;Dockerfile&amp;gt; &lt;span class="c"&gt;# exclude specific rules&lt;/span&gt;&lt;br&gt;
hadolint &lt;span class="nt"&gt;--trusted-registry&lt;/span&gt; my-company.com:500 &amp;lt;Dockerfile&amp;gt; &lt;span class="c"&gt;# Warn when using untrusted FROM images&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a href="https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/docker/lint-dockerfile.md" rel="noopener noreferrer"&gt;&lt;strong&gt;🔗  More examples and further explanations&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8threb1mjrehb1saismq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Other Good Reads
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/goldbergyoni/nodebestpractices" rel="noopener noreferrer"&gt;Our Node.js best practices repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Zgx0o8QjJk4" rel="noopener noreferrer"&gt;YouTube: Docker and Node.js Best Practices from Bret Fisher at DockerCon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/goldbergyoni/javascript-testing-best-practices" rel="noopener noreferrer"&gt;Node.js Testing Best Practices by Yoni Goldberg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@nodepractices/were-under-attack-23-node-js-security-best-practices-e33c146cb87d" rel="noopener noreferrer"&gt;Node.js Security Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
