<?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: Sliplane</title>
    <description>The latest articles on DEV Community by Sliplane (@sliplane).</description>
    <link>https://dev.to/sliplane</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%2Forganization%2Fprofile_image%2F7443%2F22afa001-8051-4418-a2a1-78cc5c5b5b09.png</url>
      <title>DEV Community: Sliplane</title>
      <link>https://dev.to/sliplane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sliplane"/>
    <language>en</language>
    <item>
      <title>What's wrong with Docker?🐳</title>
      <dc:creator>Jonas Scholz</dc:creator>
      <pubDate>Fri, 11 Aug 2023 00:11:47 +0000</pubDate>
      <link>https://dev.to/sliplane/whats-wrong-with-docker-3414</link>
      <guid>https://dev.to/sliplane/whats-wrong-with-docker-3414</guid>
      <description>&lt;p&gt;I've worked &lt;strong&gt;a lot&lt;/strong&gt; with Docker over the last 5+ years and have encountered weird behaviour, bugs, and people that hate Docker. What's the communities opinion of Docker here? What do you love, what do you hate, what have you never really understood?:D Maybe we can help each other out here :)&lt;/p&gt;

&lt;p&gt;I will start: Why is Docker support for Windows so bad? Do you think it will ever get better? 🐳👀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>5 Docker Commands You Don't Know Yet</title>
      <dc:creator>Jonas Scholz</dc:creator>
      <pubDate>Thu, 10 Aug 2023 23:31:46 +0000</pubDate>
      <link>https://dev.to/sliplane/5-docker-commands-you-dont-know-yet-2e78</link>
      <guid>https://dev.to/sliplane/5-docker-commands-you-dont-know-yet-2e78</guid>
      <description>&lt;p&gt;You just started with your Docker Journey and think you know everything? Strap in and learn some fancy new commands to impress your friends and boss with!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/95ZYXmOCd9BBK/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/95ZYXmOCd9BBK/giphy.gif" width="500" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;docker system df&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you're anything like me, you're probably building docker containers left and right without really thinking about where everything is stored. Want to find out how much storage your containers, images, volumes, and cache artifacts need? Simply run &lt;code&gt;docker system df&lt;/code&gt; and be amazed at how much of your disk is just used for docker 🤓&lt;/p&gt;

&lt;p&gt;PS: Too much space used? Try this: &lt;code&gt;docker system prune --all&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf3hyctymn244hr8tgj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf3hyctymn244hr8tgj3.png" alt="docker system df" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;code&gt;docker stats&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Continuing with monitoring commands, did you know that you can see exactly how much resources each container is using? You can see the CPU, memory, and even network usage! Especially useful if you're running containers you haven't built yourself and you need to keep a close eye on them 👀&lt;/p&gt;

&lt;p&gt;Simply run &lt;code&gt;docker stats&lt;/code&gt; to see all the juicy details!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2wii8889st0puwhlz7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2wii8889st0puwhlz7o.png" alt="docker stats" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;code&gt;docker build --cpu-quota=50000&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Everyone knows that Docker likes to use &lt;strong&gt;all&lt;/strong&gt; of the available CPU resources, making everything else SUPER slow during the build process. But what if we could tell Docker how much of your available CPU to use? 🤔&lt;/p&gt;

&lt;p&gt;The solution to this problem is the &lt;code&gt;--cpu-quota&lt;/code&gt; flag of the &lt;code&gt;docker build&lt;/code&gt; command which isn't even documented when executing &lt;code&gt;docker build --help&lt;/code&gt;! The &lt;code&gt;--cpu-quota&lt;/code&gt; flag allows you to define how much of your CPU cores can be used. Every core equals 100000. If you have a 4 core CPU and you want &lt;code&gt;docker build&lt;/code&gt; to use a maximum of 80% of your CPU, you would need to calculate 4 * 100000 * 0.8 = 320000, and then set &lt;code&gt;--cpu-quota 320000&lt;/code&gt;. On Linux or Macos you can also calculate it automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux&lt;/span&gt;
docker build &lt;span class="nt"&gt;--cpu-quota&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; ^processor /proc/cpuinfo&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;100000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; your_image_name your_docker_directory

