<?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: nguyendu</title>
    <description>The latest articles on DEV Community by nguyendu (@duong_nguyen).</description>
    <link>https://dev.to/duong_nguyen</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%2F1455056%2Ff4baddf9-f249-4103-89a1-8632a32ac50b.jpeg</url>
      <title>DEV Community: nguyendu</title>
      <link>https://dev.to/duong_nguyen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/duong_nguyen"/>
    <language>en</language>
    <item>
      <title>Optimizing Dockerfile of a NestJS Project</title>
      <dc:creator>nguyendu</dc:creator>
      <pubDate>Fri, 18 Oct 2024 16:39:49 +0000</pubDate>
      <link>https://dev.to/duong_nguyen/optimizing-dockerfile-of-a-nestjs-project-1m8h</link>
      <guid>https://dev.to/duong_nguyen/optimizing-dockerfile-of-a-nestjs-project-1m8h</guid>
      <description>&lt;p&gt;When working on Dockerizing a NestJS project, you can take several measures to optimize the Dockerfile for better performance, smaller image size, and faster build times. Here are some key strategies to consider:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Utilize Multi-Stage Builds
&lt;/h2&gt;

&lt;p&gt;Multi-stage builds allow you to separate the build and production stages of your Docker image, reducing the size of the final image by discarding unnecessary build artifacts. This also enhances security and efficiency by ensuring that only the required files for the runtime are included in the final image.&lt;/p&gt;

&lt;p&gt;Here’s an example of a multi-stage build for a NestJS project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build stage&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:20-alpine&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; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json yarn.lock ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&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;yarn build

&lt;span class="c"&gt;# Production stage&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-alpine&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=build /app/dist ./dist&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json yarn.lock ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &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/main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The build stage compiles the application.&lt;/li&gt;
&lt;li&gt;The production stage only contains the necessary files for running the application, resulting in a smaller image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Optimize Layering and Caching
&lt;/h2&gt;

&lt;p&gt;Docker builds images by creating layers for each instruction in the Dockerfile. The order of instructions affects caching behavior. If a layer changes, all subsequent layers need to be rebuilt. To optimize this, place instructions that change infrequently, such as installing dependencies, near the beginning of the Dockerfile, and instructions that change more often, like copying the source code, towards the end.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&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="s"&gt; node:20-alpine&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; package.json yarn.lock ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&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;yarn build
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By copying package.json and yarn.lock before copying the source files, Docker can reuse the cached layers for installing dependencies as long as the dependencies haven’t changed, speeding up subsequent builds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Use a .dockerignore file
&lt;/h2&gt;

&lt;p&gt;Similar to .gitignore, a .dockerignore file tells Docker which files to exclude from the build context. Excluding unnecessary files, such as node_modules, .git, and local environment files, can reduce the size of the context sent to Docker and improve build performance.&lt;/p&gt;

&lt;p&gt;Here’s an example of a typical .dockerignore for a Node.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;node_modules
.git
.env
*.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that only the essential files are copied into the Docker image, reducing the build time and improving efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Use Official Base Images
&lt;/h2&gt;

&lt;p&gt;Official base images are generally well-optimized and maintained, ensuring you get security updates and a smaller image size. The Alpine variant of Node.js is particularly popular because it is lightweight and provides a minimal environment for running applications.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&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="s"&gt; node:20-alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Alpine-based images helps keep the final image compact, which is beneficial for faster deployment and lower storage costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Run as a Non-Root User
&lt;/h2&gt;

&lt;p&gt;By default, Docker containers run as the root user, which poses a security risk. To improve security, you should run your application under a non-root user. You can create a user within the Dockerfile and switch to it before running your application.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&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;RUN &lt;/span&gt;adduser &lt;span class="nt"&gt;-D&lt;/span&gt; myuser
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; myuser&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the application as a non-root user helps mitigate the impact of any potential vulnerabilities in your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Optimizing your Dockerfile can have significant benefits, including faster build times, smaller image sizes, and improved security. By using multi-stage builds, optimizing layer caching, leveraging .dockerignore, using official base images, and running as a non-root user, you can create a more efficient and secure Docker image for your NestJS project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Remember to always test your Dockerfile thoroughly to ensure it behaves as expected under different environments and scenarios.
&lt;/h4&gt;

</description>
      <category>docker</category>
      <category>node</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
