<?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[My Personal Blog]]></title><description><![CDATA[My name is Mor and I have been working as a DevOps Engineer for Red Hat for a year and a half. During this time, I have gained a wealth of knowledge and experie]]></description><link>https://morco.io</link><generator>RSS for Node</generator><lastBuildDate>Tue, 26 May 2026 20:59:20 GMT</lastBuildDate><atom:link href="https://morco.io/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Multi-stage Docker Build: What? Why? Where?]]></title><description><![CDATA[Write about the docker multi-stage build, what it means, what it can be used for, and some examples.
An Overview of Multi-stage Docker Builds
Multi-stage Docker builds allows us to build a docker image using multiple parent images, you can start gues...]]></description><link>https://morco.io/multi-stage-docker-build-what-why-where</link><guid isPermaLink="true">https://morco.io/multi-stage-docker-build-what-why-where</guid><dc:creator><![CDATA[Mor Cohen]]></dc:creator><pubDate>Thu, 16 Mar 2023 13:49:49 GMT</pubDate><content:encoded><![CDATA[<p>Write about the docker multi-stage build, what it means, what it can be used for, and some examples.</p>
<h3 id="heading-an-overview-of-multi-stage-docker-builds">An Overview of Multi-stage Docker Builds</h3>
<p>Multi-stage Docker builds allows us to build a docker image using multiple parent images, you can start guessing what benefits it has already. One can copy essential binaries from <mark>one docker image</mark> and move them to <strong>another parent image</strong> and build a new image that does not include unnecessary binaries from the <mark>first image</mark>. This way, we can have an optimized docker image.</p>
<blockquote>
<p>The <code>FROM</code> instruction specifies the <strong><em>Parent Image</em></strong> from which you are building.</p>
<p>source: <a target="_blank" href="https://docs.docker.com/engine/reference/builder/#format">https://docs.docker.com/engine/reference/builder/#format</a></p>
</blockquote>
<h3 id="heading-example-of-using-multi-stage-builds">Example of Using Multi-stage Builds</h3>
<p>Let's assume we need to build our project, for this example, we will build a <a target="_blank" href="https://github.com/arrufat/yandex-weather-cli">CLI that provides the user with weather information</a>. The CLI is open-source and has been built with Go. After building the CLI, we would like to have a docker image that contains it - but only it, without the project itself. We will see how we can do it, and how much space and layers it saves us.</p>
<p>So we will start by cloning the project to our local environment:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/arrufat/yandex-weather-cli.git
</code></pre>
<p>Create Dockerfile:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> yandex-weather-cli
touch Dockerfile
</code></pre>
<p>Using a text editor, write the following in the <code>Dockerfile</code> we just created:</p>
<pre><code class="lang-plaintext">FROM golang:1.16
WORKDIR /go/src/github.com/arrufat/yandex-weather-cli
COPY *.go go.mod go.sum ./
RUN go mod download
RUN CGO_ENABLED=0 go build
ENTRYPOINT ["./yandex-weather-cli"]
</code></pre>
<p>And lastly, build the image:</p>
<pre><code class="lang-bash">docker build .
</code></pre>
<p>We now have an image that has the CLI bin that can be executed within a container that runs with this image. But - we also have in our image all the project, we have extra layers (for each line of instruction - <code>FROM</code>, <code>COPY</code>, etc...).</p>
<blockquote>
<p>A side note: we have some extra layers because we copied files, downloaded go modules, and built the project, these instructions cost us in extra layers :)</p>
</blockquote>
<p>So instead of just building the image and keeping everything, we can copy the desired bin (our CLI we just built) to another lightweight parent image. Modify your <code>Dockerfile</code> so it will look like this:</p>
<pre><code class="lang-bash">FROM golang:1.16 as builder
WORKDIR /go/src/github.com/arrufat/yandex-weather-cli
COPY *.go go.mod go.sum ./
RUN go mod download
RUN CGO_ENABLED=0 go build

FROM alpine:latest
WORKDIR /app
COPY --from=builder /go/src/github.com/arrufat/yandex-weather-cli/yandex-weather-cli ./
ENTRYPOINT [<span class="hljs-string">"./yandex-weather-cli"</span>]
</code></pre>
<p>The changes are:</p>
<pre><code class="lang-plaintext">-FROM golang:1.16
+FROM golang:1.16 as builder
 WORKDIR /go/src/github.com/arrufat/yandex-weather-cli
 COPY *.go go.mod go.sum ./
 RUN go mod download
 RUN CGO_ENABLED=0 go build
+
+FROM alpine:latest
+WORKDIR /app
+COPY --from=builder /go/src/github.com/arrufat/yandex-weather-cli/yandex-weather-cli ./
ENTRYPOINT ["./yandex-weather-cli"]
</code></pre>
<blockquote>
<p>1) We are now naming the first parent image as <code>builder</code>, this allows us later to copy files from it.<br />2) We've added another <code>FROM</code> instruction so our parent image is now a different one. (we are using alpine because of its size)<br />3) We are copying the CLI that we built on the <code>builder</code> parent image to the current one by using the <code>--from</code> flag.</p>
</blockquote>
<h3 id="heading-the-differences">The Differences</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Size</span>
docker images --format=<span class="hljs-string">"{{.Size}}"</span>
903MB
15.5MB

<span class="hljs-comment"># Number of layers</span>
docker <span class="hljs-built_in">history</span> full-image | wc -l
      19
docker <span class="hljs-built_in">history</span> multi-step-image | wc -l
       6
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Welcome to My New Blog]]></title><description><![CDATA[Welcome to my new blog! My name is Mor and I have been working as a DevOps Engineer for Red Hat for a year and a half. During this time, I have gained a wealth of knowledge and experience that I am excited to share with you.
As a DevOps Engineer, I h...]]></description><link>https://morco.io/welcome-to-my-new-blog</link><guid isPermaLink="true">https://morco.io/welcome-to-my-new-blog</guid><dc:creator><![CDATA[Mor Cohen]]></dc:creator><pubDate>Wed, 15 Mar 2023 11:22:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678880331974/1fe3ebbd-7fc3-498c-a619-27012fe5c359.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to my new blog! My name is Mor and I have been working as a DevOps Engineer for Red Hat for a year and a half. During this time, I have gained a wealth of knowledge and experience that I am excited to share with you.</p>
<p>As a DevOps Engineer, I have had the opportunity to work with various CI tools such as Jenkins, automation using Python, Bash, Groovy scripts, and Ansible. I worked in the department responsible for developing OpenShift, so I have extensive knowledge about OpenShift and Kubernetes as OpenShift's upstream project is Kubernetes. In addition, I have also worked with monitoring tools such as Prometheus and Grafana.</p>
<p>However, being a DevOps Engineer is not just about the technical skills. It also requires a particular mindset and approach to problem-solving. Communication is a vital part of the role as well, as you work with various people in the company, each with different roles and responsibilities. As a DevOps Engineer, you are the dot that connects everyone, making it a role with a lot of responsibility.</p>
<p>Through this blog, I hope to share my experiences, insights, and knowledge with you. I hope that my posts will help you gain a better understanding of the DevOps world and inspire you to take on new challenges.</p>
]]></content:encoded></item></channel></rss>