&lt;span class="c"&gt;# MacOS&lt;/span&gt;
docker build &lt;span class="nt"&gt;--cpu-quota&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;sysctl &lt;span class="nt"&gt;-n&lt;/span&gt; hw.logicalcpu&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;100000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; your_image_name your_docker_directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. &lt;code&gt;docker cp&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The docker cp command is useful for copying files or directories between a running Docker container and your local filesystem. This is especially handy when you need to extract logs or output files from a container. The command is quite simple: You need your containers name, the path of the file inside your container, and the path on your filesystem where the file should be copied to. Then combine it to get something like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01qd2906digcw00z6qio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01qd2906digcw00z6qio.png" alt="docker cp" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;code&gt;docker top&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Alright, last but not least we have &lt;code&gt;docker top&lt;/code&gt;! &lt;a href="https://docs.docker.com/engine/reference/commandline/top/" rel="noopener noreferrer"&gt;&lt;code&gt;docker top&lt;/code&gt;&lt;/a&gt; prints out the currently running processes inside a running container. If you start a container with &lt;code&gt;--name myapp&lt;/code&gt;, simply run &lt;code&gt;docker top myapp&lt;/code&gt; and you will see what is going on inside the container. This is especially great if you're debugging a container and you're not sure if your &lt;code&gt;CMD&lt;/code&gt; command is correct!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkih5pbsj7cfphm4ay8fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkih5pbsj7cfphm4ay8fw.png" alt="docker top containerName" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I really hope you learned one or two new docker commands today! If you need any help, or have any questions about these commands, please write a comment! And if you want to deploy your own Dockerized Apps, check out &lt;a href="https://sliplane.io?utm_source=dockercommands" rel="noopener noreferrer"&gt;Sliplane!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Understanding Next.JS Docker Images</title>
      <dc:creator>Jonas Scholz</dc:creator>
      <pubDate>Mon, 07 Aug 2023 20:07:24 +0000</pubDate>
      <link>https://dev.to/sliplane/understanding-nextjs-docker-images-2g08</link>
      <guid>https://dev.to/sliplane/understanding-nextjs-docker-images-2g08</guid>
      <description>&lt;p&gt;If you've tried to containerize a NextJS app, you've probably found the &lt;a href="https://nextjs.org/docs/pages/building-your-application/deploying#docker-image" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; to be a bit lacking. Especially for beginners, the &lt;a href="https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile" rel="noopener noreferrer"&gt;provided Dockerfile&lt;/a&gt; might be confusing. In this post, we'll go over the Dockerfile and explain what exactly is going on!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dockerfile
&lt;/h2&gt;

&lt;p&gt;Let's start by looking at the Dockerfile &lt;a href="https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile" rel="noopener noreferrer"&gt;provided by the wonderful NextJS&lt;/a&gt; team.&lt;/p&gt;

