<?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>Forem: Harsha Vaidya</title>
    <description>The latest articles on Forem by Harsha Vaidya (@hvydya).</description>
    <link>https://forem.com/hvydya</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%2F53231%2Fe7c7f7ce-4659-4a3b-9121-38c685bee6db.jpg</url>
      <title>Forem: Harsha Vaidya</title>
      <link>https://forem.com/hvydya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hvydya"/>
    <language>en</language>
    <item>
      <title>Build a Raspberry Pi K8s Server For Your Side Projects </title>
      <dc:creator>Harsha Vaidya</dc:creator>
      <pubDate>Wed, 10 Mar 2021 04:47:29 +0000</pubDate>
      <link>https://forem.com/hvydya/build-a-raspberry-pi-server-for-your-side-projects-non</link>
      <guid>https://forem.com/hvydya/build-a-raspberry-pi-server-for-your-side-projects-non</guid>
      <description>&lt;p&gt;Have you ever thought of shipping that side project of yours but felt like it's not worth the money to spend on cloud costs?&lt;/p&gt;

&lt;p&gt;This was my prime motivation to build this project: A hosting solution for all my side projects. So let me share the solution I've come up with.&lt;/p&gt;

&lt;p&gt;The goals for this project are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accessible to anyone on the local network or wifi in my case.&lt;/li&gt;
&lt;li&gt;Low maintenance.&lt;/li&gt;
&lt;li&gt;Easy to deploy or make changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To achieve these you'll be needing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Raspberry Pi ( I've used the new 4B model ) with at least 4GB of memory and 4 cores in total.&lt;/li&gt;
&lt;li&gt;At least 20 GB of free storage on your Pi.&lt;/li&gt;
&lt;li&gt;Your local network credentials if you are using wifi.&lt;/li&gt;
&lt;li&gt;A USB keyboard, Monitor with HDMI slot, a microHDMI cable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alright, once those are in place, let's start.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the &lt;a href="https://www.raspberrypi.org/software/"&gt;Raspberry Pi Imager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install Ubuntu 20.04.02 LTS (64-bit version) on your microSD card.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ubuntu.com/tutorials/how-to-install-ubuntu-on-your-raspberry-pi#3-wifi-or-ethernet"&gt;Edit the network config&lt;/a&gt; ( only if you are using wifi )&lt;/li&gt;
&lt;li&gt;Place your SD card in the slot in the Pi. Connect the keyboard and Monitor to the Pi and connect the Pi to power.&lt;/li&gt;
&lt;li&gt;Once it boots up it will ask for login and password. Use &lt;code&gt;ubuntu&lt;/code&gt; for both and it will prompt you to change the password. Set a password then.&lt;/li&gt;
&lt;li&gt;Reboot the server. &lt;code&gt;sudo reboot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;net-tools&lt;/code&gt; package. &lt;code&gt;sudo apt-get install net-tools&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the IP address of the server on your network. For this we can do &lt;code&gt;ifconfig&lt;/code&gt; and find it out. If you have used wifi for this setup, look under the &lt;code&gt;wlan0&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;Setup SSH. On your computer run the command &lt;code&gt;ssh-copy-id ubuntu@&amp;lt;ip_of_your_server&amp;gt;&lt;/code&gt; . It will prompt for the password. Supply it and you are done. Additionally update your ssh config file with a custom hostname for the pi for ease of use.&lt;/li&gt;
&lt;li&gt;Now you can remotely access the server without needing a monitor or a keyboard connected to your Pi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the setup is complete. To deploy your apps there are many ways. In this post I will be using &lt;a href="https://microk8s.io/"&gt;MicroK8s&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH into your Pi.&lt;/li&gt;
&lt;li&gt;Enable &lt;code&gt;cgroups&lt;/code&gt; on your Pi. Append &lt;code&gt;cgroup_enable=memory cgroup_memory=1&lt;/code&gt; to the end of &lt;code&gt;/boot/firmware/cmdline.txt&lt;/code&gt; in the Pi.&lt;/li&gt;
&lt;li&gt;Reboot. &lt;code&gt;sudo reboot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install microk8s. &lt;code&gt;sudo snap install microk8s --classic&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add your current user to the &lt;code&gt;microk8s&lt;/code&gt; group and gain access to the &lt;code&gt;.kube&lt;/code&gt; caching directory:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; microk8s &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; ~/.kube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Start the cluster. &lt;code&gt;microk8s start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check status. &lt;code&gt;microk8s status&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable DNS, Ingress for exposing your apps on your local network. &lt;code&gt;microk8s enable dns ingress&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the &lt;code&gt;kubectl&lt;/code&gt; config for the cluster. &lt;code&gt;microk8s config&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;kubectl&lt;/code&gt; config you got in the above step to your computer to enable access to the control plane from your computer. This eliminates the need to SSH into the server when you want to access the cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now our single-node cluster is setup and ready to be used. You can now package your projects as containers and deploy them to this setup.&lt;/p&gt;

