<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Simeon Amiase's team blog]]></title><description><![CDATA[Simeon Amiase's team blog]]></description><link>https://sesugh.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 06 Sep 2026 14:52:41 GMT</lastBuildDate><atom:link href="https://sesugh.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Problem Multi-stage Docker build solves: Guideline on how to reduce Docker images size.]]></title><description><![CDATA[Introduction
A multistage Docker build is a technique used to optimize Docker images by reducing their size and complexity. In a multistage build, a Dockerfile contains multiple FROM statements, each representing a separate stage. The stages are used...]]></description><link>https://sesugh.hashnode.dev/the-problem-multi-stage-docker-build-solves-guideline-on-how-to-reduce-docker-images-size</link><guid isPermaLink="true">https://sesugh.hashnode.dev/the-problem-multi-stage-docker-build-solves-guideline-on-how-to-reduce-docker-images-size</guid><dc:creator><![CDATA[Simeon Amiase]]></dc:creator><pubDate>Sun, 04 Aug 2024 07:00:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722754600377/63b127eb-6bcd-4a1e-924c-552e5a2611ee.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>A multistage Docker build is a technique used to optimize Docker images by reducing their size and complexity. In a multistage build, a Dockerfile contains multiple <code>FROM</code> statements, each representing a separate stage. The stages are used to build and compile the application in one or more intermediate containers, and then copy only the necessary artifacts into a final, minimal image. This approach helps to exclude build-time dependencies and files from the final image, resulting in smaller, more efficient images that are easier to deploy and maintain.</p>
<p>In this article, we will learn how to write a multistage Dockerfile and also without a multistage Dockerfile and build the images respectively.</p>
<p>This project will help visualize the size in images when they are built with multistage and also without multistage.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ol>
<li><p>Go (version 1.17 or higher)</p>
</li>
<li><p>Docker installed</p>
</li>
<li><p>A code editor (E.g Visual studio Code)</p>
</li>
</ol>
<h2 id="heading-setting-up-the-project-locally">Setting up the project locally</h2>
<p>clone the repo to your local machine</p>
<pre><code class="lang-plaintext">git clone https://github.com/SESUGH-OPS/Multistage-Docker-Build
</code></pre>
<ul>
<li><p>After cloning the repo, you will have to remove the .git directory inorder for you to add your own .git directory</p>
<p>  To remove the .git directory use the commands below</p>
<p>  Linux and Mac users</p>
<pre><code class="lang-plaintext">  cd /path/to/your/repository
  rm -rf .git
</code></pre>
<p>  Windows users</p>
<pre><code class="lang-plaintext">  cd C:\path\to\your\repository
  rmdir /s /q .git
</code></pre>
</li>
</ul>
<h3 id="heading-building-the-image-without-multibuild">Building the image without multibuild</h3>
<p>First off we try building the docker image without multibuild</p>
<ul>
<li><p>Navigate to the folder called Docker-without-multibuild</p>
<pre><code class="lang-plaintext">  cd Docker-without-multibuild
</code></pre>
</li>
<li><p>Create a dockerfile within the directory, you just navigated to</p>
<pre><code class="lang-plaintext">  touch Dockerfile
</code></pre>
</li>
<li><p>paste this code block within the dockerfile you created</p>
<pre><code class="lang-plaintext">  ###########################################
  # BASE IMAGE
  ###########################################

  FROM ubuntu 

  RUN apt-get update &amp;&amp; apt-get install -y golang-go

  ENV GO111MODULE=off

  COPY . .

  RUN CGO_ENABLED=0 go build -o /app .

  ENTRYPOINT ["/app"]
</code></pre>
<p>  Let us go over the commands</p>
<p>  <code>FROM ubuntu</code>: This command sets the base image to the official <code>ubuntu</code> image. It means that the Docker image being built will start with an Ubuntu Linux environment. The absence of a tag means it uses the latest version available at the time of building.</p>
<p>  <code>RUN apt-get update</code>: This command updates the package lists from the repositories, ensuring that the latest package versions are available for installation.</p>
<p>  <code>apt-get install -y golang-go</code>: This installs the Go programming language and its dependencies in the container. The <code>-y</code> flag automatically confirms the installation, avoiding prompts.</p>
<p>  <code>ENV GO111MODULE=off</code>: This sets the <code>GO111MODULE</code> environment variable to <code>off</code>. This configuration disables the Go module system, opting for the traditional GOPATH approach for dependency management.</p>
<p>  <code>COPY . .</code>: This copies all files and directories from the context directory on the host machine (the directory containing the Dockerfile) into the current working directory inside the container. The first <code>.</code> refers to the source (the context directory), and the second <code>.</code> refers to the destination inside the container.</p>
<p>  <code>RUN</code>: This command executes the following command inside the Docker container.</p>
<p>  <code>CGO_ENABLED=0</code>: This sets the environment variable <code>CGO_ENABLED</code> to <code>0</code>, which disables CGO (C Go). Disabling CGO ensures that the resulting Go binary is statically linked and doesn't rely on any C libraries, which can be beneficial for deployment.</p>
<p>  <code>go build -o /app .</code>: This compiles the Go application. The <code>-o /app</code> option specifies that the output binary should be saved as <code>/app</code> in the container. The <code>.</code> specifies that the Go compiler should look for the main package in the current directory, which is where the application's source code is copied.</p>
<p>  <code>ENTRYPOINT</code>: This sets the default command that will be executed when a container created from this image is started. The command is specified in execution form (using an array), which is preferred because it avoids issues with shell interpretation. In this case, it specifies that the compiled Go application binary located at <code>/app</code> should be executed when the container starts.</p>
</li>
<li><p>Run the command to build your image</p>
</li>
</ul>
<pre><code class="lang-plaintext">docker build -t &lt;image-name&gt;:&lt;tag&gt; .
e.g docker build -t webapp:v1 .
</code></pre>
<p>After building the image lets see the size of the image built by running the command</p>
<pre><code class="lang-plaintext">docker images
</code></pre>
<p>This brings out a display such as the picture below</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722747596805/2ef948da-c8c2-4195-8f6c-51e06c555de7.png" alt class="image--center mx-auto" /></p>
<p>From the image above we can see the size of the image to be over 600MB. The size on your end might be even higher.</p>
<h3 id="heading-building-the-image-with-multibuild">Building the image with multibuild</h3>
<p>Navigate to the folder called Docker-with-multibuild</p>
<pre><code class="lang-plaintext">cd Docker-with-multibuild
</code></pre>
<p>Create a dockerfile within the directory, you just navigated to</p>
<pre><code class="lang-plaintext">touch Dockerfile
</code></pre>
<p>paste this code block within the dockerfile you created</p>
<pre><code class="lang-plaintext">###########################################
# BASE IMAGE
###########################################