&lt;p&gt;The Dockerfile can be broken down into &lt;strong&gt;4&lt;/strong&gt; parts: the base image, the dependency installation, the build, and the runtime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fos00t2tf7dv9r7bh71yb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fos00t2tf7dv9r7bh71yb.png" alt="Visual Breakdown" width="800" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Base Image
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frq0nl5t26wt1phbkrcut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frq0nl5t26wt1phbkrcut.png" alt="Base Image" width="800" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first part (and first line!) of the Dockerfile is the base image that the Docker Image is built on top of. Similar to an operating system like Linux or Windows, the base image provides the foundation and structure for the rest of the image. In this case, we use &lt;code&gt;node:18-alpine&lt;/code&gt;, which is a small but powerful image that contains NodeJS. The &lt;code&gt;18&lt;/code&gt; refers to the version of NodeJS. If you want to use a different version, you could replace the &lt;code&gt;18&lt;/code&gt; with a &lt;code&gt;16&lt;/code&gt; or &lt;code&gt;20&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Installation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0lw4v1qb780sydq6wnl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0lw4v1qb780sydq6wnl3.png" alt="Dependency Installation" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As always with Next.JS projects, we first need to install our dependencies. This is done in the next block. But before we install our dependencies, we see the line:&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;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; libc6-compat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is this line here? Well, the &lt;code&gt;node:18-alpine&lt;/code&gt; image is based on Alpine Linux, which is a very small Linux distribution. However, it is so small that it doesn't have all the libraries that &lt;em&gt;some&lt;/em&gt; NodeJS packages need. The &lt;code&gt;libc6-compat&lt;/code&gt; package provides some of these libraries, reducing the chance of errors when installing dependencies. This line isn't always needed, but it's a good idea to include it just in case. If you want a more in-depth explanation of why this might be needed, check out &lt;a href="https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine" rel="noopener noreferrer"&gt;this Github Repo.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can finally start working on our dependencies! To keep everything neat and tidy, we first create a new directory called &lt;code&gt;/app&lt;/code&gt; and set it as our working directory. Then, we copy over the &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;, and &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Now you might be looking at your own Next.JS app and only see one or two of these files. That's okay! The Dockerfile is designed to work with all three of the most popular NodeJS package managers: &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;yarn&lt;/code&gt;, and &lt;code&gt;pnpm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because this Dockerfile is designed to work with all three package managers, the next part is also a bit more complicated:&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;&lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; yarn.lock &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;yarn &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; package-lock.json &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;npm ci&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; pnpm-lock.yaml &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;yarn global add pnpm &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm i &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="k"&gt;else &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Lockfile not found."&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This block of code checks which package manager you're using by checking which lockfile exists. If you're using &lt;code&gt;yarn&lt;/code&gt;, it will run &lt;code&gt;yarn --frozen-lockfile&lt;/code&gt;. If you're using &lt;code&gt;npm&lt;/code&gt;, it will run &lt;code&gt;npm ci&lt;/code&gt;. If you're using &lt;code&gt;pnpm&lt;/code&gt;, it will run &lt;code&gt;yarn global add pnpm &amp;amp;&amp;amp; pnpm i --frozen-lockfile&lt;/code&gt;. If you're using something else, it will print an error message and exit.&lt;/p&gt;

&lt;p&gt;If you know which package manager you're using, you can simplify this part of the Dockerfile. For example, if you're using &lt;code&gt;npm&lt;/code&gt;, you can remove the &lt;code&gt;yarn.lock&lt;/code&gt; and &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; files and replace the entire block with:&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it out and see if it works! If not, feel free to write a comment below and I'll be happy to help you out :)&lt;/p&gt;

&lt;h3&gt;
  
  
  The Build
&lt;/h3&gt;

&lt;p&gt;The next part of the Dockerfile contains the actual build process where we compile our NextJS app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanz80qfoxlzp9e2m1ufd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanz80qfoxlzp9e2m1ufd.png" alt="The Build" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As before, we first start a new image layer and set our working directory to &lt;code&gt;/app&lt;/code&gt;. Then, we copy over the &lt;code&gt;node_modules&lt;/code&gt; folder from our previous image layer. After copying the &lt;code&gt;node_modules&lt;/code&gt; folder, we copy over the rest of our app. This is done in two steps to improve build times. If we copied over the entire app first, then every time we made a change to our app, we would have to reinstall our dependencies. By copying over the &lt;code&gt;node_modules&lt;/code&gt; folder first, we can skip the dependency installation step if we haven't changed our dependencies! Smart, right?&lt;/p&gt;

&lt;p&gt;Finally, we run &lt;code&gt;yarn build&lt;/code&gt; to execute the command that is defined in our &lt;code&gt;package.json&lt;/code&gt; file. This command is usually &lt;code&gt;next build&lt;/code&gt;, but it can be changed to whatever you want. It doesn't really matter if we use &lt;code&gt;yarn&lt;/code&gt; or &lt;code&gt;npm&lt;/code&gt; here, because we already installed our dependencies in the previous step and the package manager doesn't really matter for the build process!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Runtime
&lt;/h3&gt;