&lt;p&gt;Alternatively, if you don't know K8s or don't want to use it, you can still deploy your projects as simple docker containers or even as plain-old services and this setup would still work.&lt;/p&gt;

&lt;p&gt;So, did we meet our goals?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We made something which we can access from our local network. ✅&lt;/li&gt;
&lt;li&gt;The server would be fine if you keep in mind the resource limits it has and always connect it power and network. ✅&lt;/li&gt;
&lt;li&gt;Since, I've used k8s deploying and making changes is a breeze. I also use Github actions for my projects which automate the building of docker images. So, effectively only one command (IDE takes care of git push 😉) I have to run to apply new changes to the deployed project. &lt;code&gt;kubectl rollout restart deployment/&amp;lt;deployment_name&amp;gt;&lt;/code&gt; ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;i&gt;Happy hacking! Hope you learnt something new today 😄.&lt;/i&gt;&lt;/p&gt;

</description>
      <category>raspberrypi</category>
      <category>kubernetes</category>
      <category>docker</category>
    </item>
    <item>
      <title>How to build a thread-safe Queue in Go?</title>
      <dc:creator>Harsha Vaidya</dc:creator>
      <pubDate>Wed, 17 Feb 2021 16:30:21 +0000</pubDate>
      <link>https://forem.com/hvydya/how-to-build-a-thread-safe-queue-in-go-lbh</link>
      <guid>https://forem.com/hvydya/how-to-build-a-thread-safe-queue-in-go-lbh</guid>
      <description>&lt;p&gt;A thread-safe queue is a queue which can be used in a multi-threaded environment without any loss in data. Before we build one, let us discuss more on why we need a thread-safe queue. Feel free to skip the explanation and head to the bottom of this blog to find the full implementation for the queue if you know the prerequisites 😄.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does one need a thread-safe queue?
&lt;/h3&gt;

&lt;p&gt;Consider &lt;a href="https://play.golang.org/p/AWYbSysN-FD"&gt;this&lt;/a&gt; go program with a queue implementation. This is the &lt;code&gt;main&lt;/code&gt; function of that program. It creates a queue with size 1 and inserts an element into it. Then we spawn two go routines which remove the inserted element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;CreateQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Start two go routines&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// This go routine will try to call the Remove function of the queue.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;removed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Removed %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;removed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"got error %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also look at the &lt;code&gt;Remove&lt;/code&gt; function. I've added the &lt;code&gt;time.Sleep&lt;/code&gt; function to show what happens when things take too long (1ns=1x10&lt;sup&gt;-9&lt;/sup&gt;s might not be too long for us but can't say the same about computers 😉) in a multi-threaded environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nanosecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Queue is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a single-threaded environment, no problem would occur and everything would work as expected i.e two &lt;code&gt;Remove&lt;/code&gt; calls which would remove the element for the first call and return an error for the second call.&lt;/p&gt;