FROM ubuntu AS build

RUN apt-get update &amp;&amp; apt-get install -y golang-go

ENV GO111MODULE=off

COPY . .

RUN CGO_ENABLED=0 go build -o /app .

##############################
## THE MAGIC OF MULTIBUILD
##############################

FROM scratch

# Copy the compiled binary from the build stage
COPY --from=build /app /app

# Set the entrypoint for the container to run the binary
ENTRYPOINT ["/app"]
</code></pre>
<p>Lets go over the commands</p>
<p><code>FROM ubuntu AS build</code>: This specifies that the base image for this stage will be <code>ubuntu</code>, and it names this stage <code>build</code>. The alias (<code>build</code>) is going to be used later to reference this stage.</p>
<p><code>RUN apt-get update</code>: This command updates the package lists to ensure that the latest versions of the packages are available.</p>
<p><code>apt-get install -y golang-go</code>: This installs the Go programming language and its dependencies in the container. The <code>-y</code> flag automatically confirms the installation prompts.</p>
<p><code>ENV GO111MODULE=off</code>: This sets the <code>GO111MODULE</code> environment variable to <code>off</code>. This disables the Go module system, opting for the traditional GOPATH approach for dependency management.</p>
<p><code>COPY . .</code>: This copies all files and directories from the current directory on the host machine (the directory containing the Dockerfile) into the current working directory inside the container.</p>
<p><code>RUN</code>: This command executes the following command inside the Docker container.</p>
<p><code>CGO_ENABLED=0</code>: This sets the environment variable <code>CGO_ENABLED</code> to <code>0</code>, which disables CGO (C Go). Disabling CGO ensures that the resulting Go binary is statically linked and doesn't rely on any C libraries.</p>
<p><code>go build -o /app .</code>: This compiles the Go application. The <code>-o /app</code> option specifies that the output binary should be saved as <code>/app</code> in the container. The <code>.</code> specifies that the Go compiler should look for the main package in the current directory.</p>
<p><code>FROM scratch</code>: This starts a new build stage using the <code>scratch</code> image, which is an empty image or a distroless image. This stage is used to create a minimal final image that only contains the compiled Go binary. Checkout distroless images <a target="_blank" href="https://github.com/GoogleContainerTools/distroless">here</a>.</p>
<p><code>COPY --from=build /app /app</code>: This copies the compiled binary from the <code>build</code> stage into the new image. The <code>--from=build</code> part specifies that the source of the copy is the <code>build</code> stage, and <code>/app</code> specifies the file to copy. The second <code>/app</code> is the destination path in the new image.</p>
<p><code>ENTRYPOINT ["/app"]</code>: This sets the default command that will be executed when a container created from this image is started. The command is specified in execution form (using an array), which is preferred because it avoids issues with shell interpretation. In this case, it specifies that the compiled Go application binary located at <code>/app</code> should be executed when the container starts.</p>
<ul>
<li>Run the command to build your image</li>
</ul>
<pre><code class="lang-plaintext">docker build -t &lt;image-name&gt;:&lt;tag&gt; .
e.g docker build -t webapp:v1 .
</code></pre>
<p>The result is a minimal Docker image that contains only the compiled Go application, reducing the image size and eliminating unnecessary dependencies.<br />Run the command below to see the size of the new image built</p>
<pre><code class="lang-plaintext">docker images
</code></pre>
<p>The display should have a minimalist image size such as the size below</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722752678550/0eba139e-1c76-4fdf-99ee-8fbe06889223.png" alt class="image--center mx-auto" /></p>
<p>This multibuild image ensures that the final deployed image is lean, secure, and contains only what is necessary to run the application, thus reducing potential vulnerabilities and resource consumption.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It's been a long ride. Congratulations on making it to the end and successfully building a docker image without multibuild and also with multibuild to see the difference in image size reduction and the use case. In this article, we covered the following:</p>
<ol>
<li><p>Setup the project locally for build phase of the project</p>
</li>
<li><p>Create a dockerfile for docker-without-multibuild and build the image</p>
</li>
<li><p>Create a dockerfile for docker-with-multibuild and build the image</p>
</li>
<li><p>Compare the size of images between multibuild and without mulitbuild</p>
</li>
</ol>
<p><strong>hasta la próxima!!!!!!!</strong></p>
]]></content:encoded></item></channel></rss>