&lt;p&gt;And finally, we are done with installing our dependencies and building our app! The last part of the Dockerfile is the runtime, where we actually run our app. This part is a bit longer, so let's go through it step by step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnnya88rvfhiybxmfdzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnnya88rvfhiybxmfdzs.png" alt="The Runtime" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, we start by creating a new image layer and setting our working directory to &lt;code&gt;/app&lt;/code&gt;. We then set the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable to &lt;code&gt;PRODUCTION&lt;/code&gt;. This signals to NextJS that we are running in production mode, which will improve performance. This can also affect other parts of your app and NodeJS. Check out this awesome &lt;a href="https://nodejs.dev/en/learn/nodejs-the-difference-between-development-and-production/" rel="noopener noreferrer"&gt;documentation page&lt;/a&gt; for more information!&lt;/p&gt;

&lt;p&gt;Next, we create a new group and user. This is done to improve security. If we didn't do this, our app would run as &lt;code&gt;root&lt;/code&gt;, which can be a security issue. Generally, you want to try to follow the &lt;a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege" rel="noopener noreferrer"&gt;"Principle of least privilege"&lt;/a&gt;, which states that you should only give your app the permissions that it needs. In this case, our app doesn't need root permissions, so we create a new user and group for it. We then finally switch to this new user with &lt;code&gt;USER nextjs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can finally copy over the build artifacts from the previous image layer. We first copy over the &lt;code&gt;./public&lt;/code&gt; folder which includes all of our static assets. Then, we copy over the &lt;code&gt;./.next/standalone&lt;/code&gt; and &lt;code&gt;./.next/static folders&lt;/code&gt;, which include all of our compiled code. This step will only work if you set your &lt;code&gt;output&lt;/code&gt; mode in your &lt;a href="https://nextjs.org/docs/pages/api-reference/next-config-js/output" rel="noopener noreferrer"&gt;Next.JS Config&lt;/a&gt;. If you don't set your &lt;code&gt;output&lt;/code&gt; mode, your dependencies will not be included!&lt;/p&gt;

&lt;p&gt;At this point we have improved security, enabled production mode, and copied over all the build artifacts. The next 3 lines are all about networking and making our Next.JS app available to the the network.&lt;/p&gt;

&lt;p&gt;We first expose port &lt;code&gt;3000&lt;/code&gt; to the network with &lt;code&gt;EXPOSE 3000&lt;/code&gt;. This doesn't actually do anything, but it's a good practice to include it so that other developers know which port the Docker Container will be running on. Next, we set the &lt;code&gt;PORT&lt;/code&gt; environment variable to &lt;code&gt;3000&lt;/code&gt;. This is used by NextJS to determine which port to run on. Finally, we set the &lt;code&gt;HOST&lt;/code&gt; environment variable to &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The last line is the actual command that is run when the Docker Container is started and is not executed during the image build process. Since we compiled the Next.JS app to a standalone file, we can simply start it with &lt;code&gt;node server.js&lt;/code&gt;. That's it! We're done! 🎉🎉🎉&lt;/p&gt;

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

&lt;p&gt;That was a long one, good job! I hope this post helped you understand the NextJS Dockerfile a bit better. If you have any questions, feel free to leave a comment below and I'll be happy to help you out! If you have any suggestions for future posts, I'd love to hear them as well. Thanks for reading! 😊&lt;/p&gt;

&lt;p&gt;Want to host your next cool dockerized Next.JS project? Check out &lt;a href="https://sliplane.io?utm_source=nextjsdocker" rel="noopener noreferrer"&gt;Sliplane!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>nextjs</category>
      <category>react</category>
      <category>devops</category>
    </item>
    <item>
      <title>Minimizing Nuxt 3 Docker Images</title>
      <dc:creator>Jonas Scholz</dc:creator>
      <pubDate>Fri, 04 Aug 2023 22:55:02 +0000</pubDate>
      <link>https://dev.to/sliplane/minimizing-nuxt-3-docker-images-5d5g</link>
      <guid>https://dev.to/sliplane/minimizing-nuxt-3-docker-images-5d5g</guid>
      <description>&lt;p&gt;You've just finished building an awesome Nuxt 3 application, but there's a catch – your Docker image is over 1 &lt;em&gt;Gigabyte&lt;/em&gt; in size, your laptop is exploding trying to upload the image and deployment feels like a never-ending wait. Fear not, fellow Nuxt enthusiast! In this blog post, we'll dive into the art of minimizing Nuxt 3 Docker images, starting with a basic unoptimized image that is 1.4 Gigabyte large and ending with a image that's only 164 MB in size. That's a 850% reduction in size! Your boss and laptop will thank you :)&lt;/p&gt;