&lt;p&gt;But for multi-threaded environments, something very interesting happens. If you were to run that program in the playground you would get a &lt;a href="https://blog.golang.org/defer-panic-and-recover"&gt;panic&lt;/a&gt; from Go. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;goroutine&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0xc00000c0a0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox828372841&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0xf9&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0xc00000c0a0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox828372841&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;56&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0x32&lt;/span&gt;
&lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox828372841&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;0xcd&lt;/span&gt;

&lt;span class="n"&gt;Program&lt;/span&gt; &lt;span class="n"&gt;exited&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="m"&gt;2.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  So what happened there?
&lt;/h4&gt;

&lt;p&gt;The two go routines start executing one after the other in parallel. The first go routine calls &lt;code&gt;Remove&lt;/code&gt; and then it checks the length in &lt;code&gt;Remove&lt;/code&gt; (which is 1) and then enters the &lt;code&gt;if&lt;/code&gt; block and sleeps for 1ns. Now the second go routine also calls &lt;code&gt;Remove&lt;/code&gt; and checks the length and gets 1 as length and enters the &lt;code&gt;if&lt;/code&gt; block and sleeps for 1ns. Why does it enter? It's because the first go routine is still sleeping, so it hasn't removed the element from the queue yet so the length was going to be 1 for sure. Now while second go routine is sleeping, the first one wakes up and removes the element. When the second one wakes up it will try to fetch the first element in the queue but, it doesn't exist! And that explains the panic we got i.e &lt;code&gt;runtime error: index out of range [0] with length 0&lt;/code&gt;.  &lt;/p&gt;

&lt;h4&gt;
  
  
  What did we learn from the above experiment?
&lt;/h4&gt;

&lt;p&gt;A small delay in the form of &lt;code&gt;time.Sleep(1 * time.Nanosecond)&lt;/code&gt; i.e sleeping for 1 ns is enough to cause problems. This tells how sensitive threads are to the code we write 🤯, meaning, if I were to add some lines to that function which take &amp;gt;= 1ns to run then we would be seeing this issue. Now I think it's clear why we need to handle operations differently in a multi-threaded environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  So what's the solution?
&lt;/h3&gt;

&lt;p&gt;TLDR; The solution is to use a &lt;a href="https://golang.org/pkg/sync/#Mutex"&gt;mutex&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Intuitively, we need a mechanism that makes sure only one thread can &lt;code&gt;Remove&lt;/code&gt; from the queue at any given instance. Particularly the &lt;code&gt;if&lt;/code&gt; block since, that caused the problem in the first place. Here the &lt;code&gt;if&lt;/code&gt; block is said to be the &lt;a href="https://en.wikipedia.org/wiki/Critical_section"&gt;critical section&lt;/a&gt; of the &lt;code&gt;Remove&lt;/code&gt; function. So, we would somehow "lock" the critical section of the &lt;code&gt;Remove&lt;/code&gt; function when a thread approaches it and then "unlock" it when it's done with the operations it has to do. To do this "lock" and "unlock" we use a &lt;code&gt;mutex&lt;/code&gt; in Go. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;mutex&lt;/code&gt; will make sure only one thread accesses the critical section at any given instance. So, when you &lt;code&gt;Remove&lt;/code&gt;, before the &lt;code&gt;if&lt;/code&gt; block, we need to &lt;code&gt;Lock&lt;/code&gt; the following operations and when we are done we can &lt;code&gt;Unlock&lt;/code&gt;. &lt;a href="https://play.golang.org/p/8EAhphA0z0c"&gt;This&lt;/a&gt; is the updated snippet and below is the updated &lt;code&gt;Remove&lt;/code&gt; which is now thread-safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nanosecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Queue is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've included the mutex in the Queue &lt;code&gt;struct&lt;/code&gt; so that every instance of the queue has it's own mutex.&lt;br&gt;
If you were to run the program now, you would see everything works fine as expected. No more panics ✨!&lt;/p&gt;
&lt;h4&gt;
  
  
  How did it work?
