<?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[TechTransitions]]></title><description><![CDATA[🛠️ Mechanical Engineer turned IT and DevOps enthusiast with a passion for all things Open Source!  From designing tangible machinery to sculpting the digital l]]></description><link>https://blog.chetan-thapliyal.cloud</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 08:30:48 GMT</lastBuildDate><atom:link href="https://blog.chetan-thapliyal.cloud/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Ultimate DevOps Monitoring with Prometheus: A Step-by-Step Guide to Real-Time Alerts]]></title><description><![CDATA[Maintaining uptime and monitoring system health is crucial for any organization. Real-time monitoring ensures that issues are identified and resolved quickly, minimizing downtime and maintaining service reliability. In this blog, we'll walk through a...]]></description><link>https://blog.chetan-thapliyal.cloud/ultimate-devops-monitoring-with-prometheus-a-step-by-step-guide-to-real-time-alerts</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/ultimate-devops-monitoring-with-prometheus-a-step-by-step-guide-to-real-time-alerts</guid><category><![CDATA[#prometheus]]></category><category><![CDATA[GCP]]></category><category><![CDATA[Devops]]></category><category><![CDATA[projects]]></category><category><![CDATA[Devops articles]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[#nodeexporter]]></category><category><![CDATA[blackbox-exporter]]></category><category><![CDATA[Alertmanager]]></category><category><![CDATA[alerting]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Thu, 25 Jul 2024 05:45:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721473158552/b9986d72-be5b-4e07-98b3-8b544c084abb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Maintaining uptime and monitoring system health is crucial for any organization. Real-time monitoring ensures that issues are identified and resolved quickly, minimizing downtime and maintaining service reliability. In this blog, we'll walk through a comprehensive DevOps monitoring project that leverages <strong>Prometheus</strong>, <strong>Node Exporter</strong>, <strong>Blackbox Exporter</strong>, and <strong>Alertmanager</strong> to provide real-time alerts and monitoring.</p>
<h2 id="heading-project-overview">Project Overview</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721887415375/f688be15-654c-4317-8f19-aa851ad12be9.png" alt class="image--center mx-auto" /></p>
<p>The project aims to set up a real-time monitoring system that:</p>
<ul>
<li><p>Monitors websites, deployed app and virtual machines (VMs).</p>
</li>
<li><p>Sends email notifications for specific conditions such as website downtime, VM unavailability, service crashes, and resource exhaustion.</p>
</li>
</ul>
<h2 id="heading-components-and-tools">Components and Tools</h2>
<p>The key components used in this project are:</p>
<ol>
<li><p><strong>Prometheus</strong>: A powerful monitoring and alerting toolkit designed for reliability and scalability.</p>
</li>
<li><p><strong>Node Exporter</strong>: Used to monitor hardware and OS metrics exposed by *nix kernels.</p>
</li>
<li><p><strong>Blackbox Exporter</strong>: Allows probing of endpoints over HTTP, HTTPS, DNS, TCP, ICMP, and gRPC.</p>
</li>
<li><p><strong>Alertmanager</strong>: Handles alerts sent by client applications such as Prometheus and manages silencing, inhibition, aggregation, and sending notifications via methods such as email.</p>
</li>
</ol>
<h2 id="heading-use-cases">Use Cases</h2>
<p>The scenarios covered in this project include:</p>
<ol>
<li><p><strong>Website Downtime</strong>: Alerts if the website is inaccessible for more than 1-2 minutes.</p>
</li>
<li><p><strong>VM Unavailability</strong>: Alerts if a virtual machine is down for more than 1 minute.</p>
</li>
<li><p><strong>Service Crashes</strong>: Alerts if a specific service (e.g., Node Exporter) on a VM is stopped or unavailable.</p>
</li>
<li><p><strong>Resource Exhaustion</strong>: Alerts if there is no storage or memory left on a VM or if the CPU usage is excessively high.</p>
</li>
</ol>
<h2 id="heading-how-it-works">How It Works</h2>
<ol>
<li><p><strong>Infrastructure Setup</strong>:</p>
<ul>
<li><p>You create a network and two virtual machines (VMs) on Google Cloud Platform (GCP) or any other cloud.</p>
</li>
<li><p>One VM (Monitoring VM) runs Prometheus, Blackbox Exporter, and Alertmanager.</p>
</li>
<li><p>Another VM (Node Exporter VM) runs Node Exporter.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721739941665/5d0c3bbd-dcd2-45e8-9d93-4d08f32ec59a.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Monitoring</strong>:</p>
<ul>
<li><p><strong>Monitoring VM</strong>:</p>
<ul>
<li><p>Prometheus collects data from the Node Exporter and Blackbox Exporter.</p>
</li>
<li><p>Blackbox Exporter checks if specified websites are running.</p>
</li>
<li><p>Alertmanager is set up to send email notifications when certain conditions are met.</p>
</li>
</ul>
</li>
<li><p><strong>Node Exporter VM</strong>:</p>
<ul>
<li>Node Exporter collects and provides server metrics like CPU usage, memory usage, etc., to Prometheus.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Data Collection and Monitoring</strong>:</p>
<ul>
<li><p><strong>Prometheus</strong>:</p>
<ul>
<li><p>Regularly collects metrics from Node Exporter and Blackbox Exporter.</p>
</li>
<li><p>Checks these metrics against predefined rules.</p>
</li>
</ul>
</li>
<li><p><strong>Blackbox Exporter</strong>:</p>
<ul>
<li>Probes (checks) specified websites to ensure they are running.</li>
</ul>
</li>
<li><p><strong>Node Exporter</strong>:</p>
<ul>
<li>Collects and provides server metrics to Prometheus.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Alerting</strong>:</p>
<ul>
<li><p>If Prometheus detects an issue (e.g., a website is down, or a server is overloaded), it triggers an alert.</p>
</li>
<li><p>The Alertmanager receives this alert and sends an email notification to the specified addresses.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-setting-up-the-environment">Setting Up the Environment</h2>
<h3 id="heading-step-1-create-virtual-machines-and-install-tools">Step 1: Create Virtual Machines and Install Tools</h3>
<ul>
<li><p>By leveraging GCP's metadata feature of VM creation, I used Terraform to create Infrastructure and Install the required tools during VM creation. You can replicate project directly:</p>
<pre><code class="lang-bash">  git <span class="hljs-built_in">clone</span> https://github.com/ChetanThapliyal/real-time-devops-monitoring.git
  <span class="hljs-built_in">cd</span> real-time-devops-monitoring/Infra
  terraform init
  <span class="hljs-comment">#add appropriate Service Account key and tfvars</span>
  terraform apply
  <span class="hljs-comment"># Infra is ready with installed tools</span>
</code></pre>
</li>
</ul>
<h3 id="heading-step-2-configure-monitoring-tools">Step 2: Configure Monitoring Tools</h3>
<h4 id="heading-create-alert-rules"><strong>Create Alert Rules</strong></h4>
<ul>
<li><p>Let's defines a set of alerting rules for Prometheus. These rules monitor various metrics and trigger alerts based on specific conditions. Create a file <code>alert_rules.yml</code> in Prometheus folder:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">cd</span> /opt/prometheus
  vi alert_rules.yml
</code></pre>
<pre><code class="lang-yaml">  <span class="hljs-comment">#alert_rules.yml</span>
  <span class="hljs-attr">groups:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">alert_rules</span>                   <span class="hljs-comment"># Name of the alert rules group</span>
    <span class="hljs-attr">rules:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">InstanceDown</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">up</span> <span class="hljs-string">==</span> <span class="hljs-number">0</span>                   <span class="hljs-comment"># Expression to detect instance down</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">1m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">"critical"</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"Endpoint <span class="hljs-template-variable">{{ $labels.instance }}</span> down"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{ $labels.instance }}</span> of job <span class="hljs-template-variable">{{ $labels.job }}</span> has been down for more than 1 minute."</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">WebsiteDown</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">probe_success</span> <span class="hljs-string">==</span> <span class="hljs-number">0</span>        <span class="hljs-comment"># Expression to detect website down</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">1m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">critical</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">The</span> <span class="hljs-string">website</span> <span class="hljs-string">at</span> {{ <span class="hljs-string">$labels.instance</span> }} <span class="hljs-string">is</span> <span class="hljs-string">down.</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">Website</span> <span class="hljs-string">down</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">HostOutOfMemory</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">node_memory_MemAvailable</span> <span class="hljs-string">/</span> <span class="hljs-string">node_memory_MemTotal</span> <span class="hljs-string">*</span> <span class="hljs-number">100</span> <span class="hljs-string">&lt;</span> <span class="hljs-number">25</span>  <span class="hljs-comment"># Expression to detect low memory</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">5m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">warning</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"Host out of memory (instance <span class="hljs-template-variable">{{ $labels.instance }}</span>)"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"Node memory is filling up (&lt; 25% left)\n  VALUE = <span class="hljs-template-variable">{{ $value }}</span>\n  LABELS: <span class="hljs-template-variable">{{ $labels }}</span>"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">HostOutOfDiskSpace</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">(node_filesystem_avail{mountpoint="/"}</span> <span class="hljs-string">*</span> <span class="hljs-number">100</span><span class="hljs-string">)</span> <span class="hljs-string">/</span> <span class="hljs-string">node_filesystem_size{mountpoint="/"}</span> <span class="hljs-string">&lt;</span> <span class="hljs-number">50</span>  <span class="hljs-comment"># Expression to detect low disk space</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">1s</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">warning</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"Host out of disk space (instance <span class="hljs-template-variable">{{ $labels.instance }}</span>)"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"Disk is almost full (&lt; 50% left)\n  VALUE = <span class="hljs-template-variable">{{ $value }}</span>\n  LABELS: <span class="hljs-template-variable">{{ $labels }}</span>"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">HostHighCpuLoad</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">(sum</span> <span class="hljs-string">by</span> <span class="hljs-string">(instance)</span> <span class="hljs-string">(irate(node_cpu{job="node_exporter_metrics",mode="idle"}[5m])))</span> <span class="hljs-string">&gt;</span> <span class="hljs-number">80</span>  <span class="hljs-comment"># Expression to detect high CPU load</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">5m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">warning</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"Host high CPU load (instance <span class="hljs-template-variable">{{ $labels.instance }}</span>)"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"CPU load is &gt; 80%\n  VALUE = <span class="hljs-template-variable">{{ $value }}</span>\n  LABELS: <span class="hljs-template-variable">{{ $labels }}</span>"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">ServiceUnavailable</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">up{job="node_exporter"}</span> <span class="hljs-string">==</span> <span class="hljs-number">0</span>  <span class="hljs-comment"># Expression to detect service unavailability</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">2m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">critical</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"Service Unavailable (instance <span class="hljs-template-variable">{{ $labels.instance }}</span>)"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"The service <span class="hljs-template-variable">{{ $labels.job }}</span> is not available\n  VALUE = <span class="hljs-template-variable">{{ $value }}</span>\n  LABELS: <span class="hljs-template-variable">{{ $labels }}</span>"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">HighMemoryUsage</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">(node_memory_Active</span> <span class="hljs-string">/</span> <span class="hljs-string">node_memory_MemTotal)</span> <span class="hljs-string">*</span> <span class="hljs-number">100</span> <span class="hljs-string">&gt;</span> <span class="hljs-number">90</span>  <span class="hljs-comment"># Expression to detect high memory usage</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">10m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">critical</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"High Memory Usage (instance <span class="hljs-template-variable">{{ $labels.instance }}</span>)"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"Memory usage is &gt; 90%\n  VALUE = <span class="hljs-template-variable">{{ $value }}</span>\n  LABELS: <span class="hljs-template-variable">{{ $labels }}</span>"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">alert:</span> <span class="hljs-string">FileSystemFull</span>
        <span class="hljs-attr">expr:</span> <span class="hljs-string">(node_filesystem_avail</span> <span class="hljs-string">/</span> <span class="hljs-string">node_filesystem_size)</span> <span class="hljs-string">*</span> <span class="hljs-number">100</span> <span class="hljs-string">&lt;</span> <span class="hljs-number">10</span>  <span class="hljs-comment"># Expression to detect file system almost full</span>
        <span class="hljs-attr">for:</span> <span class="hljs-string">5m</span>
        <span class="hljs-attr">labels:</span>
          <span class="hljs-attr">severity:</span> <span class="hljs-string">critical</span>
        <span class="hljs-attr">annotations:</span>
          <span class="hljs-attr">summary:</span> <span class="hljs-string">"File System Almost Full (instance <span class="hljs-template-variable">{{ $labels.instance }}</span>)"</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">"File system has &lt; 10% free space\n  VALUE = <span class="hljs-template-variable">{{ $value }}</span>\n  LABELS: <span class="hljs-template-variable">{{ $labels }}</span>"</span>
</code></pre>
</li>
<li><p>Let's understand what we are doing in <code>alert_rules.yml</code></p>
</li>
<li><h4 id="heading-alert-rules-structure">Alert Rules Structure</h4>
<ul>
<li><p><strong>groups</strong>: Contains a list of alert groups. Each group can have multiple rules.</p>
</li>
<li><p><strong>name</strong>: The name of the alert group.</p>
</li>
<li><p><strong>rules</strong>: A list of alert rules within the group.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-individual-alert-rules">Individual Alert Rules</h4>
<p>    Each alert rule has the following components:</p>
<ul>
<li><p><strong>alert</strong>: The name of the alert.</p>
</li>
<li><p><strong>expr</strong>: The PromQL expression used to evaluate the alert condition.</p>
</li>
<li><p><strong>for</strong>: The duration for which the condition must be true before triggering an alert.</p>
</li>
<li><p><strong>labels</strong>: Additional labels to attach to the alert.</p>
</li>
<li><p><strong>annotations</strong>: Additional information about the alert, such as a summary and description.</p>
</li>
</ul>
<h4 id="heading-explanation-of-each-alert">Explanation of Each Alert</h4>
<ol>
<li><p><strong>InstanceDown</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>InstanceDown</code></p>
</li>
<li><p><strong>expr</strong>: <code>up == 0</code></p>
<ul>
<li>Checks if any instance is down (<code>up</code> metric is 0).</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>1m</code></p>
<ul>
<li>The condition must be true for 1 minute.</li>
</ul>
</li>
<li><p><strong>labels</strong>: <code>severity: "critical"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "Endpoint {{ $labels.instance }} down"</p>
</li>
<li><p><strong>description</strong>: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minute."</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>WebsiteDown</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>WebsiteDown</code></p>
</li>
<li><p><strong>expr</strong>: <code>probe_success == 0</code></p>
<ul>
<li>Checks if the website is down (<code>probe_success</code> metric is 0).</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>1m</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "critical"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>description</strong>: "The website at {{ $labels.instance }} is down."</p>
</li>
<li><p><strong>summary</strong>: "Website down"</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>HostOutOfMemory</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>HostOutOfMemory</code></p>
</li>
<li><p><strong>expr</strong>: <code>node_memory_MemAvailable / node_memory_MemTotal * 100 &lt; 25</code></p>
<ul>
<li>Checks if available memory is less than 25%.</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>5m</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "warning"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "Host out of memory (instance {{ $labels.instance }})"</p>
</li>
<li><p><strong>description</strong>: "Node memory is filling up (&lt; 25% left)\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>HostOutOfDiskSpace</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>HostOutOfDiskSpace</code></p>
</li>
<li><p><strong>expr</strong>: <code>(node_filesystem_avail{mountpoint="/"} * 100) / node_filesystem_size{mountpoint="/"} &lt; 50</code></p>
<ul>
<li>Checks if available disk space on the root filesystem is less than 50%.</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>1s</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "warning"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "Host out of disk space (instance {{ $labels.instance }})"</p>
</li>
<li><p><strong>description</strong>: "Disk is almost full (&lt; 50% left)\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>HostHighCpuLoad</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>HostHighCpuLoad</code></p>
</li>
<li><p><strong>expr</strong>: <code>sum by (instance) (irate(node_cpu{job="node_exporter_metrics",mode="idle"}[5m])) &gt; 80</code></p>
<ul>
<li>Checks if the CPU load is greater than 80%.</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>5m</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "warning"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "Host high CPU load (instance {{ $labels.instance }})"</p>
</li>
<li><p><strong>description</strong>: "CPU load is &gt; 80%\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>ServiceUnavailable</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>ServiceUnavailable</code></p>
</li>
<li><p><strong>expr</strong>: <code>up{job="node_exporter"} == 0</code></p>
<ul>
<li>Checks if the service (<code>node_exporter</code> job) is unavailable (<code>up</code> metric is 0).</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>2m</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "critical"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "Service Unavailable (instance {{ $labels.instance }})"</p>
</li>
<li><p><strong>description</strong>: "The service {{ $labels.job }} is not available\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>HighMemoryUsage</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>HighMemoryUsage</code></p>
</li>
<li><p><strong>expr</strong>: <code>(node_memory_Active / node_memory_MemTotal) * 100 &gt; 90</code></p>
<ul>
<li>Checks if active memory usage is greater than 90%.</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>10m</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "critical"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "High Memory Usage (instance {{ $labels.instance }})"</p>
</li>
<li><p><strong>description</strong>: "Memory usage is &gt; 90%\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>FileSystemFull</strong></p>
<ul>
<li><p><strong>alert</strong>: <code>FileSystemFull</code></p>
</li>
<li><p><strong>expr</strong>: <code>(node_filesystem_avail / node_filesystem_size) * 100 &lt; 10</code></p>
<ul>
<li>Checks if available file system space is less than 10%.</li>
</ul>
</li>
<li><p><strong>for</strong>: <code>5m</code></p>
</li>
<li><p><strong>labels</strong>: <code>severity: "critical"</code></p>
</li>
<li><p><strong>annotations</strong>:</p>
<ul>
<li><p><strong>summary</strong>: "File System Almost Full (instance {{ $labels.instance }})"</p>
</li>
<li><p><strong>description</strong>: "File system has &lt; 10% free space\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>    These alert rules help ensure the health and availability of services by monitoring key metrics and notifying when certain thresholds are crossed.</p>
<h4 id="heading-main-configuration-for-prometheus"><strong>Main configuration for Prometheus</strong></h4>
<ul>
<li><p>Now let's edit the <code>prometheus.yml</code> file which is the main configuration file for Prometheus and also understand the default global configuration while configuring it:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">cd</span> /opt/prometheus
  vi prometheus.yml
  <span class="hljs-comment">#uncomment line 16 and add alert_rules.yml</span>
  <span class="hljs-comment">#shown in below screenshot</span>
</code></pre>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721831500948/e4154f99-2960-426c-8924-c7da1bcd02d7.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-global-configuration">Global Configuration</h4>
<p>  The global configuration settings apply to all scrape jobs and rule evaluations unless explicitly overridden.</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">global:</span>
    <span class="hljs-attr">scrape_interval:</span> <span class="hljs-string">15s</span> <span class="hljs-comment"># Set the scrape interval to every 15 seconds. Default is every 1 minute.</span>
    <span class="hljs-attr">evaluation_interval:</span> <span class="hljs-string">15s</span> <span class="hljs-comment"># Evaluate rules every 15 seconds. The default is every 1 minute.</span>
    <span class="hljs-comment"># scrape_timeout is set to the global default (10s).</span>
</code></pre>
<ul>
<li><p><strong>scrape_interval: 15s</strong>: This setting specifies that Prometheus will scrape metrics from all targets every 15 seconds. The default value, if not specified, is 1 minute.</p>
</li>
<li><p><strong>evaluation_interval: 15s</strong>: This setting specifies that Prometheus will evaluate alerting and recording rules every 15 seconds. The default value, if not specified, is 1 minute.</p>
</li>
<li><p><strong>scrape_timeout</strong>: This is not explicitly set here, so it defaults to 10 seconds. This is the maximum time allowed for a scrape request to complete.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-alertmanager-configuration">Alertmanager Configuration</h4>
<p>    This section configures Alertmanager instances where alerts will be sent.</p>
<ul>
<li><p>Uncomment the <code>alertmanager:9093</code> line and write your public IP address of Monitoring VM in place of <code>alertmanager</code>:</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">alerting:</span>
    <span class="hljs-attr">alertmanagers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">static_configs:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">targets:</span>
            <span class="hljs-comment"># - alertmanager:9093</span>
              <span class="hljs-bullet">-</span> <span class="hljs-string">PUBLIC_IP:9093</span> <span class="hljs-comment">#write public IP of monitoring VM</span>
</code></pre>
<ul>
<li><p><strong>alerting</strong>: The root key for alerting configurations.</p>
</li>
<li><p><strong>alertmanagers</strong>: A list of Alertmanager instances that Prometheus will send alerts to.</p>
<ul>
<li><p><strong>static_configs</strong>: Uses a static list of Alertmanager instances.</p>
</li>
<li><p><strong>targets</strong>: The list of Alertmanager endpoints. The example contains a commented-out target (<code>alertmanager:9093</code>). You would uncomment and adjust this line to specify your Alertmanager instances.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="heading-rule-files-configuration">Rule Files Configuration</h4>
<p>    This section specifies the rule files that Prometheus should load. These files contain alerting and recording rules.</p>
<ul>
<li><p>Here we'll add our <code>alert_rules.yml</code> that we wrote in our last step:</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">rule_files:</span>
    <span class="hljs-comment"># - "first_rules.yml"</span>
    <span class="hljs-comment"># - "second_rules.yml"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">alert_rules.yml</span>
</code></pre>
<ul>
<li><strong>rule_files</strong>: A list of file paths to rule files. In this example, the rule files are commented out. You would uncomment and provide paths to your actual rule files (<code>alert_rules.yml</code>).</li>
</ul>
</li>
</ul>
<h4 id="heading-scrape-configuration">Scrape Configuration</h4>
<p>    This section defines the scrape configuration for Prometheus itself. It specifies which targets Prometheus should scrape for metrics.</p>
<pre><code class="lang-yaml">    <span class="hljs-attr">scrape_configs:</span>
      <span class="hljs-comment"># The job name is added as a label `job=&lt;job_name&gt;` to any timeseries scraped from this config.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">job_name:</span> <span class="hljs-string">"prometheus"</span>

        <span class="hljs-comment"># metrics_path defaults to '/metrics'</span>
        <span class="hljs-comment"># scheme defaults to 'http'.</span>

        <span class="hljs-attr">static_configs:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">targets:</span> [<span class="hljs-string">"localhost:9090"</span>]