&lt;p&gt;You can either follow along with your own Nuxt 3 project or just check out the final &lt;a href="https://github.com/sliplane/minimizing-nuxt3-docker-image" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basic Nuxt 3 Docker Image
&lt;/h2&gt;

&lt;p&gt;While I don't know the exact Docker Image you are using, I bet it looks something like this:&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;# Use any Node.js base image that you want!&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory to /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the package.json file into the working directory before copying the rest of the files to cache the dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /app&lt;/span&gt;

&lt;span class="c"&gt;# Install the dependencies, you might want to use yarn or pnpm instead&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="c"&gt;# Copy the rest of the files into the working directory&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;

&lt;span class="c"&gt;# Build the application, again, use yarn or pnpm if you want&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Start the application. This is the default command for Nuxt 3&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", ".output/server/index.mjs"] &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Dockerfile is pretty straightforward. It starts with a Node.js 18 base image, copies the &lt;code&gt;package.json&lt;/code&gt; file, installs the dependencies, copies the rest of the files, builds the application and finally starts the application. This is a great starting point, but it's not very optimized. This results in a 1.4 Gigabyte large Docker image. Let's see if we can do better!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Using an Alpine base image
&lt;/h2&gt;

&lt;p&gt;The first thing we can do is use an Alpine base image instead of a Debian base image. This will reduce the size of our Docker image by about 1 Gigabyte!. This is a very easy change, since Alpine images are provided by Docker. All we need to do is change the base image from &lt;code&gt;node:18&lt;/code&gt; to &lt;code&gt;node:18-alpine&lt;/code&gt;:&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;# Use any Node.js base image that you want (as long as it's Alpine)!&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory to /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the package.json file into the working directory before copying the rest of the files to cache the dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /app&lt;/span&gt;

&lt;span class="c"&gt;# Install the dependencies, you might want to use yarn or pnpm instead&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="c"&gt;# Copy the rest of the files into the working directory&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;

&lt;span class="c"&gt;# Build the application, again, use yarn or pnpm if you want&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Start the application. This is the default command for Nuxt 3&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", ".output/server/index.mjs"] &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is of course a tradeoff, since Alpine images come with less preinstalled software and have a different package manager among other things. But if we are just building a Nuxt 3 application, this is a great way to reduce the size of our Docker image and the change will probably not affect us at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Ignoring unnecessary files
&lt;/h2&gt;

&lt;p&gt;The next and probably easiest thing we can do is create a &lt;code&gt;.dockerignore&lt;/code&gt; file and ignore all files that are not needed in the Docker image. This works similar to a &lt;code&gt;.gitignore&lt;/code&gt; file you might already be familiar with. The &lt;code&gt;.dockerignore&lt;/code&gt; file will simply tell Docker to ignore certain files and directories when building the image. This is highly dependent on your project, but here's an example of a &lt;code&gt;.dockerignore&lt;/code&gt; file for a Nuxt 3 project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
.output
.nuxt
.git
docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will ignore your installed &lt;code&gt;node_modules&lt;/code&gt; folder, since we will install the dependencies in the Docker image. It will also ignore the &lt;code&gt;.output&lt;/code&gt; and &lt;code&gt;.nuxt&lt;/code&gt; folders, since we will build the application in the Docker image. Finally, it will ignore the &lt;code&gt;.git&lt;/code&gt; folder and the &lt;code&gt;docs&lt;/code&gt; folder, since we don't need them in the Docker image. Depending on your project, you might need to ignore more files and folders. For example, if you are using a CI/CD tool like GitHub Actions, you might want to ignore the &lt;code&gt;.github&lt;/code&gt; folder. You get the idea. Go wild and try to ignore as many files and folders as possible. This will reduce the size of your Docker image and speed up the build process!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Using a multi-stage build
&lt;/h2&gt;