&lt;/h4&gt;

&lt;p&gt;When we acquired the lock using &lt;code&gt;q.mu.Lock()&lt;/code&gt; we made sure that only one go routine can access the &lt;code&gt;if&lt;/code&gt; block. The &lt;code&gt;defer q.mu.Unlock()&lt;/code&gt; just makes sure we unlock it after the function returns. Try not calling &lt;code&gt;Unlock&lt;/code&gt; and ponder what happens then 😉.&lt;/p&gt;
&lt;h3&gt;
  
  
  Give me the whole code 😡
&lt;/h3&gt;

&lt;p&gt;Alright I've heard you 😅. Here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"errors"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;        &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// FifoQueue &lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;FifoQueue&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Insert inserts the item into the queue&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Queue is full"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Remove removes the oldest element from the queue&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Queue is empty"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// CreateQueue creates an empty queue with desired capacity&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CreateQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;i&gt;Happy coding! Hope you learnt something new today 😄.&lt;/i&gt;&lt;/p&gt;

</description>
      <category>queue</category>
      <category>multithreading</category>
      <category>synchronization</category>
      <category>go</category>
    </item>
    <item>
      <title>Save precious build time with custom Docker registry</title>
      <dc:creator>Harsha Vaidya</dc:creator>
      <pubDate>Thu, 21 May 2020 03:34:38 +0000</pubDate>
      <link>https://forem.com/hvydya/save-precious-build-time-with-custom-docker-registry-5elb</link>
      <guid>https://forem.com/hvydya/save-precious-build-time-with-custom-docker-registry-5elb</guid>
      <description>&lt;p&gt;At our company we have a relatively new product in development. On the DevOps side, we have a pretty simple workflow for the testing stage. It involves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Git repository triggers Jenkins build.&lt;/li&gt;
&lt;li&gt;Latest pull is taken from the repository&lt;/li&gt;
&lt;li&gt;Frontend is built using npm&lt;/li&gt;
&lt;li&gt;Backend Docker image is built (which contains frontend files)&lt;/li&gt;
&lt;li&gt;The image is pushed to Dockerhub&lt;/li&gt;
&lt;li&gt;Using Ansible, we run a script in the target server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the target server (on premises):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pull the latest image.&lt;/li&gt;
&lt;li&gt;Restart all related containers using Docker Compose.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a pretty simple CI/CD system. Nothing too complex. Our codebase is consistently growing and each build took around 20 minutes. We have around 5 builds per day on average with 6 devs working on the project. So, we realised it's high time we optimised the build system a bit to handle more builds per day and reduce time for building priority images.&lt;/p&gt;

&lt;p&gt;So, we looked into our Jenkins' build log and found out that pushing and pulling from Dockerhub took the most time (around 10 minutes). Since our test servers are on premises, we decided that having a custom registry (available as a Docker image) is the best solution to save time. So I looked into the Registry documentation (which is very well written 😀) and deployed it on one of the test servers. Then, I tweaked the build script a little bit to accommodate for the changes and Voila! The build time reduced to 12 minutes flat!! &lt;/p&gt;

&lt;p&gt;One of by-products of this effort was reduced image size. I noticed that I was adding node modules and git folders (newbie mistake 😛) into the image which were bloating the image resulting in unnecessary pushes and pulls of the layers of the image. The image size reduced to 5GB from 8GB. This decreased the build time to 10 minutes flat.&lt;/p&gt;

&lt;p&gt;Some lessons learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sometimes cloud is too expensive in terms of time (network latency 😞 ).&lt;/li&gt;
&lt;li&gt;Always inspect your image sizes and keep them as low as possible.&lt;/li&gt;
&lt;li&gt;In certain situations, managing your own services instead of cloud is not a bad solution.&lt;/li&gt;
&lt;li&gt;Monitor builds periodically for rapidly changing codebases for redundancies which can be potentially delaying your builds.&lt;/li&gt;
&lt;/ol&gt;

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