</code></pre>
<ul>
<li><p><strong>scrape_configs</strong>: A list of scrape configurations.</p>
<ul>
<li><p><strong>job_name: "prometheus"</strong>: The name of the scrape job. This name is added as a label (<code>job=&lt;job_name&gt;</code>) to any time series scraped from this job.</p>
</li>
<li><p><strong>metrics_path</strong>: The path to the metrics endpoint. It defaults to <code>/metrics</code>, so it is not specified here.</p>
</li>
<li><p><strong>scheme</strong>: The protocol used to scrape metrics (HTTP or HTTPS). It defaults to <code>http</code>, so it is not specified here.</p>
</li>
<li><p><strong>static_configs</strong>: Specifies static targets to scrape.</p>
<ul>
<li><strong>targets: ["</strong><a target="_blank" href="http://localhost:9090"><strong>localhost:9090</strong></a><strong>"]</strong>: The target endpoint for this job. In this case, it is scraping Prometheus's own metrics endpoint running on <a target="_blank" href="http://localhost"><code>localhost</code></a> at port <code>9090</code>.</li>
</ul>
</li>
</ul>
</li>
<li><p>We'll add 2 jobs <code>Node Exporter</code> and <code>Blackbox exporter</code>:</p>
<pre><code class="lang-bash">      static_configs:
        - targets: [<span class="hljs-string">"localhost:9090"</span>]

    - job_name: <span class="hljs-string">"node_exporter"</span>                <span class="hljs-comment"># Job name for node exporter</span>

      static_configs:
        - targets: [<span class="hljs-string">"PUBLIC_IP_ADDRESS:9100"</span>]  <span class="hljs-comment"># Target node exporter endpoint</span>

    - job_name: <span class="hljs-string">'blackbox'</span>                     <span class="hljs-comment"># Job name for blackbox exporter</span>
      metrics_path: /probe                     <span class="hljs-comment"># Path for blackbox probe</span>
      params:
        module: [http_2xx]                     <span class="hljs-comment"># Module to look for HTTP 200 response</span>
      static_configs:
        - targets:
          - http://prometheus.io               <span class="hljs-comment"># HTTP target</span>
          - https://prometheus.io              <span class="hljs-comment"># HTTPS target</span>
          - http://PUBIC_IP_ADDRESS:8080/      <span class="hljs-comment"># HTTP target with port 8080</span>
      relabel_configs:
        - source_labels: [__address__]
          target_label: __param_target
        - source_labels: [__param_target]
          target_label: instance
        - target_label: __address__
          replacement: PUBLIC_IP_ADDRESS:9115  <span class="hljs-comment"># Blackbox exporter address</span>
</code></pre>
</li>
<li><p>You can find the example configs of how to set these jobs in :</p>
<p>  <a target="_blank" href="https://github.com/prometheus/blackbox_exporter">prometheus/blackbox_exporter</a></p>
</li>
<li><p><strong>job_name</strong>: "node_exporter"</p>
<ul>
<li><p>This job is named <code>node_exporter</code>, and this name will be added as a label (<code>job="node_exporter"</code>) to all time series scraped from this job.</p>
</li>
<li><p><strong>static_configs</strong>: Specifies static targets to scrape.</p>
<ul>
<li><strong>targets</strong>: A list of targets to scrape for metrics. Here, Prometheus will scrape metrics from a Node Exporter running at <code>PUBLIC_IP_ADDRESS:9100</code>. You would replace <code>PUBLIC_IP_ADDRESS</code> with the actual IP address of the target node.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>job_name</strong>: 'blackbox'</p>
<ul>
<li><p>This job is named <code>blackbox</code>, indicating that it is for scraping metrics using the Blackbox Exporter.</p>
</li>
<li><p><strong>metrics_path</strong>: <code>/probe</code></p>
<ul>
<li>Specifies the path for the Blackbox Exporter's probe endpoint. The default metrics path <code>/metrics</code> is overridden here.</li>
</ul>
</li>
<li><p><strong>params</strong>:</p>
<ul>
<li><p><strong>module</strong>: [http_2xx]</p>
<ul>
<li>Specifies the module for the Blackbox Exporter to use. In this case, it checks for an HTTP 200 response.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>static_configs</strong>:</p>
<ul>
<li><p><strong>targets</strong>:</p>
<ul>
<li><p>Lists the targets that the Blackbox Exporter will probe.</p>
</li>
<li><p><strong>http://prometheus.io</strong>: An HTTP target.</p>
</li>
<li><p><strong>https://prometheus.io</strong>: An HTTPS target.</p>
</li>
<li><p><strong>http://PUBLIC_IP_ADDRESS:8080/</strong>: An HTTP target with port 8080. Replace <code>PUBLIC_IP_ADDRESS</code> with the actual IP address.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>relabel_configs</strong>:</p>
<ul>
<li><p>Defines a series of relabeling rules to manipulate target labels before scraping.</p>
</li>
<li><p><strong>source_labels: [address]</strong></p>
<ul>
<li><p><strong>target_label: __param_target</strong></p>
<ul>
<li>Takes the value from the <code>__address__</code> label and sets it as the <code>__param_target</code> label. This configures the Blackbox Exporter to probe the original target address.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>source_labels: [__param_target]</strong></p>
<ul>
<li><p><strong>target_label: instance</strong></p>
<ul>
<li>Copies the value from the <code>__param_target</code> label to the <code>instance</code> label, helping identify the original target in metrics.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>target_label: address</strong></p>
<ul>
<li><p><strong>replacement: PUBLIC_IP_ADDRESS:9115</strong></p>
<ul>
<li>Overrides the <code>__address__</code> label to point to the Blackbox Exporter instance running at <code>PUBLIC_IP_ADDRESS:9115</code>. Replace <code>PUBLIC_IP_ADDRESS</code> with the actual IP address.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>This configuration file does the following:</p>
<ol>
<li><p>Sets global parameters for how often Prometheus scrapes targets and evaluates rules (every 15 seconds).</p>
</li>
<li><p>Configures an Alertmanager instance (though commented out, you would need to provide the actual address).</p>
</li>
<li><p>Specifies where Prometheus should look for alerting and recording rules (currently commented out).</p>
</li>
<li><p>Defines a scrape configuration to scrape metrics from the Prometheus server itself.</p>
</li>
</ol>
</li>
<li><p>After configuring the prometheus global configuration, restart the prometheus service:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">cd</span> /opt/prometheus
  pgrep prometheus
  3245  <span class="hljs-comment">#yours will be different</span>
  <span class="hljs-built_in">kill</span> 3245
  ./prometheus &amp;
</code></pre>
</li>
</ul>
<h4 id="heading-config-for-receiving-mail-notification">Config for receiving Mail Notification</h4>
<ul>
<li><p>For receiving mail notifications, we'll need to configure <code>alertmanager.yml</code>:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721839822404/93509adf-a969-474f-888f-0d8b7c17c19b.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>The <code>alertmanager.yml</code> file is the configuration file for Prometheus Alertmanager, which handles alerts sent by Prometheus. The configuration is divided into three main sections: <code>route</code>, <code>receivers</code>, and <code>inhibit_rules</code>.</p>
<h4 id="heading-route">Route</h4>
<p>  The <code>route</code> section defines how alerts are grouped and routed to receivers. Here’s a breakdown of the options:</p>
<pre><code class="lang-bash">  route:
    group_by: [<span class="hljs-string">'alertname'</span>]             <span class="hljs-comment"># Group by alert name</span>
    group_wait: 30s                     <span class="hljs-comment"># Wait time before sending the first notification</span>
    group_interval: 5m                  <span class="hljs-comment"># Interval between notifications</span>
    repeat_interval: 1h                 <span class="hljs-comment"># Interval to resend notifications</span>
    receiver: <span class="hljs-string">'email-notifications'</span>     <span class="hljs-comment"># Default receiver</span>
</code></pre>
<ul>
<li><p><strong>group_by</strong>: Defines how alerts are grouped together. In this case, alerts with the same <code>alertname</code> will be grouped.</p>
</li>
<li><p><strong>group_wait</strong>: The amount of time to wait before sending a notification for a new alert group. This helps in aggregating alerts and avoiding notification floods.</p>
</li>
<li><p><strong>group_interval</strong>: The minimum time interval to wait before sending a notification for new alerts that belong to the same alert group.</p>
</li>
<li><p><strong>repeat_interval</strong>: The interval at which notifications are resent if the alert is still active.</p>
</li>
<li><p><strong>receiver</strong>: The name of the default receiver to which alerts are sent if no other route matches.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="heading-receivers">Receivers</h4>
<p>        The <code>receivers</code> section defines where the alerts should be sent. Each receiver can have different configurations for different alerting mechanisms (e.g., email, Slack, webhook).</p>
<pre><code class="lang-bash">        receivers:
        - name: <span class="hljs-string">'email-notifications'</span>         <span class="hljs-comment"># Receiver name</span>
          email_configs:
          - to: your_email@tld.com                 <span class="hljs-comment"># Email recipient</span>
            from: <span class="hljs-built_in">test</span>@tld.com              <span class="hljs-comment"># Email sender</span>
            smarthost: smtp.gmail.com:587     <span class="hljs-comment"># SMTP server</span>
            auth_username: your_email         <span class="hljs-comment"># SMTP auth username</span>
            auth_identity: your_email         <span class="hljs-comment"># SMTP auth identity</span>
            auth_password: <span class="hljs-string">"xxxx xxxx xxxx xxxx"</span>  <span class="hljs-comment"># SMTP auth password</span>
            send_resolved: <span class="hljs-literal">true</span>               <span class="hljs-comment"># Send notifications for resolved alerts</span>
</code></pre>
<ul>
<li><p><strong>name</strong>: The name of the receiver. In this example, it's <code>web.hook</code>.</p>
</li>
<li><p><strong>webhook_configs</strong>: Defines the webhook configurations for the receiver. Alerts will be sent to the specified URL.</p>
</li>
<li><p>Replace <code>auth_username</code> &amp; <code>auth_identity</code> with your email address, and for <code>auth_password</code> generate an app password instead of email password.</p>
</li>
<li><p>You can read here how to generate the app password for gmail:</p>
<p>  <a target="_blank" href="https://support.google.com/mail/answer/185833?hl=en">https://support.google.com/mail/answer/185833?hl=en</a></p>
</li>
</ul>
<h4 id="heading-inhibit-rules">Inhibit Rules</h4>
<p>        The <code>inhibit_rules</code> section defines rules to mute certain alerts if others are firing. This is useful to avoid redundant alerts and reduce alert noise.</p>
<pre><code class="lang-bash">        inhibit_rules:
          - source_match:
              severity: <span class="hljs-string">'critical'</span>            <span class="hljs-comment"># Source alert severity</span>
            target_match:
              severity: <span class="hljs-string">'warning'</span>             <span class="hljs-comment"># Target alert severity</span>
            equal: [<span class="hljs-string">'alertname'</span>, <span class="hljs-string">'dev'</span>, <span class="hljs-string">'instance'</span>]  <span class="hljs-comment"># Fields to match</span>
</code></pre>
<ul>
<li><p><strong>source_match</strong>: Specifies the conditions that an alert must match to be a source alert (the alert that can inhibit others). In this case, alerts with <code>severity: 'critical'</code>.</p>
</li>
<li><p><strong>target_match</strong>: Specifies the conditions that an alert must match to be a target alert (the alert that can be inhibited). In this case, alerts with <code>severity: 'warning'</code>.</p>
</li>
<li><p><strong>equal</strong>: Lists the labels that must be equal between the source and target alerts for the inhibition to occur. Here, the inhibition will happen if the <code>alertname</code>, <code>dev</code>, and <code>instance</code> labels are equal.</p>
</li>
</ul>
<p>        <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721843765073/8152f8da-3343-493d-8523-6a8cc6565375.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-2-verify-setup">Step 2: Verify Setup</h3>
<p>Access Prometheus at <code>http://&lt;monitoring_VM_IP&gt;:9090</code> and ensure all targets are up. Check the metrics to ensure they are being collected correctly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721838252212/ddc96104-8702-413a-9936-76697e51af4a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721838284178/333bc366-123e-4196-987e-808fae7f3291.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721843969278/5746783c-e555-4e5e-b629-30e54d7a4043.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-3-simulate-downtime-and-verify-alerts">Step 3: Simulate Downtime and Verify Alerts</h3>
<p>Stop the website or VM services to trigger alerts and verify that email notifications are received as expected.</p>
<ul>
<li><p>Let's stop our application and test the alert (in NodeExporter VM, kill java process and app will be down):</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721844457944/3d1a00b9-5901-4cd0-88b4-27c9c7cf02e2.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>And within a minute we received Email notification that our website is down:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721844567170/a7b7a613-1622-47eb-82fb-accf320ee7ef.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By following these steps, you can set up a robust monitoring system using Prometheus, Node Exporter, Blackbox Exporter, and Alertmanager. This setup will ensure that you are promptly notified of any issues, allowing for quick resolution and maintaining system reliability. Implementing such a monitoring solution is a critical aspect of effective DevOps practices, ensuring that your services are always available and performing optimally.</p>
<p>Throughout this endeavor, I encountered and overcame several challenges, each of which provided valuable insights and reinforced best practices in DevOps Monitoring. The experience has been immensely rewarding, enhancing my skills and deepening my understanding of end-to-end deployment processes.</p>
<p>This project represents a significant milestone in my professional journey, showcasing my ability to design, implement, and manage complex deployment pipelines and infrastructure. As I look to the future, I am excited about the potential for further improvements and the opportunity to apply these learnings in new and innovative ways.</p>
<p>Thank you for taking the time to read about my DevOps project. I hope you found this exploration insightful and valuable. I am always eager to connect with fellow enthusiasts and professionals, so please feel free to reach out to me for further discussions or collaborations. Your feedback and suggestions are highly appreciated as they help me grow and refine my skills.</p>
<p>Let's continue to deploy, monitor and innovate together!</p>
<hr />
<p><em>Connect with me on</em><a target="_blank" href="https://www.linkedin.com/in/chetanthapliyal/"><em>LinkedIn</em></a><em>or check out the project's</em><a target="_blank" href="https://github.com/ChetanThapliyal/real-time-devops-monitoring"><em>GitHub repository</em></a><em>. Feel free to leave your comments, questions, or suggestions below.</em></p>
]]></content:encoded></item><item><title><![CDATA[3-tier Architecture Multi-Environment Deployment using Terraform, Jenkins, Docker, and GKE]]></title><description><![CDATA[In the fast-paced world of software development, the ability to deploy applications efficiently and securely is a critical skill. In this project we'll explores the Application Deployment through the lens of modern DevOps practices, showcasing a powe...]]></description><link>https://blog.chetan-thapliyal.cloud/3-tier-architecture-multi-environment-deployment-using-terraform-jenkins-docker-and-gke</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/3-tier-architecture-multi-environment-deployment-using-terraform-jenkins-docker-and-gke</guid><category><![CDATA[gke]]></category><category><![CDATA[Jenkins]]></category><category><![CDATA[Devops]]></category><category><![CDATA[GCP]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Docker]]></category><category><![CDATA[cicd]]></category><category><![CDATA[sonarqube]]></category><category><![CDATA[trivy]]></category><category><![CDATA[3-tier-architecture]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sat, 20 Jul 2024 07:54:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721383219928/d038d6e2-8880-4f6d-8a52-dc27a8da2270.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the fast-paced world of software development, the ability to deploy applications efficiently and securely is a critical skill. In this project we'll explores the Application Deployment through the lens of modern DevOps practices, showcasing a powerful multi-environment deployment pipeline for a full-stack web application.</p>
<p>At the heart of this project is Yelp Camp, a feature-rich website for campground reviews. This application serves as an ideal candidate for demonstrating advanced deployment techniques, incorporating diverse technologies such as Cloudinary for image storage, Atlas DB for user data management, and MapBox APIs for interactive location mapping.</p>
<p>We'll dive deep into the setup and configuration of each component, exploring best practices and overcoming common challenges in multi-environment deployments.</p>
<h2 id="heading-project-objectives">Project Objectives</h2>
<p>The primary goal of this project is to implement a robust 3-tier architecture, ensuring scalability, maintainability, and security. To achieve this, I've leveraged a suite of cutting-edge tools:</p>
<ol>
<li><p>Terraform: For infrastructure as code, allowing us to define and provision our deployment environments consistently and reproducibly.</p>
</li>
<li><p>Jenkins: Powering our continuous integration and continuous deployment (CI/CD) pipeline, automating build, test, and deployment processes.</p>
</li>
<li><p>Docker: Containerizing our application components for improved portability and resource efficiency.</p>
</li>
<li><p>Trivy: Integrated for comprehensive vulnerability scanning of container images and filesystems, enhancing our security posture.</p>
</li>
<li><p>SonarQube: Employed for continuous inspection of code quality, helping maintain high standards throughout the development process.</p>
</li>
<li><p>Google Kubernetes Engine (GKE): Orchestrating our containerized application, providing scalability and simplified management in a cloud environment.</p>
</li>
</ol>
<p>Pipeline incorporates multiple stages, including local deployment for testing, development and production environments with distinct security and quality checks. We will utilize Trivy for both filesystem and image scanning, ensuring that our application and its dependencies are free from known vulnerabilities. SonarQube analysis is performed to maintain code quality and identify potential issues early in the development cycle.</p>
<p>How we will achieve our objectives:</p>
<ul>
<li><p>Creating three separate environments (<code>test</code>, <code>dev</code>, <code>prod</code>) and use modular approach for resource creation using Terraform and deploying the application across these environments.</p>
</li>
<li><p><strong>Test Environment</strong>: Setting up a local development environment for testing the Yelp-Camp application (done on a GCP Compute Engine).</p>
</li>
<li><p><strong>Dev Environment</strong>: Building and deploying the application in a Docker container using a CI/CD pipeline.</p>
</li>
<li><p><strong>Prod Environment</strong>: Automating deployment of the application to a Google Kubernetes Engine (GKE) cluster through a CI/CD pipeline.</p>
</li>
<li><p>Leveraging automation wherever possible, including the use of GCP's metadata feature and startup scripts to install all necessary tools.</p>
<p>  %[https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/tree/main] </p>
</li>
</ul>
<h2 id="heading-architecture-diagram">Architecture Diagram</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721386649019/613f1452-8fc8-4843-8d44-8ea22249f078.png" alt class="image--center mx-auto" /></p>
<p>The architecture is designed to ensure smooth transitions from development to production. Here's a high-level overview of the setup:</p>
<ol>
<li><p><strong>Test Environment</strong>: Developers check if the application is running locally.</p>
</li>
<li><p><strong>Dev Environment</strong>: Uses Jenkins for continuous integration and deployment, incorporating SonarQube for code quality checks and Trivy for security scans. Docker images are built and pushed to a container registry.</p>
</li>
<li><p><strong>Prod Environment</strong>: Reuses the CI/CD pipeline to deploy the Docker images on GKE, ensuring the application is production-ready.</p>
</li>
</ol>
<h2 id="heading-setting-up-the-infrastructure-amp-environments">Setting Up the Infrastructure &amp; Environments</h2>
<h3 id="heading-creating-infrastructure">Creating Infrastructure</h3>
<p><strong>Terraform Environment</strong>:</p>
<ul>
<li><p>Ensure Terraform is installed on system.</p>
</li>
<li><p>Set up GCP credentials and configure the Google Cloud SDK (<code>gcloud</code>).</p>
</li>
</ul>
<p><strong>API's, Secrets and Keys used in YelpCamp</strong></p>
<ul>
<li><p>Cloudinary Credentials (for storing Campground Images)</p>
<ul>
<li><p>Signup to <a target="_blank" href="https://cloudinary.com">https://cloudinary.com</a> and since our application uses NodeJS, copy the credentials in local text file or somewhere safe.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721403628881/da743e46-0503-4718-a5c8-a49d194b2a7c.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p>Mapbox API key for Location:</p>
<ul>
<li><p>Signup to <a target="_blank" href="https://www.mapbox.com">https://www.mapbox.com</a> and generate access token and copy the credentials in local text file or somewhere safe.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721404156820/7461558b-d7e4-452b-94be-9bde5c4b2d93.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p>MongoDB Atlas URL for storing the Admin and User data.</p>
<ul>
<li><p>Signup to <a target="_blank" href="https://www.mongodb.com/cloud/atlas/register">https://www.mongodb.com/cloud/atlas/register</a> and 1st copy Database User's -&gt; Username and Password and Create DB user.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721404424511/bff10116-7be3-4381-bf94-40e219195c7a.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Next connect to DB using Drivers option and than copy the connection string which we will use to connect App to DB: (since there are multiple strings in it save it under double quotes. Ex. "mongo_srv://........." )</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721404732386/76d17b34-c1e5-4b39-948c-ca46204f4642.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p>Now by default this DB is accessible from only your current IP Address, so to access it from other locations we'll add 0.0.0.0/0 in Access List Entry so that it can be accessible from anywhere. (For security add only the IP addresses where you want access to DB):</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721411586565/e854685e-112f-49bb-8b86-6df519426cff.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h3 id="heading-project-structure">Project Structure</h3>
<pre><code class="lang-bash">tree -L 4
── Infra
│   ├── environments
│   │   ├── dev
│   │   ├── prod
│   │   └── <span class="hljs-built_in">test</span>
│   ├── modules
│   │   ├── compute
│   │   ├── firewall
│   │   ├── gke
│   │   └── network
│   ├── scripts
│   │   ├── jenkins.sh
│   │   ├── nodejs.sh
│   │   └── sonarqube.sh
│   ├── secrets
│   │   ├── credentials.json
│   │   └── db.md
│   ├── main.tf
│   ├── variables.tf
│   ├── providers.tf
|   ├── terraform.tfvars
│   └── outputs.tf
├── k8
│   └── deployment.yaml
├── LICENSE
├── README.md
└── src(Project Files)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721460055956/d87f01a6-061c-4c8c-ab50-5539055a3598.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>To replicate similar project structure simply clone repo:</p>
<pre><code class="lang-bash">  git <span class="hljs-built_in">clone</span> https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE.git
  <span class="hljs-built_in">cd</span> 3-tier-architecture-deployment-GKE/Infra
  <span class="hljs-comment">#Create a terraform.tfvars file for each environment </span>
  <span class="hljs-comment">#(test, dev, prod and global) with the necessary variables.</span>
  terraform init
  <span class="hljs-comment"># for custom ports variable set it to:</span>
  <span class="hljs-comment"># custom_ports = ["80", "443", "465", "6443", "3000-10000", "30000-32767"]</span>
  <span class="hljs-comment"># ssh_ports = ["22"]</span>
  terraform apply 

  <span class="hljs-built_in">cd</span> environments/<span class="hljs-built_in">test</span>
  terraform init
  terraform apply 
  <span class="hljs-comment">#Repeat same steps for dev and prod.</span>
</code></pre>
</li>
<li><p>The above commands will create Infrastructure of all 3 environments with a global VPC.</p>
</li>
<li><p>Now let's configure each environment and understand what we created.</p>
</li>
</ul>
<h2 id="heading-configuring-each-environment">Configuring each Environment</h2>
<h3 id="heading-understanding-global-vpc">Understanding Global VPC</h3>
<ul>
<li><p>We used one single VPC and same firewall rules for all 3 environments, it full-fills our project needs.</p>
</li>
<li><p><strong>Advancement:</strong> We can create seperate subnets for each env or create seperate VPC for each env.</p>
</li>
<li><p>Ports that are needed for this project:</p>
<pre><code class="lang-bash">  `22`: SSH
  `80`: HTTP
  `443`: HTTPS
  `465`: SMTP (<span class="hljs-keyword">for</span> sending emails from Jenkins to Personal email IDs)
  `6443`: For setting up kubernetes cluster
  `3000-10000`: Application ports
  `30000-32767`: Kubernetes cluster ports <span class="hljs-keyword">for</span> application deployment
</code></pre>
</li>
</ul>
<h3 id="heading-test-environment">Test Environment</h3>
<p>In the Test environment, the application is deployed locally, in this case in a GCP compute engine. This step allows developers to ensure that the basic functionality is intact before moving on to more complex environments.</p>
<ul>
<li><p>For test environment I have spinned up a compute engine with Ubuntu image and machine type of <code>e2-small</code> and disk size of 10GB.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721414902956/d3b35651-25e0-4516-9a4f-b9a599394728.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>I have leveraged Google Clouds metadata function to update the system, install NodeJS and clone our project.</p>
</li>
<li><p>SSH into server and run following commands to access <code>npm</code>:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">export</span> NVM_DIR=<span class="hljs-string">"/opt/nodejs/.nvm"</span> &amp;&amp; <span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">$NVM_DIR</span>/nvm.sh"</span>
  <span class="hljs-built_in">cd</span> /opt/3-tier-architecture-deployment-GKE
  vi .env
  <span class="hljs-comment">#add API's, Secrets and Keys we copied in previous step</span>
  <span class="hljs-comment"># Example: CLOUDINARY_CLOUD_NAME="fill values here"</span>
  npm start
</code></pre>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721414840435/0dcc0a07-08bb-4ef6-b3a0-e721c40091ad.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Access the application at <a target="_blank" href="http://ExternalIP:3000/"><code>http://ExternalIP:3000/</code></a>, add user, campgrounds and check AtlasDB and cloudinary if everything is working.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721414921784/9feac7cc-f3ea-4dbe-8684-bdd7eb98f004.jpeg" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h3 id="heading-dev-environment">Dev Environment</h3>
<p>The Dev environment is where the CI/CD magic happens. Here’s how the pipeline is configured:</p>
<ol>
<li><p><strong>Code Quality and Security</strong>: Jenkins triggers SonarQube to perform static code analysis, and Trivy scans the file system for vulnerabilities.</p>
</li>
<li><p><strong>Building Docker Images</strong>: Jenkins builds the Docker images and performs an image scan using Trivy.</p>
</li>
<li><p><strong>Pushing to Registry</strong>: The Docker images are pushed to a container registry (Dockerhub).</p>
</li>
</ol>
<h4 id="heading-infrastructure"><strong>Infrastructure</strong></h4>
<ul>
<li><p>I have created 2 VM's, one for Jenkins+Docker+Trivy and other for SonarQube.</p>
</li>
<li><p>SonarQube is running as a Docker container and can be accessed at <code>http://IP:9000</code>.</p>
<ul>
<li>Initial password and user name</li>
</ul>
</li>
<li><p>Jenkins can be accessed at port <code>8080</code>.</p>
<ul>
<li>Copy the initial password and login to server.</li>
</ul>
</li>
<li><p>Again all tools are installed through scripts when VM's are created, we just need to configure the tools.</p>
</li>
</ul>
<h4 id="heading-creating-dockerfile-for-app">Creating Dockerfile for app</h4>
<ul>
<li><p>I have created a simple Dockerfile which will be used to containerize our app:</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Use Node 18 as parent image</span>
  FROM node:18

  <span class="hljs-comment"># Change the working directory on the Docker image to /app</span>
  WORKDIR /app

  <span class="hljs-comment"># Copy package.json and package-lock.json to the /app directory</span>
  COPY package.json package-lock.json ./

  <span class="hljs-comment"># Install dependencies</span>
  RUN npm install

  <span class="hljs-comment"># Copy the rest of project files into this image</span>
  COPY . .

  <span class="hljs-comment"># Expose application port</span>
  EXPOSE 3000

  <span class="hljs-comment"># Start the application</span>
  CMD npm start
</code></pre>
</li>
</ul>
<h4 id="heading-configuring-jenkins-same-config-for-prod-environment"><strong>Configuring Jenkins (same config for Prod environment)</strong></h4>
<ul>
<li><p>Minimum Jenkins version: 2.164.2</p>
</li>
<li><p>Jenkins plugin dependencies:</p>
<ul>
<li><p>google-oauth-plugin: 0.7 (pre-installation required)</p>
</li>
<li><p>workflow-step-api: 2.19</p>
</li>
<li><p>pipeline-model-definition: 1.3.8 (pre-installation required for Pipeline DSL support)</p>
</li>
<li><p>git: 3.9.3</p>
</li>
<li><p>junit: 1.3</p>
</li>
<li><p>structs: 1.17</p>
</li>
<li><p>credentials: 2.1.16</p>
</li>
<li><p>kubernetes : latest</p>
</li>
<li><p>kubernetes cli : latest</p>
</li>
<li><p>nodejs : latest</p>
</li>
<li><p>sonarqube scanner : latest</p>
</li>
<li><p>docker : latest</p>
</li>
<li><p>docker pipeline : latest</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>Plugin for Trivy is not available so directly install it on Jenkins Server.</p>
</blockquote>
<h2 id="heading-setup">Setup</h2>
<h4 id="heading-tools">Tools</h4>
<ol>
<li><p>Go to <code>Manage Jenkins</code> -&gt; <code>Tools</code></p>
</li>
<li><p>Config <code>SonarQube Scanner</code></p>
<p> <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/blob/main/Assets/img/sq_Sc.png?raw=true" alt="sq_Sc.png" /></p>
</li>
<li><p>Config <code>Docker</code></p>
<p> <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/docker.png" alt="Docker" /></p>
</li>
<li><p>Config <code>NodeJS</code></p>
<p> <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/nodejs.png" alt="NodeJs" /></p>
</li>
</ol>
<h4 id="heading-config-credentials-for-pipeline">Config Credentials for Pipeline</h4>
<p><strong>Config SonarQube with Jenkins</strong></p>
<ol>
<li><p>Generate Token</p>
<ul>
<li><p>Login to <code>SonarQube server</code> -&gt; <code>Administration</code> -&gt; <code>Security</code> -&gt; <code>Users</code> -&gt; <code>Tokens</code> -&gt; Give Name and <code>Generate</code></p>
<p>  <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/sq_token.png" alt="SQToken|left" /></p>
</li>
<li><p>Copy Token -&gt; Go to <code>Jenkins</code> -&gt; <code>Manage Jenkins</code> -&gt; <code>Credentials</code> -&gt; <code>Global</code> -&gt; <code>Add Credentials</code> -&gt; <code>Kind</code> -&gt; <code>Secret Text</code></p>
<p>  <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/sq_cred.png" alt="SQToken" /></p>
</li>
</ul>
</li>
<li><p>Connect Sonarqube Server with Jenkins</p>
<ul>
<li><p>Go to <code>Jenkins</code> -&gt; <code>Manage Jenkins</code> -&gt; <code>System</code> -&gt; <code>SonarQube servers</code> -&gt; <code>Add SonarQube</code></p>
</li>
<li><p>Give name to server, add Server IP in <code>Server URL</code> field and select <code>Server Authentication token</code> that we configured in above step.</p>
<p>  <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/sq_server.png" alt="SQServer" /></p>
</li>
</ul>
</li>
</ol>
<p><strong>Config Githup with Jenkins</strong></p>
<ol>
<li><p>Generate <code>Github Token</code> and Copy Token -&gt; Go to <code>Jenkins</code> -&gt; <code>Manage Jenkins</code> -&gt; <code>Credentials</code> -&gt; <code>Global</code> -&gt; <code>Add Credentials</code> -&gt; <code>Kind</code> -&gt; <code>Username and Password</code></p>
</li>
<li><p>Add your github <code>Username</code> and in <code>Password</code> section paste <code>token</code>.</p>
<p> <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/github_cred.png" alt="GithubToken" /></p>
<blockquote>
<p>If you don't know how to generate Github Token follow this documentation <a target="_blank" href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens</a></p>
</blockquote>
</li>
</ol>
<p><strong>Config Docker with Jenkins</strong></p>
<ol>
<li><p>Generate <code>Docker Access Token</code> and Copy Token -&gt; Go to <code>Jenkins</code> -&gt; <code>Manage Jenkins</code> -&gt; <code>Credentials</code> -&gt; <code>Global</code> -&gt; <code>Add Credentials</code> -&gt; <code>Kind</code> -&gt; <code>Username and Password</code></p>
</li>
<li><p>Add your Dockerhub <code>Username</code> and in <code>Password</code> section paste <code>Access token</code>.</p>
<p> <img src="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/raw/main/Assets/img/docker_cred.png" alt="DockerToken" /></p>
<blockquote>
<p>Doker Access Token : <a target="_blank" href="https://docs.docker.com/security/for-developers/access-tokens/">https://docs.docker.com/security/for-developers/access-tokens/</a></p>
</blockquote>
</li>
</ol>
<h3 id="heading-creating-pipeline">Creating Pipeline</h3>
<ul>
<li><p>Now our Infra is build and tools are configured, now we'll build the pipeline. Go to Jenkins Dashboard and Create New Job -&gt; Pipeline (give name to pipeline)</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721453967962/e6c2be0b-08fa-4d08-8c6b-a5939f328f96.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Following best practices, Discard Old builds and keep 2 maximum builds.</p>
</li>
<li><p>Pipeline steps for Dev:</p>
<pre><code class="lang-bash">  pipeline {
      agent any
      tools {
          nodejs <span class="hljs-string">'nodeDev'</span>
      }
      environment {
          SCANNER_HOME= tool <span class="hljs-string">'sonar-dev'</span>
      }

      stages {
          stage(<span class="hljs-string">'Git Checkout'</span>) {
              steps {
                  git branch: <span class="hljs-string">'main'</span>, credentialsId: <span class="hljs-string">'git-cred'</span>, url: <span class="hljs-string">'https://github.com/$GITHUB_USERNAME/YelpCampAPP'</span>
              }
          }

          stage(<span class="hljs-string">'Install Package Dependencies'</span>) {
              steps {
                  sh <span class="hljs-string">"npm install"</span>
              }
          }

          stage(<span class="hljs-string">'Unit Tests'</span>) {
              steps {
                  sh <span class="hljs-string">"npm test"</span>
              }
          }

          stage(<span class="hljs-string">'Trivy FS Scan'</span>) {
              steps {
                  sh <span class="hljs-string">"trivy fs --format table -o fs-report.html ."</span>
              }
          }

          stage(<span class="hljs-string">'Sonarqube'</span>) {
              steps {
                  withSonarQubeEnv(<span class="hljs-string">'sonar'</span>) {
                      sh <span class="hljs-string">"<span class="hljs-variable">$SCANNER_HOME</span>/bin/sonar-scanner -Dsonar.projectKey=Campground -Dsonar.projectName=Campground"</span>
                  }
              }
          }

          stage(<span class="hljs-string">'Build and Tag Docker Image'</span>) {
              steps {
                  script {
                      withDockerRegistry(credentialsId: <span class="hljs-string">'docker-cred'</span>, toolName: <span class="hljs-string">'docker-dev'</span>) {
                          sh <span class="hljs-string">"docker image build -t <span class="hljs-variable">$DOCKER_UNAME</span>/camp:latest ."</span>
                      }
                  }
              }
          }

          stage(<span class="hljs-string">'Docker Image Scan'</span>) {
              steps {
                  sh <span class="hljs-string">"trivy image --format table -o trivy-image-report.html <span class="hljs-variable">$DOCKER_UNAME</span>/camp:latest"</span>
              }
          }

          stage(<span class="hljs-string">'Push Docker Image'</span>) {
              steps {
                  script {
                      withDockerRegistry([credentialsId: <span class="hljs-string">'docker-cred'</span>, toolName: <span class="hljs-string">'docker-dev'</span>]) {
                          sh <span class="hljs-string">"docker push <span class="hljs-variable">$DOCKER_UNAME</span>/camp:latest"</span>
                      }
                  }
              }
          }

          stage(<span class="hljs-string">'Docker Deployment'</span>) {
              steps {
                  script {
                      withDockerRegistry([credentialsId: <span class="hljs-string">'docker-cred'</span>, toolName: <span class="hljs-string">'docker-dev'</span>]) {
                          sh <span class="hljs-string">"docker run -d -p 3000:3000 <span class="hljs-variable">$DOCKER_UNAME</span>/camp:latest"</span>
                      }
                  }
              }
          }

      }
  }
</code></pre>
</li>
</ul>
<p>This pipeline automates the process of building, testing, scanning, and deploying a Yelp Camp application with Docker. Here are the steps:</p>
<ol>
<li><p><strong>Pipeline Setup</strong>:</p>
<ul>
<li><p><strong>Agent</strong>: Specifies that the pipeline can run on any available agent.</p>
</li>
<li><p><strong>Tools</strong>: Specifies the Node.js environment (named 'nodeDev') and SonarQube scanner (named 'sonar-dev') to be used in the pipeline.</p>
</li>
<li><p><strong>Environment</strong>: Sets the <code>SCANNER_HOME</code> environment variable to the path of the SonarQube scanner tool.</p>
</li>
</ul>
</li>
<li><p><strong>Stages</strong>:</p>
<ul>
<li><p><strong>Git Checkout</strong>:</p>
<ul>
<li>Checks out the code from the 'main' branch of the specified GitHub repository using the provided credentials.</li>
</ul>
</li>
<li><p><strong>Install Package Dependencies</strong>:</p>
<ul>
<li>Installs the Yelp Camp project dependencies by running <code>npm install</code>.</li>
</ul>
</li>
<li><p><strong>Unit Tests</strong>:</p>
<ul>
<li>Executes the unit tests using <code>npm test</code> to ensure the application code is functioning as expected.</li>
</ul>
</li>
<li><p><strong>Trivy FS Scan</strong>:</p>
<ul>
<li>Runs a filesystem scan using Trivy to detect vulnerabilities and outputs the results to an HTML report (<code>fs-report.html</code>).</li>
</ul>
</li>
<li><p><strong>SonarQube</strong>:</p>
<ul>
<li>Performs a code quality analysis using SonarQube. It uses the environment variable <code>SCANNER_HOME</code> to locate the SonarQube scanner and specifies the project key and name.</li>
</ul>
</li>
<li><p><strong>Build and Tag Docker Image</strong>:</p>
<ul>
<li>Builds a Docker image for the application and tags it with the name <code>$DOCKER_UNAME/camp:latest</code>. This stage uses Docker registry credentials to access the Docker registry.</li>
</ul>
</li>
<li><p><strong>Docker Image Scan</strong>:</p>
<ul>
<li>Scans the built Docker image using Trivy for vulnerabilities and outputs the results to an HTML report (<code>trivy-image-report.html</code>).</li>
</ul>
</li>
<li><p><strong>Push Docker Image</strong>:</p>
<ul>
<li>Pushes the tagged Docker image to the Docker registry using the provided credentials.</li>
</ul>
</li>
<li><p><strong>Docker Deployment</strong>:</p>
<ul>
<li>Deploys the Docker image by running a container from the image and mapping port 3000 on the container to port 3000 on the host.</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>This pipeline ensures that the application is built, tested, scanned for vulnerabilities, and deployed in a structured manner using Jenkins.</p>
<ul>
<li><p>You can access the application at <code>https://IP:3000</code></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721456431116/aacb8e5a-32ba-4dd4-ab54-c33f4a8a755f.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h2 id="heading-prod-environment">Prod Environment</h2>
<p>The Prod environment leverages the same CI/CD pipeline and Infra but deploys the application on GKE. This ensures consistency and reliability in the deployment process.</p>
<h3 id="heading-gke-and-kubectl-configuration">GKE and kubectl configuration</h3>
<ul>
<li><p>SSH into Jenkins Prod server and setup necessary env variables:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">export</span> PROJECT=$(gcloud info --format=<span class="hljs-string">'value(config.project)'</span>)
  <span class="hljs-built_in">export</span> CLUSTER=&lt;YOUR_CLUSTER_NAME&gt;
  <span class="hljs-built_in">export</span> ZONE=&lt;YOUR_PROJECTS_ZONE&gt;
  <span class="hljs-built_in">export</span> SA=&lt;YOUR_GCP_SA_NAME&gt;
  <span class="hljs-built_in">export</span> SA_EMAIL=<span class="hljs-variable">${SA}</span>@<span class="hljs-variable">${PROJECT}</span>.iam.gserviceaccount.com
</code></pre>
</li>
</ul>
<h4 id="heading-configure-target-gke-cluster">Configure target GKE cluster</h4>
<ol>
<li><p>Retrieve the KubeConfig for your cluster:</p>
<pre><code class="lang-bash"> gcloud container clusters get-credentials <span class="hljs-variable">$CLUSTER</span> --zone <span class="hljs-variable">$ZONE</span>
</code></pre>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721456712553/0ace8504-249c-4a23-97f1-36aa79d95a49.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>If necessary, grant your GCP login account cluster-admin permissions necessary for creating cluster role bindings:</p>
<pre><code class="lang-bash"> kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin \
      --user=$(gcloud config get-value account)
</code></pre>
</li>
</ol>
<h4 id="heading-configure-gcp-service-account">Configure GCP Service Account</h4>
<ul>
<li>We have created Service Account and GKE clusters using Jenkins so we need to just configure it.</li>
</ul>
<ol>
<li><p>Download a JSON Service Account key for your newly created service account. Take note of where the file was created, you will upload it to Jenkins in a subsequent step:</p>
<pre><code class="lang-bash"> gcloud iam service-accounts keys create ~/jenkins-gke-key.json --iam-account <span class="hljs-variable">$SA_EMAIL</span>
</code></pre>
<ul>
<li>If using cloud shell, click the 3 vertical dots and <strong>Download file</strong>, then enter "<code>jenkins-gke-key.json</code>".</li>
</ul>
</li>
<li><p>In Jenkins on the left side of the screen, click on <strong>Credentials</strong>, then <strong>System</strong>.</p>
</li>
<li><p>Click <strong>Global credentials</strong> then <strong>Add credentials</strong> on the left.</p>
</li>
<li><p>In the <strong>Kind</strong> dropdown, select <code>Google Service Account from private key</code>.</p>
</li>
<li><p>Enter your project name, then select your JSON key that was created in the preceding steps.</p>
</li>
<li><p>Click <strong>OK</strong>.</p>
</li>
</ol>
<h4 id="heading-gke-cluster-rbac-permissions">GKE Cluster RBAC Permissions</h4>
<p>Grant your GCP service account a restricted set of RBAC permissions allowing it to deploy to your GKE cluster.</p>
<ol>
<li><p>Create the custom robot-deployer cluster role (A role for granting the permissions deemed necessary for deploying to kubernetes) defined within <a target="_blank" href="rbac/robot-deployer.yaml">robot-deployer.yaml</a>:</p>
<pre><code class="lang-bash"> <span class="hljs-comment">#robot-deployer.yaml</span>
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
  name: robot-deployer
 rules:
 - apiGroups:
   - extensions
   - apps
   - v1
   resources:
   - containers
   - endpoints
   - services
   - pods
   verbs:
   - create
   - get
   - list
   - patch
   - update
   - watch
</code></pre>
<pre><code class="lang-bash"> kubectl create -f rbac/robot-deployer.yaml
</code></pre>
</li>
<li><p>Grant your GCP service account the robot-deployer role binding using <a target="_blank" href="rbac/robot-deployer-bindings.yaml">robot-deployer-bindings.yaml</a>:</p>
<pre><code class="lang-bash"> kind: RoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: restricted-rolebinding
   namespace: default
 subjects:
 - kind: User
   name: <span class="hljs-variable">${SA_EMAIL}</span>
   namespace: default
 roleRef:
   kind: ClusterRole
   name: robot-deployer
   apiGroup: rbac.authorization.k8s.io
</code></pre>
<pre><code class="lang-bash"> envsubst &lt; rbac/robot-deployer-bindings.yaml | kubectl create -f -
</code></pre>
</li>
</ol>
<h5 id="heading-references">References:</h5>
<ul>
<li><p><a target="_blank" href="https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control">Google Container Engine RBAC docs</a></p>
</li>
<li><p><a target="_blank" href="https://codeascraft.com/2018/06/05/deploying-to-google-kubernetes-engine/">Configuring RBAC for GKE deployment</a></p>
</li>
</ul>
<h4 id="heading-usage">Usage</h4>
<h4 id="heading-google-kubernetes-engine-build-step-configuration">Google Kubernetes Engine Build Step Configuration</h4>
<p>Each GKE Build Step configuration can point to a different GKE cluster. Follow the steps below to create one.</p>
<h5 id="heading-gke-build-step-parameters">GKE Build Step Parameters</h5>
<p>The GKE Build Step has the following parameters:</p>
<ol>
<li><p><code>credentialsId(string)</code>: The ID of the credentials that you uploaded earlier.</p>
</li>
<li><p><code>projectId(string)</code>: The Project ID housing the GKE cluster to be published to.</p>
</li>
<li><p><code>location(string)</code>: The Zone or Region housing the GKE cluster to be published to.</p>
</li>
<li><p><code>clusterName(string)</code>: The name of the Cluster to be published to.</p>
</li>
<li><p><code>manifestPattern(string)</code>: The file pattern of the Kubernetes manifest to be deployed.</p>
</li>
<li><p><code>verifyDeployments(boolean)</code>: [Optional] Whether the plugin will verify deployments.</p>
</li>
</ol>
<h4 id="heading-jenkins-web-ui">Jenkins Web UI</h4>
<ol>
<li><p>On the Jenkins home page, select the project to be published to GKE.</p>
</li>
<li><p>Click <strong>Configure</strong> from the left nav-bar.</p>
</li>
<li><p>At the bottom of the page there will be a button labeled <strong>Add build step</strong>, click the button then select <code>Deploy to Google Kubernetes Engine</code>.</p>
</li>
<li><p>In the <strong>Service Account Credentials</strong> dropdown, select the credentials that you uploaded earlier. This should autopopulate <strong>Project ID</strong> and <strong>Cluster</strong>, if not:</p>
</li>
</ol>
<ul>
<li><p>Select the Project ID housing the GKE cluster to be published to.</p>
</li>
<li><p>Select the Cluster to be published to.</p>
</li>
</ul>
<ol start="5">
<li>Enter the file path of the Kubernetes <a target="_blank" href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">manifest</a> within your project to be used for deployment.</li>
</ol>
<h3 id="heading-jenkins-global-environment-variables">Jenkins Global Environment Variables</h3>
<ul>
<li><p>Save following variables in Jenins Global variables:</p>
<ul>
<li><p>PROJECT_ID</p>
</li>
<li><p>CLUSTER_NAME</p>
</li>
<li><p>LOCATION</p>
</li>
<li><p>CREDENTIALS_ID</p>
</li>
</ul>
</li>
<li><p><code>Manage Jenkins</code> -&gt; <code>Configure System</code> -&gt; <code>Global properties</code> -&gt; <code>Environment Variables</code> -&gt; <code>Add</code></p>
</li>
</ul>
<h4 id="heading-yelp-camp-secrets">Yelp Camp Secrets</h4>
<ul>
<li><p>Save Yelp Camp secrets in Kubernets:</p>
<pre><code class="lang-bash">  kubectl create secret generic yelp-camp-secrets \
      --from-literal=CLOUDINARY_CLOUD_NAME=my-cloud-name \
      --from-literal=CLOUDINARY_KEY=my-cloud-key \
      --from-literal=CLOUDINARY_SECRET=my-cloud-secret \
      --from-literal=MAPBOX_TOKEN=my-mapbox-token \
      --from-literal=DB_URL=my-db-url \
      --from-literal=SECRET=my-secret <span class="hljs-comment">#write any string for it</span>
</code></pre>
</li>
</ul>
<h4 id="heading-jenkins-declarative-pipeline">Jenkins Declarative Pipeline</h4>
<ol>
<li><p>Create a file named "Jenkinsfile" in the root of your project.</p>
</li>
<li><p>Within your Jenkinsfile add a step which invokes the GKE plugin's build step class: "KubernetesEngineBuilder". See the example code below:</p>
<pre><code class="lang-bash"> pipeline {
     agent any
     tools {
         nodejs <span class="hljs-string">'nodeProd'</span>
     }
     environment {
         SCANNER_HOME = tool <span class="hljs-string">'sonar-prod'</span>
         PROJECT_ID = <span class="hljs-string">"<span class="hljs-variable">${PROJECT_ID}</span>"</span>
         CLUSTER_NAME = <span class="hljs-string">"<span class="hljs-variable">${CLUSTER_NAME}</span>"</span>
         LOCATION = <span class="hljs-string">"<span class="hljs-variable">${LOCATION}</span>"</span>
         CREDENTIALS_ID = <span class="hljs-string">'jenkins-gke-key'</span>
     }

     stages {
         stage(<span class="hljs-string">'Git Checkout'</span>) {
             steps {
                 git branch: <span class="hljs-string">'main'</span>, credentialsId: <span class="hljs-string">'git-cred'</span>, url: <span class="hljs-string">'https://github.com/$GH_USUSERNAME/YelpCampAPP'</span>
             }
         }

         stage(<span class="hljs-string">'Install Package Dependencies'</span>) {
             steps {
                 sh <span class="hljs-string">"npm install"</span>
             }
         }

         stage(<span class="hljs-string">'Unit Tests'</span>) {
             steps {
                 sh <span class="hljs-string">"npm test"</span>
             }
         }

         stage(<span class="hljs-string">'Trivy FS Scan'</span>) {
             steps {
                 sh <span class="hljs-string">"trivy fs --format table -o fs-report.html ."</span>
             }
         }

         stage(<span class="hljs-string">'Sonarqube'</span>) {
             steps {
                 withSonarQubeEnv(<span class="hljs-string">'sonar'</span>) {
                     sh <span class="hljs-string">"<span class="hljs-variable">$SCANNER_HOME</span>/bin/sonar-scanner -Dsonar.projectKey=Campground -Dsonar.projectName=Campground"</span>
                 }
             }
         }

         stage(<span class="hljs-string">'Build and Tag Docker Image'</span>) {
             steps {
                 script {
                     withDockerRegistry(credentialsId: <span class="hljs-string">'docker-cred'</span>, toolName: <span class="hljs-string">'docker-prod'</span>) {
                         sh <span class="hljs-string">"docker image build -t <span class="hljs-variable">$DOCKER_USUSERNAME</span>/camp:latest ."</span>
                     }
                 }
             }
         }

         stage(<span class="hljs-string">'Docker Image Scan'</span>) {
             steps {
                 sh <span class="hljs-string">"trivy image --format table -o trivy-image-report.html <span class="hljs-variable">$DOCKER_USUSERNAME</span>/camp:latest"</span>
             }
         }

         stage(<span class="hljs-string">'Push Docker Image'</span>) {
             steps {
                 script {
                     withDockerRegistry([credentialsId: <span class="hljs-string">'docker-cred'</span>, toolName: <span class="hljs-string">'docker-prod'</span>]) {
                         sh <span class="hljs-string">"docker push <span class="hljs-variable">$DOCKER_USUSERNAME</span>/camp:latest"</span>
                     }
                 }
             }
         }

         stage(<span class="hljs-string">'Deploy to GKE'</span>) {
             steps {
                 step([
                     <span class="hljs-variable">$class</span>: <span class="hljs-string">'KubernetesEngineBuilder'</span>, 
                     projectId: env.PROJECT_ID, 
                     clusterName: env.CLUSTER_NAME, 
                     location: env.LOCATION, 
                     manifestPattern: <span class="hljs-string">'k8/deployment.yaml'</span>, 
                     credentialsId: env.CREDENTIALS_ID, 
                     verifyDeployments: <span class="hljs-literal">true</span>])
                 <span class="hljs-built_in">echo</span> <span class="hljs-string">"Deployment Finished"</span>
             }
         }
     }
 }
</code></pre>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721460624065/6e4cd583-1512-4c74-b381-d68285ed4e00.png" alt class="image--center mx-auto" /></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721460638320/539b7ed7-5ff7-4f57-a92b-ff0ec86de2da.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Now our app is deployed to GKE, let's check if backend is connected to DB or not:</p>
<pre><code class="lang-bash">  <span class="hljs-comment">#To check all resources created</span>
  kubectl get pods

  <span class="hljs-comment">#To check if backend is connected to DB</span>
  kubectl logs POD_NAME

  <span class="hljs-comment">#Check if there is any problem with depoyment</span>
  kubectl describe pod POD_NAME
</code></pre>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721461281703/b313f350-023f-43b5-b05a-b3694fd75f12.png" alt class="image--center mx-auto" /></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721461293723/722e94b0-7fbc-4ece-9619-cf79b5431176.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
</ol>
<ul>
<li>Congratulations our app is deployed on GKE cluster and is running perfectly.</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this blog, we explored the intricacies of deploying a comprehensive DevOps project across multiple environments, from test and development to production. Through this journey, we've delved into the essential components and tools such as Docker, Kubernetes, GKE, and Terraform, highlighting their pivotal roles in modern application deployment and infrastructure management.</p>
<p>By leveraging a robust CI/CD pipeline, we ensured seamless integration and continuous delivery, streamlining the deployment process across environments. This project not only underscores the importance of automation and infrastructure as code but also demonstrates how these practices can lead to more efficient, reliable, and scalable deployments.</p>
<p>Throughout this endeavor, I encountered and overcame several challenges, each of which provided valuable insights and reinforced best practices in DevOps. The experience has been immensely rewarding, enhancing my skills and deepening my understanding of end-to-end deployment processes.</p>
<p>This project represents a significant milestone in my professional journey, showcasing my ability to design, implement, and manage complex deployment pipelines and infrastructure. As I look to the future, I am excited about the potential for further improvements and the opportunity to apply these learnings in new and innovative ways.</p>
<p>Thank you for taking the time to read about my DevOps project. I hope you found this exploration insightful and valuable. I am always eager to connect with fellow enthusiasts and professionals, so please feel free to reach out to me for further discussions or collaborations. Your feedback and suggestions are highly appreciated as they help me grow and refine my skills.</p>
<p>Let's continue to build, deploy, and innovate together!</p>
<hr />
<p><em>Connect with me on</em><a target="_blank" href="https://www.linkedin.com/in/chetanthapliyal/"><em>LinkedIn</em></a><em>or check out the project's</em><a target="_blank" href="https://github.com/ChetanThapliyal/3-tier-architecture-deployment-GKE/"><em>GitHub repository</em></a><em>. Feel free to leave your comments, questions, or suggestions below.</em></p>
]]></content:encoded></item><item><title><![CDATA[Micro-service Deployment using AKS and ArgoCD]]></title><description><![CDATA[In this project, we will implement Continuous Integration (CI) and Continuous Deployment (CD) for a multi-microservice application developed by docker team. This application, comprising several interconnected microservices, requires a robust and auto...]]></description><link>https://blog.chetan-thapliyal.cloud/micro-service-deployment-using-aks-and-argocd</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/micro-service-deployment-using-aks-and-argocd</guid><category><![CDATA[cicd]]></category><category><![CDATA[Devops]]></category><category><![CDATA[aks]]></category><category><![CDATA[ArgoCD]]></category><category><![CDATA[projects]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[deployment]]></category><category><![CDATA[Azure]]></category><category><![CDATA[azure-devops]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Fri, 28 Jun 2024 13:25:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719491324909/dbb549c6-97f2-4f0a-b081-88028adf5a17.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this project, we will implement Continuous Integration (CI) and Continuous Deployment (CD) for a multi-microservice application developed by docker team. This application, comprising several interconnected microservices, requires a robust and automated pipeline to ensure seamless integration, testing, and deployment of code changes. By establishing an efficient CI/CD pipeline, we aim to enhance the development workflow, reduce manual intervention, and ensure that our application is always in a production-ready state. The application consists of:</p>
<h4 id="heading-microservices"><strong>Microservices</strong>:</h4>
<ul>
<li><p>One written in Python (Voting Microservice)</p>
</li>
<li><p>One written in Node.js (Results Microservice)</p>
</li>
<li><p>One written in .NET (Worker Microservice)</p>
</li>
</ul>
<h4 id="heading-databases"><strong>Databases</strong>:</h4>
<ul>
<li><p>An in-memory data store (Redis)</p>
</li>
<li><p>A PostgreSQL database</p>
</li>
</ul>
<p>The source code is available in a <a target="_blank" href="https://github.com/dockersamples/example-voting-app.git">GitHub repository</a> from Docker samples. Our task as the DevOps engineer is to set up the CI/CD using Azure DevOps, Azure Pipelines and ArgoCD.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719495958285/910de73f-4880-4e22-a8fb-4a83c9e6d03d.png" alt class="image--center mx-auto" /></p>
<p>To accomplish this, we will:</p>
<ol>
<li><p>Clone the GitHub repository to run the application locally and understand its architecture.</p>
</li>
<li><p>Write Docker files and configure the pipeline for the different micro services, which use various programming languages.</p>
</li>
</ol>
<h4 id="heading-application-overview"><strong>Application Overview</strong>:</h4>
<ul>
<li><p><strong>Voting Microservice</strong>: Allows users to vote between two options (e.g., cats vs. dogs).</p>
</li>
<li><p><strong>Results Microservice</strong>: Displays the voting results.</p>
</li>
<li><p><strong>Worker Microservice</strong>: Manages data transfer between the in-memory data store (Redis) and the PostgreSQL database.</p>
</li>
</ul>
<p>Each microservice can be independently deployed. We will create separate pipelines for each:</p>
<ul>
<li><p>Voting Microservice (Python)</p>
</li>
<li><p>Worker Microservice (.NET)</p>
</li>
<li><p>Results Microservice (Node.js)</p>
</li>
</ul>
<p>This approach allows independent updates and deployments without affecting other services.</p>
<p>We will begin by running the application locally using <code>docker compose</code> to understand its functionality and then proceed to implement CI for each microservice. This practical exercise will enhance our understanding of continuous integration and deployment.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/ChetanThapliyal/Argocd-AKS-microservices-deployment">https://github.com/ChetanThapliyal/Argocd-AKS-microservices-deployment</a></div>
<p> </p>
<h3 id="heading-cicd-overview"><strong>CI/CD Overview</strong>:</h3>
<ul>
<li><p><strong>CI/CD</strong> stands for Continuous Integration and Continuous Deployment is a set of practices and tools that automate the processes of integrating code changes, building, testing, and deploying applications.</p>
</li>
<li><p><strong>CI (Continous Integration)</strong> : Automates the integration of code changes from multiple developers into a shared repository.</p>
</li>
<li><p><strong>CD (Continuous Deployment)</strong> : Automatically deploy every change that passes the automated tests to production. There is no manual approval process for deployment; the system ensures that every change that passes the tests is immediately deployed to users.</p>
</li>
<li><p>DevOps engineers set up CI to automatically:</p>
<ul>
<li><p>Run unit tests and static code analysis on changes.</p>
</li>
<li><p>Build the application and run end-to-end tests.</p>
</li>
<li><p>Create a Docker image of the application.</p>
</li>
<li><p>Push the Docker image to a registry like Docker Hub or Azure Container Registry.</p>
</li>
</ul>
</li>
</ul>
<p>This automation saves time and provides confidence that changes won’t break the application. Manual testing would be time-consuming and prone to errors.</p>
<h1 id="heading-continuous-integration">Continuous Integration</h1>
<ul>
<li><p>We will create CI pipelines using Azure Pipelines.</p>
</li>
<li><p>CI can be triggered by pull requests or commits.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719568893605/4057de0a-e30d-4960-aa56-27ac7e8ff872.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-azure-devops">Azure DevOps</h3>
<ul>
<li><p>We will use Azure DevOps to build CI pipelines for Dockerfiles (we'll create them next).</p>
</li>
<li><p>Make sure your Azure DevOps and Microsoft Azure subscriptions are set up, as we’ll use Azure Container Registry (ACR) and Azure Pipelines.</p>
</li>
<li><p>The Docker images will be pushed to ACR, but Docker Hub can be used as well if preferred.</p>
</li>
</ul>
<ol>
<li><p><strong>Access</strong><a target="_blank" href="http://dev.azure.com"><strong>Azure DevOps</strong></a>:</p>
<ul>
<li>Log in and create an account if you haven’t already.</li>
</ul>
</li>
<li><p><strong>Project Setup</strong>:</p>
<ul>
<li><p>Create a new project for your CI pipelines.</p>
</li>
<li><p>We will configure Azure Pipelines to build, test, and push Docker images for each microservice to ACR.</p>
</li>
</ul>
</li>
</ol>
<p>This approach provides a seamless integration and deployment process, ensuring each microservice is properly containerized and managed through Azure DevOps.</p>
<p>Let's start from scratch to create and set up our voting application in Azure DevOps. I will guide you through setting up a project, importing a repository, and creating CI pipelines to build Docker images for our microservices.</p>
<h3 id="heading-setting-up-your-azure-devops-project">Setting Up Your Azure DevOps Project</h3>
<ol>
<li><p><strong>Create a New Project</strong>:</p>
<ul>
<li><p>Navigate to Azure DevOps and click on "New Project."</p>
</li>
<li><p>Name your project "Voting Application" or something relevant.</p>
</li>
<li><p>Choose to keep it private if you’re working in an organizational setting.</p>
</li>
<li><p>Click "Create Project."</p>
</li>
</ul>
</li>
<li><p><strong>Use Azure Repos</strong>:</p>
<ul>
<li><p>You can use Azure Repos instead of GitHub to keep everything within Azure DevOps.</p>
</li>
<li><p>Go to the <strong>Repos</strong> section and select "Import a Repository."</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719569516139/9a2279c1-c783-413d-9ccc-91aa0cc8cc59.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Choose "Git" for the import type.</p>
</li>
<li><p>Enter the URL of your <a target="_blank" href="https://github.com/dockersamples/example-voting-app.git">GitHub repository</a> and click "Import."</p>
</li>
<li><p>Ensure that no authentication is required if the repository is public.</p>
</li>
</ul>
</li>
<li><p><strong>Set the Default Branch</strong>:</p>
<ul>
<li><p>By default, Azure DevOps might set a branch alphabetically. Make sure the default branch is <code>main</code>.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719569615206/b206f740-a57a-4fb7-bd84-df41095cd294.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Go to the <strong>Branches</strong> section, find the <code>main</code> branch, and set it as the default by clicking the three dots next to the branch name and selecting "Set as default branch."</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-setting-up-azure-container-registry-acr">Setting Up Azure Container Registry (ACR)</h3>
<ol>
<li><p><strong>Create a Resource Group</strong>:</p>
<ul>
<li><p>Go to the Azure portal and search for "Resource Groups."</p>
</li>
<li><p>Click "Create" and name it something like "AzureCICD."</p>
</li>
<li><p>Select a region (e.g., East US) and click "Review + Create."</p>
</li>
</ul>
</li>
<li><p><strong>Create a Container Registry</strong>:</p>
<ul>
<li><p>In the Azure portal, search for "Container Registry" and click "Create."</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719575083979/0d449204-45ee-4094-a50f-460dd30084bf.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select the resource group you just created.</p>
</li>
<li><p>Name the container registry something like "AzureCICD."</p>
</li>
<li><p>Choose the "Standard" plan (or "Basic" if you prefer).</p>
</li>
<li><p>Click "Review + Create."</p>
</li>
</ul>
</li>
</ol>
<blockquote>
<p><strong>Note</strong>:If you are using Azure free trial, you'll need to create a VM (as an Agent) in azure portal to run the pipelines. This VM will act as the pool (agent) for the pipeline.</p>
</blockquote>
<ol start="3">
<li><p><strong>Setting Up the Agent (Create a Virtual Machine (VM) for Azure Pipelines)</strong>:</p>
<ul>
<li><p>In Azure portal, search for "Virtual Machine" and click "Create"</p>
</li>
<li><p>Select the resource group you just created.</p>
</li>
<li><p>Name the VM <code>azureagent</code></p>
</li>
<li><p>Make sure to select SSH as authenticaation and Allow SSH access.</p>
</li>
<li><p>Click "Review + Create."</p>
<blockquote>
<p>SSH to VM, Config and Install following: Docker</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719575287086/dd3580af-d3b4-4119-9632-a377b36f3f6f.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-bash">sudo apt install docker.io
sudo usermod -aG docker <span class="hljs-variable">$USER</span>
sudo systemctl start docker
sudo systemctl <span class="hljs-built_in">enable</span> docker
</code></pre>
<p>Configure to connect VM to Azure DevOps<br />a. Go to Azure Devops Project Settings<br />b. Click Agent Pools and Select 'azureagent'<br />c. Select 'Agents' and click 'New Agent'<br />d. Follow the Azure DevOps documentation to configure the agent and link it to your Azure DevOps project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719575893748/595fe22c-1704-4f26-844f-738ef3adbf80.png" alt class="image--center mx-auto" /></p>
</blockquote>
</li>
</ul>
</li>
</ol>
<h3 id="heading-creating-dockerfiles-for-microservices">Creating Dockerfiles for Microservices</h3>
<p>Let's start by understanding how to create Dockerfiles for our three microservices. This is crucial since each stage—build, test, and image creation—depends on it. In modern containerized applications, the build is part of the Docker image creation. We’ll explore how to write Dockerfiles for each microservice by examining the repository structure and the dependencies.</p>
<h4 id="heading-writing-dockerfiles-for-microservices">Writing Dockerfiles for Microservices</h4>
<ol>
<li><p><strong>Results Microservice</strong>:</p>
<ul>
<li><p>Navigate to the repository and observe the presence of <code>server.js</code> and <code>package.json</code>, indicating it's a Node.js application.</p>
</li>
<li><p>To containerize this application:</p>
<ol>
<li><p><strong>Base Image</strong>: Use a Node.js base image (<code>node</code>) because the application is written in Node.js. This eliminates the need to install Node.js manually.</p>
</li>
<li><p><strong>Working Directory</strong>: Set up a working directory in the Dockerfile.</p>
</li>
<li><p><strong>Copy Dependencies</strong>: Copy <code>package.json</code> and run <code>npm install</code> to install dependencies.</p>
</li>
<li><p><strong>Build and Run</strong>: Copy the application code, set up the entry point using <code>CMD</code> or <code>ENTRYPOINT</code>, and expose necessary ports.</p>
<p> Here’s a simplified Dockerfile for the results microservice:</p>
<pre><code class="lang-dockerfile"> <span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>-slim

 <span class="hljs-comment"># add curl for healthcheck</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; \
     apt-get install -y --no-install-recommends curl tini &amp;&amp; \
     rm -rf /var/lib/apt/lists/*</span>

 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/<span class="hljs-built_in">local</span>/app</span>

 <span class="hljs-comment"># have nodemon available for local dev use (file watching)</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> npm install -g nodemon</span>

 <span class="hljs-keyword">COPY</span><span class="bash"> package*.json ./</span>

 <span class="hljs-keyword">RUN</span><span class="bash"> npm ci &amp;&amp; \
 npm cache clean --force &amp;&amp; \
 mv /usr/<span class="hljs-built_in">local</span>/app/node_modules /node_modules</span>

 <span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

 <span class="hljs-keyword">ENV</span> PORT <span class="hljs-number">80</span>
 <span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>

 <span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"/usr/bin/tini"</span>, <span class="hljs-string">"--"</span>]</span>
 <span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"node"</span>, <span class="hljs-string">"server.js"</span>]</span>
</code></pre>
</li>
</ol>
</li>
</ul>
</li>
<li><p><strong>Voting Microservice</strong>:</p>
<ul>
<li><p>Identify it as a Python application by files like <a target="_blank" href="http://app.py"><code>app.py</code></a> and <code>requirements.txt</code>.</p>
</li>
<li><p>Dockerfile steps will be similar to Node.js, with adaptations for Python:</p>
<ol>
<li><p><strong>Base Image</strong>: Use a Python base image (<code>python</code>).</p>
</li>
<li><p><strong>Working Directory</strong>: Define a working directory.</p>
</li>
<li><p><strong>Copy Dependencies</strong>: Copy <code>requirements.txt</code> and run <code>pip install</code>.</p>
</li>
<li><p><strong>Build and Run</strong>: Copy the application code, set up the entry point using <code>CMD</code> or <code>ENTRYPOINT</code>, and expose necessary ports.</p>
<p> Example Dockerfile for the voting microservice:</p>
<pre><code class="lang-Dockerfile"> <span class="hljs-comment"># Define a base stage that uses the official python runtime base image</span>
 <span class="hljs-keyword">FROM</span> python:<span class="hljs-number">3.11</span>-slim AS base

 <span class="hljs-comment"># Add curl for healthcheck</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; \
     apt-get install -y --no-install-recommends curl &amp;&amp; \
     rm -rf /var/lib/apt/lists/*</span>

 <span class="hljs-comment"># Set the application directory</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/<span class="hljs-built_in">local</span>/app</span>

 <span class="hljs-comment"># Install our requirements.txt</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> requirements.txt ./requirements.txt</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> pip install --no-cache-dir -r requirements.txt</span>

 <span class="hljs-comment"># Define a stage specifically for development, where it'll watch for</span>
 <span class="hljs-comment"># filesystem changes</span>
 <span class="hljs-keyword">FROM</span> base AS dev
 <span class="hljs-keyword">RUN</span><span class="bash"> pip install watchdog</span>
 <span class="hljs-keyword">ENV</span> FLASK_ENV=development
 <span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"python"</span>, <span class="hljs-string">"app.py"</span>]</span>

 <span class="hljs-comment"># Define the final stage that will bundle the application for production</span>
 <span class="hljs-keyword">FROM</span> base AS final

 <span class="hljs-comment"># Copy our code from the current folder to the working directory inside the container</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

 <span class="hljs-comment"># Make port 80 available for links and/or publish</span>
 <span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>

 <span class="hljs-comment"># Define our command to be run when launching the container</span>
 <span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"gunicorn"</span>, <span class="hljs-string">"app:app"</span>, <span class="hljs-string">"-b"</span>, <span class="hljs-string">"0.0.0.0:80"</span>, <span class="hljs-string">"--log-file"</span>, <span class="hljs-string">"-"</span>, <span class="hljs-string">"--access-logfile"</span>, <span class="hljs-string">"-"</span>, <span class="hljs-string">"--workers"</span>, <span class="hljs-string">"4"</span>, <span class="hljs-string">"--keep-alive"</span>, <span class="hljs-string">"0"</span>]</span>
</code></pre>
</li>
</ol>
</li>
</ul>
</li>
<li><p><strong>Worker Microservice</strong>:</p>
<ul>
<li><p>Recognize it as a .NET application.</p>
</li>
<li><p>Use a .NET base image and follow a similar process:</p>
<ol>
<li><p><strong>Base Image</strong>: Use a .NET SDK image.</p>
</li>
<li><p><strong>Working Directory</strong>: Set up a working directory.</p>
</li>
<li><p><strong>Copy Dependencies</strong>: Copy project files and restore dependencies.</p>
</li>
<li><p><strong>Build and Run</strong>: Build the application, set the entry point, and expose necessary ports.</p>
<p> Simplified Dockerfile for the worker microservice:</p>
<pre><code class="lang-dockerfile">   <span class="hljs-keyword">FROM</span> --platform=linux mcr.microsoft.com/dotnet/sdk:<span class="hljs-number">7.0</span> as build
   <span class="hljs-keyword">ARG</span> TARGETPLATFORM
   <span class="hljs-keyword">ARG</span> TARGETARCH
   <span class="hljs-keyword">ARG</span> BUILDPLATFORM
   <span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">"I am running on <span class="hljs-variable">$BUILDPLATFORM</span>, building for <span class="hljs-variable">$TARGETPLATFORM</span>"</span></span>

   <span class="hljs-keyword">WORKDIR</span><span class="bash"> /<span class="hljs-built_in">source</span></span>
   <span class="hljs-keyword">COPY</span><span class="bash"> *.csproj .</span>
   <span class="hljs-keyword">RUN</span><span class="bash"> dotnet restore</span>

   <span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
   <span class="hljs-keyword">RUN</span><span class="bash"> dotnet publish -c release -o /app --self-contained <span class="hljs-literal">false</span> --no-restore</span>

   <span class="hljs-comment"># app image</span>
   <span class="hljs-keyword">FROM</span> mcr.microsoft.com/dotnet/runtime:<span class="hljs-number">7.0</span>
   <span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
   <span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app .</span>
   <span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"dotnet"</span>, <span class="hljs-string">"Worker.dll"</span>]</span>
</code></pre>
</li>
</ol>
</li>
</ul>
</li>
</ol>
<h3 id="heading-creating-ci-pipelines">Creating CI Pipelines</h3>
<ol>
<li><p><strong>Create a Pipeline</strong>:</p>
<ul>
<li><p>Go back to Azure DevOps and click on the <strong>Pipelines</strong> section.</p>
</li>
<li><p>Click "New Pipeline" and select "Azure Repos Git" since we’re using Azure Repos.</p>
</li>
<li><p>Select your repository (e.g., "Voting Application").</p>
</li>
<li><p>Choose "Docker" as the template.</p>
</li>
</ul>
</li>
<li><p><strong>Configure the Pipeline</strong>:</p>
<ul>
<li><p>Select the template "Build and Push Docker Image to Azure Container Registry."</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719575756820/c21eead0-c1e8-453f-af47-f2e9f7d17f2f.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Choose the Azure Container Registry you set up earlier.</p>
</li>
<li><p>Click "Validate and configure."</p>
</li>
</ul>
</li>
<li><p><strong>Pipeline YAML Configuration</strong>:</p>
<ul>
<li><p>The template will generate a basic <code>azure-pipelines.yml</code> file for building and pushing Docker images.</p>
</li>
<li><p>Understand the main components of the pipeline:</p>
<ul>
<li><p><strong>Trigger</strong>: Specifies which branches trigger the pipeline.</p>
</li>
<li><p><strong>Resources</strong>: Defines external resources (like repositories).</p>
</li>
<li><p><strong>Variables</strong>: Defines variables used in the pipeline.</p>
</li>
<li><p><strong>Stages</strong>: Contains jobs and steps to execute.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>        Here’s a simple <code>azure-pipelines.yml</code> example for building and pushing a Docker image:</p>
<pre><code class="lang-yaml">          <span class="hljs-comment"># Docker</span>
          <span class="hljs-comment"># Build and push an image to Azure Container Registry</span>
          <span class="hljs-comment"># https://docs.microsoft.com/azure/devops/pipelines/languages/docker</span>

          <span class="hljs-attr">trigger:</span>
            <span class="hljs-attr">paths:</span>
              <span class="hljs-attr">include:</span>
                <span class="hljs-bullet">-</span> <span class="hljs-string">result/*</span>

          <span class="hljs-attr">resources:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">repo:</span> <span class="hljs-string">self</span>

          <span class="hljs-attr">variables:</span>
            <span class="hljs-comment"># Container registry service connection established during pipeline creation</span>
            <span class="hljs-attr">dockerRegistryServiceConnection:</span> <span class="hljs-string">'xyz-xyz-xyz'</span>
            <span class="hljs-attr">imageRepository:</span> <span class="hljs-string">'resultapp'</span>
            <span class="hljs-attr">containerRegistry:</span> <span class="hljs-string">'chetanazurecicd.azurecr.io'</span>
            <span class="hljs-attr">dockerfilePath:</span> <span class="hljs-string">'$(Build.SourcesDirectory)/result/Dockerfile'</span>
            <span class="hljs-attr">tag:</span> <span class="hljs-string">'$(Build.BuildId)'</span>

          <span class="hljs-comment"># Agent VM image name</span>
          <span class="hljs-attr">pool:</span>
            <span class="hljs-attr">name:</span> <span class="hljs-string">'azureagent'</span> 

          <span class="hljs-attr">stages:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">Build</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span>
            <span class="hljs-attr">jobs:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Build</span>
              <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span>
              <span class="hljs-attr">steps:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">Docker@2</span>
                <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Image</span>
                <span class="hljs-attr">inputs:</span>
                  <span class="hljs-attr">containerRegistry:</span> <span class="hljs-string">'$(dockerRegistryServiceConnection)'</span>
                  <span class="hljs-attr">repository:</span> <span class="hljs-string">'$(imageRepository)'</span>
                  <span class="hljs-attr">command:</span> <span class="hljs-string">'build'</span>
                  <span class="hljs-attr">Dockerfile:</span> <span class="hljs-string">'result/Dockerfile'</span>
                  <span class="hljs-attr">tags:</span> <span class="hljs-string">'$(tag)'</span>
          <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">Push</span>
            <span class="hljs-attr">displayName:</span> <span class="hljs-string">Push</span>
            <span class="hljs-attr">jobs:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Push</span>
              <span class="hljs-attr">displayName:</span> <span class="hljs-string">Push</span>
              <span class="hljs-attr">steps:</span>
              <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">Docker@2</span>
                <span class="hljs-attr">displayName:</span> <span class="hljs-string">Push</span> <span class="hljs-string">an</span> <span class="hljs-string">image</span> <span class="hljs-string">to</span> <span class="hljs-string">container</span> <span class="hljs-string">registry</span>
                <span class="hljs-attr">inputs:</span>
                  <span class="hljs-attr">containerRegistry:</span> <span class="hljs-string">'$(dockerRegistryServiceConnection)'</span>
                  <span class="hljs-attr">repository:</span> <span class="hljs-string">'$(imageRepository)'</span>
                  <span class="hljs-attr">command:</span> <span class="hljs-string">'push'</span>
                  <span class="hljs-attr">tags:</span> <span class="hljs-string">'$(tag)'</span>
</code></pre>
<ul>
<li><p>Replace <code>'&lt;service-connection-id&gt;'</code> with your actual service connection ID.</p>
</li>
<li><p>Since free trial doesn't support agent so we are using VM.</p>
</li>
<li><p>Replace trigger with following:</p>
<pre><code class="lang-bash">   - paths:
       include:
         - result/*
</code></pre>
</li>
<li><p>Replace Agent with Pool: VM name with:</p>
<pre><code class="lang-bash">   pool:
   name: <span class="hljs-string">'azureagent'</span>
</code></pre>
</li>
</ul>
<ol start="4">
<li><p><strong>Save and Run</strong>:</p>
<ul>
<li><p>Save the pipeline configuration and run it.</p>
</li>
<li><p>Monitor the pipeline to ensure it builds the Docker image and pushes it to the Azure Container Registry.</p>
</li>
</ul>
</li>
<li><p><strong>Create Pipelines for Other Microservices</strong>:</p>
<ul>
<li><p>Repeat the pipeline creation process for each microservice (e.g., <code>voting</code>, <code>results</code>, <code>worker</code>).</p>
</li>
<li><p>Ensure each pipeline is configured to build and push Docker images for the respective microservice.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-notes">Notes</h2>
<ul>
<li><p>The CI pipeline setup will automate building Docker images and pushing them to ACR whenever changes are made.</p>
</li>
<li><p>You can view pipeline runs in the Azure DevOps portal to monitor progress and diagnose issues.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719580626742/b6db80a5-e997-404b-a34f-5dac32a01b7c.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p>This setup will streamline your CI process, making it easier to manage and deploy your microservices using Azure DevOps and Azure Container Registry.</p>
<p>To set up an Azure CI pipeline, follow these four key components: triggers, stages, jobs, and steps. Here’s a breakdown of each component and how to configure them.</p>
<h4 id="heading-triggers">Triggers</h4>
<p>Triggers determine when a pipeline should be automatically triggered. For instance, you can set triggers based on changes to specific paths in a repository. This eliminates the need for manual triggering. An advanced example involves using path-based triggers to initiate pipelines for specific microservices within a project.</p>
<h4 id="heading-stages">Stages</h4>
<p>Stages represent different phases in the CI/CD pipeline, such as build, test, and deployment. Each stage can contain multiple jobs, allowing for parallel execution and efficient resource utilization.</p>
<h4 id="heading-jobs">Jobs</h4>
<p>Jobs are smaller units of work within a stage. They can be assigned to different agents or runners to distribute the load. This is useful for complex builds that can be split into independent tasks.</p>
<h4 id="heading-steps">Steps</h4>
<p>Steps are individual tasks within a job, such as running a script or building a Docker image. Variables can be used to pass configuration details, credentials, or other necessary data between steps.</p>
<h3 id="heading-example-ci-pipeline-configuration">Example CI Pipeline Configuration</h3>
<ol>
<li><p><strong>Triggers:</strong> Use path-based triggers to ensure that only relevant pipelines are triggered based on changes in specific paths.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">trigger:</span>
   <span class="hljs-attr">paths:</span>
     <span class="hljs-attr">include:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">'result/**'</span>
</code></pre>
</li>
<li><p><strong>Variables:</strong> Define variables for Docker registry credentials and other necessary configurations.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">variables:</span>
   <span class="hljs-attr">DOCKER_REGISTRY_SERVICE_CONNECTION:</span> <span class="hljs-string">$(dockerRegistryConnection)</span>
   <span class="hljs-attr">IMAGE_REPOSITORY:</span> <span class="hljs-string">'resultapp'</span>
</code></pre>
</li>
<li><p><strong>Stages, Jobs, and Steps:</strong> Define build and push stages, with respective jobs and steps to build and push Docker images.</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">stages:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">Build</span>
    <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span>
    <span class="hljs-attr">jobs:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Build</span>
      <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span>
      <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">Docker@2</span>
        <span class="hljs-attr">displayName:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Image</span>
        <span class="hljs-attr">inputs:</span>
          <span class="hljs-attr">containerRegistry:</span> <span class="hljs-string">'$(dockerRegistryServiceConnection)'</span>
          <span class="hljs-attr">repository:</span> <span class="hljs-string">'$(imageRepository)'</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">'build'</span>
          <span class="hljs-attr">Dockerfile:</span> <span class="hljs-string">'result/Dockerfile'</span>
          <span class="hljs-attr">tags:</span> <span class="hljs-string">'$(tag)'</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">Push</span>
    <span class="hljs-attr">displayName:</span> <span class="hljs-string">Push</span>
    <span class="hljs-attr">jobs:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Push</span>
      <span class="hljs-attr">displayName:</span> <span class="hljs-string">Push</span>
      <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">Docker@2</span>
        <span class="hljs-attr">displayName:</span> <span class="hljs-string">Push</span> <span class="hljs-string">an</span> <span class="hljs-string">image</span> <span class="hljs-string">to</span> <span class="hljs-string">container</span> <span class="hljs-string">registry</span>
        <span class="hljs-attr">inputs:</span>
          <span class="hljs-attr">containerRegistry:</span> <span class="hljs-string">'$(dockerRegistryServiceConnection)'</span>
          <span class="hljs-attr">repository:</span> <span class="hljs-string">'$(imageRepository)'</span>
          <span class="hljs-attr">command:</span> <span class="hljs-string">'push'</span>
          <span class="hljs-attr">tags:</span> <span class="hljs-string">'$(tag)'</span>
</code></pre>
</li>
</ol>
<h3 id="heading-testing-the-pipeline">Testing the Pipeline</h3>
<ol>
<li><p><strong>Commit Changes:</strong> Make a change in the specified path (e.g., <code>result/server.js</code>).</p>
</li>
<li><p><strong>Verify:</strong> Ensure the pipeline triggers automatically and runs the defined stages successfully.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719576091607/64858df3-a882-4663-810d-e2fb1c394b42.png" alt class="image--center mx-auto" /></p>
<p>By structuring your pipeline with these components, you can efficiently manage CI/CD processes, ensuring that only relevant parts of your application are built and deployed based on specific triggers.</p>
<h1 id="heading-continuous-deployment">Continuous Deployment</h1>
<p>Let's dive into setting up the continuous deployment (CD) part for pipeline using the GitOps approach. Here’s how to configure it and explain the setup:</p>
<h3 id="heading-setting-up-continuous-deployment-with-gitops">Setting Up Continuous Deployment with GitOps</h3>
<p>Now we will set up continuous deployment (CD) using the GitOps approach, which leverages Git repositories as the source of truth for declarative infrastructure and application configurations.</p>
<h4 id="heading-gitops-overview">GitOps Overview</h4>
<p>GitOps is a modern approach to continuous deployment that uses Git repositories for managing infrastructure and application configuration. It is a practice where Git repositories are used as the single source of truth for infrastructure and application configurations. The key components typically include:</p>
<ul>
<li><p><strong>Git Repository</strong>: Stores all configuration files (like Kubernetes YAML manifests).</p>
</li>
<li><p><strong>Continuous Deployment Tool (Argo CD)</strong>: Watches Git repositories for changes and automatically applies them to the Kubernetes cluster.</p>
</li>
</ul>
<h3 id="heading-understanding-continuous-deployment-cd-workflow">Understanding Continuous Deployment (CD) Workflow</h3>
<p>In Continuous Integration (CI), where we built Docker images and pushed them to Azure Container Registry (ACR). Now we will focus on Continuous deployment (CD), which involves deploying these newly created container images to our Kubernetes cluster.</p>
<h4 id="heading-cd-workflow-components">CD Workflow Components</h4>
<ol>
<li><p><strong>Developer Action</strong>:</p>
<ul>
<li><p>A developer makes changes to the source code stored in Azure Repos (e.g., modifying voting options in <a target="_blank" href="http://app.py"><code>app.py</code></a>).</p>
</li>
<li><p>Commits and pushes the changes to Azure Repos.</p>
</li>
</ul>
</li>
<li><p><strong>Azure Pipelines (CI/CD)</strong>:</p>
<ul>
<li><p><strong>Build Stage</strong>: Automatically triggered upon a new commit.</p>
<ul>
<li>Builds the Docker image for the updated application.</li>
</ul>
</li>
<li><p><strong>Push Stage</strong>: Pushes the Docker image to Azure Container Registry (ACR).</p>
</li>
</ul>
</li>
<li><p><strong>Update Stage (New Addition)</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: To update Kubernetes manifests (<code>deployment.yaml</code>) in the Azure Repos with the newly created Docker image tag.</p>
</li>
<li><p><strong>Script</strong>: A shell script (<a target="_blank" href="http://updateKmanifest.sh"><code>updateK8manifest.sh</code></a>) is introduced to automate the update process.</p>
<ul>
<li>The script finds and updates the image tag in the appropriate Kubernetes manifest file (<code>deployment.yaml</code>).</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>GitOps with Argo CD</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Monitors the Azure Repos for changes in Kubernetes manifests.</p>
</li>
<li><p><strong>Deployment</strong>: Automatically deploys updated manifests to the AKS cluster.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-detailed-workflow">Detailed Workflow</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719579003422/dc207d47-7919-426e-9076-34d85266740b.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>CI Phase</strong>: Handles the build and push stages to ACR.</p>
<ul>
<li>Developer commits changes → Build triggers → Docker image created → Push to ACR.</li>
</ul>
</li>
<li><p><strong>Update Stage</strong>: Automates the update of Kubernetes manifests in Azure Repos.</p>
<ul>
<li>Shell script updates <code>deployment.yaml</code> with the new Docker image tag.</li>
</ul>
</li>
<li><p><strong>GitOps (Argo CD)</strong>:</p>
<ul>
<li><p>Listens for changes in Azure Repos, specifically in Kubernetes manifests.</p>
</li>
<li><p>Detects updates made by the update stage and deploys them to AKS.</p>
</li>
</ul>
</li>
<li><p><strong>End-to-End CI/CD Pipeline</strong>:</p>
<ul>
<li><p>Azure Repos acts as a central repository.</p>
</li>
<li><p>CI handles image creation and ACR push.</p>
</li>
<li><p>Update stage bridges CI with CD by updating Kubernetes manifests.</p>
</li>
<li><p>GitOps (Argo CD) ensures automatic deployment of changes to the AKS cluster based on updated manifests.</p>
</li>
</ul>
</li>
</ul>
<p>Let's proceed with setting up the Azure Kubernetes Service (AKS) and configuring Argo CD for GitOps.</p>
<h3 id="heading-setting-up-kubernetes-service">Setting Up Kubernetes Service</h3>
<h4 id="heading-creating-azure-kubernetes-service-aks">Creating Azure Kubernetes Service (AKS)</h4>
<ol>
<li><p><strong>Creating Kubernetes Cluster</strong>:</p>
<ul>
<li><p>Navigate to Azure Portal and click on "Create a resource".</p>
</li>
<li><p>Search for "Kubernetes Service (AKS)" and select it.</p>
</li>
<li><p>Click on "Create" to start configuring the AKS.</p>
</li>
</ul>
</li>
<li><p><strong>Configuration Details</strong>:</p>
<ul>
<li><p><strong>Basics</strong>:</p>
<ul>
<li><p>Choose a subscription and resource group (<code>azurecicd</code>).</p>
</li>
<li><p>Specify a cluster name (<code>azure-devops-aks</code>).</p>
</li>
<li><p>Select a region (e.g., <code>West US 2</code> for this demo).</p>
</li>
<li><p>Choose Kubernetes version and networking configuration.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Node Pools</strong>:</p>
<ul>
<li><p><strong>Agent Pool</strong>:</p>
<ul>
<li><p>Configure the node pool settings:</p>
<ul>
<li><p>Set minimum and maximum node counts (<code>1</code> to <code>2</code> for autoscaling) (enough for this project).</p>
</li>
<li><p>Specify other details like node size, disk type, etc.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Scaling Options</strong>:</p>
<ul>
<li>Enable autoscaling for the node pool to handle varying workload demands automatically.</li>
</ul>
</li>
<li><p><strong>Networking</strong>:</p>
<ul>
<li>Configure network settings and optionally enable public IP per node for easy service access.</li>
</ul>
</li>
<li><p><strong>Review + Create</strong>:</p>
<ul>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719576397064/74e75d5b-185d-45a3-bb98-5616a8a77115.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Review the configuration details.</p>
</li>
<li><p>Click on "Create" to start provisioning the AKS cluster.</p>
</li>
<li><p>Azure will validate the configuration and deploy the cluster. This process may take several minutes.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-configuring-argo-cd-for-gitops">Configuring Argo CD for GitOps</h3>
<h4 id="heading-overview">Overview</h4>
<p>Now that we have our AKS cluster ready, we'll proceed with setting up Argo CD to manage deployments using GitOps principles.</p>
<ol>
<li><p><strong>Accessing Azure Kubernetes Cluster</strong>:</p>
<ul>
<li><p>Use Azure CLI to configure kubectl to connect to your AKS cluster:</p>
<pre><code class="lang-bash">  az aks get-credentials --resource-group az-devops --name azuredevops --overwrite-existing
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Installing Argo CD</strong>:</p>
<ul>
<li><p>Follow the official Argo CD documentation for installation. Here’s a summarized approach:</p>
<ul>
<li><p>Visit the <a target="_blank" href="https://argoproj.github.io/argo-cd/getting_started/#1-install-argo-cd">Argo CD installation guide</a>.</p>
</li>
<li><p>Execute the installation commands:</p>
<pre><code class="lang-bash">  kubectl create namespace argocd
  kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
</code></pre>
</li>
</ul>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719576582186/fed1a1d9-833d-417a-8029-0c7b6c03af40.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Accessing Argo CD Dashboard</strong>:</p>
<ul>
<li><p>Once installed, get Argocd initial password for login:</p>
<pre><code class="lang-bash">  kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath=<span class="hljs-string">'{.data.password}'</span>
</code></pre>
</li>
<li><p>Now decode the output of above command:</p>
<pre><code class="lang-bash">    <span class="hljs-built_in">echo</span> -n <span class="hljs-variable">$PASSWORD</span> | base64 -d
</code></pre>
</li>
<li><p>Now to access UI of Argocd, 1st change the type of Argocd Server from ClusterIP to Nodeport:</p>
</li>
<li><pre><code class="lang-bash">      kubectl edit svc/argocd-server -n argocd
</code></pre>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719576786135/f5d25702-fc9c-451b-b962-650dd41f79c0.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719576685857/a855cb09-46f2-42db-bc47-96ee22379a12.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Copy the NodeIP of cluster and HTTP NodePort:</p>
<pre><code class="lang-bash">  kubectl get nodes -o wide
  kubectl get svc -n argocd
</code></pre>
</li>
<li><p>Open the port in Network Security group of AKS cluster:</p>
<ul>
<li><p>Go to Azure portal and search for "Virtual machine scale sets" and click of existing Node pool.</p>
</li>
<li><p>Go to Instance -&gt; Networking -&gt; Inbound Traffic and add destination port as copied above as well as port <code>30000-36000</code>for Kubernetes cluster later on.</p>
</li>
</ul>
</li>
<li><p>Access the Argo CD UI in your browser at <a target="_blank" href="https://NodeIp:NodePort/argocd"><code>https://NodeIp:NodePort/argocd</code></a> (accept any security warnings). (Username: admin, Password: decoded above).</p>
</li>
</ul>
</li>
<li><p><strong>Configuring Argo CD with Azure DevOps Git Repository</strong>:</p>
<ul>
<li><p><strong>Access Token Creation</strong>:</p>
<ul>
<li>Generate a personal access token (PAT) in Azure DevOps with read permissions for repository access.</li>
</ul>
</li>
<li><p><strong>Connecting Repository</strong>:</p>
<ul>
<li><p>Go to Argo CD UI → <code>Settings</code> → <code>Repositories</code>.</p>
</li>
<li><p>Add a new repository:</p>
<ul>
<li><p>Connection method: <code>via HTTPS</code></p>
</li>
<li><p>Repository URL: Paste your Azure DevOps Git repository HTTPS URL and replace the User/Org Name with access token. (Example XYZ with PAT)</p>
<pre><code class="lang-bash">  https://XYZ@dev.azure.com/XYZ/ArgocdDeployment/_git/ArgocdDeployment
  https://PAT@dev.azure.com/XYZ/ArgocdDeployment/_git/ArgocdDeployment
</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Install Argo CD on your Kubernetes cluster</strong></p>
<ul>
<li><p>Create an application in Argo CD for your voting application.</p>
</li>
<li><p>Specify the Git repository URL and path to the Kubernetes manifests (e.g., <code>/k8-specification</code>).</p>
</li>
</ul>
</li>
<li><p><strong>Syncing and Deploying Applications</strong>:</p>
<ul>
<li><p>Argo CD watches for changes in the Git repository (e.g., when a new Docker image is pushed to ACR).</p>
</li>
<li><p>Automatically applies these changes to the Kubernetes cluster, ensuring the latest version of the application is deployed.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-creating-a-new-stage-for-updating-and-writing-shell-script-in-pipelines">Creating a New Stage for Updating and Writing Shell Script in Pipelines</h3>
<p>Now that we have the Argo CD setup, we’ll create a new stage in our CI/CD pipeline to automatically update the Kubernetes manifest with the latest image from the Azure Container Registry (ACR). We will write a shell script that identifies the new image and updates the Kubernetes YAML file accordingly.</p>
<p><strong>Steps to Create the New Update Stage and Shell Script</strong>:</p>
<ol>
<li><p><strong>Create New Stage in Pipeline</strong>:</p>
<ul>
<li><p>Add a new stage named <code>update</code> in your Azure Pipeline configuration.</p>
</li>
<li><p>Set the <code>displayName</code> to <code>Update</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Write the Update Shell Script</strong>:</p>
<ul>
<li>The script will fetch the latest image from ACR and update the corresponding tag in the Kubernetes deployment YAML file.</li>
</ul>
</li>
<li><p><strong>Shell Script Details</strong>:</p>
<ul>
<li><p><strong>Identify Image Pattern</strong>: The repository and registry names are constant. The only changing part is the image tag, which corresponds to the build number.</p>
</li>
<li><p><strong>Shell Script Tasks</strong>:</p>
<ul>
<li><p>Fetch the latest build ID from the Azure Pipeline.</p>
</li>
<li><p>Clone the Git repository where the deployment files are stored.</p>
</li>
<li><p>Update the image tag in the Kubernetes deployment YAML file.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-bash">           <span class="hljs-comment">#!/bin/bash</span>

           <span class="hljs-built_in">set</span> -x

           <span class="hljs-comment"># Set the repository URL</span>
           REPO_URL=<span class="hljs-string">"https://&lt;ACCESS-TOKEN&gt;@dev.azure.com/&lt;AZURE-DEVOPS-ORG-NAME&gt;/voting-app/_git/voting-app"</span>

           <span class="hljs-comment"># Clone the git repository into the /tmp directory</span>
           git <span class="hljs-built_in">clone</span> <span class="hljs-string">"<span class="hljs-variable">$REPO_URL</span>"</span> /tmp/temp_repo

           <span class="hljs-comment"># Navigate into the cloned repository directory</span>
           <span class="hljs-built_in">cd</span> /tmp/temp_repo

           <span class="hljs-comment"># Make changes to the Kubernetes manifest file(s)</span>
           sed -i <span class="hljs-string">"s|image:.*|image: &lt;ACR-REGISTRY-NAME&gt;/<span class="hljs-variable">$2</span>:<span class="hljs-variable">$3</span>|g"</span> k8s-specifications/<span class="hljs-variable">$1</span>-deployment.yaml

           <span class="hljs-comment"># Add the modified files</span>
           git add .

           <span class="hljs-comment"># Commit the changes</span>
           git commit -m <span class="hljs-string">"Update Kubernetes manifest"</span>

           <span class="hljs-comment"># Push the changes back to the repository</span>
           git push

           <span class="hljs-comment"># Cleanup: remove the temporary directory</span>
           rm -rf /tmp/temp_repo
</code></pre>
<ol start="4">
<li><p><strong>Add the Script to the Azure Repository</strong>:</p>
<ul>
<li><p>Navigate to your Azure DevOps repository.</p>
</li>
<li><p>Create a new folder named <code>scripts</code>.</p>
</li>
<li><p>Add the shell script <code>updatek8smanifest.sh</code> to the <code>scripts</code> folder.</p>
</li>
</ul>
</li>
<li><p><strong>Configure the New Update Stage in Azure Pipeline</strong>:</p>
<ul>
<li><p>In your pipeline YAML, add a task to run the <code>updatek8smanifest.sh</code> script.</p>
<pre><code class="lang-yaml">  <span class="hljs-bullet">-</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">Update</span>
  <span class="hljs-attr">displayName:</span> <span class="hljs-string">Update</span>
  <span class="hljs-attr">jobs:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">job:</span> <span class="hljs-string">Update</span>
     <span class="hljs-attr">displayName:</span> <span class="hljs-string">Update</span>
     <span class="hljs-attr">steps:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-attr">task:</span> <span class="hljs-string">ShellScript@2</span>
        <span class="hljs-attr">inputs:</span>
        <span class="hljs-attr">scriptPath:</span> <span class="hljs-string">'scripts/updateK8sManifests.sh'</span>
        <span class="hljs-attr">args:</span> <span class="hljs-string">'vote $(imageRepository) $(tag)'</span>
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Run the Pipeline</strong>:</p>
<ul>
<li><p>Save and run your pipeline. It should trigger the <code>update</code> stage, which will:</p>
<ul>
<li><p>Clone the repository.</p>
</li>
<li><p>Update the image tag in the deployment YAML.</p>
</li>
<li><p>Commit and push the changes.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719576979770/81f69965-6d40-4125-82f2-b11a3461b335.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>This setup ensures that every new image build updates the Kubernetes deployment automatically with the latest image, maintaining continuous deployment without manual intervention.</p>
<h2 id="heading-demo-changing-the-voting-options">Demo: Changing the Voting Options</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719579052162/1a4ac1a4-7bd8-4571-80a6-21f15b7c4933.png" alt class="image--center mx-auto" /></p>
<p>Let's demonstrate how a developer can make a change (e.g., modifying the voting options) and trigger the end-to-end CI/CD process:</p>
<ol>
<li><p><strong>Developer Action</strong>:</p>
<ul>
<li><p>Navigate to the voting application code (e.g., <code>voting-app</code>).</p>
</li>
<li><p>Edit <a target="_blank" href="http://app.py"><code>app.py</code></a> to modify the voting options (e.g., from cats vs dogs to summer vs winter).</p>
</li>
<li><p>Commit and push the changes to the Azure DevOps repository.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-python">    <span class="hljs-comment"># Before</span>
    options = [<span class="hljs-string">'cats'</span>, <span class="hljs-string">'dogs'</span>]

    <span class="hljs-comment"># After</span>
    options = [<span class="hljs-string">'summer'</span>, <span class="hljs-string">'winter'</span>]
</code></pre>
<ol start="2">
<li><p><strong>CI/CD Pipeline Triggers</strong>:</p>
<ul>
<li>The commit triggers the CI pipeline defined earlier, which builds the Docker image and pushes it to ACR.</li>
</ul>
</li>
<li><p><strong>CI Pipeline (Azure DevOps)</strong>:</p>
<ul>
<li><p><strong>Build Stage</strong>: Builds the Docker image.</p>
</li>
<li><p><strong>Push Stage</strong>: Pushes the Docker image to ACR.</p>
</li>
</ul>
</li>
<li><p><strong>CD Pipeline (GitOps Approach)</strong>:</p>
<ul>
<li><p>Uses Argo CD to manage deployments based on Git repository changes.</p>
</li>
<li><p>Monitors the Git repository for changes to Kubernetes YAML manifests (deployment, service, etc.).</p>
</li>
</ul>
</li>
</ol>
<h4 id="heading-monitoring-deployment">Monitoring Deployment</h4>
<ul>
<li><p><strong>Argo CD UI</strong>: Monitor the Argo CD dashboard to see deployments and synchronization status.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719577056309/4b7903f7-1963-4345-a3a2-eac204ffef37.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719577046787/bc6e321c-6702-41db-aff8-925234ce98db.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Kubernetes Dashboard</strong>: Optionally, use the Kubernetes dashboard to view pod status, service endpoints, etc.</p>
</li>
</ul>
<h4 id="heading-final-verification">Final Verification</h4>
<ul>
<li><p>Once Argo CD synchronizes the deployment, verify the changes in your voting application.</p>
</li>
<li><p>Access the application URL and confirm that the new voting options (summer vs winter) are visible and functional.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this tutorial, we have walked through the seamless integration of Azure DevOps and GitOps for a complete CI/CD pipeline. By following these steps, we demonstrated how a developer can make a simple change to an application, triggering an automated build, push, and deployment process that ensures quick and reliable updates to a live environment.</p>
<p>Here are the key takeaways:</p>
<ol>
<li><p><strong>Efficient Workflow</strong>: Using Azure DevOps for CI/CD pipelines streamlines the development process, reducing the time and effort required to build, test, and deploy changes.</p>
</li>
<li><p><strong>GitOps Best Practices</strong>: By incorporating GitOps with tools like Argo CD, we can ensure that the desired state of our applications is maintained as defined in the Git repository. This approach enhances the consistency, reliability, and traceability of deployments.</p>
</li>
<li><p><strong>Automation and Monitoring</strong>: The integration of Argo CD allows for continuous monitoring and synchronization of application states, providing an intuitive UI for real-time updates and deployment statuses. This helps in quickly identifying and resolving any issues that might arise during deployment.</p>
</li>
<li><p><strong>Simplified Management</strong>: Kubernetes dashboards and Argo CD UIs provide clear visibility into the status of applications, making it easier for teams to manage and verify deployments.</p>
</li>
</ol>
<p>By implementing this CI/CD pipeline with Azure DevOps and GitOps, you can achieve a more robust, automated, and efficient deployment process. This not only improves the development cycle but also ensures high availability and reliability of your applications.</p>
<p>Thank you for following along with this tutorial. We hope it helps you in building a streamlined and effective CI/CD pipeline for your own projects. Happy coding! ✨</p>
]]></content:encoded></item><item><title><![CDATA[Implementing a Security-Centric Cloud Native CI/CD Pipeline: A Real-World Demonstration (using Terraform and GCP)]]></title><description><![CDATA[In today's software development landscape, the swift delivery of new features and updates is paramount; however, this must be balanced against the increasing importance of robust security practices. CI/CD (Continuous Integration/Continuous Delivery o...]]></description><link>https://blog.chetan-thapliyal.cloud/implementing-a-security-centric-cloud-native-cicd-pipeline-a-real-world-demonstration-using-terraform-and-gcp</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/implementing-a-security-centric-cloud-native-cicd-pipeline-a-real-world-demonstration-using-terraform-and-gcp</guid><category><![CDATA[GCP]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[projects]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sat, 08 Jun 2024 07:26:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1717757921674/7ae30840-9d1f-4c98-8cf5-21cab942d46d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's software development landscape, the swift delivery of new features and updates is paramount; however, this must be balanced against the increasing importance of robust security practices. CI/CD (Continuous Integration/Continuous Delivery or Deployment) pipelines provide a framework for automating the building, testing, and deployment of applications, bolstering both speed and reliability. This project demonstrates a CI/CD pipeline where security is integrated as a first-class citizen throughout every stage.</p>
<h2 id="heading-project-overview"><strong>Project Overview</strong></h2>
<p>The core objective of this project is to establish a CI/CD pipeline that prioritizes the following principles:</p>
<ul>
<li><p><strong>Security by Design:</strong> Security considerations are embedded in all phases of the development and deployment workflow.</p>
</li>
<li><p><strong>Automation:</strong> Leveraging automation to maximize efficiency, reduce potential human error, and enforce security best practices.</p>
</li>
<li><p><strong>Continuous Monitoring:</strong> Implementing systems and application-level monitoring for proactive issue detection and rapid response.</p>
</li>
<li><p><strong>Infrastructure as Code with Terraform:</strong> Utilizing Terraform, a popular Infrastructure as Code (IaC) tool, to predictably create, change, and improve cloud infrastructure.</p>
</li>
<li><p><strong>Google Cloud as the Cloud Platform:</strong> Leveraging Google Cloud's compute engine services and products to provision and manage the required infrastructure components.</p>
</li>
</ul>
<h3 id="heading-key-technolohttpscloudgooglecomdocsterraformresource-managementmanaging-infrastructure-asgihttpscloudgooglecomdocsterraformes"><strong>Key Technol</strong><a target="_blank" href="https://cloud.google.com/docs/terraform/resource-management/managing-infrastructure-as..."><strong>o</strong></a><strong>g</strong><a target="_blank" href="https://cloud.google.com/docs/terraform"><strong>i</strong></a><strong>es</strong></h3>
<ul>
<li><p><strong>Kubernetes:</strong> Container orchestration for application deployment and management.</p>
</li>
<li><p><strong>Jenkins:</strong> CI/CD automation server.</p>
</li>
<li><p><strong>SonarQube:</strong> Static code analysis to ensure code quality and identify potential security issues.</p>
</li>
<li><p><strong>Aqua Trivy:</strong> Vulnerability scanning for code dependencies and container images.</p>
</li>
<li><p><strong>Nexus Repository:</strong> Secure storage for build artifacts.</p>
</li>
<li><p><strong>Docker:</strong> Containerization for application packaging.</p>
</li>
<li><p><strong>Docker Hub:</strong> Docker image registry.</p>
</li>
<li><p><strong>Kubeaudit:</strong> Tool to audit Kubernetes clusters for various different security concerns.</p>
</li>
<li><p><strong>Grafana</strong>: For system and application-level monitoring and alerting.</p>
</li>
<li><p><strong>Prometheus</strong>: For collecting and querying metrics from services and endpoints.</p>
</li>
<li><p><strong>Gmail</strong>: For status notifications and alerts.</p>
</li>
</ul>
<h3 id="heading-workflow"><strong>Workflow</strong></h3>
<p>A client requests a feature or change in the application and creates a Jira ticket. The Jira ticket is then assigned to a developer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717760640031/2d51cbe8-7dd1-4d7a-af33-4885e53f9dbf.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Development and Version Control:</strong></p>
<ul>
<li><p>Developers work on feature branches within a Git repository (e.g., GitHub) and successfully test the new feature in local environment.</p>
</li>
<li><p>Once changes are pushed along with source code to GitHub repository, it trigger the CI/CD pipeline.</p>
</li>
</ul>
</li>
<li><p><strong>Build and Unit Testing:</strong></p>
<ul>
<li><p>The project's build system (e.g., Maven) compiles the code, and find out if there are any syntax base errors in the code.</p>
</li>
<li><p>Once code compilation is successful, Unit tests are executed to validate code functionality.</p>
</li>
</ul>
</li>
<li><p><strong>Code Quality and Security Analysis:</strong></p>
<ul>
<li><p>SonarQube analyzes code for maintainability, potential bugs, and security vulnerabilities.</p>
</li>
<li><p>Aqua Trivy scans for vulnerabilities within project dependencies.</p>
</li>
</ul>
</li>
<li><p><strong>Artifact Creation and Storage:</strong></p>
<ul>
<li><p>A build artifact (e.g., JAR, WAR) is generated.</p>
</li>
<li><p>The artifact is pushed to Nexus Repository for secure storage and proper release.</p>
</li>
</ul>
</li>
<li><p><strong>Docker Image Creation:</strong></p>
<ul>
<li><p>Docker builds a container image incorporating the build artifact and tag it properly.</p>
</li>
<li><p>Aqua Trivy scans the image for vulnerabilities.</p>
</li>
<li><p>Docker image is pushed to dockerhub.</p>
</li>
</ul>
</li>
<li><p><strong>Kubernetes Deployment:</strong></p>
<ul>
<li><p>Kube Audit secures the Kubernetes cluster.</p>
</li>
<li><p>The image is deployed to the Kubernetes cluster if all security scans pass.</p>
</li>
</ul>
</li>
<li><p>Mail Notification</p>
<ul>
<li><p>Client and devops engineer will receive the mail notification if pipeline is successful or failed.</p>
</li>
<li><p>Notifications are sent to mail for deployment status, errors, and critical alerts.</p>
</li>
</ul>
</li>
<li><p><strong>Monitoring:</strong></p>
<ul>
<li><p>Monitoring tools (Prometheus and Grafana) track the health of the system and application.</p>
</li>
<li><p>For system-level monitoring of hardware, Jenkins is used. Node Exporter monitors Jenkins.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-step-by-step-project-execution">Step-by-Step Project Execution</h2>
<h3 id="heading-phase-1-creating-infrastructure">Phase 1: Creating Infrastructure</h3>
<p>The project kicks off with the creation of an isolated network environment a critical step for maintaining security and control. This phase includes:</p>
<ol>
<li><p><strong>Network Environment Creation:</strong> Setting up a dedicated and secure network environment to isolate and protect the project's infrastructure from external threats.</p>
<ul>
<li><p>Create a Custom VPC on Google Cloud Platform with custom firewall rules allowing traffic to specific ports.</p>
<h4 id="heading-terraform-code">Terraform Code:</h4>
<pre><code class="lang-bash">  <span class="hljs-comment"># Network creation</span>
  <span class="hljs-comment">#-----------------#</span>
  resource <span class="hljs-string">"google_compute_network"</span> <span class="hljs-string">"dev-cicd-vpc"</span> {
      auto_create_subnetworks = <span class="hljs-literal">true</span>
      description             = <span class="hljs-string">"VPC for secure CICD pipeline."</span>
      mtu                     = 1460
      name                    = <span class="hljs-string">"dev-cicd-vpc"</span>
      project                 = var.gcp_project_id
      routing_mode            = <span class="hljs-string">"REGIONAL"</span>
  }

  <span class="hljs-comment"># Firewall Rules</span>
  <span class="hljs-comment">#-----------------#</span>

  <span class="hljs-comment">## Custom firewall rules</span>
  resource <span class="hljs-string">"google_compute_firewall"</span> <span class="hljs-string">"dev-cicd-vpc-allow-custom"</span> {
      name                    = <span class="hljs-string">"dev-cicd-vpc-allow-custom"</span>
      project                 = var.gcp_project_id
      network                 = google_compute_network.dev-cicd-vpc.name
      description             = <span class="hljs-string">"Allows connection from any source to any instance on the network using custom protocols."</span>
      direction               = <span class="hljs-string">"INGRESS"</span>
      priority                = 65534
      source_ranges           = [<span class="hljs-string">"10.128.0.0/9"</span>, <span class="hljs-string">"0.0.0.0/0"</span>] 
      allow {
          protocol = <span class="hljs-string">"tcp"</span> 
          ports    = [<span class="hljs-string">"80"</span>, <span class="hljs-string">"443"</span>, <span class="hljs-string">"465"</span>, <span class="hljs-string">"6443"</span>, <span class="hljs-string">"3000-10000"</span>, <span class="hljs-string">"30000-32767"</span>]
      }
  }

  <span class="hljs-comment">## ICMP</span>
  resource <span class="hljs-string">"google_compute_firewall"</span> <span class="hljs-string">"dev-cicd-vpc-allow-icmp"</span> {
      network     = google_compute_network.dev-cicd-vpc.name
      project     = var.gcp_project_id
      direction   = <span class="hljs-string">"INGRESS"</span>
      priority    = 65534
      source_ranges = [<span class="hljs-string">"0.0.0.0/0"</span>]
      name        = <span class="hljs-string">"dev-cicd-vpc-allow-icmp"</span> 
      description = <span class="hljs-string">"Allows ICMP connections from any source to any instance on the network."</span>
      allow {
          protocol = <span class="hljs-string">"icmp"</span>
      }
  }

  <span class="hljs-comment">## SSH</span>
  resource <span class="hljs-string">"google_compute_firewall"</span> <span class="hljs-string">"dev-cicd-vpc-allow-ssh"</span> {
      network     = google_compute_network.dev-cicd-vpc.name
      project     = var.gcp_project_id
      direction   = <span class="hljs-string">"INGRESS"</span>
      priority    = 65534
      source_ranges = [<span class="hljs-string">"0.0.0.0/0"</span>]
      name        = <span class="hljs-string">"dev-cicd-vpc-allow-ssh"</span>
      description = <span class="hljs-string">"Allows TCP connections from any source to any instance on the network using port 22."</span>
      allow {
          protocol = <span class="hljs-string">"tcp"</span> 
          ports    = [<span class="hljs-string">"22"</span>]
      }
  }
</code></pre>
</li>
</ul>
</li>
</ol>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">To install the various DevOps tools, I used Bash scripts and leveraged GCP's startup script feature when creating VMs.</div>
</div>

<blockquote>
<p><a target="_blank" href="https://github.com/ChetanThapliyal/Secure-cloudNative-CI-CD-pipeline">Project Repo</a></p>
</blockquote>
<ol start="2">
<li><p><strong>Kubernetes Cluster Deployment:</strong> Establishing a robust Kubernetes (K8s) cluster as the foundation for the project's deployment needs. This cluster is thoroughly scanned and secured to ensure a resilient platform.</p>
<ul>
<li><p>Create 3 VM's on GCP for Kubernetes (1 Master and 2 Slave Nodes) and configure Kubernetes on them.</p>
<pre><code class="lang-bash">  <span class="hljs-comment">## Master Node VM</span>
  resource <span class="hljs-string">"google_compute_instance"</span> <span class="hljs-string">"cluster-instances-node-master"</span> {
      boot_disk {
          auto_delete = <span class="hljs-literal">true</span>
          device_name = <span class="hljs-string">"k8-cluster-nodes"</span>

          initialize_params {
          image = <span class="hljs-string">"projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240307b"</span>
          size  = 25
          <span class="hljs-built_in">type</span>  = <span class="hljs-string">"pd-balanced"</span>
          }

          mode = <span class="hljs-string">"READ_WRITE"</span>
      }

      can_ip_forward      = <span class="hljs-literal">false</span>
      deletion_protection = <span class="hljs-literal">false</span>
      enable_display      = <span class="hljs-literal">false</span>

      labels = {
          goog-ec-src = <span class="hljs-string">"vm_add-tf"</span>
          node        = <span class="hljs-string">"master"</span>
      }

      machine_type = <span class="hljs-string">"e2-medium"</span>

      metadata = {
          startup-script = file(<span class="hljs-string">"./scripts/masterVM.sh"</span>)
      }

      name = <span class="hljs-string">"cluster-instances-node-master"</span>

      network_interface {
          access_config {
          network_tier = <span class="hljs-string">"STANDARD"</span>
          }

          queue_count = 0
          stack_type  = <span class="hljs-string">"IPV4_ONLY"</span>
          network     = google_compute_network.dev-cicd-vpc.name
      }

      scheduling {
          automatic_restart   = <span class="hljs-literal">true</span>
          on_host_maintenance = <span class="hljs-string">"MIGRATE"</span>
          preemptible         = <span class="hljs-literal">false</span>
          provisioning_model  = <span class="hljs-string">"STANDARD"</span>
      }

      service_account {
          email  = var.gcp_service_account_email
          scopes = [<span class="hljs-string">"https://www.googleapis.com/auth/cloud-platform"</span>]
      }

      shielded_instance_config {
          enable_integrity_monitoring = <span class="hljs-literal">true</span>
          enable_secure_boot          = <span class="hljs-literal">false</span>
          enable_vtpm                 = <span class="hljs-literal">true</span>
      }

      tags = [<span class="hljs-string">"http-server"</span>, <span class="hljs-string">"https-server"</span>, <span class="hljs-string">"lb-health-check"</span>]
      zone = <span class="hljs-string">"asia-south1-c"</span>
  }

  <span class="hljs-comment">## Slave Node VM (2 nodes)</span>
  resource <span class="hljs-string">"google_compute_instance"</span> <span class="hljs-string">"cluster-instances-node-slave"</span> {
      count = 2

      boot_disk {
          auto_delete = <span class="hljs-literal">true</span>
          device_name = <span class="hljs-string">"k8-cluster-nodes"</span>

          initialize_params {
          image = <span class="hljs-string">"projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240307b"</span>
          size  = 25
          <span class="hljs-built_in">type</span>  = <span class="hljs-string">"pd-balanced"</span>
          }

          mode = <span class="hljs-string">"READ_WRITE"</span>
      }

      can_ip_forward      = <span class="hljs-literal">false</span>
      deletion_protection = <span class="hljs-literal">false</span>
      enable_display      = <span class="hljs-literal">false</span>

      labels = {
          goog-ec-src = <span class="hljs-string">"vm_add-tf"</span>
          node        = <span class="hljs-string">"slave0<span class="hljs-variable">${count.index + 1}</span>"</span>
      }

      machine_type = <span class="hljs-string">"e2-medium"</span>

      metadata = {
          startup-script = file(<span class="hljs-string">"./scripts/slaveVM.sh"</span>)
      }

      name = <span class="hljs-string">"cluster-instances-node-slave0<span class="hljs-variable">${count.index + 1}</span>"</span>

      network_interface {
          access_config {
          network_tier = <span class="hljs-string">"STANDARD"</span>
          }

          queue_count = 0
          stack_type  = <span class="hljs-string">"IPV4_ONLY"</span>
          network     = google_compute_network.dev-cicd-vpc.name
      }

      scheduling {
          automatic_restart   = <span class="hljs-literal">true</span>
          on_host_maintenance = <span class="hljs-string">"MIGRATE"</span>
          preemptible         = <span class="hljs-literal">false</span>
          provisioning_model  = <span class="hljs-string">"STANDARD"</span>
      }

      service_account {
          email  = var.gcp_service_account_email
          scopes = [<span class="hljs-string">"https://www.googleapis.com/auth/cloud-platform"</span>]
      }

      shielded_instance_config {
          enable_integrity_monitoring = <span class="hljs-literal">true</span>
          enable_secure_boot          = <span class="hljs-literal">false</span>
          enable_vtpm                 = <span class="hljs-literal">true</span>
      }

      tags = [<span class="hljs-string">"http-server"</span>, <span class="hljs-string">"https-server"</span>, <span class="hljs-string">"lb-health-check"</span>]
      zone = <span class="hljs-string">"asia-south1-c"</span>
  }
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Essential Server Setup:</strong> Configuring and deploying essential servers to support the CI/CD processes. This includes:</p>
<ul>
<li><p><strong>Jenkins Server:</strong> For continuous integration and deployment automation.</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Jenkins VM</span>
  <span class="hljs-comment">#-----------------#</span>

  resource <span class="hljs-string">"google_compute_instance"</span> <span class="hljs-string">"jenkins"</span> {
      boot_disk {
          auto_delete = <span class="hljs-literal">true</span>
          device_name = <span class="hljs-string">"jenkins-vm"</span>

          initialize_params {
          image = <span class="hljs-string">"projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240307b"</span>
          size  = 30
          <span class="hljs-built_in">type</span>  = <span class="hljs-string">"pd-balanced"</span>
          }

          mode = <span class="hljs-string">"READ_WRITE"</span>
      }

      can_ip_forward      = <span class="hljs-literal">false</span>
      deletion_protection = <span class="hljs-literal">false</span>
      enable_display      = <span class="hljs-literal">false</span>

      labels = {
          goog-ec-src = <span class="hljs-string">"vm_add-tf"</span>
          jenkins     = <span class="hljs-string">""</span>
      }

      machine_type = <span class="hljs-string">"e2-standard-2"</span>

      metadata = {
          startup-script = file(<span class="hljs-string">"./scripts/jenkins.sh"</span>)
      }

      name = <span class="hljs-string">"jenkins"</span>

      network_interface {
          access_config {
          network_tier = <span class="hljs-string">"STANDARD"</span>
          }

          queue_count = 0
          stack_type  = <span class="hljs-string">"IPV4_ONLY"</span>
          network     = google_compute_network.dev-cicd-vpc.name
      }

      scheduling {
          automatic_restart   = <span class="hljs-literal">true</span>
          on_host_maintenance = <span class="hljs-string">"MIGRATE"</span>
          preemptible         = <span class="hljs-literal">false</span>
          provisioning_model  = <span class="hljs-string">"STANDARD"</span>
      }

      service_account {
          email  = var.gcp_service_account_email
          scopes = [<span class="hljs-string">"https://www.googleapis.com/auth/cloud-platform"</span>]
      }

      shielded_instance_config {
          enable_integrity_monitoring = <span class="hljs-literal">true</span>
          enable_secure_boot          = <span class="hljs-literal">false</span>
          enable_vtpm                 = <span class="hljs-literal">true</span>
      }

      tags = [<span class="hljs-string">"http-server"</span>, <span class="hljs-string">"https-server"</span>, <span class="hljs-string">"lb-health-check"</span>]
      zone = <span class="hljs-string">"asia-south1-c"</span>
  }
</code></pre>
</li>
<li><p><strong>SonarQube Server:</strong> For continuous code quality and security analysis.</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Sonarqube VM</span>
  <span class="hljs-comment">#---------------#</span>
  resource <span class="hljs-string">"google_compute_instance"</span> <span class="hljs-string">"sonarqube"</span> {
      boot_disk {
          auto_delete = <span class="hljs-literal">true</span>
          device_name = <span class="hljs-string">"k8-cluster-nodes"</span>

          initialize_params {
          image = <span class="hljs-string">"projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240307b"</span>
          size  = 20
          <span class="hljs-built_in">type</span>  = <span class="hljs-string">"pd-balanced"</span>
          }

          mode = <span class="hljs-string">"READ_WRITE"</span>
      }

      can_ip_forward      = <span class="hljs-literal">false</span>
      deletion_protection = <span class="hljs-literal">false</span>
      enable_display      = <span class="hljs-literal">false</span>

      labels = {
          goog-ec-src = <span class="hljs-string">"vm_add-tf"</span>
          sonarqube   = <span class="hljs-string">""</span>
      }

      machine_type = <span class="hljs-string">"e2-medium"</span>

      metadata = {
          startup-script = file(<span class="hljs-string">"./scripts/sonarqube.sh"</span>)
      }

      name = <span class="hljs-string">"sonarqube"</span>

      network_interface {
          access_config {
          network_tier = <span class="hljs-string">"STANDARD"</span>
          }

          queue_count = 0
          stack_type  = <span class="hljs-string">"IPV4_ONLY"</span>
          network     = google_compute_network.dev-cicd-vpc.name
      }

      scheduling {
          automatic_restart   = <span class="hljs-literal">true</span>
          on_host_maintenance = <span class="hljs-string">"MIGRATE"</span>
          preemptible         = <span class="hljs-literal">false</span>
          provisioning_model  = <span class="hljs-string">"STANDARD"</span>
      }

      service_account {
          email  = var.gcp_service_account_email
          scopes = [<span class="hljs-string">"https://www.googleapis.com/auth/cloud-platform"</span>]
      }

      shielded_instance_config {
          enable_integrity_monitoring = <span class="hljs-literal">true</span>
          enable_secure_boot          = <span class="hljs-literal">false</span>
          enable_vtpm                 = <span class="hljs-literal">true</span>
      }

      tags = [<span class="hljs-string">"http-server"</span>, <span class="hljs-string">"https-server"</span>, <span class="hljs-string">"lb-health-check"</span>]
      zone = <span class="hljs-string">"asia-south1-c"</span>
  }
</code></pre>
</li>
<li><p><strong>Monitoring Servers:</strong> To support system and application-level monitoring from the outset.</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Monitoring VM</span>
  <span class="hljs-comment">#-----------------#</span>

  resource <span class="hljs-string">"google_compute_instance"</span> <span class="hljs-string">"monitor"</span> {
      boot_disk {
          auto_delete = <span class="hljs-literal">true</span>
          device_name = <span class="hljs-string">"monitoring"</span>

          initialize_params {
          image = <span class="hljs-string">"projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240307b"</span>
          size  = 20
          <span class="hljs-built_in">type</span>  = <span class="hljs-string">"pd-balanced"</span>
          }

          mode = <span class="hljs-string">"READ_WRITE"</span>
      }

      can_ip_forward      = <span class="hljs-literal">false</span>
      deletion_protection = <span class="hljs-literal">false</span>
      enable_display      = <span class="hljs-literal">false</span>

      labels = {
          goog-ec-src = <span class="hljs-string">"vm_add-tf"</span>
          monitor     = <span class="hljs-string">""</span>
      }

      machine_type = <span class="hljs-string">"e2-standard-2"</span>

      metadata = {
          startup-script = file(<span class="hljs-string">"./scripts/monitoring.sh"</span>)
      }

      name = <span class="hljs-string">"monitor"</span>

      network_interface {
          access_config {
          network_tier = <span class="hljs-string">"PREMIUM"</span>
          }

          queue_count = 0
          stack_type  = <span class="hljs-string">"IPV4_ONLY"</span>
          network     = google_compute_network.dev-cicd-vpc.name
      }

      scheduling {
          automatic_restart   = <span class="hljs-literal">true</span>
          on_host_maintenance = <span class="hljs-string">"MIGRATE"</span>
          preemptible         = <span class="hljs-literal">false</span>
          provisioning_model  = <span class="hljs-string">"STANDARD"</span>
      }

      service_account {
          email  = var.gcp_service_account_email
          scopes = [<span class="hljs-string">"https://www.googleapis.com/auth/cloud-platform"</span>]
      }

      shielded_instance_config {
          enable_integrity_monitoring = <span class="hljs-literal">true</span>
          enable_secure_boot          = <span class="hljs-literal">false</span>
          enable_vtpm                 = <span class="hljs-literal">true</span>
      }

      tags = [<span class="hljs-string">"http-server"</span>, <span class="hljs-string">"https-server"</span>, <span class="hljs-string">"lb-health-check"</span>]
      zone = <span class="hljs-string">"asia-south1-c"</span>
  }
</code></pre>
</li>
</ul>
</li>
</ol>
<h3 id="heading-phase-2-version-control-and-notification-system">Phase 2: Version Control and Notification System</h3>
<p>In this phase, the focus is on version control and establishing a notification system to keep stakeholders informed:</p>
<ol>
<li><p><strong>Version Control with GitHub:</strong></p>
<ul>
<li><p><strong>Private Repository Setup:</strong> Source code is pushed to a private GitHub repository to ensure security and privacy.</p>
</li>
<li><p><strong>Branching Strategy:</strong> Implementing a branching strategy (e.g., feature branches, development, main) to manage code changes efficiently.</p>
</li>
</ul>
</li>
<li><p><strong>Mail Notification System:</strong></p>
<ul>
<li><p><strong>Configuration:</strong> Setting up an email notification system to alert stakeholders about the project's progress and any critical issues.</p>
</li>
<li><p><strong>Integration:</strong> Integrating the notification system with the CI/CD pipeline to provide real-time updates on build statuses, deployments, and alerts.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-phase-3-building-the-cicd-pipeline">Phase 3: Building the CI/CD Pipeline</h3>
<p>The CI/CD pipeline is the heart of the project, automating the deployment process and ensuring robust security measures:</p>
<ol>
<li><p><strong>Pipeline Design and Implementation:</strong></p>
<ul>
<li><strong>Jenkins Pipeline Configuration:</strong> Defining a declarative Jenkins pipeline (Jenkinsfile) that outlines the steps for building, testing, and deploying the application.</li>
</ul>
</li>
<li><p><strong>Security Measures:</strong></p>
<ul>
<li><p><strong>Code Quality Analysis with SonarQube:</strong> Integrating SonarQube to perform static code analysis and ensure code quality.</p>
</li>
<li><p><strong>Vulnerability Scanning with Aqua Trivy:</strong> Scanning code dependencies and Docker images for vulnerabilities to enhance security.</p>
</li>
</ul>
</li>
<li><p><strong>Automated Deployment:</strong></p>
<ul>
<li><p><strong>Artifact Creation and Storage:</strong> Building the application artifacts (e.g., JAR, WAR) and securely storing them in Nexus Repository.</p>
</li>
<li><p><strong>Container Image Build and Scan:</strong> Creating Docker container images and scanning them for vulnerabilities before deployment.</p>
</li>
<li><p><strong>Kubernetes Deployment:</strong> Automating the deployment of container images to the Kubernetes cluster, ensuring a smooth transition from development to production.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-phase-4-monitoring-at-scale">Phase 4: Monitoring at Scale</h3>
<p>In the final phase, system-level and application-level monitoring are implemented to maintain the health of the application and provide real-time insights:</p>
<ol>
<li><p><strong>System Monitoring with Prometheus and Grafana:</strong></p>
<ul>
<li><p><strong>Metric Collection:</strong> Prometheus collects metrics from various services and endpoints, providing detailed insights into system performance.</p>
</li>
<li><p><strong>Visualization and Alerting:</strong> Grafana visualizes these metrics and sets up alerting mechanisms to notify of any performance issues or anomalies.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717831119406/20642f42-60fc-412f-b76f-1c33e2f08401.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Application Monitoring:</strong></p>
<ul>
<li><p><strong>Endpoint Monitoring with Blackbox Exporter:</strong> Ensuring that web endpoints are monitored for availability and responsiveness.</p>
</li>
<li><p><strong>Traffic and Performance Monitoring:</strong> Monitoring website traffic and application performance to ensure optimal user experience.</p>
</li>
</ul>
</li>
<li><p><strong>Continuous Improvement:</strong></p>
<ul>
<li><p><strong>Feedback Loop:</strong> Using monitoring data to identify areas for improvement and optimize the CI/CD pipeline and deployment processes continually.</p>
</li>
<li><p><strong>Proactive Maintenance:</strong> Implementing proactive measures based on monitoring insights to prevent issues before they impact users.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-security-considerations"><strong>Security Considerations</strong></h3>
<ul>
<li><p><strong>Pre-deployment Kubernetes Security:</strong> The Kubernetes cluster is hardened to minimize potential attack surfaces.</p>
</li>
<li><p><strong>Pipeline as Code:</strong> Pipeline configuration (e.g., Jenkinsfile) is treated as code, enabling versioning and peer review.</p>
</li>
<li><p><strong>Vulnerability Scanning:</strong> Scans at the code and image stages proactively identify issues.</p>
</li>
<li><p><strong>Monitoring:</strong> Anomalies or suspicious behavior are detected early.</p>
</li>
</ul>
<h3 id="heading-benefits-of-a-secure-cicd-pipeline"><strong>Benefits of a Secure CI/CD Pipeline</strong></h3>
<ul>
<li><p><strong>Enhanced Security Posture:</strong> Integration of security measures throughout the process mitigates risks.</p>
</li>
<li><p><strong>Increased Confidence:</strong> Rigorous testing and security checks lead to more reliable releases.</p>
</li>
<li><p><strong>Improved Agility:</strong> Automation streamlines development and reduces time to market.</p>
</li>
<li><p><strong>Reduced Operational Overhead:</strong> Fewer manual processes minimize potential errors.</p>
</li>
</ul>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>This project exemplifies a comprehensive CI/CD pipeline that can serve as a blueprint for organizations looking to implement or refine their own CI/CD strategies. It demonstrates the importance of each phase and the inter-connectedness of various tools and practices that contribute to a successful software delivery lifecycle.</p>
]]></content:encoded></item><item><title><![CDATA[Optimizing Docker Images with Multistage Builds: A Hugo Portfolio Example]]></title><description><![CDATA[Docker has revolutionized the way we build, package, and deploy applications. However, as projects grow in complexity, the size of Docker images can quickly balloon, leading to slower build times, increased storage requirements, and reduced performan...]]></description><link>https://blog.chetan-thapliyal.cloud/optimizing-docker-images-with-multistage-builds-a-hugo-portfolio-example</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/optimizing-docker-images-with-multistage-builds-a-hugo-portfolio-example</guid><category><![CDATA[Docker]]></category><category><![CDATA[Hugo]]></category><category><![CDATA[distroless]]></category><category><![CDATA[#dockerprojects]]></category><category><![CDATA[multistage docker build]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Fri, 26 Apr 2024 20:19:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714155257973/f3bb0b2f-96d7-4988-bec6-b630dfa4cebc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Docker has revolutionized the way we build, package, and deploy applications. However, as projects grow in complexity, the size of Docker images can quickly balloon, leading to slower build times, increased storage requirements, and reduced performance. This is where multistage builds come into play.</p>
<p>Docker images are templates that house the instructions for the associated container. These images are built in read-only layers, and each layer represents a step in the build process. Optimizing these layers is crucial for creating lean and efficient Docker images.</p>
<p>One powerful technique for optimizing Docker images is the use of multistage builds. Multistage builds allow you to separate the build process from the final image, resulting in a smaller and more streamlined container.</p>
<p>Let's explore this concept in detail and use a real-world example of a portfolio website bui<a target="_blank" href="https://medium.com/@navneetskahlon/optimizing-docker-images-best-practices-and...">l</a>t with Hugo to illustrate the process.</p>
<h2 id="heading-understanding-docker-images-and-layers"><strong>Understanding Docker Images and Layers</strong></h2>
<p>Before diving into multistage builds, let's briefly discuss what Docker image is and how Docker images work.</p>
<h3 id="heading-what-is-docker-image">What is Docker Image?</h3>
<p>A Docker <a target="_blank" href="https://medium.com/@navneetskahlon/optimizing-docker-images-best-practices-and...">i</a>mage is a lightweight, stand-alone, executable package that includes everything needed to run a piece of software, including the code, a runtime, libraries, environment variables, and config files.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712061549886/fa4e7f71-0d1d-484e-b7c6-bbae61b71a6b.png" alt class="image--center mx-auto" /></p>
<p>A Docker image is built using a series of instructions defined in a <code>Dockerfile</code>. Each instruction creates a new layer in the image, and these layers are stacked on top of each other. Images contain the code or binary, runtimes, dependencies, and other filesystem objects to run an application. The image relies on the host operating system (OS) kernel.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712061291623/cdc5c538-ce2a-4d90-abbe-81b2a5eb4ac6.png" alt class="image--center mx-auto" /></p>
<p>Docker images are designed to be immutable, meaning that once an image is built, it cannot be changed. Any updates or modifications to the software or environment must be made by creating a new image, rather than modifying the existing one. This makes it easy to roll back to a previous version of the image if necessary, and to deploy the same image consistently across different environments.</p>
<p>When you make changes to your application and rebuild the image, only the modified layers are rebuilt, while the unchanged layers are cached. This layered approach allows for efficient image building and sharing.</p>
<p>There are three specific types of commands that can be used to build and run Dockerfiles:</p>
<ol>
<li><p><strong>RUN</strong> - To run this command you will need a separate new layer and this command is mainly used to build images and install packages and applications.</p>
</li>
<li><p><strong>CMD</strong> - The CMD describes the default container parameters or commands. The user can easily override the default command when you use this.</p>
</li>
<li><p><strong>ENTRYPOINT</strong> - A container with an ENTRYPOINT is preferred when you want to define an executable. You can only override it if you use the --entrypoint flag.</p>
</li>
</ol>
<h2 id="heading-the-problem-with-monolithic-dockerfiles"><strong>The Problem with Monolithic Dockerfiles</strong></h2>
<p>Traditionally, Dockerfiles are written as a single, monolithic set of instructions. This approach works well for simple projects, but as the complexity grows, it can lead to several issues:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712310721590/e91b61ea-efbf-43af-880f-65878fd90ba5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-why-the-image-is-so-large">Why <strong>the image is so Large?</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714155961952/a03eeeec-c79d-4c27-9658-cfca99b6f1a5.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Large Image Sizes:</strong> Including all the dependencies, build tools, and artifacts in a single image result in a large image size.</p>
</li>
<li><p><strong>Slow Build Times:</strong> Rebuilding the entire image from scratch every time a change is made can be time-consuming.</p>
</li>
<li><p><strong>Security Risks:</strong> Unnecessary tools and libraries included in the final image can introduce potential security vulnerabilities.</p>
</li>
</ol>
<p>The solution that Docker has for this problem is a multi-stage image build.</p>
<h2 id="heading-introducing-multistage-builds-distroless"><strong>Introducing Multistage Builds (Distroless)</strong></h2>
<p>The key to minimizing the size of Docker image is to reduce the number of layers. Multistage builds enable us to achieve this by separating the build process from the final image.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714155734992/deca91ce-54bd-458b-aa22-95959aee4852.png" alt class="image--center mx-auto" /></p>
<p>Here's how it works:</p>
<ol>
<li><p><strong>Build Stage</strong>: In the first stage, you build your application, including all the necessary dependencies and tooling. This stage can be quite large, as it includes the entire build process.</p>
</li>
<li><p><strong>Final Stage</strong>: In the second stage, you copy only the necessary artifacts from the build stage and create a smaller, more streamlined image.</p>
</li>
</ol>
<p>By separating these stages, we can ensure that final Docker image only contains the essential components required to run your application, leaving behind the bulky build dependencies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714156351048/e54505fe-d544-4a35-b797-1e55df7a4df6.png" alt class="image--center mx-auto" /></p>
<p>It involves downloading a new image after initial build is complete, and copying all application files, assets, and library dependencies.</p>
<h2 id="heading-the-project-portfolio-website-with-hugo">The Project: Portfolio Website with Hugo</h2>
<p>Hugo is a fast and modern static site generator written in Go, and it's designed to make website creation simple and efficient. Static site generators like Hugo are an excellent match for Docker, as they produce a set of static files that are easy to serve with a lightweight HTTP server.</p>
<h2 id="heading-the-challenge-image-size-reduction">The Challenge: Image Size Reduction</h2>
<p>The challenge presented is to optimize a Docker image for a portfolio website created with Hugo. The initial Docker image size is <code>434MB</code>, which is quite large for a simple portfolio website. The goal is to reduce the image size without sacrificing functionality.</p>
<p>To tackle this challenge, two Dockerfiles are created: one for development (<code>dev</code>) and one for production (<code>prod</code>). The production Dockerfile is a Multistage build designed for image optimization.</p>
<h4 id="heading-development-dockerfile">Development Dockerfile</h4>
<p>The development Dockerfile is a standard build, containing all the necessary tools and dependencies for a development environment. The development Dockerfile included everything needed to build the Hugo site, including the full Hugo binary, a web server for testing, and various other dependencies.</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> golang:alpine

<span class="hljs-comment"># Set the working directory</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copy your Hugo project files</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

<span class="hljs-comment"># Install Hugo and compatibility libraries</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache hugo libc6-compat libgcc libstdc++</span>

<span class="hljs-comment"># Install Node.js and npm</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache nodejs npm</span>

<span class="hljs-comment"># Install PostCSS for Hugo</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install -g postcss-cli</span>

<span class="hljs-comment"># Generate your website's static content</span>
<span class="hljs-keyword">RUN</span><span class="bash"> hugo</span>

<span class="hljs-comment"># Install NGINX</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache nginx</span>

<span class="hljs-comment"># Optional: Copy your custom Nginx configuration if needed</span>
<span class="hljs-comment"># COPY nginx.conf /etc/nginx/nginx.conf</span>

<span class="hljs-comment"># Remove Hugo and any build dependencies (optional, for size reduction)</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk del --no-cache hugo</span>

<span class="hljs-comment"># Expose the port NGINX uses</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>

<span class="hljs-comment"># Command to start NGINX when the container runs</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"nginx"</span>, <span class="hljs-string">"-g"</span>, <span class="hljs-string">"daemon off;"</span>]</span>
</code></pre>
<h4 id="heading-explanation">Explanation:</h4>
<ol>
<li><p><strong>Base Image</strong>: The Dockerfile starts by using the <code>golang:alpine</code> base image, which is a minimal and lightweight version of the Go programming language runtime environment based on the Alpine Linux distribution.</p>
</li>
<li><p><strong>Working Directory</strong>: The <code>WORKDIR /app</code> command sets the working directory inside the container to <code>/app</code>, which is where the project files will be copied.</p>
</li>
<li><p><strong>Copying Project Files</strong>: The <code>COPY . .</code> command copies all the files and directories from the current context (your local machine) to the <code>/app</code> directory inside the container.</p>
</li>
<li><p><strong>Installing Hugo and Dependencies</strong>: The <code>RUN apk add --no-cache hugo libc6-compat libgcc libstdc++</code> command installs the Hugo static site generator and its required compatibility libraries on the Alpine Linux system.</p>
</li>
<li><p><strong>Installing Node.js and npm</strong>: The <code>RUN apk add --no-cache nodejs npm</code> command installs Node.js and npm, which are required for the PostCSS installation in the next step.</p>
</li>
<li><p><strong>Installing PostCSS</strong>: The <code>RUN npm install -g postcss-cli</code> command installs the PostCSS command-line interface globally, which is used for processing CSS files.</p>
</li>
<li><p><strong>Generating Static Content</strong>: The <code>RUN hugo</code> command generates the static content of the Hugo website.</p>
</li>
<li><p><strong>Installing NGINX</strong>: The <code>RUN apk add --no-cache nginx</code> command installs the NGINX web server, which will be used to serve the generated static content.</p>
</li>
<li><p><strong>Removing Hugo and Build Dependencies</strong>: The <code>RUN apk del --no-cache hugo</code> command removes the Hugo package and any build dependencies to reduce the overall size of the final Docker image.</p>
</li>
<li><p><strong>Exposing Port</strong>: The <code>EXPOSE 80</code> command exposes port 80 on the container, which is the default port for the NGINX web server.</p>
</li>
<li><p><strong>Starting NGINX</strong>: The <code>CMD ["nginx", "-g", "daemon off;"]</code> command specifies the command to be executed when the container starts, which is to run the NGINX web server in the foreground.</p>
</li>
</ol>
<p>This Dockerfile sets up a complete environment for building and serving a Hugo-based website using the Go programming language and the Alpine Linux distribution. It installs the necessary dependencies, generates the static content, and sets up NGINX to serve the website.</p>
<ul>
<li><p>To build image run:</p>
<pre><code class="lang-bash">  docker build -f Dockerfile.dev -t my-hugo-site:dev .
  docker images
</code></pre>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714160456092/7560b7a4-3eab-4cac-ae81-b205d1c213b5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-solution-implementing-multistage-dockerfiles">The Solution: Implementing Multistage Dockerfiles</h3>
<h4 id="heading-production-dockerfile-multistage-build">Production Dockerfile: Multistage Build</h4>
<p>The production Dockerfile is where the magic happened. It is divided into multiple stages:</p>
<ol>
<li><p><strong>Build Stage</strong>: This stage installed Hugo and built the static website.</p>
</li>
<li><p><strong>Optimization Stage</strong>: Here, unnecessary files and dependencies are removed.</p>
</li>
<li><p><strong>Final Stage</strong>: The last stage copied only the necessary artifacts from the previous stages, resulting in a much lighter image.</p>
</li>
</ol>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># Stage 1: Build Stage</span>
<span class="hljs-keyword">FROM</span> golang:alpine AS build

<span class="hljs-comment"># Set the working directory within the container</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copy your Hugo project files</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . . </span>

<span class="hljs-comment"># Install Hugo</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache hugo</span>

<span class="hljs-comment"># Install Node.js and npm (npm includes npx)</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache nodejs npm</span>

<span class="hljs-comment"># Install PostCSS</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install -g postcss-cli</span>

<span class="hljs-comment"># Generate your website's static content </span>
<span class="hljs-keyword">RUN</span><span class="bash"> hugo</span>

<span class="hljs-comment"># Stage 2: Web Server Stage</span>
<span class="hljs-keyword">FROM</span> nginx:alpine

<span class="hljs-comment"># Set NGINX's default serving directory </span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/share/nginx/html</span>

<span class="hljs-comment"># Copy the generated static website from the build stage</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app/public /usr/share/nginx/html</span>

<span class="hljs-comment"># Optional: Copy your custom Nginx configuration if needed</span>
<span class="hljs-comment"># COPY nginx.conf /etc/nginx/nginx.conf</span>

<span class="hljs-comment"># Expose the port NGINX uses</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8080</span>

<span class="hljs-comment"># Command to start NGINX when the container runs</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"nginx"</span>, <span class="hljs-string">"-g"</span>, <span class="hljs-string">"daemon off;"</span>] </span>

<span class="hljs-comment">#env var</span>
<span class="hljs-keyword">ENV</span> NODE_ENV=production \
HOSTNAME=<span class="hljs-string">"0.0.0.0"</span> \
NEXT_TELEMETRY_DISABLED=<span class="hljs-number">1</span>
</code></pre>
<h4 id="heading-explanation-1">Explanation:</h4>
<p>This Prod Dockerfile uses a multi-stage build approach to create a Docker image for a Hugo-based website. Let's break it down step by step:</p>
<p><strong>Stage 1: Build Stage</strong></p>
<ol>
<li><p><strong>Base Image</strong>: The first stage uses the <code>golang:alpine</code> base image, which is a minimal and lightweight version of the Go programming language runtime environment based on the Alpine Linux distribution.</p>
</li>
<li><p><strong>Working Directory</strong>: The <code>WORKDIR /app</code> command sets the working directory inside the container to <code>/app</code>, where the project files will be copied.</p>
</li>
<li><p><strong>Copying Project Files</strong>: The <code>COPY . .</code> command copies all the files and directories from the current context (your local machine) to the <code>/app</code> directory inside the container.</p>
</li>
<li><p><strong>Installing Hugo</strong>: The <code>RUN apk add --no-cache hugo</code> command installs the Hugo static site generator on the Alpine Linux system.</p>
</li>
<li><p><strong>Installing Node.js and npm</strong>: The <code>RUN apk add --no-cache nodejs npm</code> command installs Node.js and npm, which are required for the PostCSS installation in the next step.</p>
</li>
<li><p><strong>Installing PostCSS</strong>: The <code>RUN npm install -g postcss-cli</code> command installs the PostCSS command-line interface, which is used for processing CSS files.</p>
</li>
<li><p><strong>Generating Static Content</strong>: The <code>RUN hugo</code> command generates the static content of the Hugo website.</p>
</li>
</ol>
<p><strong>Stage 2: Web Server Stage</strong></p>
<ol>
<li><p><strong>Base Image</strong>: The second stage uses the <code>nginx:alpine</code> base image, which is a minimal and lightweight version of the NGINX web server based on the Alpine Linux distribution.</p>
</li>
<li><p><strong>Working Directory</strong>: The <code>WORKDIR /usr/share/nginx/html</code> command sets the working directory inside the container to the default NGINX serving directory.</p>
</li>
<li><p><strong>Copying Static Content</strong>: The <code>COPY --from=build /app/public /usr/share/nginx/html</code> command copies the generated static content from the previous build stage to the NGINX serving directory.</p>
</li>
<li><p><strong>Exposing Port</strong>: The <code>EXPOSE 8080</code> command exposes port 8080 on the container, which is the default port for the NGINX web server.</p>
</li>
<li><p><strong>Starting NGINX</strong>: The <code>CMD ["nginx", "-g", "daemon off;"]</code> command specifies the command to be executed when the container starts, which is to run the NGINX web server in the foreground.</p>
</li>
<li><p><strong>Environment Variables</strong>: The <code>ENV</code> command sets three environment variables:</p>
<ul>
<li><p><code>NODE_ENV=production</code>: Sets the Node.js environment to production mode.</p>
</li>
<li><p><code>HOSTNAME="0.0.0.0"</code>: Sets the hostname to "0.0.0.0".</p>
</li>
<li><p><code>NEXT_TELEMETRY_DISABLED=1</code>: Disables Next.js telemetry.</p>
</li>
</ul>
</li>
</ol>
<p>This Dockerfile uses a multi-stage build approach to create a Docker image for a Hugo-based website. The first stage builds the static content using Go, Hugo, and PostCSS, while the second stage sets up the NGINX web server to serve the generated content. The resulting image is a lightweight and production-ready container for the Hugo website.</p>
<ul>
<li><p>To build image run:</p>
<pre><code class="lang-bash">  docker build -f Dockerfile.dev -t my-hugo-site:dev .
  docker images
</code></pre>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714161910427/d26cf370-0cb6-43cf-9d8a-62814e2ab0a9.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-results-a-dramatic-reduction">The Results: A Dramatic Reduction</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714162068962/ecafac7e-32a7-470f-94da-cae1926d1ecb.png" alt class="image--center mx-auto" /></p>
<p>By implementing Multistage builds, the final production image size is reduced from <code>434MB</code> to an impressive <code>61MB</code>. This not only makes the image easier to handle and quicker to deploy but also reduces the attack surface for potential security vulnerabilities.</p>
<h3 id="heading-how-you-can-achieve-similar-results">How You Can Achieve Similar Results</h3>
<p>To achieve similar results, consider the following steps:</p>
<ol>
<li><p><strong>Analyze Your Current Dockerfile</strong>: Understand what is necessary for your application to run.</p>
</li>
<li><p><strong>Implement Multistage Builds</strong>: Use separate stages for building and optimizing your Docker image.</p>
</li>
<li><p><strong>Optimize Your Artifacts</strong>: Be selective about what you copy into your final image.</p>
</li>
<li><p><strong>Iterate and Test</strong>: Continuously test your Docker images to ensure functionality while optimizing.</p>
</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Docker image optimization is both an art and a science. By leveraging Multistage builds and being mindful of the artifacts included in the final image, significant efficiencies can be realized. This case study with a Hugo-based portfolio website demonstrates the potential for optimization, reducing the image size by nearly 90% without compromising on functionality.</p>
<p>Remember, the key to optimization is understanding your application's requirements and continuously iterating on your Dockerfile to find the perfect balance between functionality and efficiency. Happy Dockering!</p>
]]></content:encoded></item><item><title><![CDATA[Building Blocks of Networks: Devices]]></title><description><![CDATA[Slow internet? Constant connection drops? No internet during rain? Ever wondered why? Understanding the devices that make up your network is the first step to fixing common problems and optimizing your online experience. Let's dive in and discover th...]]></description><link>https://blog.chetan-thapliyal.cloud/building-blocks-of-networks-devices</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/building-blocks-of-networks-devices</guid><category><![CDATA[networking]]></category><category><![CDATA[networking for beginners]]></category><category><![CDATA[networking for devops]]></category><category><![CDATA[network devices]]></category><category><![CDATA[Basics of Networking]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sun, 25 Feb 2024 19:01:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708884105386/fe711a6e-262e-4a9c-bdc7-d502a6d82281.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Slow internet? Constant connection drops? No internet during rain? Ever wondered why? Understanding the devices that make up your network is the first step to fixing common problems and optimizing your online experience. Let's dive in and discover the key players in your network's world.</p>
<h2 id="heading-cables-the-pathways-of-data"><strong>Cables: The Pathways of Data</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708883619193/4009928d-e1be-4166-ae43-fbdf27bbb7db.png" alt class="image--center mx-auto" /></p>
<p>We live in a world where devices outnumber people, and the invisible threads that bind them together are cables. A simple cable might not seem like much, but it plays a crucial role in how we work, play, and communicate.</p>
<p>But not all cables are created equal!</p>
<h3 id="heading-copper-cables">Copper Cables ⚡</h3>
<p><strong>Copper cables</strong>, the traditional workhorses, has been used for electrical wiring for centuries due to its conductivity. Data travels through copper cables as electrical voltages representing the zeros and ones of digital information. These zeros and ones are represented by different voltage levels within the wire:</p>
<ul>
<li><p><strong>One:</strong> A higher voltage level is used to signify a digital "one." The actual voltage can vary depending on the specific signaling standard, but a common example is 5 volts.</p>
</li>
<li><p><strong>Zero:</strong> A lower voltage level, often close to zero volts (ground), represents a digital "zero."</p>
</li>
</ul>
<p>Devices and computers connected by copper cables have circuitry designed to detect these voltage fluctuations:</p>
<ul>
<li><p><strong>Threshold:</strong> They have a built-in voltage threshold. Anything above the threshold is interpreted as a "one," and anything below is interpreted as a "zero."</p>
</li>
<li><p><strong>Clock signals:</strong> For accurate timing and ensuring data is read correctly, devices often use a separate "clock signal" This clock signal provides a steady pulse that helps the device know precisely when to check the voltage level on the data line.</p>
</li>
</ul>
<p><strong>Example</strong></p>
<p>Imagine a series of rapid voltage changes sent down the copper cable: 5 volts, 0 volts, 5 volts, 0 volts, 0 volts. The receiving device, synchronized with the clock signal, would interpret this as the binary sequence 10100.</p>
<h4 id="heading-copper-cables-cat5e-cat6-and-cat7"><strong>Copper Cables: Cat5e, Cat6, and Cat7</strong></h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708884695216/e91d5319-a9a7-4eca-a1db-f8b2c69bd53e.png" alt class="image--center mx-auto" /></p>
<p>The most common copper cables in networking have names like Cat5, Cat5e, and Cat6. These categories relate to how tightly the wires inside are twisted, which affects data speeds and how well they resist interference. The main differences between these cable categories are their speed, frequency, common uses, and improvements.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>Cat5e</strong></td><td><strong>Cat6</strong></td><td><strong>Cat7</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Speed</td><td>1 Gbps</td><td>10 Gbps (limited to shorter distances)</td><td>10 Gbps</td></tr>
<tr>
<td>Frequency</td><td>100 MHz</td><td>250 MHz</td><td>600 MHz (sometimes 1000 MHz)</td></tr>
<tr>
<td>Common Uses</td><td>Most home networks, streaming, general internet use</td><td>Home and business networks requiring higher speeds and better interference resistance</td><td>Specialized environments like data centers</td></tr>
<tr>
<td>Improvements</td><td>N/A</td><td>Thicker conductors, more shielding, tighter twists</td><td>Individual shielding for each wire pair, overall cable shielding</td></tr>
<tr>
<td>Connector</td><td>RJ45</td><td>RJ45</td><td>Different connector (not RJ45)</td></tr>
</tbody>
</table>
</div><h4 id="heading-crosstalk-in-copper-cables">Crosstalk in copper cables</h4>
<p>While reliable and affordable, copper cables have limitations. "Crosstalk" is a common issue where an electrical pulse on one wire accidentally leaks onto another. This interference gets worse over longer distances or when lots of cables are bundled together, slowing down data and potentially causing errors.</p>
<h3 id="heading-fiber">Fiber</h3>
<p>Enter fiber optic cables – the high-speed champions of data transmission. Instead of metal wires, fiber cables contain incredibly thin strands of glass called optical fibers. Data hurtles through these fibers as pulses of light, making them blazing fast compared to copper. What's more, light doesn't suffer from the same interference problems as electricity, allowing fiber cables to carry clear signals over vast distances.</p>
<p><strong>It's All About Light Pulses</strong></p>
<p>Unlike copper cables, fiber optic cables don't use voltage levels to transmit data. Instead, they rely on pulses of light:</p>
<ul>
<li><p><strong>One:</strong> A pulse of light is sent down the fiber to represent a digital "one."</p>
</li>
<li><p><strong>Zero:</strong> The absence of a light pulse represents a digital "zero."</p>
</li>
</ul>
<p><strong>How Devices Detect Zeros and Ones in Fiber</strong></p>
<p>Devices connected to fiber optic cables use special components to detect these light pulses:</p>
<ul>
<li><p><strong>Photodetector:</strong> A photodetector is a light-sensitive device that converts the light pulses back into electrical signals. When a light pulse hits the photodetector, it generates a tiny electrical current.</p>
</li>
<li><p><strong>Threshold:</strong> Similar to copper cables, there's a threshold for the electrical current. If the current surpasses the threshold, it's registered as a "one." No current (or current below the threshold) means a "zero."</p>
</li>
<li><p><strong>Clock signals:</strong> As with copper, clock signals are essential in fiber optics to ensure accurate timing and synchronization between the sending and receiving devices.</p>
</li>
</ul>
<p><strong>Example</strong></p>
<p>Imagine a series of light flashes traveling through the fiber optic cable: flash, no flash, flash, flash, no flash. The receiving device, using the photodetector and in sync with the clock signal, would interpret this as the binary sequence 10110.</p>
<h4 id="heading-key-advantages-of-fiber-optics"><strong>Key Advantages of Fiber Optics</strong></h4>
<ul>
<li><p><strong>Speed:</strong> Light travels incredibly fast through glass fibers, enabling far higher data transmission speeds compared to copper.</p>
</li>
<li><p><strong>Interference Immunity:</strong> Light signals aren't affected by electromagnetic interference like electrical signals are. This makes fiber optic cables ideal for noisy environments or when signal integrity is critical.</p>
</li>
<li><p><strong>Distance:</strong> Light signals can travel much longer distances within fiber optic cables before weakening compared to electrical signals in copper.</p>
</li>
</ul>
<h2 id="heading-hubs-switches-and-routers-managing-data-traffic"><strong>Hubs, Switches and Routers: Managing Data Traffic</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708886230224/a845ef74-2361-466e-adb4-23d6f21b406a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-hubs-layer-1-physical-the-simplest-connection"><strong>Hubs (Layer 1: Physical): The Simplest Connection</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708886012980/bff5e539-5d99-42cd-9b28-f7fe3f611629.png" alt class="image--center mx-auto" /></p>
<p>A physical layer device that allows for connections from many computers at once. A hub acts like a basic junction box. It simply receives data packets (frames) on one port and broadcasts them out to all other ports. Think of it as shouting in a crowded room – everyone hears the same message, regardless of whether it's intended for them.</p>
<h4 id="heading-collision-domain">Collision Domain</h4>
<p>It is a network segment where only one device can communicate at a time. If multiple system try sending data at the same time, the electrical pulse sent across the cable can interfere with each other. This causes these systems to have to wait for a quiet period before they try sending their data again.</p>
<h3 id="heading-switches-layer-2-data-link-smarter-traffic-control"><strong>Switches (Layer 2: Data Link): Smarter Traffic Control</strong></h3>
<p>Switches are far more sophisticated than hubs. They operate at Layer 2, the data link layer. This means they can read the MAC addresses (unique hardware identifiers) of devices connected to them. Using this information, switches cleverly build a "map" of the network, allowing them to send data packets <em>only</em> to the intended destination. It is like a smart traffic cop. It reads the destination address of data packets and only sends them where they need to go. This dramatically improves network efficiency!</p>
<p><strong>When to Use What</strong></p>
<ul>
<li><p><strong>Hubs:</strong> Rarely used in modern networks. Might be seen in very small, simple home setups or specialized legacy applications.</p>
</li>
<li><p><strong>Switches:</strong> The standard for building home and business networks. They offer the efficiency, performance, and security needed for today's connected devices.</p>
</li>
</ul>
<h3 id="heading-routers-layer-3-network-navigating-the-internet"><strong>Routers (Layer 3: Network): Navigating the Internet</strong></h3>
<p>If hubs and switches are the traffic cops within your local network, routers are the guides that help you navigate the vast expanse of the internet. These intelligent devices operate at Layer 3, the network layer, of the OSI model, making decisions about where to send your data as it hops between different networks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708886394052/4bd80a4d-3cae-41ad-8f01-f6133325eca4.png" alt class="image--center mx-auto" /></p>
<p><strong>Beyond your LAN:</strong> While hubs and switches connect devices within a single network (LAN), routers link <em>different</em> networks together, creating the vast internet.</p>
<p><strong>IP Addresses:</strong> Routers understand IP addresses, the unique numerical identifiers assigned to devices on the internet. Every time you access a website or send an email, your data packets contain both your IP address (the source) and the destination IP address.</p>
<p><strong>Routing Tables:</strong> Routers maintain routing tables – essentially maps of the internet. These tables tell the router which paths are available to reach different destinations.</p>
<p><strong>Border Gateway Protocol (BGP):</strong> Routers share data with each other via this protocol, which lets them learn about the most optimal paths to forward traffic. Think of it as the GPS system of the internet.</p>
<p><strong>Beyond Basic Routing</strong></p>
<p>Routers also perform other vital functions:</p>
<p><strong>Connecting Networks:</strong> Routers connect different networks, like your home network to your internet service provider's network.</p>
<p><strong>Firewalls:</strong> Many routers have built-in firewalls, protecting your network from unauthorized access.</p>
<p><strong>Network Address Translation (NAT):</strong> Routers enable multiple devices on your home network to share a single public IP address facing the internet.</p>
<h2 id="heading-servers-and-clients-the-providers-and-the-requesters"><strong>Servers and Clients: The Providers and the Requesters</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708887066781/5869f2b4-fb7e-4534-b868-92faedfe63ac.png" alt class="image--center mx-auto" /></p>
<p>In most networks, devices are mainly either servers (data providers) or clients (data consumers). Realistically, almost any device can be both client and server depending on the situation. It's more about the function at that moment.</p>
<p><strong>Example:</strong> Your email server is called that because it primarily serves emails, but it also needs to ask a DNS server for addresses, making it a client at that time.</p>
<h3 id="heading-servers-the-powerhouses-of-resources"><strong>Servers: The Powerhouses of Resources</strong></h3>
<p>Think of a server as a powerful computer designed to store and share resources. These resources can be:</p>
<ul>
<li><p><strong>Files:</strong> Websites, documents, images, videos</p>
</li>
<li><p><strong>Databases:</strong> Stores vast collections of organized information</p>
</li>
<li><p><strong>Applications:</strong> Software you can access over the network</p>
</li>
<li><p><strong>Services:</strong> Email, printing, specialized processing tasks</p>
</li>
</ul>
<p>Servers are optimized for continuous availability, often having redundant power supplies, specialized hardware, and robust software.</p>
<h3 id="heading-clients-the-consumers-of-services"><strong>Clients: The Consumers of Services</strong></h3>
<p>Clients are the devices or software programs that access the resources provided by servers. Examples of clients include:</p>
<ul>
<li><p><strong>Web browsers:</strong> Chrome, Firefox, Safari (requesting websites)</p>
</li>
<li><p><strong>Email Clients:</strong> Outlook, Thunderbird (connecting to email servers)</p>
</li>
<li><p><strong>Smartphones:</strong> Apps on your phone act as clients connecting to various backend services.</p>
</li>
<li><p><strong>Other Devices:</strong> Smart TVs, gaming consoles, etc.</p>
</li>
</ul>
<h3 id="heading-the-client-server-dance"><strong>The Client-Server Dance</strong></h3>
<p>The relationship between clients and servers is a request-response dialogue:</p>
<ol>
<li><p><strong>Request:</strong> A client sends a request to a server for a specific resource or service.</p>
</li>
<li><p><strong>Process:</strong> The server processes the request, often fetching data, performing calculations, or preparing a response.</p>
</li>
<li><p><strong>Response:</strong> The server sends the requested data or result back to the client.</p>
</li>
<li><p><strong>Receipt:</strong> The client receives and displays the information or uses the provided service.</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>The digital world we rely on is built upon a complex network of devices, each playing a crucial role in connecting us to information, entertainment, and each other. From the humble copper cable to the powerful fiber optic lines, the lightning-fast switches, and the intelligent routers – these components work in concert to bring the internet into your home.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding TCP/IP: The Secret Language of the Internet]]></title><description><![CDATA[Think of the internet as a gigantic, complex postal system. For your messages (emails, photos, website requests, etc.) to reach their destination, they need to be packaged, stamped with an address, and given a delivery route. This is where the TCP/IP...]]></description><link>https://blog.chetan-thapliyal.cloud/understanding-tcpip-the-secret-language-of-the-internet</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/understanding-tcpip-the-secret-language-of-the-internet</guid><category><![CDATA[networking]]></category><category><![CDATA[networking for beginners]]></category><category><![CDATA[networking for devops]]></category><category><![CDATA[tcp/ip-model]]></category><category><![CDATA[TCP/IP]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sun, 25 Feb 2024 14:40:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1707333077982/9c94617e-64e4-44cd-a4b4-4de85e528e18.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Think of the internet as a gigantic, complex postal system. For your messages (emails, photos, website requests, etc.) to reach their destination, they need to be packaged, stamped with an address, and given a delivery route. This is where the TCP/IP model comes in – it's the blueprint for how data moves across the internet. Before diving into TCP/IP, let's travel back in time to a world without networking models and discover why TCP/IP reigns supreme.</p>
<h2 id="heading-world-without-networking-models-a-messy-past"><strong>World Without Networking Models: A Messy Past</strong></h2>
<p>In today's interconnected world, it's easy to take for granted the fact that our computers, phones, and everything in between can seamlessly talk to each other. But this simplicity wasn't always the case. Before the dominance of TCP/IP, the world of computer networking was a chaotic mess.</p>
<h3 id="heading-the-wild-west-of-proprietary-networks"><strong>The Wild West of Proprietary Networks</strong></h3>
<p>Imagine trying to have a conversation where everyone speaks a different language – that's what the digital world was like before TCP/IP came along. Computers from different brands couldn't communicate without elaborate workarounds. That was the norm!</p>
<p>Companies like IBM had their own proprietary networking models (like SNA), essentially creating isolated islands of connectivity. If you had equipment from multiple vendors, you needed multiple, complex networks just for things to function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708870685258/c991cd51-2204-4540-9eca-ed0cbf022543.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-showdown-osi-vs-tcpip"><strong>The Showdown - OSI vs. TCP/IP</strong></h3>
<p>The need for open standards was clear. The International Organization for Standardization (ISO) stepped in to create the Open Systems Interconnection (OSI) model – a grand vision of universal computer communication. Meanwhile, a scrappier effort funded by the U.S. Department of Defense led to the development of a competing model: TCP/IP.</p>
<p>Throughout the 1990s, companies grappled with either OSI, TCP/IP, or the headache of supporting both. However, by the end of the decade, TCP/IP emerged as the clear winner. OSI, hindered by a slower development process, faded into obscurity.</p>
<h3 id="heading-why-tcpip-won"><strong>Why TCP/IP Won</strong></h3>
<p>It's fascinating that TCP/IP, a model largely built by enthusiastic volunteers, triumphed. This victory highlights the power of streamlined development and adaptability in the fast-paced world of technology.</p>
<ul>
<li><p><strong>Simplicity &amp; Adaptability:</strong> TCP/IP's design focused on core essentials for networking, making it streamlined and efficient. It could easily adapt to new technologies and evolving needs.</p>
</li>
<li><p><strong>Open Standards:</strong> TCP/IP was developed out in the open, encouraging collaboration and preventing any single vendor from controlling it. This fostered innovation and competition.</p>
</li>
<li><p><strong>Volunteer-Driven Development:</strong> Passionate volunteers drove the development of TCP/IP, leading to rapid progress and flexibility compared to the slower, more formal process behind OSI.</p>
</li>
<li><p><strong>Focus on Practicality:</strong> TCP/IP solved real-world problems. It didn't get bogged down in an overly theoretical model, making it easier to adopt and use.</p>
</li>
<li><p><strong>Early Successes:</strong> TCP/IP was used in the early days of the internet, giving it a foothold and building momentum as the internet exploded in popularity.</p>
</li>
</ul>
<p><strong>Compared to OSI:</strong></p>
<ul>
<li><p><strong>Complexity:</strong> OSI's seven-layer model was more complex and rigid compared to TCP/IP's more streamlined approach.</p>
</li>
<li><p><strong>Bureaucracy:</strong> OSI's development involved a large committee-based process, often slowing down progress and innovation.</p>
</li>
<li><p><strong>Poor Timing:</strong> OSI was finalized when TCP/IP had already gained significant traction, making it difficult to displace the established protocol.</p>
</li>
</ul>
<h2 id="heading-what-is-the-tcpip-model"><strong>What is the TCP/IP Model?</strong></h2>
<p>TCP/IP (Transmission Control Protocol/Internet Protocol) isn't just one thing; it's a massive collection of protocols (like rules and guidelines) that govern how computers communicate. These protocols are carefully documented in <a target="_blank" href="https://www.ietf.org/standards/rfcs/">Requests For Comments (RFCs)</a>. What's ingenious about TCP/IP is that it builds upon existing work. If a standard, like Ethernet, already exists, TCP/IP doesn't reinvent the wheel – it simply references it!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708871603751/97fa53b0-1c97-4c44-9604-4d7d2416824c.png" alt class="image--center mx-auto" /></p>
<p>TCP/IP is a set of rules that govern how computers talk to each other over a network. It's broken down into several layers, each with specific responsibilities for efficient data transmission.</p>
<h3 id="heading-the-tcpip-layers-the-magic-behind-the-scenes"><strong>The TCP/IP Layers: The Magic Behind the Scenes</strong></h3>
<p>The reason you can fire up your laptop and instantly access websites or use apps is because TCP/IP is built into its operating system and hardware. Imagine all the invisible agreements happening behind the scenes ensuring your messages get sent and received flawlessly.</p>
<p>Let's break down the layers:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Layer Number</td><td>Layer Name</td><td>Protocols</td><td>Addressing</td><td>Devices</td></tr>
</thead>
<tbody>
<tr>
<td>5</td><td>Application</td><td>HTTP, SMTP, FTP</td><td>None</td><td>Your computer, web servers, email clients</td></tr>
<tr>
<td>4</td><td>Transport</td><td>TCP, UDP</td><td>Port numbers</td><td>Your computer, web servers, email clients</td></tr>
<tr>
<td>3</td><td>Network (Internet)</td><td>IP</td><td>IP addresses</td><td>Routers</td></tr>
<tr>
<td>2</td><td>Data Link</td><td>Ethernet</td><td>MAC addresses</td><td>Network switches, network cards</td></tr>
<tr>
<td>1</td><td>Physical</td><td>N/A</td><td>N/A</td><td>Cables, network hubs</td></tr>
</tbody>
</table>
</div><p><strong>Explanation of the Layers</strong></p>
<ol>
<li><p><strong>Physical Layer:</strong> This is the hardware – cables, connectors, and signals that physically transmit bits (ones and zeros). Like roads and trucks.</p>
</li>
<li><p><strong>Data Link Layer:</strong> Think of this as traffic rules on a single road segment – making sure devices understand each other's signals. Ethernet is a key example.</p>
</li>
<li><p><strong>Network (Internet) Layer:</strong> This layer, with IP being its star, is like a GPS system. Finding the best path to your destination, it routes data across multiple networks to reach its final address (IP address).</p>
</li>
<li><p><strong>Transport Layer:</strong> This decides how to deliver your package. It sorts out which client and server programs are supposed to get that data. TCP is for reliable delivery (think signed-for mail), UDP is for faster, less guaranteed transmission (like postcards).</p>
</li>
<li><p><strong>Application Layer:</strong> This is where software you interact with lives – web browsers (HTTP), email clients (SMTP), etc. It's the actual contents of your package.</p>
</li>
</ol>
<h3 id="heading-key-points"><strong>Key Points</strong></h3>
<ul>
<li><p>Data travels down the layers at the sender, getting packaged and stamped, then back up the layers at the receiver to be 'unpacked'.</p>
</li>
<li><p>Each layer is responsible for ensuring things are working smoothly at its level.</p>
</li>
</ul>
<h2 id="heading-the-takeaway"><strong>The Takeaway</strong></h2>
<p>The history of networking models offers important lessons. It reminds us how standards foster seamless communication while highlighting the risks of incompatible, closed systems. Though OSI didn't stick around, its influence remains; we still use its terminology today.</p>
<p>The TCP/IP model might seem complex at first, but understanding these layers gives you a big-picture view of how the fantastic internet actually works!</p>
<ul>
<li><p>The <strong>physical layer</strong> is the delivery truck and the roads.</p>
</li>
<li><p>The <strong>data link layer</strong> is how the delivery trucks get from one intersection to the next over and over.</p>
</li>
<li><p>The <strong>network layer</strong> identifies which roads need to be taken to get from address A to address B.</p>
</li>
<li><p>The <strong>transport layer</strong> ensures that delivery driver knows how to knock on your door to tell you your package has arrived. And</p>
</li>
<li><p><strong>Application layer</strong> is the contents of the package itself.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Introduction to Networking 🌐]]></title><description><![CDATA[Every one of us uses networks in our day-to-day lives. Some of us may not even have a concept of the network at all. Instead, we simply enjoy the functions of the network—the ability to post messages to social media sites, make phone calls, search fo...]]></description><link>https://blog.chetan-thapliyal.cloud/introduction-to-networking</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/introduction-to-networking</guid><category><![CDATA[networking for devops]]></category><category><![CDATA[networking for cloud]]></category><category><![CDATA[networking]]></category><category><![CDATA[networking for beginners]]></category><category><![CDATA[tcp/ip-model]]></category><category><![CDATA[Networking, IP Address, IPv4, IPv6.]]></category><category><![CDATA[networkingbasics]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Wed, 07 Feb 2024 18:51:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1707037592602/ab594a3b-0b83-4a1a-a952-36178ff88244.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every one of us uses networks in our day-to-day lives. Some of us may not even have a concept of the network at all. Instead, we simply enjoy the functions of the network—the ability to post messages to social media sites, make phone calls, search for information on the Internet, listen to music, and download countless apps to phones—without caring about how it works or how their favorite device connects to the network.</p>
<p>Welcome to the world of networking! Whether you are a seasoned IT professional or new to tech, seeking to deepen your understanding of technological infrastructure, the landscape of networking serves as an essential cornerstone. It is a must-know skill. In this blog, we will unravel the intricacies of networking, understand its significance, and explore the fundamental concepts that underpin seamless connectivity.</p>
<h3 id="heading-so-what-is-networking"><strong>So, what is Networking?</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707039537076/358d6cca-3fa9-44da-b72e-a6ef6278a0df.png" alt="basic-networks" class="image--center mx-auto" /></p>
<p>At its core, networking is the art of facilitating communication and data exchange between devices. This contains a complex web of interconnected systems that transmit information across local and global networks. From the home Wi-Fi setup to the expansive architecture of multinational corporations, networking forms the backbone of our everyday digital interactions.</p>
<h3 id="heading-how-it-works-standards-and-protocols"><strong>How it works? (Standards and Protocols)</strong></h3>
<p>At the heart of networking lies a universal set of rules, or protocols, that govern how devices communicate with each other. These protocols are defined by standards which serve as the agreed-upon framework for establishing seamless connectivity. From the physical transmission of data to the complexities of information exchange, these standards and protocols ensure the harmonious operation of our digital world. Examples of such protocols are Transmission Control Protocol (TCP) A.K.A. Internet Protocol (IP), User Datagram Protocol (UDP), File Transfer Protocol (FTP), Hypertext Transfer Protocol (HTTP) etc.</p>
<h3 id="heading-networking-model-networking-architecture"><strong>Networking Model (</strong>networking architecture<strong>)</strong></h3>
<p>To navigate the labyrinth of networking protocols and standards, the industry has devised networking models that categorize and structure these crucial elements. These models serve as blueprints, guiding network engineers and professionals in understanding how various networking components function together to form a cohesive network.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707329802113/3d0415ef-89d8-4cc9-922a-019dc235561b.png" alt class="image--center mx-auto" /></p>
<p>There are two important models that explain how computers communicate and share data: the <strong>OSI/ISO model</strong> and the <strong>TCP/IP model</strong>. These models help us understand how information moves through a network and make data transfer more effective.</p>
<h3 id="heading-next-blog-with-tcpip-the-cornerstone-of-modern-networking"><strong>Next blog with TCP/IP: The Cornerstone of Modern Networking</strong></h3>
<p>In today's digital landscape, the TCP/IP model stands tall as the pervasive framework for networking. Supported across diverse computing platforms, from mobile devices to enterprise servers, TCP/IP embodies the essence of modern connectivity. It underpins the operation of innumerable networks and serves as a cornerstone in networking certifications and training, reflecting its unparalleled importance in today's IT environment.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Networking is the art of enabling communication and data exchange between devices, forming the foundation of our digital interactions. It is guided by universal protocols and standards that ensure seamless connectivity, and it is structured by networking models such as the OSI/ISO model and the TCP/IP model, which help us comprehend how information flows through a network and improve data transmission.</p>
<p>In the modern digital world, the significance of TCP/IP will not only deepen your understanding of technological infrastructure but also equip you with essential skills for navigating the ever-evolving landscape of modern IT.</p>
<p>So, welcome to the fascinating world of networking, where unraveling its complexities and embracing its significance will empower you to navigate the digital realm with confidence and expertise.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Simple Domain Verification Tool: Introducing GoVerifyDomain 🌐]]></title><description><![CDATA[In today's digital landscape, ensuring the authenticity and security of online communications has become increasingly important. One crucial aspect of this is verifying the legitimacy of domain names. Domain verification helps prevent phishing attack...]]></description><link>https://blog.chetan-thapliyal.cloud/building-a-simple-domain-verification-tool-introducing-goverifydomain</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/building-a-simple-domain-verification-tool-introducing-goverifydomain</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[projects]]></category><category><![CDATA[Devops]]></category><category><![CDATA[domain]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Thu, 17 Aug 2023 10:56:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1692269579147/b9105a78-cc91-4cab-9a4b-055b8fbe16c9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's digital landscape, ensuring the authenticity and security of online communications has become increasingly important. One crucial aspect of this is verifying the legitimacy of domain names. Domain verification helps prevent phishing attacks, spoofing, and other malicious activities by confirming that the claimed sender's domain is legitimate. In this tutorial, we will introduce you to a simple domain verification tool called "GoVerifyDomain." We'll explore the terms and concepts involved in domain verification and guide you through the process of building this tool step by step.</p>
<h2 id="heading-understanding-domain-verification">Understanding Domain Verification</h2>
<p>Domain verification involves the process of confirming the authenticity and legitimacy of a domain name address or domain before considering it trustworthy. This verification process is essential to prevent spam, phishing, and other malicious activities. Domain verification primarily revolves around examining DNS records associated with it.</p>
<p>The key components involved in email verification include:</p>
<ol>
<li><p><strong>Domain</strong>: A domain is a human-readable address used to access websites and send emails. For example, "<a target="_blank" href="http://example.com">example.com</a>" is a domain.</p>
</li>
<li><p><strong>MX Record</strong>: MX (Mail Exchange) records are DNS records that specify the mail servers responsible for receiving email messages on behalf of a domain. These records are essential for email delivery.</p>
</li>
<li><p><strong>TXT Record</strong>: TXT records are general-purpose text-based DNS records used to provide additional information about a domain. They are often used for SPF and DMARC configurations.</p>
</li>
<li><p><strong>SPF (Sender Policy Framework)</strong>: SPF is an email authentication protocol that helps prevent email spoofing by allowing domain owners to specify which mail servers are authorized to send emails on behalf of their domain.</p>
</li>
<li><p><strong>DMARC (Domain-based Message Authentication, Reporting, and Conformance)</strong>: DMARC is a policy framework that builds upon SPF and DKIM (DomainKeys Identified Mail) to provide better email authentication and reporting. It helps prevent domain spoofing and phishing attacks.</p>
</li>
</ol>
<h2 id="heading-introducing-goverifydomain">Introducing GoVerifyDomain</h2>
<p>GoVerifyDomain is a command-line tool developed in the Go programming language that simplifies the process of verifying domains. The tool utilizes DNS lookups to retrieve and analyze the necessary records, providing valuable insights into the authenticity of the domain. Let's explore how GoVerifyDomain works and how each term is implemented within the tool.</p>
<h2 id="heading-how-goverifydomain-works">How GoVerifyDomain Works</h2>
<p>The core functionality of GoVerifyDomain revolves around the <code>net</code> package in Go, which allows for DNS lookups to retrieve information about a domain's MX, SPF, and DMARC records. Let's break down the key components of the provided code snippet:</p>
<ol>
<li><p>The program accepts user input for a domain name to be verified. It then initiates the verification process.</p>
</li>
<li><p>For each domain, the <code>checkDomain</code> function is called. This function performs the following steps:</p>
<ul>
<li><p>It uses <code>net.LookupMX</code> to retrieve MX records for the domain, checking if there are any mail exchange servers associated with the domain.</p>
</li>
<li><p>It uses <code>net.LookupTXT</code> to retrieve TXT records for SPF and DMARC verification. The program looks for records starting with "v=spf1" to identify SPF records and "v=DMARC1" to identify DMARC records. If found, it indicates that the domain has SPF or DMARC policies in place.</p>
</li>
</ul>
</li>
<li><p>Once the DNS lookups are performed, the program prints the results, including whether the domain has MX, SPF, or DMARC records, along with the content of the SPF and DMARC records if present.</p>
</li>
</ol>
<h1 id="heading-lets-build">Let's build</h1>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you have/know the following:</p>
<ol>
<li><p>Basic understanding of Go programming concepts.</p>
<blockquote>
<p>You can refer to this repo for Basics: <a target="_blank" href="https://github.com/ChetanThapliyal/get-started-with-Go/tree/main">https://github.com/ChetanThapliyal/get-started-with-Go/tree/main</a><br />OR<br />Read the Go blog Series:</p>
<p><a target="_blank" href="https://tech-transitions.hashnode.dev/series/learn-golang">https://tech-transitions.hashnode.dev/series/learn-golang</a></p>
</blockquote>
</li>
<li><p>Go programming language installed on your machine. You can download and install Go from the official website: <a target="_blank" href="https://golang.org/dl/">https://golang.org/dl/</a></p>
</li>
</ol>
<h3 id="heading-step-1-setting-up-the-project">Step 1: Setting Up the Project</h3>
<ol>
<li><p>Create a new directory for your project:</p>
<pre><code class="lang-sh"> mkdir verify-Domain
 <span class="hljs-built_in">cd</span> verify-Domain
</code></pre>
</li>
<li><p>Inside the project directory, create a file named <code>main.go</code>:</p>
<pre><code class="lang-sh"> touch main.go
</code></pre>
</li>
</ol>
<h3 id="heading-step-2-writing-the-go-code">Step 2: Writing the Go Code</h3>
<ol>
<li><p>Open <code>main.go</code> in a text editor and copy the following code:</p>
<pre><code class="lang-go"> <span class="hljs-keyword">package</span> main

 <span class="hljs-keyword">import</span> (
     <span class="hljs-string">"bufio"</span>
     <span class="hljs-string">"fmt"</span>
     <span class="hljs-string">"log"</span>
     <span class="hljs-string">"net"</span>
     <span class="hljs-string">"os"</span>
     <span class="hljs-string">"strings"</span>
 )

 <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
     <span class="hljs-comment">// Initialize a scanner to read input from the user</span>
     scanner := bufio.NewScanner(os.Stdin)

     <span class="hljs-comment">// Loop to repeatedly ask for input until "exit" is entered</span>
     <span class="hljs-keyword">for</span> {
         fmt.Print(<span class="hljs-string">"Enter a domain name to verify (or type 'exit' to quit): "</span>)
         scanner.Scan()
         input := scanner.Text()

         <span class="hljs-comment">// Exit the loop if user enters "exit"</span>
         <span class="hljs-keyword">if</span> input == <span class="hljs-string">"exit"</span> {
             fmt.Println(<span class="hljs-string">"Exiting..."</span>)
             <span class="hljs-keyword">break</span>
         }

         <span class="hljs-comment">// Call the function to check the domain/email</span>
         checkDomain(input)
     }

     <span class="hljs-comment">// Check for any errors while reading input</span>
     <span class="hljs-keyword">if</span> err := scanner.Err(); err != <span class="hljs-literal">nil</span> {
         log.Fatalf(<span class="hljs-string">"Error: could not read from input: %v\n"</span>, err)
     }
 }

 <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">checkDomain</span><span class="hljs-params">(domain <span class="hljs-keyword">string</span>)</span></span> {
     <span class="hljs-keyword">var</span> hasMX, hasSPF, hasDMARC <span class="hljs-keyword">bool</span>
     <span class="hljs-keyword">var</span> spfRecord, dmarcRecord <span class="hljs-keyword">string</span>

     <span class="hljs-comment">// Lookup MX records for the domain</span>
     mxRecords, err := net.LookupMX(domain)
     <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
         log.Printf(<span class="hljs-string">"Error looking up MX records for %s: %v\n"</span>, domain, err)
     }

     <span class="hljs-comment">// Check if MX records were found</span>
     <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(mxRecords) &gt; <span class="hljs-number">0</span> {
         hasMX = <span class="hljs-literal">true</span>
     }

     <span class="hljs-comment">// Lookup TXT records for the domain</span>
     txtRecords, err := net.LookupTXT(domain)
     <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
         log.Printf(<span class="hljs-string">"Error looking up TXT records for %s: %v\n"</span>, domain, err)
     }

     <span class="hljs-comment">// Loop through TXT records to find SPF record</span>
     <span class="hljs-keyword">for</span> _, record := <span class="hljs-keyword">range</span> txtRecords {
         <span class="hljs-keyword">if</span> strings.HasPrefix(record, <span class="hljs-string">"v=spf1"</span>) {
             hasSPF = <span class="hljs-literal">true</span>
             spfRecord = record
             <span class="hljs-keyword">break</span>
         }
     }

     <span class="hljs-comment">// Lookup TXT records for DMARC</span>
     dmarcRecords, err := net.LookupTXT(<span class="hljs-string">"_dmarc."</span> + domain)
     <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
         log.Printf(<span class="hljs-string">"Error looking up DMARC records for %s: %v\n"</span>, domain, err)
     }

     <span class="hljs-comment">// Loop through DMARC records to find DMARC record</span>
     <span class="hljs-keyword">for</span> _, record := <span class="hljs-keyword">range</span> dmarcRecords {
         <span class="hljs-keyword">if</span> strings.HasPrefix(record, <span class="hljs-string">"v=DMARC1"</span>) {
             hasDMARC = <span class="hljs-literal">true</span>
             dmarcRecord = record
             <span class="hljs-keyword">break</span>
         }
     }

     <span class="hljs-comment">// Print the results</span>
     fmt.Println(domain)
     fmt.Printf(<span class="hljs-string">"hasMX : %v\n"</span>, hasMX)
     fmt.Printf(<span class="hljs-string">"hasSPF : %v\n"</span>, hasSPF)
     fmt.Printf(<span class="hljs-string">"spfRecord : %s\n"</span>, spfRecord)
     fmt.Printf(<span class="hljs-string">"hasDMARC : %v\n"</span>, hasDMARC)
     fmt.Printf(<span class="hljs-string">"dmarcRecord : %s\n"</span>, dmarcRecord)
     fmt.Println()
 }
</code></pre>
</li>
</ol>
<h3 id="heading-step-3-running-the-codetool">Step 3: Running the Code/Tool</h3>
<ol>
<li><p>Open a terminal window and navigate to your project directory.</p>
</li>
<li><p>Run the following command to build and run the web server:</p>
<pre><code class="lang-sh"> go run main.go
</code></pre>
<p> You should see something like this:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692264144841/545dea2b-5273-476f-915b-d36ce39ecb8d.png" alt /></p>
<p> Enter the domain name, for example <code>github.com</code> :</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692263998571/4cd1ce40-d2d4-41a0-b729-c2af6d8be604.png" alt="Add the domain name:" /></p>
</li>
</ol>
<h3 id="heading-understanding-the-code">Understanding The Code</h3>
<p>The provided code snippet demonstrates the core functionality of GoVerifyDomain. The tool prompts the user to enter a domain name and then checks the corresponding MX, SPF, and DMARC records. Let's break down the code step by step.</p>
<ol>
<li><p><strong>Importing Necessary Packages</strong>: The tool uses the</p>
<p> <code>bufio</code>: Provides buffered I/O functions for input and output operations.</p>
<p> <code>fmt</code>: Implements formatted I/O for console output.</p>
<p> <code>log</code>: Offers a simple logging package for writing logs</p>
<p> <code>net</code>: Offers networking functions, including DNS lookups and network connections.</p>
<p> <code>os</code>: Provides operating system functionalities, including file operations.</p>
<p> <code>strings</code>: Implements string manipulation and searching functions.</p>
</li>
<li><p><strong>Main Function</strong>: The <code>main</code> function serves as the entry point of the program:</p>
<ul>
<li><p>It initializes a scanner to read input from the user.</p>
</li>
<li><p>It enters a loop that repeatedly asks the user to input a domain name to verify until the user enters "exit."</p>
</li>
<li><p>Within the loop, it reads the input using the scanner and stores it in the <code>input</code> variable.</p>
</li>
<li><p>If the user enters "exit," the program prints a message and exits the loop.</p>
</li>
<li><p>Otherwise, it calls the <code>checkDomain</code> function to perform the verification.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-detailed-understanding-of-functions">Detailed Understanding of Functions</h3>
<h3 id="heading-checkdomain-function"><code>checkDomain</code> function</h3>
<p>This function does the following:</p>
<ol>
<li><p>It starts by declaring variables (<code>hasMX</code>, <code>hasSPF</code>, <code>hasDMARC</code>) to track whether certain attributes are present for the given domain. It also declares <code>spfRecord</code> and <code>dmarcRecord</code> to store corresponding records.</p>
</li>
<li><p>It looks up MX records for the domain using the <code>net.LookupMX</code> function, which is like asking the internet where the domain's emails are sent.</p>
</li>
<li><p>It checks if MX records were found; if yes, it sets the <code>hasMX</code> variable to <code>true</code>.</p>
</li>
<li><p>It looks up TXT records for the domain, which can contain various types of information, like authentication details.</p>
</li>
<li><p>It loops through the retrieved TXT records to find an SPF record. If such a record is found (indicating email sender authentication), it sets <code>hasSPF</code> to <code>true</code>, and stores the SPF record in <code>spfRecord</code>.</p>
</li>
<li><p>It looks up DMARC records for the domain, which help control email handling policies.</p>
</li>
<li><p>It loops through the DMARC records to find a DMARC record. If found, it sets <code>hasDMARC</code> to <code>true</code> and stores the DMARC record in <code>dmarcRecord</code>.</p>
</li>
</ol>
<p>Finally, it prints the domain's verification results, including whether MX, SPF, and DMARC attributes were found, along with the actual SPF and DMARC records if available.</p>
<h3 id="heading-understanding-the-output"><strong>Understanding the Output:</strong></h3>
<ul>
<li><p>The tool's output will include the domain name you entered, whether it has MX records, whether it has SPF records, and if DMARC records are present.</p>
</li>
<li><p>If SPF or DMARC records are found, the tool will display their content.</p>
</li>
</ul>
<h3 id="heading-interpreting-results"><strong>Interpreting Results:</strong></h3>
<ul>
<li><p>A "hasMX" result of <code>true</code> indicates that the domain has mail servers configured (MX records).</p>
</li>
<li><p>A "hasSPF" result of <code>true</code> indicates that the domain has SPF records for sender authentication.</p>
</li>
<li><p>A "hasDMARC" result of <code>true</code> indicates that the domain has DMARC records for email handling policies.</p>
</li>
<li><p>The "spfRecord" and "dmarcRecord" results display the actual records found.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations to all those who have successfully journeyed through the development of "GoVerifyDomain" and have implemented this insightful tool! Your dedication and effort have led you to a better understanding of domain verification, an essential aspect of cybersecurity. By now, you've not only grasped the mechanics of DNS queries and records but have also taken a step forward in enhancing digital communication security. Your accomplishment demonstrates your commitment to learning and your readiness to tackle real-world challenges in the tech landscape.</p>
<p>As you move forward, armed with the knowledge and practical experience gained from this endeavor, remember that even the simplest tools can pave the way for more profound discoveries. The road ahead holds limitless opportunities to dive deeper into cybersecurity, contribute to online safety, and shape the future of technology. Whether you're a newcomer or a seasoned coder, your journey has just begun, and we look forward to witnessing your continued growth and innovation.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Simple Web Server with Go]]></title><description><![CDATA[Are you a beginner looking to learn about building a basic web server using the Go programming language? In this tutorial, we'll walk you through creating a straightforward web server that serves static files and handles basic HTTP requests. By the e...]]></description><link>https://blog.chetan-thapliyal.cloud/building-a-simple-web-server-with-go</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/building-a-simple-web-server-with-go</guid><category><![CDATA[Go Language]]></category><category><![CDATA[projects]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Tue, 15 Aug 2023 04:30:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691736671626/997dc362-bd1c-4e0a-b546-32e289df2e2a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Are you a beginner looking to learn about building a basic web server using the Go programming language? In this tutorial, we'll walk you through creating a straightforward web server that serves static files and handles basic HTTP requests. By the end of this tutorial, you'll have a solid understanding of the key concepts involved in building a web server with Go.</p>
<h2 id="heading-what-is-a-web-server"><strong>What is a Web Server?</strong></h2>
<p>A web server is a software application that handles incoming requests from clients (typically web browsers) and responds by serving web content. When you type a URL into your web browser and hit Enter, your browser sends a request to a web server, which processes the request and sends back the appropriate response. This response can be a web page, an image, a file, or even dynamic content generated by the server.</p>
<p>Web servers play a crucial role in the architecture of the World Wide Web, as they facilitate the exchange of information between clients and servers. They are fundamental building blocks for serving websites, web applications, and other online services.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you have the following:</p>
<ol>
<li><p>Basic understanding of Go programming concepts.</p>
<blockquote>
<p>You can refer to this repo for Basics: <a target="_blank" href="https://github.com/ChetanThapliyal/get-started-with-Go/tree/main">https://github.com/ChetanThapliyal/get-started-with-Go/tree/main</a><br />OR<br />Read the Go blog Series:</p>
<p><a target="_blank" href="https://tech-transitions.hashnode.dev/series/learn-golang">https://tech-transitions.hashnode.dev/series/learn-golang</a></p>
</blockquote>
</li>
<li><p>Go programming language installed on your machine. You can download and install Go from the official website: <a target="_blank" href="https://golang.org/dl/">https://golang.org/dl/</a></p>
</li>
</ol>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Let's start by creating a simple web server that serves static HTML files and handles HTTP requests. Follow these steps:</p>
<h3 id="heading-step-1-setting-up-the-project">Step 1: Setting Up the Project</h3>
<ol>
<li><p>Create a new directory for your project:</p>
<pre><code class="lang-sh"> mkdir WebServer-with-Go
 <span class="hljs-built_in">cd</span> WebServer-with-Go
</code></pre>
</li>
<li><p>Inside the project directory, create a subdirectory named <code>static</code>:</p>
<pre><code class="lang-sh"> mkdir static
</code></pre>
</li>
<li><p>Create two HTML files named <code>index.html</code> and <code>form.html</code> inside the <code>static</code> directory. You can use any text editor to create these files and add basic HTML content.</p>
<pre><code class="lang-bash"> <span class="hljs-built_in">cd</span> static
 touch index.html form.html hello.html
</code></pre>
<blockquote>
<p>Visit this to populate the above files (copy the code from the link mentioned below and paste in the above files):</p>
<p><strong><mark>form.html</mark></strong> : <a target="_blank" href="https://github.com/ChetanThapliyal/WebServer-wih-Go/blob/main/static/form.html">https://github.com/ChetanThapliyal/WebServer-wih-Go/blob/main/static/form.html</a></p>
<p><strong><mark>index.html</mark></strong>: <a target="_blank" href="https://github.com/ChetanThapliyal/WebServer-wih-Go/blob/main/static/index.html">https://github.com/ChetanThapliyal/WebServer-wih-Go/blob/main/static/index.html</a><br /><mark>hello.html</mark> : <a target="_blank" href="https://github.com/ChetanThapliyal/WebServer-wih-Go/blob/main/static/hello.html">https://github.com/ChetanThapliyal/WebServer-wih-Go/blob/main/static/hello.html</a></p>
</blockquote>
</li>
<li><p>Use <code>tree</code> command to check directory structure:</p>
<pre><code class="lang-go"> tree
 WebServer-with-Go/
 ├── main.<span class="hljs-keyword">go</span>
 └── static
     ├── form.html
     ├── hello.html
     └── index.html
</code></pre>
</li>
</ol>
<h3 id="heading-step-2-writing-the-go-code">Step 2: Writing the Go Code</h3>
<ol>
<li><p>Create a file named <code>main.go</code> in the project directory.</p>
</li>
<li><p>Open <code>main.go</code> in a text editor and copy the following code:</p>
<pre><code class="lang-go"> <span class="hljs-keyword">package</span> main

 <span class="hljs-keyword">import</span> (
     <span class="hljs-string">"fmt"</span>
     <span class="hljs-string">"log"</span>
     <span class="hljs-string">"net/http"</span>
 )

 <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">helloHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
     <span class="hljs-keyword">if</span> r.URL.Path != <span class="hljs-string">"/hello"</span> {
         http.Error(w, <span class="hljs-string">"404 Not Found"</span>, http.StatusNotFound)
         <span class="hljs-keyword">return</span>
     }
     <span class="hljs-keyword">if</span> r.Method != <span class="hljs-string">"GET"</span> {
         http.Error(w, <span class="hljs-string">"Method is not supported"</span>, http.StatusNotFound)
         <span class="hljs-keyword">return</span>
     }
     fmt.Fprintf(w, <span class="hljs-string">"Hello there"</span>)
 }

 <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">formHandler</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
     <span class="hljs-keyword">if</span> err := r.ParseForm(); err != <span class="hljs-literal">nil</span> {
         fmt.Fprintf(w, <span class="hljs-string">"ParseForm() err: %v"</span>, err)
         <span class="hljs-keyword">return</span>
     }
     fmt.Fprintf(w, <span class="hljs-string">"POST Request Successful\n"</span>)
     name := r.FormValue(<span class="hljs-string">"name"</span>)
     address := r.FormValue(<span class="hljs-string">"address"</span>)
     fmt.Fprintf(w, <span class="hljs-string">"Name = %s\n"</span>, name)
     fmt.Fprintf(w, <span class="hljs-string">"Address = %s"</span>, address)
 }

 <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
     fileServer := http.FileServer(http.Dir(<span class="hljs-string">"./static"</span>))
     http.Handle(<span class="hljs-string">"/"</span>, fileServer)
     http.HandleFunc(<span class="hljs-string">"/form"</span>, formHandler)
     http.HandleFunc(<span class="hljs-string">"/hello"</span>, helloHandler)

     fmt.Printf(<span class="hljs-string">"Starting server at port 8080\n"</span>)

     <span class="hljs-keyword">if</span> err := http.ListenAndServe(<span class="hljs-string">":8080"</span>, <span class="hljs-literal">nil</span>); err != <span class="hljs-literal">nil</span> {
         log.Fatal(err)
     }
 }
</code></pre>
</li>
</ol>
<h3 id="heading-step-3-running-the-web-server">Step 3: Running the Web Server</h3>
<ol>
<li><p>Open a terminal window and navigate to your project directory.</p>
</li>
<li><p>Run the following command to build and run the web server:</p>
<pre><code class="lang-sh"> go run main.go
</code></pre>
</li>
<li><p>Open your web browser and visit <a target="_blank" href="http://localhost:8080">http://localhost:8080</a> to see your web server in action. You should be able to see the following:</p>
<p> <a target="_blank" href="http://localhost:8080">localhost:8080</a><br /> <a target="_blank" href="http://localhost:8080/hello.html">localhost:8080/hello.html</a><br /> <a target="_blank" href="http://localhost:8080/form.html">localhost:8080/form.html</a></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691737187612/24714052-15b7-4a87-8496-6aa18dcb3d2b.png" alt class="image--center mx-auto" /></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691737166404/de9a3d2e-e69a-4515-97d5-17a0bd1ff936.png" alt class="image--center mx-auto" /></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691737106805/c0e5cc30-7cd1-4fa1-9c9b-a44d0fb108cb.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h2 id="heading-general-understanding-of-the-code">General Understanding of the Code</h2>
<p>Let's break down the key components of the code you just created:</p>
<ol>
<li><p><strong>Importing Packages</strong>: We import necessary packages like</p>
<p> <code>fmt</code>: Package for formatted I/O (used for printing messages).</p>
<p> <code>log</code>: Package for logging.</p>
<p> <code>net/http</code> Package for building HTTP servers &amp; for handling HTTP requests and responses.</p>
</li>
<li><p><strong>Handlers</strong>: We define two handler functions,</p>
<p> <code>helloHandler</code>: Handles requests to the "/hello" route. It checks if the URL path is "/hello" and if the HTTP method is "GET". If not, it returns a 404 error. If everything is in order, it responds with "Hello there".</p>
<p> <code>formHandler</code>: Handles POST requests to the "/form" route. It parses the form data from the request, extracts the values for the "name" and "address" fields, and then responds with a success message along with the extracted data.</p>
<p> to handle specific paths and HTTP methods.</p>
</li>
<li><p><strong>Serving Static Files</strong>: We create a file server to serve static files from the <code>static</code> directory using <code>http.FileServer</code>.</p>
</li>
<li><p><strong>Route Handling</strong>: We use <code>http.HandleFunc</code> to associate our handler functions with specific routes, such as <code>/hello</code> and <code>/form</code>.</p>
</li>
<li><p><strong>Listening and Serving</strong>: We use <code>http.ListenAndServe</code> to start the web server on port 8080. If an error occurs, we log it.</p>
</li>
</ol>
<h3 id="heading-detailed-understanding-of-functions">Detailed Understanding of Functions</h3>
<h3 id="heading-hellohandler"><code>helloHandler</code></h3>
<ol>
<li><p><code>func helloHandler(w http.ResponseWriter, r *http.Request)</code>: This line defines the function with two parameters:</p>
<ul>
<li><p><code>w http.ResponseWriter</code>: This parameter allows you to write the HTTP response back to the client.</p>
</li>
<li><p><code>r *http.Request</code>: This parameter holds information about the incoming HTTP request.</p>
</li>
</ul>
</li>
<li><p><code>if r.URL.Path != "/hello" { ... }</code>: This line checks whether the URL path of the incoming request (<code>r.URL.Path</code>) is not equal to "/hello". If it's not, it means the request is not intended for the "/hello" route. In that case, the server responds with a "404 Not Found" error and returns early.</p>
</li>
<li><p><code>if r.Method != "GET" { ... }</code>: This line checks whether the HTTP method used in the request (<code>r.Method</code>) is not "GET". If the method is not "GET", it means that the "/hello" route only supports GET requests. If another method is used (like POST or PUT), the server responds with a "Method is not supported" error and returns early.</p>
</li>
<li><p><code>fmt.Fprintf(w, "Hello there")</code>: If the URL path is "/hello" and the HTTP method is "GET", this line writes the response "Hello there" to the <code>w</code> (ResponseWriter) parameter, which sends the response back to the client.</p>
</li>
</ol>
<h3 id="heading-formhandler"><code>formHandler</code></h3>
<ol>
<li><p><code>if err := r.ParseForm(); err != nil { ... }</code>: This line parses the form data from the incoming request (<code>r</code>) and populates the <code>r.Form</code> map with the form values. If there's an error during parsing, it means the form data is not correctly structured, and the server responds with an error message indicating the parsing error.</p>
</li>
<li><p><code>fmt.Fprintf(w, "POST Request Successful\n")</code>: After successfully parsing the form data, the server writes "POST Request Successful" to the response. This indicates that the form submission was received and processed successfully.</p>
</li>
<li><p><code>name := r.FormValue("name")</code> and <code>address := r.FormValue("address")</code>: These lines extract the values of the "name" and "address" fields from the parsed form data. The <code>r.FormValue</code> function is used to retrieve the value associated with a specific form key.</p>
</li>
<li><p><code>fmt.Fprintf(w, "Name = %s\n", name)</code> and <code>fmt.Fprintf(w, "Address = %s", address)</code>: These lines write the extracted "name" and "address" values to the response. The <code>%s</code> placeholder is replaced with the actual values.</p>
</li>
</ol>
<h3 id="heading-main"><code>main()</code></h3>
<ol>
<li><p><code>fileServer := http.FileServer(http.Dir("./static"))</code>: This line creates an HTTP file server (<code>fileServer</code>) that serves static files from the "./static" directory. The <code>http.Dir("./static")</code> part indicates the directory from which the files will be served.</p>
</li>
<li><p><code>http.Handle("/", fileServer)</code>: This line sets up a handler for the root ("/") route. Any request to the root route will be served by the <code>fileServer</code> created in the previous step, meaning that static files from the "./static" directory will be served when you access the root URL.</p>
</li>
<li><p><code>http.HandleFunc("/form", formHandler)</code>: This line sets up a handler for the "/form" route. When a request is made to the "/form" route, the <code>formHandler</code> function we discussed earlier will be called to handle the request.</p>
</li>
<li><p><code>http.HandleFunc("/hello", helloHandler)</code>: Similarly, this line sets up a handler for the "/hello" route. Requests to the "/hello" route will be handled by the <code>helloHandler</code> function.</p>
</li>
<li><p><code>fmt.Printf("Starting server at port 8080\n")</code>: This line prints a message indicating that the server is starting. You'll see this message in the console when you run the program.</p>
</li>
<li><p><code>if err := http.ListenAndServe(":8080", nil); err != nil { ... }</code>: This line starts the HTTP server on port 8080. The <code>http.ListenAndServe(":8080", nil)</code> function call does the following:</p>
<ul>
<li><p>It listens for incoming HTTP requests on port 8080.</p>
</li>
<li><p>It uses the handlers you set up earlier (for "/", "/form", and "/hello") to route and handle the requests.</p>
</li>
</ul>
</li>
</ol>
<p>    If there's an error during server startup or while serving requests, the <code>log.Fatal(err)</code> line will print the error and terminate the program.</p>
<h3 id="heading-usage"><strong>Usage</strong></h3>
<p>When this program is executed, it starts an HTTP server on port 8080. Here's what it does for different routes:</p>
<ul>
<li><p>Visiting the root ("/") route serves static files from the "./static" directory.</p>
</li>
<li><p>Accessing the "/form" route displays a simple HTML form. Upon submitting the form, it processes the data and displays the "name" and "address" values.</p>
</li>
<li><p>Accessing the "/hello" route responds with "Hello there".</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've successfully created a simple web server using the Go programming language. You've learned about serving static files, handling different HTTP requests, and setting up routes. This project provides a foundation for building more complex web applications and APIs using Go. Feel free to explore and expand upon this project to learn more about web development with Go.</p>
<p>Remember, practice makes perfect! Experiment with the code, add new features and explore the Go documentation to deepen your understanding of web development and the Go programming language. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Structs, Methods and Interfaces in Go (Blog 13 of the Go Series)]]></title><description><![CDATA[In the world of programming, organizing and managing data is a crucial task. Go, offers several powerful tools for this purpose, including structs, methods, and interfaces. Let's explore these concepts to understand how they contribute to building ef...]]></description><link>https://blog.chetan-thapliyal.cloud/structs-methods-and-interfaces-in-go-blog-13-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/structs-methods-and-interfaces-in-go-blog-13-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[#Devopscommunity]]></category><category><![CDATA[Devops articles]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Mon, 14 Aug 2023 04:30:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691735008317/87ca93c7-03bd-47d8-96c2-2c8c8210e69b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the world of programming, organizing and managing data is a crucial task. Go, offers several powerful tools for this purpose, including structs, methods, and interfaces. Let's explore these concepts to understand how they contribute to building efficient and modular code.</p>
<h2 id="heading-structs">Structs</h2>
<p>At the heart of Go's data organization is the struct, a user-defined composite data type that groups fields of different types. Structs allow developers to encapsulate related information into a single entity, making code more readable and maintainable. Structs are used to represent data structures and can contain both named and anonymous fields.</p>
<p>Here's a simple example of a struct definition:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}
</code></pre>
<p>In this example, <code>Person</code> is a struct that contains two fields: <code>Name</code> of type <code>string</code> and <code>Age</code> of type <code>int</code>.</p>
<h2 id="heading-initializing-and-accessing-structs">Initializing and Accessing Structs</h2>
<p>There are several ways to initialize a struct.</p>
<h3 id="heading-1-literal-syntax">1. Literal syntax:</h3>
<p>The most common way to initialize a struct is using literal syntax, which involves specifying the values of the struct's fields in curly braces.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

person := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}
</code></pre>
<p>In this example, a <code>Person</code> struct is created with <code>Name</code> set to "Alice" and <code>Age</code> set to 30.</p>
<h3 id="heading-2-anonymous-struct">2. Anonymous struct:</h3>
<p>An anonymous struct is a struct that is defined without a name. It can be useful when you need to create a temporary struct with a specific set of values.</p>
<pre><code class="lang-go">person := <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}{
    Name: <span class="hljs-string">"Bob"</span>,
    Age:  <span class="hljs-number">40</span>,
}
</code></pre>
<p>In this example, an anonymous struct is created with <code>Name</code> set to "Bob" and <code>Age</code> set to 40.</p>
<h3 id="heading-3-new-keyword">3. New keyword:</h3>
<p>The <code>new</code> keyword is used to allocate memory for all the fields of the new struct and returns a pointer to the newly created struct.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

personPtr := <span class="hljs-built_in">new</span>(Person)
personPtr.Name = <span class="hljs-string">"Charlie"</span>
personPtr.Age = <span class="hljs-number">50</span>
</code></pre>
<p>In this example, a new <code>Person</code> struct is created using <code>new</code>, and its fields are set individually using dot notation.</p>
<h3 id="heading-4-zero-value">4. Zero value:</h3>
<p>In Go, if you create a struct without initializing any of its fields, they will be set to their zero values. For strings, the zero value is <code>""</code>, and for integers, the zero value is <code>0</code>.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">var</span> person Person    
        fmt.Printf(<span class="hljs-string">"%+v"</span>, person) <span class="hljs-comment">//%+v is used to print the contents of a struct's fields and its values, commonly used for debugging purposes.</span>
}
</code></pre>
<p>In this example, a new <code>Person</code> struct is created with <code>Name</code> set to <code>""</code> and <code>Age</code> set to <code>0</code>.</p>
<h3 id="heading-5-amp-operator">5. <code>&amp;</code> Operator:</h3>
<p>You can create a new struct instance using the <code>&amp;</code> operator, which returns a pointer to a newly created struct instance. Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-comment">// Using the &amp; operator to initialize a struct</span>
personPtr := &amp;Person{Name: <span class="hljs-string">"Charlie"</span>, Age: <span class="hljs-number">20</span>}
</code></pre>
<blockquote>
<p>Note that you can also use a combination of these methods to initialize a struct. For example, you could use literal syntax to initialize some fields and then set others individually using dot notation.</p>
</blockquote>
<h2 id="heading-accessing-struct-fields">Accessing Struct Fields</h2>
<p>You can access the fields of a struct using the dot notation (<code>.</code>). Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

person1 := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

<span class="hljs-comment">// Accessing struct fields using dot notation</span>
fmt.Println(person1.Name) <span class="hljs-comment">// Output: Alice</span>
fmt.Println(person1.Age)  <span class="hljs-comment">// Output: 30</span>
</code></pre>
<p>In this example, we define a struct <code>Person</code> with two fields, <code>Name</code> and <code>Age</code>. We create a new <code>Person</code> instance called <code>person1</code> and initialize its fields.</p>
<p>To access the fields of the <code>person1</code> instance, we use the dot notation and print the values of <code>Name</code> and <code>Age</code> using the <code>fmt.Println</code> function.</p>
<p>You can also access the fields of a struct using a pointer to the struct. In this case, you use the dereference operator (<code>*</code>) to access the struct fields.</p>
<p>Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

person1 := &amp;Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

<span class="hljs-comment">// Accessing struct fields using a pointer</span>
fmt.Println((*person1).Name) <span class="hljs-comment">// Output: Alice</span>
fmt.Println((*person1).Age)  <span class="hljs-comment">// Output: 30</span>
</code></pre>
<p>In this example, we create a pointer to a <code>Person</code> struct called <code>person1</code>. We use the dereference operator (<code>*</code>) to access the struct fields and print the values of <code>Name</code> and <code>Age</code> using the <code>fmt.Println</code> function.</p>
<h2 id="heading-passing-struct-to-functions">Passing Struct to Functions</h2>
<p>In Go, you can pass structs to functions just like any other type.</p>
<p>Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">PrintPersonInfo</span><span class="hljs-params">(p Person)</span></span> {
    fmt.Printf(<span class="hljs-string">"Name: %s, Age: %d\n"</span>, p.Name, p.Age)
}

person1 := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

<span class="hljs-comment">// Passing a struct to a function</span>
PrintPersonInfo(person1)
</code></pre>
<p>In this example, we define a struct <code>Person</code> with two fields, <code>Name</code> and <code>Age</code>. We create a new <code>Person</code> instance called <code>person1</code> and initialize its fields.</p>
<p>We define a function <code>PrintPersonInfo</code> that takes a <code>Person</code> struct as a parameter and prints its fields.</p>
<p>We then call the <code>PrintPersonInfo</code> function and pass it the <code>person1</code> instance.</p>
<blockquote>
<p>When you pass a struct to a function, a copy of the struct is created and passed to the function. Any changes made to the struct within the function are local to that function and do not affect the original struct.</p>
</blockquote>
<p>If you want to modify the original struct inside the function, you can pass a pointer to the struct instead.</p>
<p>Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">UpdatePersonAge</span><span class="hljs-params">(p *Person, newAge <span class="hljs-keyword">int</span>)</span></span> {
    p.Age = newAge
}

person1 := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

<span class="hljs-comment">// Passing a pointer to a struct to a function</span>
UpdatePersonAge(&amp;person1, <span class="hljs-number">35</span>)

fmt.Printf(<span class="hljs-string">"Name: %s, Age: %d\n"</span>, person1.Name, person1.Age) <span class="hljs-comment">// Output: Name: Alice, Age: 35</span>
</code></pre>
<p>In this example, we define a struct <code>Person</code> with two fields, <code>Name</code> and <code>Age</code>. We create a new <code>Person</code> instance called <code>person1</code> and initialize its fields.</p>
<p>We define a function <code>UpdatePersonAge</code> that takes a pointer to a <code>Person</code> struct and an integer <code>newAge</code> as parameters. We update the <code>Age</code> field of the struct using the pointer.</p>
<p>We then call the <code>UpdatePersonAge</code> function and pass it a pointer to the <code>person1</code> instance. After the function call, we print the <code>Name</code> and <code>Age</code> fields of the <code>person1</code> instance to verify that the <code>Age</code> field has been updated.</p>
<h2 id="heading-comparing-structs">Comparing Structs</h2>
<p>In Go, you can compare two structs using the <code>==</code> operator. The <code>==</code> operator compares each field of the two structs for equality.</p>
<p>Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

person1 := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}
person2 := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}
person3 := Person{Name: <span class="hljs-string">"Bob"</span>, Age: <span class="hljs-number">25</span>}

<span class="hljs-comment">// Comparing two structs for equality</span>
fmt.Println(person1 == person2) <span class="hljs-comment">// Output: true</span>
fmt.Println(person1 == person3) <span class="hljs-comment">// Output: false</span>
</code></pre>
<p>In this example, we define a struct <code>Person</code> with two fields, <code>Name</code> and <code>Age</code>. We create three new <code>Person</code> instances and initialize their fields.</p>
<p>We use the <code>==</code> operator to compare <code>person1</code> and <code>person2</code> for equality. Since the fields of the two structs have the same values, the comparison returns <code>true</code>.</p>
<p>We use the <code>==</code> operator again to compare <code>person1</code> and <code>person3</code> for equality. Since the <code>Name</code> and <code>Age</code> fields of the two structs have different values, the comparison returns <code>false</code>.</p>
<blockquote>
<p>It's important to note that two structs with the same fields and values are not necessarily equal if they are of different types. In Go, each struct type is distinct and cannot be compared to another struct type, even if the two types have the same fields and values.</p>
</blockquote>
<p>Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-keyword">type</span> Employee <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

person1 := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}
employee1 := Employee{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

<span class="hljs-comment">// Comparing two structs of different types</span>
fmt.Println(person1 == employee1) <span class="hljs-comment">// Compile error: cannot compare Person and Employee</span>
</code></pre>
<p>In this example, we define two struct types, <code>Person</code> and <code>Employee</code>, with the same fields and types. We create a <code>Person</code> instance called <code>person1</code> and an <code>Employee</code> instance called <code>employee1</code> with the same field values.</p>
<p>When we try to compare <code>person1</code> and <code>employee1</code> for equality using the <code>==</code> operator, we get a compile error because the two struct types are different and cannot be compared.</p>
<hr />
<h1 id="heading-methods">Methods</h1>
<p>A method is a function that is associated with a specific type of struct. It can be defined using the <code>func</code> keyword, the name of the method, the name of the struct type (with the <code>receiver</code> keyword), and any parameters and return types.</p>
<p>Whenever there's a strong relationship between a function and a struct, it makes sense to use a method.</p>
<p>Syntax : <code>func (&lt;receiver&gt;) &lt;method_name&gt;(&lt;parameters&gt;)&lt;return_param&gt; { //code}</code></p>
<p>Here's an example of a method definition in Go:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-comment">// A method associated with the Person struct</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(p Person)</span> <span class="hljs-title">SayHello</span><span class="hljs-params">()</span></span> {
    fmt.Printf(<span class="hljs-string">"Hello, my name is %s and I am %d years old\n"</span>, p.Name, p.Age)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Creating a new Person instance</span>
    person := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

    <span class="hljs-comment">// Calling the SayHello method on the Person instance</span>
    person.SayHello() <span class="hljs-comment">//Output: Hello, my name is Alice and I am 30 years old</span>
}
</code></pre>
<p>In this example, we define a <code>Person</code> struct with two fields, <code>Name</code> and <code>Age</code>. We also define a method <code>SayHello</code> associated with the <code>Person</code> struct.</p>
<p>The <code>SayHello</code> method has a <code>receiver</code> of type <code>Person</code>, which means that it is associated with the <code>Person</code> struct. The <code>receiver</code> is passed as the first argument to the method and is accessed using the <code>p</code> variable.</p>
<p>Inside the <code>SayHello</code> method, we use the <code>fmt.Printf</code> function to print a message that includes the <code>Name</code> and <code>Age</code> fields of the <code>Person</code> instance.</p>
<p>In the <code>main</code> function, we create a new <code>Person</code> instance called <code>person</code> and initialize its fields. We then call the <code>SayHello</code> method on the <code>person</code> instance using the <code>.</code> operator.</p>
<p>This example demonstrates how to define a method associated with a struct type, and how to call the method on an instance of the struct using the <code>.</code> operator.</p>
<p>It's important to note that methods can also be defined with pointers to the struct as the receiver. This allows the method to modify the struct's fields. Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-comment">// A method associated with the Person struct using a pointer receiver</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(p *Person)</span> <span class="hljs-title">SetAge</span><span class="hljs-params">(age <span class="hljs-keyword">int</span>)</span></span> {
    p.Age = age
}
</code></pre>
<p>This method takes a pointer to the <code>Person</code> struct as its receiver (<code>*Person</code>), which allows it to modify the <code>Age</code> field of the struct.</p>
<h2 id="heading-method-sets">Method Sets</h2>
<p>A method set is the set of methods that can be called on a specific type of struct.</p>
<p>There are two types of method sets in Go:</p>
<ol>
<li><p>Value receiver method set</p>
</li>
<li><p>Pointer receiver method set</p>
</li>
</ol>
<p>The value receiver method set contains all of the methods that are associated with a struct using a value receiver. These methods can be called on an instance of the struct or a pointer to the struct.</p>
<p>The pointer receiver method set contains all of the methods that are associated with a struct using a pointer receiver. These methods can only be called on a pointer to the struct.</p>
<p>Here's an example that demonstrates how method sets work:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-keyword">type</span> Person <span class="hljs-keyword">struct</span> {
    Name <span class="hljs-keyword">string</span>
    Age  <span class="hljs-keyword">int</span>
}

<span class="hljs-comment">// A value receiver method associated with the Person struct</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(p Person)</span> <span class="hljs-title">SayHello</span><span class="hljs-params">()</span></span> {
    fmt.Printf(<span class="hljs-string">"Hello, my name is %s and I am %d years old\n"</span>, p.Name, p.Age)
}

<span class="hljs-comment">// A pointer receiver method associated with the Person struct</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(p *Person)</span> <span class="hljs-title">SetAge</span><span class="hljs-params">(age <span class="hljs-keyword">int</span>)</span></span> {
    p.Age = age
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Creating a new Person instance</span>
    person := Person{Name: <span class="hljs-string">"Alice"</span>, Age: <span class="hljs-number">30</span>}

    <span class="hljs-comment">// Calling the SayHello method on the Person instance</span>
    person.SayHello()

    <span class="hljs-comment">// Calling the SetAge method on the Person instance using a pointer</span>
    (&amp;person).SetAge(<span class="hljs-number">35</span>)

    <span class="hljs-comment">// Calling the SayHello method on the Person instance again</span>
    person.SayHello()

    <span class="hljs-comment">// Creating a pointer to the Person instance</span>
    pointer := &amp;person

    <span class="hljs-comment">// Calling the SetAge method on the pointer to the Person instance</span>
    pointer.SetAge(<span class="hljs-number">40</span>)

    <span class="hljs-comment">// Calling the SayHello method on the Person instance again</span>
    person.SayHello()
}
</code></pre>
<p>In this example, we define a <code>Person</code> struct with two fields, <code>Name</code> and <code>Age</code>. We also define two methods, <code>SayHello</code> and <code>SetAge</code>, associated with the <code>Person</code> struct.</p>
<p>The <code>SayHello</code> method is associated with the <code>Person</code> struct using a value receiver. This means that it can be called on an instance of the <code>Person</code> struct or a pointer to the struct.</p>
<p>The <code>SetAge</code> method is associated with the <code>Person</code> struct using a pointer receiver. This means that it can only be called on a pointer to the <code>Person</code> struct.</p>
<p>In the <code>main</code> function, we create a new <code>Person</code> instance called <code>person</code> and initialize its fields. We then call the <code>SayHello</code> method on the <code>person</code> instance.</p>
<p>We then call the <code>SetAge</code> method on the <code>person</code> instance using a pointer. This works because we are calling a method from the value receiver method set on a pointer to the <code>Person</code> struct.</p>
<p>We then create a pointer to the <code>person</code> instance called <code>pointer</code>. We call the <code>SetAge</code> method on the <code>pointer</code> to the <code>Person</code> instance. This works because we are calling a method from the pointer receiver method set on a pointer to the <code>Person</code> struct.</p>
<p>Finally, we call the <code>SayHello</code> method on the <code>person</code> instance again to see the updated value of the <code>Age</code> field.</p>
<p>Output:</p>
<pre><code class="lang-go">Hello, my name is Alice and I am <span class="hljs-number">30</span> years old
Hello, my name is Alice and I am <span class="hljs-number">35</span> years old
Hello, my name is Alice and I am <span class="hljs-number">40</span> years old
</code></pre>
<hr />
<h1 id="heading-interfaces">Interfaces</h1>
<p>Interfaces are a set of method signatures that a type must implement in order to satisfy the interface. Interfaces provide a way to specify behavior without specifying the underlying implementation. This makes interfaces a powerful tool for decoupling code and promoting code reuse.</p>
<p>A type implements an interface by implementing its methods. The go language interfaces are implemented implicitly. And it does not have any specific keyword to implement an interface.</p>
<p>Here's an example that demonstrates how to define and use interfaces in Go:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-comment">// Define the Shape interface</span>
<span class="hljs-keyword">type</span> Shape <span class="hljs-keyword">interface</span> {
    Area() <span class="hljs-keyword">float64</span>
}

<span class="hljs-comment">// Define the Circle struct</span>
<span class="hljs-keyword">type</span> Circle <span class="hljs-keyword">struct</span> {
    x, y, r <span class="hljs-keyword">float64</span>
}

<span class="hljs-comment">// Define the Area method on the Circle struct</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(c Circle)</span> <span class="hljs-title">Area</span><span class="hljs-params">()</span> <span class="hljs-title">float64</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-number">3.14</span> * c.r * c.r
}

<span class="hljs-comment">// Define the Rectangle struct</span>
<span class="hljs-keyword">type</span> Rectangle <span class="hljs-keyword">struct</span> {
    width, height <span class="hljs-keyword">float64</span>
}

<span class="hljs-comment">// Define the Area method on the Rectangle struct</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(r Rectangle)</span> <span class="hljs-title">Area</span><span class="hljs-params">()</span> <span class="hljs-title">float64</span></span> {
    <span class="hljs-keyword">return</span> r.width * r.height
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Create a Circle instance</span>
    circle := Circle{x: <span class="hljs-number">0</span>, y: <span class="hljs-number">0</span>, r: <span class="hljs-number">5</span>}

    <span class="hljs-comment">// Create a Rectangle instance</span>
    rectangle := Rectangle{width: <span class="hljs-number">10</span>, height: <span class="hljs-number">5</span>}

    <span class="hljs-comment">// Define a slice of Shape interfaces and add Circle and Rectangle instances to it</span>
    shapes := []Shape{circle, rectangle}

    <span class="hljs-comment">// Loop through the shapes slice and call the Area method on each instance</span>
    <span class="hljs-keyword">for</span> _, shape := <span class="hljs-keyword">range</span> shapes {
        fmt.Printf(<span class="hljs-string">"Area of shape: %.2f\n"</span>, shape.Area())
    }
}
</code></pre>
<p>In this example, we define an interface called <code>Shape</code> with a single method signature called <code>Area</code>, which returns a float64. We then define two structs, <code>Circle</code> and <code>Rectangle</code>, and implement the <code>Area</code> method on each struct.</p>
<p>In the <code>main</code> function, we create a <code>Circle</code> instance and a <code>Rectangle</code> instance. We then define a slice of <code>Shape</code> interfaces and add the <code>Circle</code> and <code>Rectangle</code> instances to it. This works because both <code>Circle</code> and <code>Rectangle</code> implement the <code>Area</code> method defined by the <code>Shape</code> interface.</p>
<p>We then loop through the <code>shapes</code> slice and call the <code>Area</code> method on each instance. Because both <code>Circle</code> and <code>Rectangle</code> implement the <code>Area</code> method, the correct implementation is called for each instance.</p>
<p>The output of the program will be:</p>
<pre><code class="lang-go">Area of shape: <span class="hljs-number">78.50</span>
Area of shape: <span class="hljs-number">50.00</span>
</code></pre>
<p>This example demonstrates how to define and use interfaces in Go. By defining an interface with a set of method signatures, we can create types that implement the interface and use them interchangeably.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Structs, methods, and interfaces are fundamental concepts in Go that allow developers to create well-structured, modular, and flexible code. Structs enable data organization, methods add behavior to data, and interfaces define behavior contracts. By leveraging these features, Go developers can build robust and maintainable applications that scale effectively. Whether you're building a simple application or a complex system, understanding these concepts will empower you to write clean and efficient Go code.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Pointers in Go: Your Guide to Memory Magic (Blog 13 of the Go Series)]]></title><description><![CDATA[In the world of programming, pointers play a pivotal role in managing memory and achieving efficient pass-by-reference behavior. In Go, pointers are denoted by the * symbol and hold the memory addresses of other variables. In this article, we will ex...]]></description><link>https://blog.chetan-thapliyal.cloud/understanding-pointers-in-go-your-guide-to-memory-magic-blog-13-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/understanding-pointers-in-go-your-guide-to-memory-magic-blog-13-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sun, 13 Aug 2023 06:30:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691731861923/4bdab5ed-56ca-485c-beb4-ba7f93fc434e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the world of programming, pointers play a pivotal role in managing memory and achieving efficient pass-by-reference behavior. In Go, pointers are denoted by the <code>*</code> symbol and hold the memory addresses of other variables. In this article, we will explore the intricacies of pointers and their applications in Go programming.</p>
<h2 id="heading-the-basics-of-pointers">The Basics of Pointers</h2>
<p>In Go, pointers are a fundamental concept that allows us to reference and manipulate data indirectly. Consider the following code snippet:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    x := <span class="hljs-number">1</span>
    <span class="hljs-keyword">var</span> ptr *<span class="hljs-keyword">int</span> = &amp;x

    fmt.Println(<span class="hljs-string">"x ="</span>, x)
    fmt.Println(<span class="hljs-string">"Memory address of x ="</span>, &amp;x)
}
</code></pre>
<p>In this example, we declare a variable <code>x</code> with the value 1. We then declare a pointer variable <code>ptr</code> of type <code>*int</code> that points to the memory address of <code>x</code>. This enables us to access and modify the original value of <code>x</code> through the pointer.</p>
<h2 id="heading-address-and-dereference-operator">Address and Dereference Operator</h2>
<p>The memory address is represented by a hexadecimal number, which is a base 16 number system. The address of a variable can be obtained by using the <code>&amp;</code> operator followed by the variable name. For instance:</p>
<pre><code class="lang-go">x := <span class="hljs-number">10</span>
fmt.Println(<span class="hljs-string">"Value of x:"</span>, x) <span class="hljs-comment">// prints: Value of x: 10</span>
fmt.Println(<span class="hljs-string">"Address of x:"</span>, &amp;x) <span class="hljs-comment">// prints: Address of x: 0xc0000180a0</span>
fmt.Printf(<span class="hljs-string">"Type of x: %T"</span>, &amp;x)
</code></pre>
<p>In the above example, <code>x</code> holds the value <code>10</code> and <code>&amp;x</code> holds the memory address of <code>x</code>, which is <code>0xc0000180a0</code>.</p>
<p>To access the value at the memory address held by a pointer variable, we use the <code>*</code> operator. This is known as the <strong><em>dereference operator</em></strong>.</p>
<p>The <code>&amp;</code> operator, known as the address operator, allows us to retrieve the memory address of <code>x</code>. Furthermore, to access the value stored at a memory address held by a pointer, the <code>*</code> operator comes into play. This is referred to as the dereference operator. For instance:</p>
<pre><code class="lang-go">x := <span class="hljs-number">10</span>
ptr := &amp;x
fmt.Println(<span class="hljs-string">"Value of x:"</span>, x)   <span class="hljs-comment">// prints: Value of x: 10</span>
fmt.Println(<span class="hljs-string">"Value of ptr:"</span>, *ptr) <span class="hljs-comment">// prints: Value of ptr: 10</span>
fmt.Printf(<span class="hljs-string">"Type of x: %T"</span>, &amp;x)
</code></pre>
<p>In this case, <code>ptr</code> holds the memory address of <code>x</code>, and by applying the dereference operator, we can retrieve the value stored at that memory address.</p>
<p>To access the value at the memory address held by <code>ptr</code>, we use the <code>*</code> operator. This gives us the value of <code>x</code>, which is <code>10</code>.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    i := <span class="hljs-number">10</span>
    fmt.Printf(<span class="hljs-string">"%T %v \n"</span>, &amp;i, &amp;i)
    fmt.Printf(<span class="hljs-string">"%T %v \n"</span>, *(&amp;i), *(&amp;i))
}
</code></pre>
<blockquote>
<p>Note that when using pointers in Go, it's important to handle <strong>nil pointers</strong> properly to avoid runtime errors.</p>
</blockquote>
<h2 id="heading-navigating-pass-by-value-and-pass-by-reference">Navigating Pass-by-Value and Pass-by-Reference</h2>
<p>Go employs a unique approach to function arguments, where all arguments are passed by value. However, when working with pointers, a copy of the memory address is passed, thereby enabling functions to modify the original variable. This is an essential distinction to grasp.</p>
<blockquote>
<ul>
<li><p>The function is called by directly passing the value of the variable as an argument. The parameter is copied into another location of your memory.</p>
</li>
<li><p>So, when accessing or modifying the variable within your function, only the copy is accessed or modified, and the original value is never modified.</p>
</li>
</ul>
</blockquote>
<p>When a variable is passed by value, as in the case of:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    x := <span class="hljs-number">10</span>
    increment(x)
    fmt.Println(x)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">increment</span><span class="hljs-params">(a <span class="hljs-keyword">int</span>)</span></span> {
    a++
}
</code></pre>
<p>In the above example, the <code>increment</code> function takes an argument <code>a</code> of type <code>int</code>. When we call <code>increment(x)</code>, a copy of <code>x</code> is passed to the function. The <code>increment</code> function increments the value of <code>a</code>, but this does not affect the original variable <code>x</code> because it's a copy.</p>
<p>To pass by reference, pointers come into play, as illustrated in:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    x := <span class="hljs-number">10</span>
    increment(&amp;x)
    fmt.Println(x)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">increment</span><span class="hljs-params">(a *<span class="hljs-keyword">int</span>)</span></span> {
    (*a)++
}
</code></pre>
<p>In the above example, we pass the memory address of <code>x</code> to the <code>increment</code> function using the <code>&amp;</code> operator. The <code>increment</code> function takes a pointer argument <code>a</code> of type <code>*int</code>. To access the value at the memory address held by <code>a</code>, we use the <code>*</code> operator, which dereferences the pointer.</p>
<p>When we call <code>increment(&amp;x)</code>, the <code>increment</code> function modifies the value at the memory address held by <code>a</code>, which is the same memory address held by <code>x</code>. Therefore, the value of <code>x</code> is also incremented to <code>11</code>.</p>
<blockquote>
<p>Note that using pointers in Go can be useful for passing large data structures or modifying function arguments in place. However, it also requires careful handling to avoid errors such as nil pointers or memory leaks.</p>
</blockquote>
<p><strong>Slices and Maps are passed by reference, by default.</strong></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Pointers in Go stand as a cornerstone for achieving pass-by-reference behavior, enabling us to manipulate data indirectly and enhance the efficiency of our code. By grasping the concepts of memory addresses, dereferencing, and pass-by-value vs. pass-by-reference, developers can unlock the full potential of Go's pointer system. As you embark on your journey with Go programming, remember that while pointers offer powerful capabilities, they also demand a mindful approach to ensure the stability and integrity of your code.</p>
]]></content:encoded></item><item><title><![CDATA[Unlocking the Magic of Functions in Go (Blog 12 of the Go Series)]]></title><description><![CDATA[Welcome to the world of functions in Go! If you're just starting your journey into programming, you might have come across the term "functions" quite frequently. But what exactly are functions, and how can they make your code more efficient, readable...]]></description><link>https://blog.chetan-thapliyal.cloud/unlocking-the-magic-of-functions-in-go-blog-12-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/unlocking-the-magic-of-functions-in-go-blog-12-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Developer]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sun, 13 Aug 2023 04:30:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691729609488/040b1daa-7179-45f3-8f67-3e3801381e95.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to the world of functions in Go! If you're just starting your journey into programming, you might have come across the term "functions" quite frequently. But what exactly are functions, and how can they make your code more efficient, readable, and powerful? In this beginner-friendly guide, we'll demystify functions, explore their different aspects, and equip you with the knowledge you need to wield them effectively in your Go programs.</p>
<h3 id="heading-what-are-functions">What Are Functions?</h3>
<p>Functions are like the building blocks of your code. They're like mini-programs within a program that help you perform specific tasks. Imagine you're baking a cake, and you have a secret recipe for the perfect frosting. Instead of writing the frosting instructions every time you bake a cake, you can create a function called "makeFrosting" that encapsulates those instructions. This way, you can easily reuse your frosting recipe whenever you need it.</p>
<h3 id="heading-function-declaration">Function Declaration</h3>
<p>Declaring a function is like telling the computer, "Hey, I'm creating a set of instructions, and I want to give it a name." Here's how you declare a function in Go:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">functionName</span><span class="hljs-params">(parameters)</span> <span class="hljs-title">returnType</span></span> {
    <span class="hljs-comment">// Your instructions here</span>
}
</code></pre>
<ul>
<li><p><code>func</code>: This is a keyword in Go that signals the start of a function declaration.</p>
</li>
<li><p><code>functionName</code>: Replace this with the name you want to give your function.</p>
</li>
<li><p><code>parameters</code>: These are like inputs that your function needs to do its job. They're like ingredients for your recipe.</p>
</li>
<li><p><code>returnType</code>: This specifies what type of result your function will provide after it's done executing.</p>
</li>
</ul>
<p>For example, let's create a function that adds two numbers:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">add</span><span class="hljs-params">(x <span class="hljs-keyword">int</span>, y <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> x + y
}
</code></pre>
<p>In this function, <code>x</code> and <code>y</code> are the parameters, and <code>int</code> is the return type indicating that the function will return an integer value.</p>
<h3 id="heading-naming-conventions-of-function">Naming Conventions of function</h3>
<ul>
<li><p>must begin with a letter.</p>
</li>
<li><p>can have any number of additional letters and symbols.</p>
</li>
<li><p>cannot contain spaces.</p>
</li>
<li><p>case-sensitive.</p>
</li>
</ul>
<h3 id="heading-calling-a-function">Calling a Function</h3>
<p>Now that you've defined your function, how do you use it? You "call" the function by using its name and providing the required inputs, like this:</p>
<pre><code class="lang-go">result := add(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>)
fmt.Println(result) <span class="hljs-comment">// Output: 8</span>
</code></pre>
<p>The <code>add</code> function takes two arguments (<code>3</code> and <code>5</code>) and returns their sum (<code>8</code>), which is then stored in the <code>result</code> variable.</p>
<h3 id="heading-parameters-vs-arguments">Parameters vs. Arguments</h3>
<p>Here's a fun analogy to understand the difference between parameters and arguments: Imagine you're ordering a pizza (calling a function). You tell the pizza place what type of pizza you want (parameters) and then provide the specific details (arguments) when you place your order.</p>
<ul>
<li><p>Parameters: These are like placeholders that define what your function expects. They're listed in the function declaration.</p>
</li>
<li><p>Arguments: These are the actual values or expressions you provide when you call the function.</p>
</li>
</ul>
<h3 id="heading-passing-the-torch-call-by-value-and-call-by-reference">Passing the Torch: Call by Value and Call by Reference</h3>
<p>Think of functions as helpful wizards that can perform tasks for you. Just like wizards, functions sometimes need items (values) to perform their magic. In Go, there are two ways to hand over these items to functions: "call by value" and "call by reference."</p>
<ul>
<li><p><strong>Call by Value</strong>: Imagine you're sharing a recipe card with a friend. You give them a copy, and they go cook the dish. In Go, when you pass values to a function, a copy of those values is made, and the function works with the copies. Any changes the function makes won't affect the original values.</p>
<pre><code class="lang-go">  <span class="hljs-keyword">package</span> main
  <span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

  <span class="hljs-comment">// A function that swaps values (call by value)</span>
  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">swap</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
      <span class="hljs-keyword">var</span> temp <span class="hljs-keyword">int</span>
      temp = a
      a = b
      b = temp
      <span class="hljs-keyword">return</span> temp
  }

  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
      p := <span class="hljs-number">10</span>
      q := <span class="hljs-number">20</span>
      fmt.Printf(<span class="hljs-string">"p = %d and q = %d"</span>, p, q)

      <span class="hljs-comment">// Call the function</span>
      swap(p, q)
      fmt.Printf(<span class="hljs-string">"\np = %d and q = %d"</span>, p, q)
  }
</code></pre>
<p>  Output:</p>
<pre><code class="lang-go">  p = <span class="hljs-number">10</span> and q = <span class="hljs-number">20</span>
  p = <span class="hljs-number">10</span> and q = <span class="hljs-number">20</span>
</code></pre>
</li>
<li><p><strong>Call by Reference</strong>: Now, imagine you're lending your friend your favorite book. They can read it, make notes, and return it. In Go, when you pass values by reference (using pointers), the function gets to work with the original values directly. Any changes the function makes are reflected in the original values.</p>
<pre><code class="lang-go">  <span class="hljs-keyword">package</span> main
  <span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

  <span class="hljs-comment">// A function that swaps values (call by reference)</span>
  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">swap</span><span class="hljs-params">(a, b *<span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
      <span class="hljs-keyword">var</span> temp <span class="hljs-keyword">int</span>
      temp = *a
      *a = *b
      *b = temp
      <span class="hljs-keyword">return</span> temp
  }

  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
      p := <span class="hljs-number">10</span>
      q := <span class="hljs-number">20</span>
      fmt.Printf(<span class="hljs-string">"p = %d and q = %d"</span>, p, q)

      <span class="hljs-comment">// Call the function</span>
      swap(&amp;p, &amp;q)
      fmt.Printf(<span class="hljs-string">"\np = %d and q = %d"</span>, p, q)
  }
</code></pre>
<p>  Output:</p>
<pre><code class="lang-go">  p = <span class="hljs-number">10</span> and q = <span class="hljs-number">20</span>
  p = <span class="hljs-number">20</span> and q = <span class="hljs-number">10</span>
</code></pre>
</li>
</ul>
<h3 id="heading-the-return-of-the-functions-return-types-and-variadics">The Return of the Functions: Return Types and Variadics</h3>
<p>In the world of Go, functions aren't just one-trick ponies. They can not only perform tasks but also deliver results. Let's explore the fascinating realm of return types and variadic functions.</p>
<ul>
<li><p><strong>Return Types</strong>: Think of return types as the "flavors" of ice cream a function can serve. A function can have a single return type or even multiple return types.</p>
<pre><code class="lang-go">  <span class="hljs-keyword">package</span> main
  <span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

  <span class="hljs-comment">// A function with a single return type</span>
  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addNumbers</span><span class="hljs-params">(x <span class="hljs-keyword">int</span>, y <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
      <span class="hljs-keyword">return</span> x + y
  }

  <span class="hljs-comment">// A function with multiple return types</span>
  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">operations</span><span class="hljs-params">(x <span class="hljs-keyword">int</span>, y <span class="hljs-keyword">int</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>)</span></span> {
      sum := x + y
      diff := x - y
      <span class="hljs-keyword">return</span> sum, diff
  }

  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
      result := addNumbers(<span class="hljs-number">5</span>, <span class="hljs-number">7</span>)
      fmt.Println(result) <span class="hljs-comment">// Output: 12</span>

      sum, difference := operations(<span class="hljs-number">30</span>, <span class="hljs-number">10</span>)
      fmt.Println(sum, difference) <span class="hljs-comment">// Output: 40, 20</span>
  }
</code></pre>
</li>
<li><p><strong>Variadic Functions</strong>: Variadic functions are like buffet spreads – they can handle a variable number of arguments. This means you can write functions that work with different quantities of inputs without having to create separate versions of the function.</p>
<pre><code class="lang-go">  <span class="hljs-keyword">package</span> main
  <span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

  <span class="hljs-comment">// A variadic function to sum numbers</span>
  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sumNum</span><span class="hljs-params">(nums ...<span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
      sum := <span class="hljs-number">0</span>
      <span class="hljs-keyword">for</span> _, value := <span class="hljs-keyword">range</span> nums {
          sum += value
      }
      <span class="hljs-keyword">return</span> sum
  }

  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
      fmt.Println(sumNum())                    <span class="hljs-comment">// Output: 0</span>
      fmt.Println(sumNum(<span class="hljs-number">10</span>))                  <span class="hljs-comment">// Output: 10</span>
      fmt.Println(sumNum(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>))              <span class="hljs-comment">// Output: 30</span>
      fmt.Println(sumNum(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>, <span class="hljs-number">40</span>, <span class="hljs-number">50</span>))  <span class="hljs-comment">// Output: 150</span>
  }
</code></pre>
</li>
</ul>
<h3 id="heading-named-return-values-and-the-enigma-of-recursion">Named Return Values and the Enigma of Recursion</h3>
<p>Have you ever heard of functions that play hide-and-seek with themselves? These are called "recursive functions." They're like those never-ending mirror mazes where you keep seeing reflections of yourself.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-comment">// A recursive function to calculate factorial</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">factorial</span><span class="hljs-params">(n <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">if</span> n == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
    }
    <span class="hljs-keyword">return</span> n * factorial(n<span class="hljs-number">-1</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    result := factorial(<span class="hljs-number">5</span>)
    fmt.Println(result) <span class="hljs-comment">// Output: 120</span>
}
</code></pre>
<p>In this example, the <code>factorial</code> function calls itself, going deeper and deeper until it reaches the base case <code>(n==0)</code>, and then it starts "unwinding" the calls, multiplying the results together.</p>
<h3 id="heading-the-anonymous-charm-functions-without-names">The Anonymous Charm: Functions without Names</h3>
<p>Meet the mysterious "anonymous functions." They're like ninjas in the programming world – they do their job swiftly without revealing their identity.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main
<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Define and immediately call an anonymous function</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        fmt.Println(<span class="hljs-string">"Hello from an anonymous function!"</span>)
    }()

    <span class="hljs-comment">// Assign an anonymous function to a variable</span>
    add := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(a, b <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
        <span class="hljs-keyword">return</span> a + b
    }

    sum := add(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>)
    fmt.Println(sum) <span class="hljs-comment">// Output: 7</span>
}
</code></pre>
<p>In this example, we unleash the power of an anonymous function by defining it and immediately calling it. We also assign an anonymous function to the variable <code>add</code> and use it just like any other function.</p>
<h3 id="heading-high-order-functions">High-Order Functions</h3>
<p>High-order functions are like the maestros of the programming world. They can take other functions as arguments or even return functions. It's like having a conductor who can bring in different musicians to create beautiful symphonies.</p>
<p>Here's a simple example of a high-order function:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">applyFunction</span><span class="hljs-params">(fn <span class="hljs-keyword">func</span>(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span>, <span class="hljs-title">a</span>, <span class="hljs-title">b</span> <span class="hljs-title">int</span>) <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> fn(a, b)
}

result := applyFunction(add, <span class="hljs-number">4</span>, <span class="hljs-number">7</span>)
fmt.Println(result) <span class="hljs-comment">// Output: 11</span>
</code></pre>
<p>In this example, the <code>applyFunction</code> function takes another function (<code>add</code>) as an argument, along with two integers (<code>4</code> and <code>7</code>). It then uses the provided function to perform the addition and returns the result.</p>
<h3 id="heading-defer-statements">Defer Statements</h3>
<p>Think of a defer statement as a "to-do" list for your program. You can schedule a function call to happen after the current function completes, no matter how it ends. It's like making sure you close the oven door after you've put the cake in, even if you get distracted.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">defer</span> fmt.Println(<span class="hljs-string">"World"</span>)
    fmt.Println(<span class="hljs-string">"Hello"</span>)
}
</code></pre>
<p>In this snippet, the <code>World</code> print statement is deferred, meaning it will be executed after the <code>Hello</code> print statement. The output will be:</p>
<pre><code class="lang-go">Hello
World
</code></pre>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Functions are like your trusty sidekicks in the world of programming. They help you break down complex tasks, make your code more readable, and enable you to create more efficient and modular programs. With the power of functions, you can unleash your creativity and build amazing things with Go. Whether you're baking cakes, calculating sums, or orchestrating grand symphonies of code, functions are your go-to tool for achieving programming greatness. So go ahead, define, call, and embrace the magic of functions in Go!</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Maps in Go: A Deep Dive into Key-Value Pairs (Blog 11 of the Go Series)]]></title><description><![CDATA[In the realm of Go programming, efficiency and simplicity reign supreme. When it comes to managing data relationships, maps emerge as a powerful tool that provides an elegant solution. In this comprehensive guide, we will unravel the nuances of maps ...]]></description><link>https://blog.chetan-thapliyal.cloud/mastering-maps-in-go-a-deep-dive-into-key-value-pairs-blog-11-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/mastering-maps-in-go-a-deep-dive-into-key-value-pairs-blog-11-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[coding]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sat, 12 Aug 2023 08:30:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691729318432/04e968d6-41d4-4217-b2df-084911632562.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the realm of Go programming, efficiency and simplicity reign supreme. When it comes to managing data relationships, maps emerge as a powerful tool that provides an elegant solution. In this comprehensive guide, we will unravel the nuances of maps in Go, from their declaration and initialization to accessing, modifying, and checking for the existence of key-value pairs.</p>
<h2 id="heading-the-power-of-maps">The Power of Maps</h2>
<p>Maps offer a seamless way to store and retrieve key-value pairs. At their core, maps are implemented as hash tables, a mechanism that allows for lightning-fast access to data. This means that no matter how large the map becomes, retrieval operations remain constant-time operations, ensuring optimal performance.</p>
<h3 id="heading-declaration-and-initialization">Declaration and Initialization</h3>
<p>The journey into the world of maps begins with declaration and initialization. Declaring a map involves specifying the types of keys and values it will hold. Let's take a look at a few ways to declare and initialize maps:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Declaration</span>
<span class="hljs-keyword">var</span> m <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>

<span class="hljs-comment">// Initialization of an empty map</span>
m = <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>)

<span class="hljs-comment">// Declaration and initialization with key-value pairs</span>
n := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">string</span>{
    <span class="hljs-string">"foo"</span>: <span class="hljs-string">"bar"</span>,
    <span class="hljs-string">"baz"</span>: <span class="hljs-string">"qux"</span>,
}
</code></pre>
<p>Maps can be declared and initialized using composite literal syntax, offering a concise and expressive way to create maps with predefined key-value pairs.</p>
<h3 id="heading-accessing-and-modifying-elements">Accessing and Modifying Elements</h3>
<p>Accessing elements within a map is as simple as using the square bracket notation with the key. Here's how you can retrieve a value based on a key:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Accessing an element in a map</span>
value := n[<span class="hljs-string">"foo"</span>]
fmt.Println(value) <span class="hljs-comment">// Output: bar</span>
</code></pre>
<p>But what if the key doesn't exist? In such cases, Go gracefully returns the zero value of the value type. For example:</p>
<pre><code class="lang-go">value2 := n[<span class="hljs-string">"nonexistent"</span>]
fmt.Println(value2) <span class="hljs-comment">// Output: ""</span>
</code></pre>
<p>Modifying elements within a map is just as straightforward. Using the same square bracket notation, you can assign new values to existing keys or introduce new key-value pairs:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Modifying an element in a map</span>
n[<span class="hljs-string">"foo"</span>] = <span class="hljs-string">"updated"</span>
fmt.Println(n[<span class="hljs-string">"foo"</span>]) <span class="hljs-comment">// Output: updated</span>

<span class="hljs-comment">// Adding a new element to a map</span>
n[<span class="hljs-string">"newKey"</span>] = <span class="hljs-string">"newValue"</span>
fmt.Println(n[<span class="hljs-string">"newKey"</span>]) <span class="hljs-comment">// Output: newValue</span>
</code></pre>
<h3 id="heading-checking-for-existence">Checking for Existence</h3>
<p>Maps facilitate effortless checking for the existence of keys. By utilizing the two-value assignment form of the square bracket notation, you can not only retrieve values but also ascertain whether a key exists within the map:</p>
<pre><code class="lang-go">value, exists := n[<span class="hljs-string">"foo"</span>]
<span class="hljs-keyword">if</span> exists {
    fmt.Println(value) <span class="hljs-comment">// Output: updated</span>
} <span class="hljs-keyword">else</span> {
    fmt.Println(<span class="hljs-string">"Key does not exist"</span>)
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Maps in Go are your ally in efficiently managing key-value relationships. With constant-time access, intuitive declaration, initialization, modification methods, and the ability to effortlessly check for the existence of keys, maps shine as a foundational data structure. By mastering the art of working with maps, you empower your Go programs with a versatile tool that enhances both performance and readability. Whether you're handling configuration data, tracking resources, or managing any form of associative data, maps are your go-to solution in the world of Go programming. Embrace the power of maps, and unlock a new realm of efficiency and elegance in your code.</p>
]]></content:encoded></item><item><title><![CDATA[Unlocking the Power of Slices in Go (Blog 10 of the Go Series)]]></title><description><![CDATA[In the world of Go programming, slices stand out as a versatile and essential concept. While they might seem similar to arrays at first glance, slices offer a level of dynamism and functionality that can greatly enhance your coding experience. In thi...]]></description><link>https://blog.chetan-thapliyal.cloud/unlocking-the-power-of-slices-in-go-blog-10-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/unlocking-the-power-of-slices-in-go-blog-10-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[#Devopscommunity]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sat, 12 Aug 2023 06:30:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691726930733/0d1ceeaa-f627-40b9-8cd6-2f788019a817.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the world of Go programming, slices stand out as a versatile and essential concept. While they might seem similar to arrays at first glance, slices offer a level of dynamism and functionality that can greatly enhance your coding experience. In this guide, we'll delve into the intricacies of slices in Go, exploring their components, creation, manipulation, and usage.</p>
<h2 id="heading-understanding-slices">Understanding Slices</h2>
<p>At its core, a slice is a dynamic, flexible window into an underlying array. While arrays have fixed sizes, slices allow you to work with variable lengths of data. They provide a reference to a contiguous segment of an array, and this reference comes with three crucial components:</p>
<h3 id="heading-1-pointer">1. Pointer</h3>
<p>A slice is implemented as a data structure that contains a pointer to the first element of the slice within the underlying array. This allows for efficient access to the elements within the slice.</p>
<h3 id="heading-2-length">2. Length</h3>
<p>The length of a slice represents the number of elements it encompasses. It defines the size of the accessible segment within the underlying array. The <code>len()</code> function provides a quick way to retrieve the length of a slice.</p>
<h3 id="heading-3-capacity">3. Capacity</h3>
<p>The capacity of a slice is the maximum number of elements the underlying array can hold without requiring reallocation of memory. It signifies the total space available for elements within the slice. The <code>cap()</code> function allows you to determine the capacity of a slice.</p>
<blockquote>
<p>📌 Note that the capacity of a slice can be greater than its length, but it can never be smaller. When the length of a slice is increased beyond its capacity, a new underlying array is allocated with a larger capacity, and the elements from the old array are copied to the new array.</p>
</blockquote>
<p>A slice does not store any data, it just describes a section of an underlying array.</p>
<pre><code class="lang-go">s := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>)
fmt.Println(<span class="hljs-built_in">len</span>(s)) <span class="hljs-comment">// Output: 5</span>
fmt.Println(<span class="hljs-built_in">cap</span>(s)) <span class="hljs-comment">// Output: 8</span>
</code></pre>
<p>Here the length of the slice is 4, which means that there are 4 elements accessible through the slice. The capacity of the slice is 5, which means that the underlying array can hold up to 5 elements without reallocating memory.</p>
<pre><code class="lang-go">      +-----+-----+-----+-----+-----+-----+-----+-----+
      |  <span class="hljs-number">0</span>  |  <span class="hljs-number">1</span>  |  <span class="hljs-number">2</span>  |  <span class="hljs-number">3</span>  |  <span class="hljs-number">4</span>  |  <span class="hljs-number">5</span>  |  <span class="hljs-number">6</span>  |  <span class="hljs-number">7</span>  |
      +-----+-----+-----+-----+-----+-----+-----+-----+
         ^                          ^                 ^
         |                          |                 |
      Pointer                    Length(<span class="hljs-number">4</span>)        Capacity(<span class="hljs-number">8</span>)

In this diagram, the pointer points to the first element of the
underlying array. The length of the slice is <span class="hljs-number">4</span>, which means that there
are <span class="hljs-number">4</span> elements accessible through the slice. The capacity of the slice
is <span class="hljs-number">8</span>, which means that the underlying array can hold up to <span class="hljs-number">8</span> elements
without reallocating memory.
</code></pre>
<h2 id="heading-creating-slices">Creating Slices</h2>
<p>Go provides multiple ways to create slices tailored to your needs. Let's explore some common methods:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Creating an empty slice with a capacity of 3</span>
s1 := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>)

<span class="hljs-comment">// Creating a slice with initial values</span>
s2 := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}
</code></pre>
<h2 id="heading-accessing-and-modifying-elements">Accessing and Modifying Elements</h2>
<p>Accessing and modifying elements within a slice is straightforward and closely resembles working with arrays:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Accessing an element at index 1</span>
value := s2[<span class="hljs-number">1</span>]

<span class="hljs-comment">// Modifying an element at index 1</span>
s2[<span class="hljs-number">1</span>] = <span class="hljs-number">4</span>
</code></pre>
<p>It's important to note that changes made to a slice affect the underlying array. Other slices that share the same underlying array will reflect these modifications.</p>
<pre><code class="lang-go">names := [<span class="hljs-number">4</span>]<span class="hljs-keyword">string</span>{<span class="hljs-string">"John"</span>, <span class="hljs-string">"Paul"</span>, <span class="hljs-string">"George"</span>, <span class="hljs-string">"Ringo"</span>}
a := names[<span class="hljs-number">0</span>:<span class="hljs-number">2</span>]
b := names[<span class="hljs-number">1</span>:<span class="hljs-number">3</span>]
b[<span class="hljs-number">0</span>] = <span class="hljs-string">"XXX"</span>
fmt.Println(names) <span class="hljs-comment">// Output: [John XXX George Ringo]</span>
</code></pre>
<h2 id="heading-slicing-a-slice">Slicing a Slice</h2>
<p>Slicing allows you to extract a portion of a slice, creating a new slice with a subset of the original elements:</p>
<pre><code class="lang-go">numbers := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
newSlice := numbers[<span class="hljs-number">1</span>:<span class="hljs-number">3</span>] <span class="hljs-comment">// Contains [2, 3]</span>
newSlice1 := numbers[:<span class="hljs-number">3</span>] <span class="hljs-comment">// Contains [1, 2, 3]</span>
newSlice2 := numbers[<span class="hljs-number">3</span>:] <span class="hljs-comment">// Contains [4, 5]</span>
</code></pre>
<h2 id="heading-appending-to-a-slice">Appending to a Slice</h2>
<p>Appending elements to a slice is a fundamental operation that accommodates dynamic data growth:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Appending a value to the end of a slice</span>
s1 = <span class="hljs-built_in">append</span>(s1, <span class="hljs-number">1</span>)

<span class="hljs-comment">// Appending multiple values to the end of a slice</span>
s1 = <span class="hljs-built_in">append</span>(s1, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>)

<span class="hljs-comment">// Creating a new slice based on an existing one</span>
slice1 := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}
slice2 := <span class="hljs-built_in">append</span>(slice1, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>)
</code></pre>
<h2 id="heading-copying-a-slice">Copying a Slice</h2>
<p>When you need to duplicate a slice's contents, the <code>copy()</code> function is your go-to tool:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Create a new slice with the same length and capacity as the original slice</span>
s5 := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-built_in">len</span>(s2), <span class="hljs-built_in">cap</span>(s2))

<span class="hljs-comment">// Copy the values from s2 into s5</span>
<span class="hljs-built_in">copy</span>(s5, s2)
</code></pre>
<h2 id="heading-creating-a-slice-from-an-array">Creating a Slice from an Array</h2>
<p>Slices offer a convenient way to extract segments from arrays:</p>
<pre><code class="lang-go">numbers := [<span class="hljs-number">5</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
slice := numbers[<span class="hljs-number">1</span>:<span class="hljs-number">3</span>] <span class="hljs-comment">// Contains [2, 3]</span>
</code></pre>
<p>Remember that the end index of a slice is exclusive, meaning the slice includes elements up to, but not including, the specified index.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Slices in Go are a potent tool that empowers developers with the ability to work with dynamic data, efficiently manage memory, and build flexible data structures. Their ability to reference and manipulate arrays with ease makes them a cornerstone of Go programming. By understanding the components of slices, their creation, modification, and various operations, you'll be well-equipped to wield this powerful tool in your Go projects. So, go ahead and slice your way to more efficient, flexible, and elegant Go code!</p>
]]></content:encoded></item><item><title><![CDATA[Arrays in Go: Your Gateway to Structured Data Storage (Blog 9 of the Go Series)]]></title><description><![CDATA[Arrays, one of the foundational data structures in programming, provide a structured and efficient way to store collections of elements. In Go, arrays are particularly interesting due to their fixed size and ability to hold values of any data type. T...]]></description><link>https://blog.chetan-thapliyal.cloud/arrays-in-go-your-gateway-to-structured-data-storage-blog-9-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/arrays-in-go-your-gateway-to-structured-data-storage-blog-9-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Developer]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Sat, 12 Aug 2023 03:30:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691725210781/4c610a02-ba0e-4c03-bbef-4946633a6cb0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Arrays, one of the foundational data structures in programming, provide a structured and efficient way to store collections of elements. In Go, arrays are particularly interesting due to their fixed size and ability to hold values of any data type. This article will serve as your comprehensive guide to arrays in Go, exploring their creation, manipulation, and usage.</p>
<h2 id="heading-array-basics">Array Basics</h2>
<p>An array in Go is a collection of elements of the same data type, residing in contiguous memory locations. It's worth noting that arrays have a fixed size that cannot be altered at runtime, distinguishing them from more flexible structures like slices.</p>
<h3 id="heading-creating-arrays">Creating Arrays</h3>
<p>Creating an array involves specifying the data type and the desired number of elements. Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> numbers [<span class="hljs-number">5</span>]<span class="hljs-keyword">int</span>
    fmt.Println(numbers) <span class="hljs-comment">// Output: [0 0 0 0 0]</span>
}
</code></pre>
<p>You can also initialize arrays with values upon declaration:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    arr := [<span class="hljs-number">5</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>, <span class="hljs-number">40</span>, <span class="hljs-number">50</span>}
    fmt.Println(arr) <span class="hljs-comment">// Output: [10 20 30 40 50]</span>
}
</code></pre>
<p>Go provides a convenient ellipsis notation that allows the compiler to infer the array size based on the number of provided values:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    arr := [...]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
    fmt.Println(arr) <span class="hljs-comment">// Output: [1 2 3 4 5]</span>
}
</code></pre>
<h3 id="heading-accessing-array-elements-array-indexes">Accessing Array Elements (Array Indexes)</h3>
<p>Array elements can be accessed using their index values, which start from <strong>0</strong> and go up to <strong>length-1</strong>. For instance:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    arr := [<span class="hljs-number">5</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
    fmt.Println(arr[<span class="hljs-number">0</span>]) <span class="hljs-comment">// Output: 1</span>
    fmt.Println(arr[<span class="hljs-number">2</span>]) <span class="hljs-comment">// Output: 3</span>
    fmt.Println(arr[<span class="hljs-number">4</span>]) <span class="hljs-comment">// Output: 5</span>
}
</code></pre>
<h3 id="heading-changing-array-elements">Changing Array Elements</h3>
<p>You can modify array elements by assigning new values to them using their index:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    arr := [<span class="hljs-number">5</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
    fmt.Println(arr) <span class="hljs-comment">// Output: [1 2 3 4 5]</span>
    arr[<span class="hljs-number">1</span>] = <span class="hljs-number">7</span>
    fmt.Println(arr) <span class="hljs-comment">// Output: [1 7 3 4 5]</span>
}
</code></pre>
<h2 id="heading-iterating-through-arrays">Iterating Through Arrays</h2>
<p>You can traverse array elements using traditional loops or the range loop construct:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    arr := [<span class="hljs-number">5</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}

    <span class="hljs-comment">// Using a traditional loop</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">len</span>(arr); i++ {
        fmt.Println(arr[i])
    }

    <span class="hljs-comment">// Using a range loop</span>
    <span class="hljs-keyword">for</span> index, value := <span class="hljs-keyword">range</span> arr {
        fmt.Printf(<span class="hljs-string">"Index: %d, Value: %d\n"</span>, index, value)
    }
}
</code></pre>
<h2 id="heading-multi-dimensional-arrays">Multi-Dimensional Arrays</h2>
<p>Go supports multi-dimensional arrays, which are essentially arrays of arrays. These arrays are suitable for representing tabular or grid-like data structures.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> arr [<span class="hljs-number">2</span>][<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span>

    arr[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>] = <span class="hljs-number">1</span>
    arr[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] = <span class="hljs-number">2</span>
    arr[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">3</span>

    arr[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>] = <span class="hljs-number">4</span>
    arr[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>] = <span class="hljs-number">5</span>
    arr[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">6</span>

    fmt.Println(arr) <span class="hljs-comment">// Output: [[1 2 3] [4 5 6]]</span>
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Arrays in Go offer a simple and efficient means of organizing and accessing collections of data. By understanding how to create, access, and manipulate array elements, you'll be better equipped to work with fixed-size data structures. However, remember that slices provide more flexibility for dynamically-sized collections, making them a preferred choice in many scenarios. As you continue your journey with Go, mastering arrays will serve as a solid foundation for understanding more complex data structures and enhancing your programming capabilities.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Control Flow in Go (Blog 8 of the Go Series)]]></title><description><![CDATA[Control flow is a fundamental concept in programming that enables you to dictate the order in which statements are executed in your code. It allows you to make decisions, repeat actions, and create logical structures in your programs. In this article...]]></description><link>https://blog.chetan-thapliyal.cloud/mastering-control-flow-in-go-blog-8-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/mastering-control-flow-in-go-blog-8-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops articles]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[ #2Articles1Week]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Fri, 11 Aug 2023 13:30:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691724884182/7ffd5298-6eee-4c2d-b3df-5689d07f0127.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Control flow is a fundamental concept in programming that enables you to dictate the order in which statements are executed in your code. It allows you to make decisions, repeat actions, and create logical structures in your programs. In this article, we'll explore the various control flow structures available in the Go programming language, accompanied by illustrative examples.</p>
<h2 id="heading-1-if-statements">1. If Statements</h2>
<p>The <code>if</code> statement is used to execute a block of code only if a specified condition is true.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    age := <span class="hljs-number">18</span>

    <span class="hljs-keyword">if</span> age &gt;= <span class="hljs-number">18</span> {
        fmt.Println(<span class="hljs-string">"You are an adult."</span>)
    } <span class="hljs-keyword">else</span> {
        fmt.Println(<span class="hljs-string">"You are a minor."</span>)
    }
}
</code></pre>
<h2 id="heading-2-switch-statements">2. Switch Statements</h2>
<p>The <code>switch</code> statement allows you to compare a value against multiple possible matches and execute the code block associated with the first matching case.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    day := <span class="hljs-string">"Wednesday"</span>

    <span class="hljs-keyword">switch</span> day {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"Monday"</span>:
        fmt.Println(<span class="hljs-string">"It's the start of the week."</span>)
    <span class="hljs-keyword">case</span> <span class="hljs-string">"Wednesday"</span>:
        fmt.Println(<span class="hljs-string">"It's the middle of the week."</span>)
    <span class="hljs-keyword">default</span>:
        fmt.Println(<span class="hljs-string">"It's another day of the week."</span>)
    }
}
</code></pre>
<h2 id="heading-3-for-loops">3. For Loops</h2>
<p>Go supports a versatile <code>for</code> loop that can be used for various iterations, including traditional loops, while loops, and even infinite loops.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Traditional for loop</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">5</span>; i++ {
        fmt.Println(i)
    }

    <span class="hljs-comment">// While loop equivalent</span>
    num := <span class="hljs-number">1</span>
    <span class="hljs-keyword">for</span> num &lt;= <span class="hljs-number">5</span> {
        fmt.Println(num)
        num++
    }

    <span class="hljs-comment">// Infinite loop with break statement</span>
    count := <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> {
        fmt.Println(<span class="hljs-string">"Looping..."</span>)
        count++
        <span class="hljs-keyword">if</span> count &gt;= <span class="hljs-number">3</span> {
            <span class="hljs-keyword">break</span>
        }
    }
}
</code></pre>
<h2 id="heading-4-range-loops">4. Range Loops</h2>
<p>The <code>range</code> keyword is used to iterate over elements of an array, slice, map, string, or channel.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    numbers := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}

    <span class="hljs-keyword">for</span> index, value := <span class="hljs-keyword">range</span> numbers {
        fmt.Printf(<span class="hljs-string">"Index: %d, Value: %d\n"</span>, index, value)
    }

    <span class="hljs-comment">// Iterating over a map</span>
    colors := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">string</span>{
        <span class="hljs-string">"red"</span>:   <span class="hljs-string">"#FF0000"</span>,
        <span class="hljs-string">"green"</span>: <span class="hljs-string">"#00FF00"</span>,
        <span class="hljs-string">"blue"</span>:  <span class="hljs-string">"#0000FF"</span>,
    }

    <span class="hljs-keyword">for</span> key, value := <span class="hljs-keyword">range</span> colors {
        fmt.Printf(<span class="hljs-string">"Key: %s, Value: %s\n"</span>, key, value)
    }
}
</code></pre>
<h2 id="heading-5-break-and-continue">5. Break and Continue</h2>
<p>The <code>break</code> statement is used to exit a loop prematurely, while the <code>continue</code> statement is used to skip the rest of the current iteration and move to the next one.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">5</span>; i++ {
        <span class="hljs-keyword">if</span> i == <span class="hljs-number">3</span> {
            <span class="hljs-keyword">break</span> <span class="hljs-comment">// Exit the loop when i is 3</span>
        }
        fmt.Println(i)
    }

    <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">5</span>; i++ {
        <span class="hljs-keyword">if</span> i == <span class="hljs-number">3</span> {
            <span class="hljs-keyword">continue</span> <span class="hljs-comment">// Skip printing when i is 3</span>
        }
        fmt.Println(i)
    }
}
</code></pre>
<h2 id="heading-6-defer-statements">6. Defer Statements</h2>
<p>The <code>defer</code> statement is used to schedule a function call to be executed after the surrounding function returns.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">defer</span> fmt.Println(<span class="hljs-string">"This will be printed last."</span>)
    fmt.Println(<span class="hljs-string">"This will be printed first."</span>)
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Control flow structures are essential tools in programming that allow you to create flexible and efficient code. Go provides a concise and expressive syntax for implementing control flow, enabling you to create complex logic and decision-making processes. By mastering these control flow concepts and incorporating them into your programs, you can create robust and dynamic applications that respond to various scenarios and user interactions. As you continue your journey with Go, remember that a deep understanding of control flow will serve as a strong foundation for building sophisticated software.</p>
]]></content:encoded></item><item><title><![CDATA[Operators in Go (Blog 7 of the Go Series)]]></title><description><![CDATA[Operators are fundamental elements in any programming language, including Go. They allow you to manipulate values, perform calculations, compare values, and more. In this article, we'll delve into the different types of operators available in Go and ...]]></description><link>https://blog.chetan-thapliyal.cloud/operators-in-go-blog-7-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/operators-in-go-blog-7-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[#Devopscommunity]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Fri, 11 Aug 2023 11:30:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691724746979/11c19df4-e952-436a-ab51-5c8979104d4b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Operators are fundamental elements in any programming language, including Go. They allow you to manipulate values, perform calculations, compare values, and more. In this article, we'll delve into the different types of operators available in Go and explore how they are used in combination with control flow statements.</p>
<h2 id="heading-arithmetic-operators">Arithmetic Operators</h2>
<p>Arithmetic operators are used to perform basic mathematical operations. Let's see how they work:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    a := <span class="hljs-number">10</span>
    b := <span class="hljs-number">3</span>

    fmt.Println(a + b) <span class="hljs-comment">// Addition: 13</span>
    fmt.Println(a - b) <span class="hljs-comment">// Subtraction: 7</span>
    fmt.Println(a * b) <span class="hljs-comment">// Multiplication: 30</span>
    fmt.Println(a / b) <span class="hljs-comment">// Division: 3</span>
    fmt.Println(a % b) <span class="hljs-comment">// Modulus: 1</span>

    a++
    fmt.Println(a) <span class="hljs-comment">// Increment: 11</span>
    b--
    fmt.Println(b) <span class="hljs-comment">// Decrement: 2</span>
}
</code></pre>
<h2 id="heading-comparison-operators">Comparison Operators</h2>
<p>Comparison operators are used to compare two values or expressions. They return a Boolean value indicating whether the comparison is true or false:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    a := <span class="hljs-number">10</span>
    b := <span class="hljs-number">3</span>

    fmt.Println(a == b) <span class="hljs-comment">// Equal: false</span>
    fmt.Println(a != b) <span class="hljs-comment">// Not Equal: true</span>
    fmt.Println(a &gt; b)  <span class="hljs-comment">// Greater Than: true</span>
    fmt.Println(a &lt; b)  <span class="hljs-comment">// Less Than: false</span>
    fmt.Println(a &gt;= b) <span class="hljs-comment">// Greater Than or Equal: true</span>
    fmt.Println(a &lt;= b) <span class="hljs-comment">// Less Than or Equal: false</span>
}
</code></pre>
<h2 id="heading-logical-operators">Logical Operators</h2>
<p>Logical operators are used to perform operations on Boolean values. They allow you to combine or negate conditions:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    x := <span class="hljs-literal">true</span>
    y := <span class="hljs-literal">false</span>

    fmt.Println(x &amp;&amp; y) <span class="hljs-comment">// Logical AND: false</span>
    fmt.Println(x || y) <span class="hljs-comment">// Logical OR: true</span>
    fmt.Println(!x)     <span class="hljs-comment">// Logical NOT: false</span>
}
</code></pre>
<h2 id="heading-assignment-operators">Assignment Operators</h2>
<p>Assignment operators are used to assign values to variables or update their values:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    c := <span class="hljs-number">5</span>

    c += <span class="hljs-number">2</span> <span class="hljs-comment">// Equivalent to c = c + 2</span>
    fmt.Println(c) <span class="hljs-comment">// Output: 7</span>

    c *= <span class="hljs-number">3</span> <span class="hljs-comment">// Equivalent to c = c * 3</span>
    fmt.Println(c) <span class="hljs-comment">// Output: 21</span>

    c %= <span class="hljs-number">4</span> <span class="hljs-comment">// Equivalent to c = c % 4</span>
    fmt.Println(c) <span class="hljs-comment">// Output: 1</span>
}
</code></pre>
<h2 id="heading-other-operators">Other Operators</h2>
<p>In addition to the operators mentioned above, Go provides several other operators that serve specific purposes:</p>
<ul>
<li><p>The <code>&amp;</code> operator is the address operator, used to obtain the memory address of a variable.</p>
</li>
<li><p>The <code>*</code> operator is the dereference operator, used to access the value pointed to by a pointer.</p>
</li>
<li><p>The <code>&lt;-</code> operator is used for sending and receiving values on channels.</p>
</li>
<li><p>The <code>?:</code> operator is the ternary conditional operator, which allows you to choose between two values based on a condition.</p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    c := <span class="hljs-number">5</span>
    p := &amp;c
    fmt.Println(p)  <span class="hljs-comment">// Memory address of c</span>
    fmt.Println(*p) <span class="hljs-comment">// Value of c</span>

    ch := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>)
    <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        ch &lt;- <span class="hljs-number">42</span>
    }()
    fmt.Println(&lt;-ch) <span class="hljs-comment">// Receive value from channel</span>

    res := <span class="hljs-string">""</span>
    <span class="hljs-keyword">if</span> a &gt; b {
        res = <span class="hljs-string">"a &gt; b"</span>
    } <span class="hljs-keyword">else</span> {
        res = <span class="hljs-string">"a &lt;= b"</span>
    }
    fmt.Println(res)
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding operators and control flow is essential for writing efficient and meaningful Go programs. With the knowledge of arithmetic, comparison, logic, assignment, and other operators, you can manipulate values and control the flow of your program's execution. By mastering these concepts, you'll be better equipped to create powerful and expressive Go applications.</p>
]]></content:encoded></item><item><title><![CDATA[Variable Scope, Type Casting and Constants in Go (Blog 6 of the Go Series)]]></title><description><![CDATA[In the realm of programming, understanding the scope of variables and how to manipulate their types is crucial for writing efficient, maintainable, and error-free code. In this comprehensive guide, we'll explore two fundamental concepts in Go: variab...]]></description><link>https://blog.chetan-thapliyal.cloud/variable-scope-type-casting-and-constants-in-go-blog-6-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/variable-scope-type-casting-and-constants-in-go-blog-6-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Google]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Scripting]]></category><category><![CDATA[#codingNewbies]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Fri, 11 Aug 2023 03:02:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691722768530/dd07dfcc-8be9-4533-9b7f-9a46b7dcfcc4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the realm of programming, understanding the scope of variables and how to manipulate their types is crucial for writing efficient, maintainable, and error-free code. In this comprehensive guide, we'll explore two fundamental concepts in Go: variable scope and type casting. By delving into these concepts, you'll gain the knowledge and tools necessary to enhance your programming skills and create more robust applications.</p>
<h3 id="heading-variable-scope-in-go">Variable Scope in Go</h3>
<p>Variable scope refers to the visibility and accessibility of a variable within a program. In Go, the variable scope is categorized into two types: local scope and global scope.</p>
<p><strong>Local Scope</strong>: Variables declared within a function or block have local scope, making them accessible only within that specific function or block. After execution, these variables are destroyed. For instance:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">someFunction</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> x <span class="hljs-keyword">int</span> <span class="hljs-comment">// x has local scope</span>
    x = <span class="hljs-number">10</span>
    fmt.Println(x) <span class="hljs-comment">// prints 10</span>
}
</code></pre>
<p><strong>Global Scope</strong>: Variables declared outside of functions or blocks possess global scope, enabling access from any part of the program. These variables persist throughout the program's lifetime:</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> x <span class="hljs-keyword">int</span> <span class="hljs-comment">// x has global scope</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">someFunction</span><span class="hljs-params">()</span></span> {
    x = <span class="hljs-number">10</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Println(x) <span class="hljs-comment">// prints 0</span>
    someFunction()
    fmt.Println(x) <span class="hljs-comment">// prints 10</span>
}
</code></pre>
<p>Importantly, when a variable shares its name with one in a nested scope, the inner variable takes precedence within that scope. It's crucial to note that a local variable with the same name as a global variable will override the global variable's value only within the function or block where it's declared.</p>
<p>Understanding variable scope aids in avoiding naming conflicts and structuring code logically, enhancing its readability and maintainability.</p>
<h3 id="heading-finding-variable-types">🔍 Finding Variable Types</h3>
<p>In Go, determining a variable's type is essential for effective debugging and runtime manipulation. Two approaches are commonly used: employing the <code>%T</code> format specifier with the <code>fmt.Printf</code> function and utilizing the <code>reflect</code> package.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"reflect"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> x <span class="hljs-keyword">int</span>
    <span class="hljs-keyword">var</span> y <span class="hljs-keyword">float64</span>
    <span class="hljs-keyword">var</span> z <span class="hljs-keyword">string</span>

    <span class="hljs-comment">// Using %T format specifier</span>
    fmt.Printf(<span class="hljs-string">"x is of type %T\n"</span>, x)
    fmt.Printf(<span class="hljs-string">"y is of type %T\n"</span>, y)
    fmt.Printf(<span class="hljs-string">"z is of type %T\n"</span>, z)

    <span class="hljs-comment">// Using the reflect package</span>
    fmt.Println(reflect.TypeOf(x))
    fmt.Println(reflect.TypeOf(y))
    fmt.Println(reflect.TypeOf(z))
}
</code></pre>
<h3 id="heading-type-casting-in-go">Type Casting in Go</h3>
<p>Type casting, also known as type conversion, is the process of converting a value from one type to another. In Go, typecasting can be explicit or implicit.</p>
<p><strong>Explicit Type Casting</strong>: Performed manually by the programmer using the syntax <code>T(expression)</code>, converting <code>expression</code> to type <code>T</code>. For instance:</p>
<pre><code class="lang-go">x := <span class="hljs-number">10</span>
y := <span class="hljs-keyword">float64</span>(x) <span class="hljs-comment">// Explicit conversion to float64</span>
</code></pre>
<p><strong>Implicit Type Casting</strong>: Automatically executed by the Go compiler when assigning values between compatible types. For example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> i <span class="hljs-keyword">int</span> = <span class="hljs-number">42</span>
<span class="hljs-keyword">var</span> f <span class="hljs-keyword">float64</span> = i <span class="hljs-comment">// Implicit conversion to float64</span>
</code></pre>
<h2 id="heading-strconv-package"><code>strconv</code> package</h2>
<p><code>strconv</code> package provides functions for converting strings to numeric types and vice versa. It is useful when dealing with input/output or configuration files where values are typically read in as strings.</p>
<p>Some of the important functions in the <code>strconv</code> package include:</p>
<ol>
<li><p><code>Atoi</code> <strong>and</strong> <code>ParseInt</code><br /> These functions convert a <em>string to an integer</em>.<br /> <code>Atoi</code> is a shorthand for <code>ParseInt(s, 10, 0)</code>, which converts a string <code>s</code> to a base-10 integer with a default bit size of 0.<br /> The <code>ParseInt</code> function takes three arguments: the string to convert, the base (usually 10), and the bit size (32, 64, or 0 for the size of the platform's native int type).</p>
</li>
<li><p><code>Itoa</code> <strong>and</strong> <code>FormatInt</code><br /> These functions convert an <em>integer to a string</em>.<br /> <code>Itoa</code> is a shorthand for <code>FormatInt(int64(i), 10)</code>, which converts an integer <code>i</code> to a base-10 string.<br /> The <code>FormatInt</code> function takes the integer to convert, the base (usually 10), and the bit size.</p>
</li>
<li><p><code>ParseFloat</code> <strong>and</strong> <code>FormatFloat</code><br /> These functions convert a <em>string to a float64</em> and vice versa.<br /> <code>ParseFloat</code> takes three arguments: the string to convert, the bit size (32 or 64), and the precision (the number of bits to use for the mantissa).<br /> <code>FormatFloat</code> takes the float to convert, the format specifier, and the precision.</p>
</li>
</ol>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"strconv"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Converting a string to an integer</span>
    numStr := <span class="hljs-string">"42"</span>
    num, _ := strconv.**Atoi**(numStr)        
    fmt.Printf(<span class="hljs-string">"String %s converted to integer %d\n"</span>, numStr, num)

    <span class="hljs-comment">// Converting an integer to a string</span>
    numInt := <span class="hljs-number">12345</span>
    numStr = strconv.**Itoa**(numInt)
    fmt.Printf(<span class="hljs-string">"Integer %d converted to string %s\n"</span>, numInt, numStr)

    <span class="hljs-comment">// Parsing a string to a floating-point number</span>
    floatStr := <span class="hljs-string">"3.14159"</span>
    float, _ := strconv.**ParseFloat**(floatStr, <span class="hljs-number">64</span>)
    fmt.Printf(<span class="hljs-string">"String %s parsed to float %f\n"</span>, floatStr, float)

    <span class="hljs-comment">// Formatting an integer to a binary string</span>
    binaryStr := strconv.**FormatInt**(<span class="hljs-keyword">int64</span>(numInt), <span class="hljs-number">2</span>)
    fmt.Printf(<span class="hljs-string">"Integer %d formatted to binary string %s\n"</span>, numInt, binaryStr)
}
</code></pre>
<p>In the above example, <code>Atoi</code> function is used to convert a string representation of an integer to an actual integer.</p>
<p><code>Itoa</code> function is used to convert an integer to its string representation.</p>
<p><code>ParseFloat</code> function is used to parse a string representation of a floating-point number to its actual value.</p>
<p><code>FormatInt</code> function is used to format an integer to its binary string representation.</p>
<h3 id="heading-reflect-package"><code>reflect</code> Package</h3>
<p>The reflect package in Go provides a way to examine and manipulate the types of values at runtime. Using this package, you can convert a value to another type using the <code>Value.Convert()</code> method. However, this method is slower than the other methods and should be used sparingly.</p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"reflect"</span>

<span class="hljs-keyword">var</span> i <span class="hljs-keyword">int</span> = <span class="hljs-number">42</span>
v := reflect.ValueOf(i)  <span class="hljs-comment">// Creating a reflect.Value from i</span>
f := v.Convert(reflect.TypeOf(<span class="hljs-keyword">float64</span>(<span class="hljs-number">0</span>))).Float()  <span class="hljs-comment">// Converting v to a float64 value</span>
fmt.Println(f)           <span class="hljs-comment">// Output: 42.0</span>
</code></pre>
<p>Note that in the above example, we had to provide a target type <code>(float64(0))</code> to the <code>Convert()</code> method to convert the value <code>v</code> to the desired type.</p>
<h2 id="heading-constants-in-go">Constants in Go</h2>
<p>Constants, immutable values, are defined using the <code>const</code> keyword in Go. They can be typed or untyped. Untyped constants have their types inferred based on the context in which they are used.</p>
<h3 id="heading-typed-constants">Typed Constants</h3>
<p>A typed constant has an explicit type specified and can only be assigned to a variable of the same type or a compatible type. For example:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Define integer constant</span>
<span class="hljs-keyword">const</span> i <span class="hljs-keyword">int</span> = <span class="hljs-number">10</span>

<span class="hljs-comment">// Define float constant</span>
<span class="hljs-keyword">const</span> f <span class="hljs-keyword">float64</span> = <span class="hljs-number">3.14</span>

<span class="hljs-comment">// Define string constant</span>
<span class="hljs-keyword">const</span> s <span class="hljs-keyword">string</span> = <span class="hljs-string">"Hello, world!"</span>

<span class="hljs-comment">// Define boolean constant</span>
<span class="hljs-keyword">const</span> b <span class="hljs-keyword">bool</span> = <span class="hljs-literal">true</span>
</code></pre>
<h3 id="heading-untyped-constants">Untyped constants</h3>
<p>Untyped constant has no explicit type specified and can be assigned to a variable of any compatible type. Go automatically infers the type of an untyped constant based on the context in which it is used. For example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">const</span> untypedConst = <span class="hljs-number">42</span>
<span class="hljs-keyword">const</span> a = <span class="hljs-number">10</span> <span class="hljs-comment">// untyped constant</span>
<span class="hljs-keyword">const</span> b = <span class="hljs-string">"hello"</span> <span class="hljs-comment">// untyped constant</span>
</code></pre>
<h3 id="heading-difference-between-typed-and-untyped">Difference between Typed and Untyped</h3>
<p>The difference between typed and untyped constants is important when doing arithmetic or comparisons with constants. For example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">const</span> typedConst <span class="hljs-keyword">int</span> = <span class="hljs-number">10</span>
<span class="hljs-keyword">const</span> untypedConst = <span class="hljs-number">10</span>

<span class="hljs-keyword">var</span> x <span class="hljs-keyword">int</span> = typedConst / <span class="hljs-number">3</span> <span class="hljs-comment">// valid arithmetic operation</span>
<span class="hljs-keyword">var</span> y <span class="hljs-keyword">int</span> = untypedConst / <span class="hljs-number">3</span> <span class="hljs-comment">// valid arithmetic operation</span>

<span class="hljs-keyword">var</span> z <span class="hljs-keyword">float64</span> = typedConst / <span class="hljs-number">3</span> <span class="hljs-comment">// invalid arithmetic operation, different types</span>
<span class="hljs-keyword">var</span> w <span class="hljs-keyword">float64</span> = untypedConst / <span class="hljs-number">3</span> <span class="hljs-comment">// valid arithmetic operation, inferred as float64</span>

<span class="hljs-keyword">var</span> a <span class="hljs-keyword">bool</span> = typedConst == <span class="hljs-number">10</span> <span class="hljs-comment">// valid comparison, same types</span>
<span class="hljs-keyword">var</span> b <span class="hljs-keyword">bool</span> = untypedConst == <span class="hljs-number">10</span> <span class="hljs-comment">// valid comparison, inferred as int</span>
</code></pre>
<p>In general, untyped constants are more flexible and can be used in a wider range of contexts than typed constants, but typed constants offer better type safety.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Mastering variable scope and type casting in Go empowers you to write more efficient, organized, and dynamic code. By understanding where variables are accessible and how to manipulate their types, you'll be better equipped to design robust and maintainable applications. These fundamental concepts serve as building blocks for developing sophisticated software solutions in the Go programming language.</p>
]]></content:encoded></item><item><title><![CDATA[Escape Sequences in Go (Blog 5 of the Go Series)]]></title><description><![CDATA[Escape sequences are powerful tools in any programming language, offering developers a way to represent non-printable characters and format output effectively. In Go, escape sequences play a crucial role in manipulating strings and achieving the desi...]]></description><link>https://blog.chetan-thapliyal.cloud/escape-sequences-in-go-blog-5-of-the-go-series</link><guid isPermaLink="true">https://blog.chetan-thapliyal.cloud/escape-sequences-in-go-blog-5-of-the-go-series</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Scripting]]></category><category><![CDATA[#codingNewbies]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Chetan Thapliyal]]></dc:creator><pubDate>Fri, 11 Aug 2023 02:59:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691722682965/19a88a5f-5cc8-45b3-aef7-8ee46d456092.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Escape sequences are powerful tools in any programming language, offering developers a way to represent non-printable characters and format output effectively. In Go, escape sequences play a crucial role in manipulating strings and achieving the desired output. In this blog post, we will delve into the world of escape sequences in Go, exploring common examples and providing a hands-on code demonstration.</p>
<h3 id="heading-understanding-escape-sequences">Understanding Escape Sequences</h3>
<p>Escape sequences are combinations of characters that are used to represent characters that are either non-printable or have special meanings. These sequences are often used within strings to add formatting or include characters that cannot be directly entered. Go, like many other programming languages, uses the backslash (<code>\</code>) as the escape character. Let's take a look at some commonly used escape sequences in Go:</p>
<ol>
<li><p><code>\n</code>: Represents a newline character.</p>
</li>
<li><p><code>\t</code>: Represents a tab character.</p>
</li>
<li><p><code>\b</code>: Represents a backspace character.</p>
</li>
<li><p><code>\r</code>: Represents a carriage return.</p>
</li>
<li><p><code>\"</code>: Represents a double quote character.</p>
</li>
<li><p><code>\'</code>: Represents a single quote character.</p>
</li>
<li><p><code>\\</code>: Represents a backslash character.</p>
</li>
<li><p><code>\x00</code>: Represents a null character.</p>
</li>
</ol>
<h3 id="heading-code-demonstration">Code Demonstration</h3>
<p>Here's a practical example showcasing these escape sequences in action:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    fmt.Println(<span class="hljs-string">"Escape Sequences in Go:\n"</span>)

    <span class="hljs-comment">// New Line</span>
    fmt.Println(<span class="hljs-string">"This is on the first line.\nThis is on the second line."</span>)

    <span class="hljs-comment">// Tab</span>
    fmt.Println(<span class="hljs-string">"This is some text.\tThis is indented by a tab."</span>)

    <span class="hljs-comment">// Backspace</span>
    fmt.Println(<span class="hljs-string">"This is some text.\b\b\b\b\b\bThis is overwritten by backspaces."</span>)

    <span class="hljs-comment">// Carriage Return</span>
    fmt.Println(<span class="hljs-string">"This is some text.\rThis overwrites the beginning of the line."</span>)

    <span class="hljs-comment">// Double Quote</span>
    fmt.Println(<span class="hljs-string">"\"This is in double quotes.\""</span>)

    <span class="hljs-comment">// Single Quote</span>
    fmt.Println(<span class="hljs-string">"'This is in single quotes.'"</span>)

    <span class="hljs-comment">// Backslash</span>
    fmt.Println(<span class="hljs-string">"This uses a backslash: \\"</span>)

    <span class="hljs-comment">// Null Character</span>
    fmt.Println(<span class="hljs-string">"This is before a null character.\x00This is after a null character."</span>)
}
</code></pre>
<p>Output:</p>
<pre><code class="lang-go">Escape Sequences in Go:

This is on the first line.
This is on the second line.
This is some text.    This is indented by a tab.
This is some text.This is overwritten by backspaces.
This is some text.
This overwrites the beginning of the line.
<span class="hljs-string">"This is in double quotes."</span>
<span class="hljs-string">'This is in single quotes.'</span>
This uses a backslash: \
This is before a null character.This is after a null character.
</code></pre>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Escape sequences are invaluable tools when it comes to formatting output and representing non-printable characters within strings in Go. While they enhance the flexibility and readability of your code, it's crucial to use them correctly and avoid common errors. This blog post has provided a comprehensive overview of frequently used escape sequences in Go, along with a practical code demonstration. By mastering escape sequences, you'll be well-equipped to create more sophisticated and visually appealing output in your Go programs.</p>
]]></content:encoded></item></channel></rss>