&lt;p&gt;The next thing we can do is use a multi-stage build. This is a very powerful feature of Docker that allows us to build our application in one Docker image and then copy the built application into a second Docker image. This allows us to use a very large Docker image to build our application, but then use a very small Docker image to run our application. This is a great way to reduce the size of our Docker image, since we don't need all the build tools in our final Docker image. Let's see how this works in practice:&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;# Use a large Node.js base image to build the application and name it "build"&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:18-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="c"&gt;# Exact same steps as before&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 /app&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="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Create a new Docker image and name it "prod"&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:18-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;prod&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the built application from the "build" image into the "prod" image&lt;/span&gt;
&lt;span class="c"&gt;# This will only copy whatever is in the .output folder and ignore useless files like node_modules!&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/.output /app/.output&lt;/span&gt;

&lt;span class="c"&gt;# Start is the same as before&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", ".output/server/index.mjs"] &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Using a distroless image
&lt;/h2&gt;

&lt;p&gt;Using a distroless image is another great way to reduce the size of your Docker image, but implies a few tradeoffs for relatively small gains (13 MB in our case). Distroless images are Docker images that don't contain any operating system packages. This means that you can't use any tools like &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;curl&lt;/code&gt; in your Docker image. For most applications, this is not a problem. The best way to find out if this works for you is to simply try it out. For that, you can just change the prodution image to a distroless image like this:&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;# Use a large Node.js base image to build the application and name it "build"&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:18-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="c"&gt;# Copy the package.json and package-lock.json files into the working directory before copying the rest of the files&lt;/span&gt;
&lt;span class="c"&gt;# This will cache the dependencies and speed up subsequent builds if the dependencies don't change&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json /app&lt;/span&gt;

&lt;span class="c"&gt;# You might want to use yarn or pnpm instead&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="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Instead of using a node:18-alpine image, we are using a distroless image. These are provided by google: https://github.com/GoogleContainerTools/distroless&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;gcr.io/distroless/nodejs:18&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;prod&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the built application from the "build" image into the "prod" image&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/.output /app/.output&lt;/span&gt;

&lt;span class="c"&gt;# Since this image only contains node.js, we do not need to specify the node command and simply pass the path to the index.mjs file!&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/app/.output/server/index.mjs"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we are using the &lt;code&gt;node:18-alpine&lt;/code&gt; image for the build stage, since the &lt;code&gt;gcr.io/distroless/nodejs:18&lt;/code&gt; image doesn't contain any build tools. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Using a CDN for static assets
&lt;/h2&gt;

&lt;p&gt;If you have a lot of static assets such as images or videos in your application, you can use a CDN to serve those assets. This will reduce the size of your Docker image, since you don't need to copy the static assets into the Docker image. Instead, you can just reference the static assets from the CDN. This doesn't just decrease the size of your Docker image, but also speeds up your application and reduces the load on your server! To serve static assets from a CDN, you will need to &lt;a href="https://nuxt.com/docs/api/composables/use-runtime-config#appcdnurl" rel="noopener noreferrer"&gt;configure your Nuxt App&lt;/a&gt; and upload the static assets to the CDN. How you upload your static assets to the CDN depends on what CDN you are using and goes beyond the scope of this blog post. What you will need to do in any case, is remove the static assets from your Docker image. You can do that by only copying the server files into your final production image like this:&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="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-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 /app&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="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;gcr.io/distroless/nodejs:18&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;prod&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/.output/server /app/.output/server&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000/tcp&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/app/.output/server/index.mjs"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Result
&lt;/h2&gt;

&lt;p&gt;Our final Docker image is only 164 MB in size, which is a 850% reduction! If you want to have a reproducible example, you can check out the &lt;a href="https://github.com/sliplane/minimizing-nuxt3-docker-image" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yjn9y2bq60rd8ut1dpt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yjn9y2bq60rd8ut1dpt.png" alt="docker images ls output" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;At this point your Docker image should be less than 200 MB in size, which is pretty good! Of course, you can always go further and optimize your Docker image even more. But at some point you are going to hit diminishing returns. If you are tired of optimizing Docker images and want to focus on shipping your product, &lt;a href="https://sliplane.io" rel="noopener noreferrer"&gt;check out Sliplane&lt;/a&gt; to host your next project without giving up control over your own infrastructure!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>nuxt</category>
      <category>devops</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
