<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yankee Maharjan</title>
    <description>The latest articles on DEV Community by Yankee Maharjan (@yankee).</description>
    <link>https://dev.to/yankee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F53292%2F9e023eeb-7932-4731-b31b-84ca1173e735.jpg</url>
      <title>DEV Community: Yankee Maharjan</title>
      <link>https://dev.to/yankee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yankee"/>
    <language>en</language>
    <item>
      <title>Build CLI blazingly fast with python-fire 🔥</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Mon, 05 Jun 2023 02:37:07 +0000</pubDate>
      <link>https://dev.to/yankee/build-cli-blazingly-fast-with-python-fire-gc7</link>
      <guid>https://dev.to/yankee/build-cli-blazingly-fast-with-python-fire-gc7</guid>
      <description>&lt;p&gt;Command line applications are developers best friend. Want to get something done quickly? Just a few keystrokes and you already have what you are looking for.&lt;/p&gt;

&lt;p&gt;Python is the first language many developers pick if they need to hack together something quickly. But what we scrap together is not a CLI in its entirety most of the time, you need to manage flags, parse the arguments, chain sub-commands, and many more which is a hassle, thus results in multiple small  and unmanaged scripts.&lt;/p&gt;

&lt;p&gt;In todays article we are going to put an end to this and see how we can build reasonably feature rich CLI in mere minutes without any fancy decorators or anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create and activate a  virtual environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv

&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate

&lt;span class="c"&gt;# Install python-fire 🔥&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;fire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Your first sub-command
&lt;/h3&gt;

&lt;p&gt;Our CLI application is going to be an aggregation of  bunch of tools, so we will just call it tools CLI.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://github.com/google/python-fire"&gt;python-fire&lt;/a&gt; you can use either function or class to create your subcommands. But I find working with classes more intuitive and manageable. Our first command is going to be a sub-command that shows us the UTC time.&lt;/p&gt;

&lt;p&gt;We will create a new method &lt;code&gt;utc()&lt;/code&gt; which will be our sub-command and we have an argument called &lt;code&gt;pretty&lt;/code&gt; which will be the &lt;strong&gt;flag&lt;/strong&gt; for our sub-command which prints UTC date time in more human readable format. &lt;strong&gt;This argument already has a default value so this is not a required flag.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tools.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;fire&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pretty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""
        Get UTC date time
        """&lt;/span&gt;
        &lt;span class="n"&gt;utc_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pretty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;## strftime format codes:
&lt;/span&gt;            &lt;span class="c1"&gt;# https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
&lt;/span&gt;            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%B %d :: %H:%M %p"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we need to run this file as a script so at the end of our file we need to add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have our CLI ready! Let’s run it!!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python tools.py utc
python tools.py utc &lt;span class="nt"&gt;--pretty&lt;/span&gt;

&lt;span class="c"&gt;# For help message&lt;/span&gt;
python tools.py

&lt;span class="c"&gt;# For sub-command help message&lt;/span&gt;
python tools.py utc &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rmSNRYDU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8qguq0oehpq551xbcge.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rmSNRYDU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8qguq0oehpq551xbcge.gif" alt="Image description" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s a bit overwhelming to type through all of these overheads &lt;code&gt;python tools.py &amp;lt;command&amp;gt;&lt;/code&gt;; well it’s not even like a CLI I was hoping for 🤷‍♂️.&lt;br&gt;
You might have questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How can I invoke it from any location I want?&lt;/li&gt;
&lt;li&gt;I want to name it to something I find intuitive, how do I do that?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well for that you would want to create a distribution for it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Package for Command Line 📦
&lt;/h3&gt;

&lt;p&gt;First we need to revamp our program a little to accommodate packaging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# REMOVE THIS CHUNK
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ADD THIS CHUNK
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s create a &lt;code&gt;setup.py&lt;/code&gt; file to manage our packaging/distribution. You can use this file as a reference to create your own CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# setup.py
&lt;/span&gt;&lt;span class="s"&gt;"""Package setup"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;setuptools&lt;/span&gt;

&lt;span class="c1"&gt;# Development Requirements
&lt;/span&gt;&lt;span class="n"&gt;requirements_dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"pytest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"black"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mypy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"flake8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"isort"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;setuptools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tools_cli"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Yankee Maharjan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://yankee.dev/build-cli-blazingly-fast-with-python-fire"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Collection of handy tools using CLI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;license&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;setuptools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_packages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"*.egg-info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="n"&gt;install_requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"fire"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;extras_require&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;requirements_dev&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;entry_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"console_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"to = tools:run"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line you need to focus here is the &lt;code&gt;entry_points&lt;/code&gt;, which describes the entry point to our program as a console script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;entry_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"console_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"to = tools:run"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;to&lt;/code&gt; is the name of our CLI, you can name it to anything you like. If you want to name it to &lt;code&gt;brr&lt;/code&gt; it will go like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;entry_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"console_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"brr = tools:run"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tools:run&lt;/code&gt; represent the name of our module followed by the function it needs to run. Console Scripts always require a function to run hence the modification we did earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feels like a CLI 💆‍♂️
&lt;/h3&gt;

&lt;p&gt;Now let’s install our CLI in an editable mode within our virtual environment. This is like hot reloading for your CLI, whatever changes you make is reflected instantly.&lt;/p&gt;

&lt;p&gt;Inside your project directory run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use your CLI using the command &lt;code&gt;to&lt;/code&gt; or whatever you put on the &lt;strong&gt;console_scripts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;to utc
to utc &lt;span class="nt"&gt;--pretty&lt;/span&gt;
to utc &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8siYvkPV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5durgucov9ev0pggh7e4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8siYvkPV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5durgucov9ev0pggh7e4.gif" alt="Image description" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is pretty neat!&lt;/p&gt;

&lt;p&gt;Now how do I make sure I can run it from any location I want?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Deactivate your virtual environment:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deactivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the project in editable mode again on your global site-packages:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now this is done, you will have your CLI accessible throughout the system. But note that if you make any changes to the main CLI logic, it will be reflected instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Nested Commands ➿
&lt;/h3&gt;

&lt;p&gt;If you have made it this far, then you are set to make your own CLI and get done with most of the use cases. But if you want to see some more then stick around for a bit.&lt;/p&gt;

&lt;p&gt;Let’s add other commands to our tool, first a sub-command called &lt;code&gt;leap()&lt;/code&gt; that validates if the given year is leap or not, lastly a sub-command called &lt;code&gt;pw()&lt;/code&gt; to generate a strong password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;calendar&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;string&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;secrets&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...):&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;leap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# required: since no default value here
&lt;/span&gt;        &lt;span class="s"&gt;"""
        Check if given year is leap or not
        """&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isleap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""
        Generate strong password
        """&lt;/span&gt;
        &lt;span class="n"&gt;alphabet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ascii_letters&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digits&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;punctuation&lt;/span&gt;
        &lt;span class="n"&gt;pwd_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;

        &lt;span class="n"&gt;pwd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pwd_length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;pwd&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alphabet&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run the commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;leap&lt;/span&gt; &lt;span class="mi"&gt;2022&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pw&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pw&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pw&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ph9Md8VU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrxayr0squz5yxyarmir.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ph9Md8VU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrxayr0squz5yxyarmir.gif" alt="Image description" width="800" height="327"&gt;&lt;/a&gt;&lt;br&gt;
Sometimes there are related commands that you want to group together, like in our case we can group &lt;code&gt;utc&lt;/code&gt; and &lt;code&gt;leap&lt;/code&gt; under something like &lt;code&gt;datetime&lt;/code&gt; or &lt;code&gt;dt&lt;/code&gt; for short. Basically what we want to do here is nested commands.&lt;/p&gt;

&lt;p&gt;Let’s group our commands. We will move our &lt;code&gt;leap()&lt;/code&gt; and &lt;code&gt;utc()&lt;/code&gt; method inside of a new class called &lt;code&gt;DateTime&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pretty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="s"&gt;"""
        Get UTC time
        """&lt;/span&gt;

        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

        &lt;span class="n"&gt;utc_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pretty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%B %d :: %H:%M %p"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utc_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;leap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# required: since no default value here
&lt;/span&gt;        &lt;span class="s"&gt;"""
        Check if given year is leap or not
        """&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isleap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...):&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sub-command is determined by whatever we put as variable name when instantiating the new &lt;code&gt;DateTime&lt;/code&gt; class. Here we have named it as &lt;code&gt;dt&lt;/code&gt;, but you can name it as &lt;code&gt;datetime&lt;/code&gt;, &lt;code&gt;dtt&lt;/code&gt; or whatever you want. &lt;/p&gt;

&lt;p&gt;Now, we have more organized sub-commands for our CLI. If you want to run commands that are related to date time you can do so using &lt;code&gt;to dt &amp;lt;command-name&amp;gt;&lt;/code&gt; ; for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="n"&gt;utc&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="n"&gt;leap&lt;/span&gt; &lt;span class="mi"&gt;2025&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u9DvIEA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1pwnzwivh1fnagrfykz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u9DvIEA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1pwnzwivh1fnagrfykz.gif" alt="Image description" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Password command will be normal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pw&lt;/span&gt;
&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;pw&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Using python-fire makes the process of creating CLIs really easy and intuitive because you are using nothing but Python functions and classes. I hope this mini rundown of the tool and how to package it for your daily use has been helpful.&lt;/p&gt;

</description>
      <category>python</category>
      <category>cli</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Streamline Github Actions Releases with Github CLI</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Tue, 14 Feb 2023 04:08:37 +0000</pubDate>
      <link>https://dev.to/yankee/streamline-github-actions-releases-with-github-cli-3mio</link>
      <guid>https://dev.to/yankee/streamline-github-actions-releases-with-github-cli-3mio</guid>
      <description>&lt;p&gt;GitHub Actions is the default choice for CI/CD in many Open Source and Enterprise projects. It gets regular feature updates and is flexible enough to get most of the things done.&lt;/p&gt;

&lt;p&gt;One of the powerful feature it provides is the ability to re-use Actions, which is available on &lt;a href="https://github.com/marketplace?type=actions"&gt;Marketplace&lt;/a&gt; and we can use it from any GH repos. Most common Actions that I see being used almost everywhere are related to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;creating a Release&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;generating Release Notes for the release&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and uploading any Artifacts for the release&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, I was doing the same until recently. Playing around with the &lt;a href="https://github.com/cli/cli"&gt;GitHub CLI&lt;/a&gt; I figured everything I mentioned above could be done with it effortlessly! ✨ Not to mention it is flexible and provides options to move things our way. ++ It's already installed on the GitHub Actions runner.&lt;/p&gt;

&lt;p&gt;Enough talk, now let's see it in Action 🥁&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Release
&lt;/h2&gt;

&lt;p&gt;GitHub CLI provides a built-in sub-command to create a release. 🌟&lt;/p&gt;

&lt;p&gt;For a basic example: we want to create a release whenever we push a tag 🏷️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create Release&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release create ${GITHUB_REF#refs/*/} -t ${GITHUB_REF#refs/*/}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;gh release create &amp;lt;tag&amp;gt;&lt;/code&gt; : create a new release with the latest tag pushed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-t &amp;lt;tag&amp;gt;&lt;/code&gt;: Set title of the release; same as the pushed tag&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apart from general releases, we can also create &lt;strong&gt;draft releases&lt;/strong&gt; and &lt;strong&gt;prerelease&lt;/strong&gt; with the following flags.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-d&lt;/code&gt; : draft release&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-p&lt;/code&gt;: prerelease&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Generate Release Notes
&lt;/h2&gt;

&lt;p&gt;Now this one is pretty easy. We just have to pass the &lt;code&gt;--generate_notes&lt;/code&gt; flag to the above command and it will be generated for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create Release&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release create ${GITHUB_REF#refs/*/} -t ${GITHUB_REF#refs/*/} --generate-notes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want more flexibility then it also provides options to generate release notes from a file or from STDIN with the &lt;code&gt;-F&lt;/code&gt; flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upload artifacts with the Release
&lt;/h2&gt;

&lt;p&gt;Now this gets more interesting. You won't believe me if I say it.&lt;/p&gt;

&lt;p&gt;To upload artifacts to our release all we have to do is pass the file or directory names to the same command!&lt;/p&gt;

&lt;p&gt;I am taking an &lt;a href="https://github.com/yankeexe/12ft-browser-extension/blob/main/.github/workflows/release.yaml"&gt;example of my repository&lt;/a&gt; where I build browser extension artifacts for Chrome and Firefox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write-all&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create GH Release&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Artifacts&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./release.sh&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create Release&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release create ${GITHUB_REF#refs/*/} -t ${GITHUB_REF#refs/*/} 12_ft_chrome.zip 12_ft_firefox.zip --generate-notes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;permissions: write-all&lt;/code&gt;: For uploading artifacts, we will need to assign additional permissions to our &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;./release.sh&lt;/code&gt;: Builds Release Artifacts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;12_ft_&amp;lt;browser&amp;gt;.zip&lt;/code&gt;: are the artifacts generated by the above script&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we want a separate step to upload our artifacts, we can do so with the following change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write-all&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GH&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Release"&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Artifacts"&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./release.sh&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create Release&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release create ${GITHUB_REF#refs/*/} -t ${GITHUB_REF#refs/*/} --generate-notes&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload Artifact to Release&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh release upload  ${GITHUB_REF#refs/*/} 12_ft_chrome.zip 12_ft_firefox.zip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;We don't have to dabble around with multiple third-party actions, all of it can be done from a single command using GitHub CLI. This is more manageable, and effortless.&lt;/p&gt;

&lt;p&gt;Hope this has been helpful! ✨&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/yankeexe/12ft-browser-extension/blob/main/.github/workflows/release.yaml"&gt;&lt;strong&gt;Full reference to the above Action YAML&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;🚀&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>cloud</category>
      <category>programming</category>
    </item>
    <item>
      <title>6 Tools to Run Kubernetes Locally</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Thu, 05 Aug 2021 08:00:07 +0000</pubDate>
      <link>https://dev.to/yankee/6-tools-to-run-kubernetes-locally-4pmi</link>
      <guid>https://dev.to/yankee/6-tools-to-run-kubernetes-locally-4pmi</guid>
      <description>&lt;p&gt;Kubernetes is a big and complicated technology and it clearly requires some time and dedication to wrap your head around. There is no vendor lock-in meaning it runs the same no matter which managed cloud platform you use it on. This means using it locally will be no different from using it on the cloud.&lt;/p&gt;

&lt;p&gt;There are multiple tools for running Kubernetes on your local machine, but it basically boils down to two approaches on how it is done: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;running it from a single binary package &lt;/li&gt;
&lt;li&gt;running it as a container using Docker in Docker (DinD)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Kubernetes Marketplace
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/alexellis" rel="noopener noreferrer"&gt;
        alexellis
      &lt;/a&gt; / &lt;a href="https://github.com/alexellis/arkade" rel="noopener noreferrer"&gt;
        arkade
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open Source Marketplace For Developer Tools
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;arkade - Open Source Marketplace For Developer Tools&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;arkade is how developers install the latest versions of their favourite CLI tools and Kubernetes apps.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;arkade get&lt;/code&gt;, you'll have &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;terraform&lt;/code&gt;, and &lt;code&gt;jq&lt;/code&gt; on your machine faster than you can type &lt;code&gt;apt-get install&lt;/code&gt; or &lt;code&gt;brew update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/alexellis/arkadedocs/arkade-logo-sm.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Falexellis%2Farkadedocs%2Farkade-logo-sm.png" alt="arkade logo" width="150" height="150"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/sponsors/alexellis" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d750efd4012d261eac0d1261f4f72e0205723b53b8d34996800cd0afa38cf4d8/68747470733a2f2f696d672e736869656c64732e696f2f7374617469632f76313f6c6162656c3d53706f6e736f72266d6573736167653d254532253944254134266c6f676f3d476974487562266c696e6b3d68747470733a2f2f6769746875622e636f6d2f73706f6e736f72732f616c6578656c6c6973" alt="Sponsor this"&gt;&lt;/a&gt; &lt;a href="https://github.com/alexellis/arkade/actions/workflows/build.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/alexellis/arkade/actions/workflows/build.yml/badge.svg" alt="CI Build"&gt;&lt;/a&gt;
&lt;a href="https://github.com/alexellis/arkade/actions/workflows/e2e-url-checker.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/alexellis/arkade/actions/workflows/e2e-url-checker.yml/badge.svg" alt="URL Checker"&gt;&lt;/a&gt;
&lt;a href="https://godoc.org/github.com/alexellis/arkade" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/42e495f7f4f578ddbc36657f09c3ca8baa62a4bd445e16680ea04aadcb55f7d8/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f616c6578656c6c69732f61726b6164653f7374617475732e737667" alt="GoDoc"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6cd0120cc4c5ac11d28b2c60f76033b52db98dac641de3b2644bb054b449d60c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667" alt="License: MIT"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1d1e2c2be95256cbfd71730215b40eec69f54fdaffe48188f82e2dee11eea740/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f616c6578656c6c69732f61726b6164652f746f74616c"&gt;&lt;img src="https://camo.githubusercontent.com/1d1e2c2be95256cbfd71730215b40eec69f54fdaffe48188f82e2dee11eea740/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f616c6578656c6c69732f61726b6164652f746f74616c" alt="Downloads"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With over 120 CLIs and 55 Kubernetes apps (charts, manifests, installers) available for Kubernetes, gone are the days of contending with dozens of README files just to set up a development stack with the usual suspects like ingress-nginx, Postgres, and cert-manager.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/alexellis/arkade#arkade---open-source-marketplace-for-developer-tools" rel="noopener noreferrer"&gt;arkade - Open Source Marketplace For Developer Tools&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#support-arkade-" rel="noopener noreferrer"&gt;Support arkade 👋&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#should-you-try-arkade" rel="noopener noreferrer"&gt;Should you try arkade?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#getting-arkade" rel="noopener noreferrer"&gt;Getting arkade&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#usage-overview" rel="noopener noreferrer"&gt;Usage overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#download-cli-tools-with-arkade" rel="noopener noreferrer"&gt;Download CLI tools with arkade&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#install-system-packages" rel="noopener noreferrer"&gt;Install System Packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#install-packages-from-oci-images" rel="noopener noreferrer"&gt;Install packages from OCI images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#install-clis-during-ci-with-github-actions" rel="noopener noreferrer"&gt;Install CLIs during CI with GitHub Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#bump-helm-chart-versions" rel="noopener noreferrer"&gt;Bump Helm chart versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/alexellis/arkade#verify-and-upgrade-images-in-helm-charts" rel="noopener noreferrer"&gt;Verify and upgrade images in Helm charts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/alexellis/arkade#upgrade-images-within-a-helm-chart" rel="noopener noreferrer"&gt;Upgrade images within a Helm chart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/alexellis/arkade#verify-images-within-a-helm-chart" rel="noopener noreferrer"&gt;Verify&lt;/a&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/alexellis/arkade" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Before we move on to talk about all the tools, it will be beneficial if you installed &lt;code&gt;arkade&lt;/code&gt; on your machine. It will help you get these tools with a single command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sLS&lt;/span&gt; https://get.arkade.dev | &lt;span class="nb"&gt;sudo &lt;/span&gt;sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Features?
&lt;/h2&gt;

&lt;p&gt;All of the tools listed here more or less offer the same feature, including but not limited to: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multi-Node cluster&lt;/li&gt;
&lt;li&gt;Persistent volumes &lt;/li&gt;
&lt;li&gt;Networking&lt;/li&gt;
&lt;li&gt;Certificates&lt;/li&gt;
&lt;li&gt;Bare-metal support&lt;/li&gt;
&lt;li&gt;Dashboard &lt;/li&gt;
&lt;li&gt;Kubernetes Versions&lt;/li&gt;
&lt;li&gt;Add-ons&lt;/li&gt;
&lt;li&gt;Cross-platform&lt;/li&gt;
&lt;li&gt;Tracks upstream Kubernetes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Single package binary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/k3s-io/k3s" rel="noopener noreferrer"&gt;k3s&lt;/a&gt;&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146388504%2FEuqE3teij.png" alt="K3s logo.png"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;k3s is a lightweight Kubernetes distribution from Rancher Labs. It is specifically targeted for running on IoT and Edge devices, meaning it is a perfect candidate for your Raspberry Pi or a virtual machine. &lt;/p&gt;

&lt;p&gt;It comes with a single binary of mere &amp;lt;40 MB and takes as low as 500 MB of RAM.  &lt;/p&gt;

&lt;p&gt;You can bootstrap k3s quickly using  &lt;a href="https://github.com/alexellis/k3sup" rel="noopener noreferrer"&gt;k3sup&lt;/a&gt; !&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  arkade get k3sup 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/k0sproject/k0s" rel="noopener noreferrer"&gt;k0s&lt;/a&gt;&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146395939%2FRQI9JmCfU.png" alt="k0s.png"&gt;
k0s is the latest entry on the block. By name, you might think it's a more stripped version of k3s, but it's an entirely different distribution from an entirely different company, called Mirantis. Contrary to the name, it comes in a larger binary of 150 MB+.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can be run as a binary or in DinD mode. k0s takes security seriously and out of the box, it meets the &lt;a href="https://www.sdxcentral.com/security/definitions/what-does-mean-fips-compliant/" rel="noopener noreferrer"&gt;FIPS compliance&lt;/a&gt;.  Although, a new distribution, k0s has reached the production-ready status, so there wouldn't be an issue for development usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  arkade get k0s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/ubuntu/microk8s" rel="noopener noreferrer"&gt;Microk8s&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146540551%2FJ5ApDUbjf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146540551%2FJ5ApDUbjf.jpeg" alt="Micro k8s.jpg"&gt;&lt;/a&gt;&lt;br&gt;
  MicroK8s is a Kubernetes distribution by Canonical, the company behind Ubuntu. You already saw this coming; it can only be installed using &lt;code&gt;snap&lt;/code&gt;.  It comes with loads of add-ons baked in like Fluentd, Grafana and Prometheus. &lt;/p&gt;

&lt;p&gt;If you are on Ubuntu or its derivatives that uses &lt;code&gt;snap&lt;/code&gt; you'll feel right at home using MicroK8s.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;microk8s &lt;span class="nt"&gt;--classic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker in Docker (DinD)
&lt;/h2&gt;

&lt;p&gt;Running Docker inside of Docker (Inception anyone?) is a popular way of bootstrapping Kubernetes. The isolating nature of Docker makes running a multi-node cluster a breeze on a single machine, and also ensures the running instance does not affect the machine itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As the title suggests, you need to have Docker installed on your machine to go this route.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/kubernetes/minikube" rel="noopener noreferrer"&gt;minikube&lt;/a&gt;&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146684436%2Fclc9TZbZ4.png" alt="Minikube.png"&gt;
Despite running on top of Docker and similar container technologies, minikube is really flexible in how it operates and supports multiple virtualization drivers making it adaptable to different computing environments.  These include KVM2, Virtualbox, Podman, Hyperkit, Hyper-V and many more.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  arkade get minikube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/kubernetes-sigs/kind" rel="noopener noreferrer"&gt;KinD&lt;/a&gt;&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146781587%2FSgSgJa0dZ.png" alt="Kind.png"&gt;
Kubernetes in Docker (KinD) is similar to minikube but it does not spawn VM's to run clusters and works only with Docker.  KinD for the most part has the least bells and whistles and offers an intuitive developer experience in getting started with Kubernetes in no time.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  arkade get kind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/rancher/k3d/" rel="noopener noreferrer"&gt;k3d&lt;/a&gt;&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1628146849609%2FXZXhr_4Sk.png" alt="k3d.png"&gt;
k3d is basically running k3s inside of Docker. It provides an instant benefit over using k3s on a local machine, that is, multi-node clusters. Running inside Docker, we can easily spawn multiple instances of our k3s Nodes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  arkade get k3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Either you choose a single binary package or DinD approach, Kubernetes has made itself pretty accessible. For new learners, the barrier to entry is low, and the feedback loop is instantaneous. &lt;/p&gt;

&lt;p&gt;I hope this article has been helpful in deciding which tool to use for running your local Kubernetes instance.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>cloud</category>
      <category>docker</category>
    </item>
    <item>
      <title>Practical Guide to Git Worktree</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Mon, 12 Apr 2021 17:45:00 +0000</pubDate>
      <link>https://dev.to/yankee/practical-guide-to-git-worktree-58o0</link>
      <guid>https://dev.to/yankee/practical-guide-to-git-worktree-58o0</guid>
      <description>&lt;p&gt;Git has a solution to all of our problems, you just need to know where to look. As developers, context switching is a part of the job that you need to account for in more than a few occasions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem Statement
&lt;/h3&gt;

&lt;p&gt;Imagine this; you are working on a feature where you have made bunch of changes to files that are not yet commited, and suddenly you need to work on a hot fix or a more priority feature. There are two ways you can tackle this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/yankee/mastering-git-stash-workflow-223"&gt;Using Git Stash workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using Git Worktree (You are here! 📍)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Git worktree to the rescue 🌳
&lt;/h3&gt;

&lt;p&gt;Git worktree helps you manage multiple working trees attached to the same repository.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In short, you can check out multiple branches at the same time by maintaining multiple clones of the same repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK back to our problem! Update changes? New Feature? Hot Fix? Whatever it is, you need to change to a different branch and work on it without any changes to your current work directory.&lt;/p&gt;

&lt;p&gt;Let’s say it’s a new feature, your workflow would look like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create an replica of your project and switch to a new branch&lt;/li&gt;
&lt;li&gt;create a new feature&lt;/li&gt;
&lt;li&gt;push it&lt;/li&gt;
&lt;li&gt;back to previous working directory&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create worktree
&lt;/h3&gt;

&lt;p&gt;Let’s say the name of your feature is &lt;code&gt;feature-x&lt;/code&gt; and you want the branch with the same name. You can create additional worktree on the same directory or move it to a desired path, I prefer the later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git worktree add&lt;/code&gt; command creates a worktree along with a branch that is named after the final word in your path.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

git worktree add &amp;lt;PATH&amp;gt;

&lt;span class="c"&gt;# Create feature-x directory and branch with the same name.&lt;/span&gt;
git worktree add ../feature-x


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll5h29lxleual7qez3o2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll5h29lxleual7qez3o2.gif" alt="Creating new git worktree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Named Branch
&lt;/h3&gt;

&lt;p&gt;If you want to give you branch a unique name then you can use the &lt;code&gt;-b&lt;/code&gt; flag with the &lt;code&gt;add&lt;/code&gt; command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature-xyz ../feature-xyz


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv38rqcy4vkpafms1fr4u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv38rqcy4vkpafms1fr4u.gif" alt="Git worktree creating new named branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Track remote branch
&lt;/h3&gt;

&lt;p&gt;Let’s say you want to switch to a new branch that is tracking the branch at remote, where you want to push changes to.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; &amp;lt;branch-name&amp;gt; &amp;lt;PATH&amp;gt; &amp;lt;remote&amp;gt;/&amp;lt;branch-name&amp;gt;

git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; feature-zzz ../feature-x origin/feature-zzz


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create worktree with local branch
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

git worktree add &amp;lt;PATH&amp;gt; &amp;lt;branch-name&amp;gt;

git worktree add ../feature-xz feature-xz


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;View the list of worktrees with &lt;code&gt;git worktree list&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching Worktrees
&lt;/h3&gt;

&lt;p&gt;As much easy it is to create a worktree, it is equally difficult to navigate back and forth between them if they are spread across. You have to &lt;code&gt;git worktree list&lt;/code&gt; and then copy the path navigate to the worktree of your choice. To minimize this friction, I have built a small tool that let’s you switch between worktrees just with their partial or complete directory name.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/yankeexe/git-worktree-switcher" rel="noopener noreferrer"&gt;Download wt CLI tool&lt;/a&gt; for faster switching between worktrees.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this I can simply switch between my worktrees.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5bpg3fracpfoyb68lbt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5bpg3fracpfoyb68lbt.gif" alt="wt cli tool to switch between git worktrees"&gt;&lt;/a&gt;&lt;br&gt;
You can &lt;code&gt;wt list&lt;/code&gt; which is equivalent to &lt;code&gt;git worktree list&lt;/code&gt; to see the list of your worktrees. Now to move to &lt;code&gt;feature-x&lt;/code&gt; worktree directory, I can just use &lt;code&gt;wt feature-x&lt;/code&gt; to cd into that directory to continue with the work. To go back to my main worktree directory I can just &lt;code&gt;wt -&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove Worktrees
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmzezl1l6yl7cwiu9fltw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmzezl1l6yl7cwiu9fltw.gif" alt="Remove git worktrees"&gt;&lt;/a&gt;&lt;br&gt;
Now that you have created a new worktree, switched to it and made your changes and pushed it. To remove the worktree, we can run: &lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;git worktree remove &amp;lt;name-of-worktree&amp;gt;&lt;/p&gt;

&lt;p&gt;git worktree remove feature-x&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Git worktree is a handy feature that let's you context switch in your project to try out things on a completely different environment, without modifying your main work directory. This might come handy occasionally but it's pretty neat being able to do so without breaking a sweat. &lt;/p&gt;

&lt;p&gt;I hope this guide has been helpful, if you have any queries or corrections, feel free to reach out to me.&lt;/p&gt;

</description>
      <category>github</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Streamline your projects using Makefile</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Sat, 26 Dec 2020 16:17:53 +0000</pubDate>
      <link>https://dev.to/yankee/streamline-projects-using-makefile-28fe</link>
      <guid>https://dev.to/yankee/streamline-projects-using-makefile-28fe</guid>
      <description>&lt;p&gt;&lt;code&gt;make&lt;/code&gt; is one of the tools that we use heavily for streamlining tasks on our projects. It has proven to be helpful specifically for streamlining the development process, repeating mundane tasks with custom CLI like subcommands and mainly &lt;strong&gt;onboarding new team members&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/vybdPTfNLo4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;With a set of rules in &lt;strong&gt;Makefile&lt;/strong&gt;, you can get up and running in no time, keeping the process sane and saving time and effort for everyone in the team. We'll be going through the basics to some interesting stuffs we can do with Makefile.&lt;/p&gt;

&lt;p&gt;There are two pieces to this equation, one is the &lt;code&gt;make&lt;/code&gt; CLI tool and the next is the Makefile . The basics is &lt;code&gt;make&lt;/code&gt; reads the &lt;strong&gt;rules&lt;/strong&gt; from the Makefile and executes them. What I will be showing today is just a small part of what &lt;code&gt;make&lt;/code&gt; is capable of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Makefile
&lt;/h2&gt;

&lt;p&gt;If you have worked with &lt;code&gt;YAML&lt;/code&gt; files before then you will feel right at home writing Makefiles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anatomy of Rules
&lt;/h3&gt;

&lt;p&gt;Every &lt;code&gt;Makefile&lt;/code&gt; consists of rules with the anatomy of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dependencies&lt;/span&gt;
    recipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;target&lt;/strong&gt;: 
target can be an executable, object or just a name for an action that we want to carry out. We will be using targets purely with the placeholder name for the rule. Be mindful about the name, as it should resonate with the action we want to perform with no confusion whatsoever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dependencies&lt;/strong&gt;: 
Dependencies are the rules that needs to be executed, in order for the current rule to work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;recipe&lt;/strong&gt;: 
recipe is the meat of the &lt;code&gt;Makefile&lt;/code&gt;, it is the action that we want to perform with our &lt;code&gt;target&lt;/code&gt; name. Make sure to put a &lt;code&gt;tab&lt;/code&gt; character at the start of every recipe line (just like YAML). You can also replace the &lt;code&gt;tab&lt;/code&gt; character with anything you want using the &lt;code&gt;.RECIPEPREFIX&lt;/code&gt; variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next we will be looking into some examples on how to make use of &lt;code&gt;Makefile&lt;/code&gt;. These examples will be based on setting up development environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Rules
&lt;/h3&gt;

&lt;p&gt;A basic rule where you just want to put some alias is straight forward. &lt;/p&gt;

&lt;p&gt;Let’s say you have a &lt;strong&gt;python&lt;/strong&gt; project and you want to hand it over to a new team member. How do you streamline the setup process. Maybe it can look something like this. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;br&gt;
&lt;code&gt;#&lt;/code&gt; is for comments. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;@&lt;/code&gt; symbol is to disable printing the recipe to stdout. &lt;br&gt;
Test without the &lt;code&gt;@&lt;/code&gt; symbol at the beginning of the recipe.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:=&lt;/code&gt; is the expansion operator which prevents using subsequent value with the same variable name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SHELL&lt;/code&gt; variable determines the default shell to execute the recipe.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt;/bin/bash

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;format check&lt;/span&gt;

&lt;span class="nl"&gt;venv&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; setup a virtual environment&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv

&lt;span class="nl"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; install dev dependencies&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; .[dev]
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Installing pre-commit hook..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;pre-commit &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="nl"&gt;format&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; format code using black&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;black .

&lt;span class="nl"&gt;check&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; check for formatting using black&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;black &lt;span class="nt"&gt;--check&lt;/span&gt; &lt;span class="nt"&gt;--diff&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; .

&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; run pytest&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;pytest &lt;span class="nt"&gt;-vvv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do something similar with your existing project.&lt;/p&gt;

&lt;p&gt;Now to get up and running, all you have to do is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make venv 

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; venv/bin/activate 

&lt;span class="nv"&gt;$ &lt;/span&gt;make setup

&lt;span class="nv"&gt;$ &lt;/span&gt;make format 

&lt;span class="c"&gt;# and so on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rules with Dependencies
&lt;/h3&gt;

&lt;p&gt;Taking the reference from the example above, suppose we want to print out the output of &lt;code&gt;check&lt;/code&gt; target every time we run the &lt;code&gt;format&lt;/code&gt; target. So how do we create that dependency? It’s plain simple, we just have to update the &lt;code&gt;format&lt;/code&gt; target to look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;format&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;check &lt;/span&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; run the formatter on files.&lt;/span&gt;
 &lt;span class="err"&gt;@black&lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have added the dependency of &lt;code&gt;check&lt;/code&gt; to the right of the target, just like showcased on the anatomy &lt;strong&gt;Anatomy of Rules&lt;/strong&gt; section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variables
&lt;/h2&gt;

&lt;p&gt;We can also define variables if we have some piece of command for repeated use. For this example we will be taking the reference of the &lt;code&gt;Django&lt;/code&gt; management command. &lt;/p&gt;

&lt;p&gt;Variables are normally written with all caps and uses &lt;code&gt;:=&lt;/code&gt; to assign variable name to a value. Variables can be accessed using either &lt;code&gt;$()&lt;/code&gt; or &lt;code&gt;${}&lt;/code&gt; syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;DJANGO_MANAGE&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; python manage.py
&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; 
 &lt;span class="err"&gt;@${DJANGO_MANAGE}&lt;/span&gt; &lt;span class="err"&gt;runserver&lt;/span&gt;

&lt;span class="nl"&gt;show&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; 
 &lt;span class="err"&gt;@${DJANGO_MANAGE}&lt;/span&gt; &lt;span class="err"&gt;showmigrations&lt;/span&gt;

&lt;span class="nl"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; 
 &lt;span class="err"&gt;@${DJANGO_MANAGE}&lt;/span&gt; &lt;span class="err"&gt;migrate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also your &lt;strong&gt;SHELL environment variables&lt;/strong&gt; are converted in to Makefile environment variables, so you can directly make use of them while creating your rules. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In our shell we can export an environment variable called &lt;code&gt;INFO&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Run make help to show all the available rules."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now in the Makefile we can refer to it as any variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;info&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; show project info&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;${INFO}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Default target
&lt;/h2&gt;

&lt;p&gt;If you just run &lt;code&gt;make&lt;/code&gt; on your command line nothing is going to happen. But we can change that by using the &lt;code&gt;.DEFAULTGOAL&lt;/code&gt; special variable and assigning the target we want to run by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;.DEFAULT_GOAL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, next time you run &lt;code&gt;make&lt;/code&gt; it is going to run the &lt;code&gt;Django&lt;/code&gt; server by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self documenting
&lt;/h2&gt;

&lt;p&gt;Now we have bunch of targets on our &lt;code&gt;Makefile&lt;/code&gt; and we also called this combo as a custom mini CLI app. Wouldn’t it be great, if we could have a help command similar to a real CLI app? Say no more, thanks to the &lt;a href="https://dev.to/victoria/how-to-create-a-self-documenting-makefile-2b0e"&gt;blog&lt;/a&gt; from &lt;a href="https://dev.to/victoria"&gt;Victoria Drake&lt;/a&gt; we have the script to do so. &lt;/p&gt;

&lt;p&gt;Just create a &lt;code&gt;help&lt;/code&gt; target and assign it as a &lt;code&gt;.DEFAULT_GOAL&lt;/code&gt;. With this, all the comments we have been writing on our target gets converted into a nice help message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;.DEFAULT_GOAL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;help&lt;/span&gt; 
&lt;span class="nl"&gt;help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; Show this help&lt;/span&gt;
 &lt;span class="nl"&gt;@egrep -h '\s#\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = "&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;.*?&lt;/span&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="nf"&gt; "}; {printf "&lt;/span&gt;\0&lt;span class="nf"&gt;33[36m%-20s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m %s&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$2}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Include other Makefiles
&lt;/h2&gt;

&lt;p&gt;We can separate out Makefiles based on the tasks they perform and &lt;code&gt;include&lt;/code&gt; them into the main &lt;code&gt;Makefile&lt;/code&gt;. We usually have separate &lt;code&gt;Makefile&lt;/code&gt; managed for &lt;strong&gt;environment variables&lt;/strong&gt;,  &lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;Kubernetes&lt;/strong&gt;. This offloads all the tasks from project set up to Deployment to the Makefile.&lt;/p&gt;

&lt;p&gt;I will show a brief example of each of the file just to give an example: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Since make runs each recipe on a new instance of the shell, we can lazy evaluate the variables using &lt;code&gt;?=&lt;/code&gt; meaning, they are initialized only when referenced for a single shell instance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Makefile&lt;/strong&gt;&lt;br&gt;
Root makefile composed of other Makefiles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt;/bin/bash
&lt;span class="nv"&gt;APP_ROOT&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nv"&gt;$(PWD)&lt;/span&gt;
&lt;span class="nv"&gt;TMP_PATH&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;/.tmp
&lt;span class="nv"&gt;VENV_PATH&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;/.venv

&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ENVIRONMENT_OVERRIDE_PATH&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;/env/Makefile.override

&lt;span class="k"&gt;-include&lt;/span&gt;&lt;span class="sx"&gt; $(ENVIRONMENT_OVERRIDE_PATH)&lt;/span&gt;
&lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="sx"&gt; $(APP_ROOT)/targets/Makefile.docker&lt;/span&gt;
&lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="sx"&gt; $(APP_ROOT)/targets/Makefile.k8s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Environment Variables&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Makefile.override&lt;/em&gt;&lt;br&gt;
Makefile containing just the essential environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;STAGE&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &amp;lt;stage&amp;gt;
&lt;span class="nv"&gt;SERVICE_NAME&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &amp;lt;service-name&amp;gt;
&lt;span class="nv"&gt;AKS_RESOURCE_GROUP&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &amp;lt;resource-group&amp;gt;
&lt;span class="nv"&gt;AKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &amp;lt;cluster-name&amp;gt;
&lt;span class="nv"&gt;REGISTRY_URL&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &amp;lt;registry-url&amp;gt;
&lt;span class="nv"&gt;AZ_ACR_REPO_NAME&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &amp;lt;repo-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Makefile.docker&lt;/em&gt;&lt;br&gt;
Makefile containing docker rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GIT_COMMIT&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-c-8&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;git rev-parse HEAD&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BRANCH&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;shell&lt;/span&gt; git rev-parse &lt;span class="nt"&gt;--abbrev-ref&lt;/span&gt; HEAD&lt;span class="nf"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_BUILD_FLAGS&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt;
&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_BUILD_PATH&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;
&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_FILE&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;/Dockerfile

&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TARGET_IMAGE&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nv"&gt;$(REGISTRY_URL)&lt;/span&gt;/&lt;span class="nv"&gt;$(AZ_ACR_REPO_NAME)&lt;/span&gt;/&lt;span class="nv"&gt;$(SERVICE_NAME)&lt;/span&gt;
&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TARGET_IMAGE_LATEST&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nv"&gt;$(TARGET_IMAGE)&lt;/span&gt;:&lt;span class="nv"&gt;$(BRANCH)&lt;/span&gt;-&lt;span class="nv"&gt;$(GIT_COMMIT)&lt;/span&gt;

&lt;span class="nl"&gt;acr-docker-login&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    az acr login &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$(AZ_ACR_REPO_NAME)&lt;/span&gt;

&lt;span class="nl"&gt;docker-build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker build &lt;span class="nv"&gt;$(DOCKER_BUILD_FLAGS)&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$(SERVICE_NAME)&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$(DOCKER_FILE)&lt;/span&gt; &lt;span class="nv"&gt;$(DOCKER_BUILD_PATH)&lt;/span&gt;

&lt;span class="nl"&gt;docker-tag&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker tag &lt;span class="nv"&gt;$(SERVICE_NAME)&lt;/span&gt; &lt;span class="nv"&gt;$(TARGET_IMAGE_LATEST)&lt;/span&gt;

&lt;span class="nl"&gt;docker-push&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;acr-docker-login&lt;/span&gt;
    docker push &lt;span class="nv"&gt;$(TARGET_IMAGE_LATEST)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Makefile.k8s&lt;/em&gt;&lt;br&gt;
Makefile containing rules for Kubernetes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="k"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OVERLAY_PATH&lt;/span&gt; &lt;span class="o"&gt;?=&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;/k8s/overlays/&lt;span class="nv"&gt;$(STAGE)&lt;/span&gt;/

&lt;span class="err"&gt;define&lt;/span&gt; &lt;span class="err"&gt;kustomize-image-edit&lt;/span&gt;
    &lt;span class="err"&gt;cd&lt;/span&gt; &lt;span class="err"&gt;$(OVERLAY_PATH)&lt;/span&gt; &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="err"&gt;kustomize&lt;/span&gt; &lt;span class="err"&gt;edit&lt;/span&gt; &lt;span class="err"&gt;set&lt;/span&gt; &lt;span class="err"&gt;image&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(1)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$(APP_ROOT)&lt;/span&gt;
&lt;span class="err"&gt;endef&lt;/span&gt;

&lt;span class="nl"&gt;kubectl-apply&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    kustomize build &lt;span class="nv"&gt;$(OVERLAY_PATH)&lt;/span&gt;
    kustomize build &lt;span class="nv"&gt;$(OVERLAY_PATH)&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -

&lt;span class="nl"&gt;update-kubeconfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    az aks get-credentials &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$(AKS_RESOURCE_GROUP)&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$(AKS_CLUSTER_NAME)&lt;/span&gt;

&lt;span class="nl"&gt;aks-deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;update-kubeconfig&lt;/span&gt;
    &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;call&lt;/span&gt; kustomize-image-edit,&lt;span class="nv"&gt;$(TARGET_IMAGE_LATEST)&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;
    make kubectl-apply

&lt;span class="nl"&gt;aks-delete&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;update-kubeconfig&lt;/span&gt;
    kubectl delete namespace &lt;span class="nv"&gt;$(STAGE)&lt;/span&gt;&lt;span class="nt"&gt;-api&lt;/span&gt;

&lt;span class="nl"&gt;kustomize-edit&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;call&lt;/span&gt; kustomize-image-edit,&lt;span class="nv"&gt;$(TARGET_IMAGE_LATEST)&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have orchestrated all these Makefiles, it is easier to keep track of all the rules and makes working with Makefiles sane, if you are doing a lot with it.&lt;/p&gt;

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

&lt;p&gt;So with the use of &lt;code&gt;Makefile&lt;/code&gt; we can streamline a lot of redundant tasks in our projects without having to remember overwhelmingly long and varying commands. &lt;/p&gt;

&lt;p&gt;It increases the productivity of the whole team; with easier project setup and redundant tasks outsourced to the &lt;code&gt;Makefile&lt;/code&gt; with intuitive target names, leaving the devs to focus on more serious tasks at hand.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>cli</category>
    </item>
    <item>
      <title>How Rolling and Rollback Deployments work in Kubernetes</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Sun, 25 Oct 2020 08:42:27 +0000</pubDate>
      <link>https://dev.to/yankee/how-rolling-and-rollback-deployments-work-in-kubernetes-5ob</link>
      <guid>https://dev.to/yankee/how-rolling-and-rollback-deployments-work-in-kubernetes-5ob</guid>
      <description>&lt;p&gt;Kubernetes has been used heavily on production for the past few years. It offers a plethora of solutions for orchestrating your containers using its declarative API. One of the prominent feature of Kubernetes is its resilience with the ability to perform Rolling and Rollback Deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Primer&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Deployments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Deployment is one of the mechanisms for handling workloads (applications) in Kubernetes. It is managed by &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/" rel="noopener noreferrer"&gt;Kubernetes Deployment Controller&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In Kubernetes, controllers are control loops that watch the state of your cluster, then make or request changes where needed. Each controller tries to move the current cluster state closer to the desired state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In case of deployment here, the desired state we want to achieve is for the pods. Everything is declarative in K8s, so the desired state is written as a spec in Deployment manifest file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# deployment.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.14.2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If any of our pod instances should fail or update(a status change), the Kubernetes system responds to the difference between manifest spec and status by making a correction, i.e. matching the state of &lt;code&gt;Deployment&lt;/code&gt; as defined on the spec.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Deployment under the hood&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Deployment is an abstraction over &lt;code&gt;ReplicaSet&lt;/code&gt;. Under the hood, Deployment creates a ReplicaSet which in turn creates pods on our cluster. As per the name, &lt;code&gt;ReplicaSet&lt;/code&gt; is used for managing the replicas of our pods.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In summary, Controller reads the Deployment spec, forwards the pod configuration to ReplicaSet and then it creates the pods with proper replicas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5926%2F1%2A6Nk_o7OgLxap7YeoT2nchw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5926%2F1%2A6Nk_o7OgLxap7YeoT2nchw.png" alt="**Deployment &amp;gt; ReplicaSet &amp;gt; Pods**"&gt;&lt;/a&gt;&lt;strong&gt;&lt;em&gt;Deployment &amp;gt; ReplicaSet &amp;gt; Pods&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rolling Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Kubernetes promises zero down time and one of the reasons behind it is Rolling Deployments. With Rolling Deployments, Kubernetes makes sure that the traffic to the pods are not interrupted when updated pods are being deployed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rollback Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Rollback Deployment means, going back to the previous instance of the deployment if there is some issue with the current deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Hands on&lt;/strong&gt; 🙌
&lt;/h2&gt;

&lt;p&gt;Let’s get our hands-on with Kubernetes and see how these deployment strategies are carried out.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Setup KinD&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We will setup a single node Kubernetes cluster on our local machine using KinD (Kubernetes in Docker). Make sure you have Docker running.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://kind.sigs.k8s.io/docs/user/quick-start/" rel="noopener noreferrer"&gt;Install KinD&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will create a K8s cluster using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kind create cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our cluster ready we are ready for Deployments.&lt;/p&gt;

&lt;p&gt;For the purpose of this tutorial, we won’t be touching any YAML files and will be fully utilizing the power of &lt;code&gt;kubectl&lt;/code&gt; CLI tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Create Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s create our first Deployment using the &lt;code&gt;nginx&lt;/code&gt; image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create deployment test-nginx &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.18-alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like mentioned earlier, a Deployment creates a &lt;code&gt;ReplicaSet&lt;/code&gt; followed by &lt;code&gt;Pods&lt;/code&gt;. You can check these newly created resources using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get deploy,rs,po &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ABPNB73wic-lm6ETxKBA_dQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ABPNB73wic-lm6ETxKBA_dQ.png" alt="List newly created Deployment, ReplicaSet and Pod"&gt;&lt;/a&gt;&lt;em&gt;List newly created Deployment, ReplicaSet and Pod&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can check to make sure the &lt;code&gt;Replicaset&lt;/code&gt; was created by our &lt;code&gt;Deployment&lt;/code&gt; using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl describe rs &amp;lt;replica-set-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2214%2F1%2A1vXq7RDIyCOH50ZmK7VAdA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2214%2F1%2A1vXq7RDIyCOH50ZmK7VAdA.png" alt="Check ReplicaSet created by Deployment"&gt;&lt;/a&gt;&lt;em&gt;Check ReplicaSet created by Deployment&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can do the same with Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl describe po &amp;lt;pod-name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Scale Deployment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s scale the deployment to have 3 instances of &lt;code&gt;nginx&lt;/code&gt; pods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl scale deploy test-nginx &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2At1jYzWl1JNy9S2vvG_xuZw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2At1jYzWl1JNy9S2vvG_xuZw.png" alt="Creating 3 replicas of nginx pods"&gt;&lt;/a&gt;&lt;em&gt;Creating 3 replicas of nginx pods&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we have significant number of pods on our cluster. Let’s try out the Deployment strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Hands-on: Rolling Update Deployment&lt;/strong&gt; 🍥⏩
&lt;/h3&gt;

&lt;p&gt;Let’s say you were having some issues with &lt;code&gt;v18&lt;/code&gt; of nginx and the &lt;code&gt;v19&lt;/code&gt; fixes it for you. You need to rollout a new update of nginx image to your pod.&lt;/p&gt;

&lt;p&gt;By updating the image of the current pods (state change), Kubernetes will rollout a new Deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nb"&gt;set &lt;/span&gt;image deploy test-nginx &lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx:1.19-alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we set the new image, we can see the old pods getting terminated and new pods getting created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKuckqy4F8_SnYitb3U1Zcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKuckqy4F8_SnYitb3U1Zcw.png" alt="Rolling update, new pod replacing old ones"&gt;&lt;/a&gt;&lt;em&gt;Rolling update, new pod replacing old ones&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can see Kubernetes at work, making sure the pods are maintained properly. The last of the old pod doesn’t get terminated until the complete replicas for the new pods are created. The old pods also have a &lt;strong&gt;&lt;em&gt;grace period&lt;/em&gt;&lt;/strong&gt; which makes sure the traffic it is serving isn’t disconnected for certain time until the requests can be safely routed to the newly created pods.&lt;/p&gt;

&lt;p&gt;We successfully updated all our pods to use &lt;code&gt;nginx v19&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl describe deploy test-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ai_itv0eTq5kGpVxXRb8ejw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ai_itv0eTq5kGpVxXRb8ejw.png" alt="Pods updated to nginx v19"&gt;&lt;/a&gt;&lt;em&gt;Pods updated to nginx v19&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Hands-on: Rollback Deployment&lt;/strong&gt; 🍥⏪
&lt;/h3&gt;

&lt;p&gt;Let’s assume the new nginx update has even more problems than the last one and now you realized how blissful life was with the old version. Time for a rollback to the previous version of nginx.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;But how do we do that?&lt;/em&gt;&lt;/strong&gt; You might have noticed that there are now two &lt;code&gt;ReplicaSets&lt;/code&gt;. It’s due to the same Deployment pattern we discussed earlier, we update our Deployment, it creates a new ReplicaSet which creates new Pods. Kubernetes holds history of up to 10 ReplicaSet by default, we can update that figure by using &lt;code&gt;revisionHistoryLimit&lt;/code&gt; on our Deployment spec.&lt;/p&gt;

&lt;p&gt;These history are tracked as rollouts. Only the latest rollout is active.&lt;/p&gt;

&lt;p&gt;By now, we have made two changes to our Deployment &lt;code&gt;test-nginx&lt;/code&gt; so the rollout history should be two.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get rs 

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deploy test-nginx

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl rollout &lt;span class="nb"&gt;history &lt;/span&gt;deploy test-nginx &lt;span class="nt"&gt;--revision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AgOsETG1h7JZ_buPrFc_eSg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AgOsETG1h7JZ_buPrFc_eSg.png" alt="Rollout history for test-nginx Deployment"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Rollout history for test-nginx Deployment&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alright let’s get to rolling back our update to the previous rollout. We want to rollback to the stage where we were using nginx v18 which is rollout &lt;code&gt;Revision 1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl rollout undo deploy test-nginx &lt;span class="nt"&gt;--to-revision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ACBfbT_dXYdLw9lhtBGut4Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ACBfbT_dXYdLw9lhtBGut4Q.png" alt="Rollout undo pod states"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Rollout undo pod states&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Like the Rolling Update Deployment, the Rollback Deployment terminates the current pods and replaces them with the pods containing the spec from Revision 1.&lt;/p&gt;

&lt;p&gt;If you check the rollout history once again, you can see that the Revision 1 has been used to create the latest pods tagging it with Revision 3. There is no point in maintaining the same spec repeated for multiple revisions, so Kubernetes removes the Revision 1 since we have the latest Revision 3 of the same spec.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A3v4H7G4c7dVsCvPJUeow5Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A3v4H7G4c7dVsCvPJUeow5Q.png" alt="Revision history after rollout undo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Revision history after rollout undo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we are back on the nginx v18. with the Rollback Deployment. You can check that out by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl describe deploy test-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2078%2F1%2ACj3FfsLEdiB3IZyXxnRtGw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2078%2F1%2ACj3FfsLEdiB3IZyXxnRtGw.png" alt="Check rollback nginx version"&gt;&lt;/a&gt;&lt;em&gt;Check rollback nginx version&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt; 🚀
&lt;/h2&gt;

&lt;p&gt;Kubernetes makes it easy to control the Deployment of our applications with these strategies. This was just a rundown of how Rolling and Rollback Update Deployments work from a ground level. In real-life, we rarely do all these steps manually, since we hand it down to our CI/CD pipeline like &lt;a href="https://argoproj.github.io/argo-cd/" rel="noopener noreferrer"&gt;ArgoCD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading. Hope this guide has been helpful for you to understand how Rolling and Rollback Deployments work in Kubernetes. If you have any corrections, suggestions, or feedback feel free to DM me on &lt;a href="https://twitter.com/yankexe" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or comment down below.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>deployment</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Setting up multi-node Kubernetes cluster locally with K3s and Multipass</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Sat, 24 Oct 2020 15:12:04 +0000</pubDate>
      <link>https://dev.to/yankee/setting-up-multi-node-kubernetes-cluster-locally-with-k3s-and-multipass-3oj0</link>
      <guid>https://dev.to/yankee/setting-up-multi-node-kubernetes-cluster-locally-with-k3s-and-multipass-3oj0</guid>
      <description>&lt;p&gt;There are a lot of tools that allow you to setup a local Kubernetes cluster in no time. But with a full-blown K8s running on your local machine, you will soon hit a wall if you want to play with multi-node cluster.&lt;/p&gt;

&lt;p&gt;For tackling this very issue, we will be looking into how we can setup a lightweight Kubernetes cluster using &lt;a href="https://k3s.io/"&gt;K3s&lt;/a&gt; and &lt;a href="https://multipass.run/"&gt;Multipass&lt;/a&gt; for our VMs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are interested in what makes K3s so light, you can watch the talk on &lt;a href="https://www.youtube.com/watch?v=-HchRyqNtkU"&gt;K3s under the hood&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installing Multipass
&lt;/h3&gt;

&lt;p&gt;Multipass is a command line tool to orchestrate virtual Ubuntu instances on your local machine. With the CLI, you can spawn VMs within minutes allocating optimal CPU, memory and disk space.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/canonical/multipass#install-multipass"&gt;Download Multipass&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Installing K3sup (ketchup)
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;We talked about K3s but it can be daunting to set up if you just want a quick hands on with Kubernetes. To abstract all that we will be installing a handy CLI called &lt;a href="https://github.com/alexellis/k3sup"&gt;k3sup&lt;/a&gt;. It will bootstrap Kubernetes cluster on our VMs using K3s within a minute! 🚀&lt;/p&gt;

&lt;p&gt;k3sup uses SSH under the hood, so make sure you have SSH service on your machine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/alexellis/k3sup#download-k3sup-tldr"&gt;Install k3sup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating Virtual machines
&lt;/h2&gt;

&lt;p&gt;Nodes are just virtual machines on Kubernetes working in sync. For our cluster we will be creating 3 virtual machines, each with 1CPU, 1GB RAM, 2GB Storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating keys
&lt;/h3&gt;

&lt;p&gt;If you have SSH installed and already have &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt; and &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; , you can skip this part and move to **creating config file **section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create Private/Public key:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the aforementioned files on your system. Copy the contents of &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Creating config file&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a file called &lt;code&gt;multipass.yaml&lt;/code&gt; and place your public key in &lt;code&gt;ssh-rsa&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# multipass.yaml&lt;/span&gt;
&lt;span class="na"&gt;ssh_authorized_keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ssh-rsa &amp;lt;add-your-public-key&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This config file makes sure the public key is stored on the virtual machine once it’s created. Let’s create our VMs with proper names based on their roles we will be assigning (master/worker).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;multipass launch &lt;span class="nt"&gt;--cpus&lt;/span&gt; 1 &lt;span class="nt"&gt;--mem&lt;/span&gt; 1G &lt;span class="nt"&gt;--disk&lt;/span&gt; 2G &lt;span class="nt"&gt;--name&lt;/span&gt; master-node &lt;span class="nt"&gt;--cloud-init&lt;/span&gt; multipass.yaml

&lt;span class="nv"&gt;$ &lt;/span&gt;multipass launch &lt;span class="nt"&gt;--cpus&lt;/span&gt; 1 &lt;span class="nt"&gt;--mem&lt;/span&gt; 1G &lt;span class="nt"&gt;--disk&lt;/span&gt; 2G &lt;span class="nt"&gt;--name&lt;/span&gt; agent-master &lt;span class="nt"&gt;--cloud-init&lt;/span&gt; multipass.yaml

&lt;span class="nv"&gt;$ &lt;/span&gt;multipass launch &lt;span class="nt"&gt;--cpus&lt;/span&gt; 1 &lt;span class="nt"&gt;--mem&lt;/span&gt; 1G &lt;span class="nt"&gt;--disk&lt;/span&gt; 2G &lt;span class="nt"&gt;--name&lt;/span&gt; agent-worker &lt;span class="nt"&gt;--cloud-init&lt;/span&gt; multipass.yaml

&lt;span class="nv"&gt;$ &lt;/span&gt;multipass &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In K3s terms, a master node is called the server and the rest of the nodes are called agents. Agents are simply the nodes that gets added to the master node; they can be another master node or a worker node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding K8s sauce with k3sup
&lt;/h2&gt;

&lt;p&gt;Now that we have our VMs ready, let’s install Kubernetes on them. First we will be creating a master node to setup a control plane.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a master node
&lt;/h3&gt;

&lt;p&gt;We will need the &lt;code&gt;IP&lt;/code&gt; and &lt;code&gt;username&lt;/code&gt; of our virtual machine to SSH into and install Kubernetes. Run &lt;code&gt;multipass ls&lt;/code&gt; and take note of IP of &lt;code&gt;master-node&lt;/code&gt; . All the usernames for VMs are &lt;code&gt;ubuntu&lt;/code&gt; by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k3sup &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ip&lt;/span&gt; &amp;lt;IP&amp;gt; &lt;span class="nt"&gt;--user&lt;/span&gt; ubuntu &lt;span class="nt"&gt;--k3s-extra-args&lt;/span&gt; &lt;span class="s2"&gt;"--cluster-init"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are passing the &lt;code&gt;--k3s-extra-args "--cluster-init"&lt;/code&gt; to make sure this node is prepared to connect with another master node, else it might cause errors.&lt;/p&gt;

&lt;p&gt;Once installed it downloads the &lt;code&gt;kubeconfig&lt;/code&gt; file on the directory where you invoked your command. You can set environment variable &lt;code&gt;KUBECONFIG&lt;/code&gt; with path to recently downloaded &lt;code&gt;kubeconfig&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# mac / linux&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;path-to-kubeconfig&amp;gt;

&lt;span class="c"&gt;# windows&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;setx KUBECONFIG &amp;lt;path-to-kubeconfig&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can &lt;code&gt;kubectl get nodes&lt;/code&gt; to view the nodes on your cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a second master node (HA)
&lt;/h3&gt;

&lt;p&gt;Multi master setup on local machine is an overkill for most use cases but for the purpose of this tutorial we are going to add it anyway. To join a new master node in the cluster we use the &lt;code&gt;join&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Here, all we have to do is introduce the server IP and username (previously created) that this node should connect to . And additionally pass the &lt;code&gt;--server&lt;/code&gt; flag specifying this will be a server node (master).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k3sup &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ip&lt;/span&gt; &amp;lt;IP-of-agent-master&amp;gt; &lt;span class="nt"&gt;--user&lt;/span&gt; ubuntu &lt;span class="nt"&gt;--server-ip&lt;/span&gt; &amp;lt;IP-of-master-node&amp;gt; &lt;span class="nt"&gt;--server-user&lt;/span&gt; ubuntu &lt;span class="nt"&gt;--server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s about it. Now you can &lt;code&gt;kubectl get nodes&lt;/code&gt; again, and you’ll see two master nodes that is Highly Available (HA).&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a worker node
&lt;/h2&gt;

&lt;p&gt;Finally, we have to setup our worker node where we will be deploying our applications and services.&lt;/p&gt;

&lt;p&gt;For this grab the IP of &lt;code&gt;agent-worker&lt;/code&gt; and pass on the same command as before minus the &lt;code&gt;--server&lt;/code&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k3sup &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="nt"&gt;--ip&lt;/span&gt; &amp;lt;IP-of-agent-worker&amp;gt; &lt;span class="nt"&gt;--user&lt;/span&gt; ubuntu &lt;span class="nt"&gt;--server-ip&lt;/span&gt; &amp;lt;IP-of-master-node&amp;gt; &lt;span class="nt"&gt;--server-user&lt;/span&gt; ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you &lt;code&gt;kubectl get nodes&lt;/code&gt; , you will find two master nodes and a single worker node composing your multi node cluster setup. You can create new VMs and add more master or worker nodes depending on how you plan to utilize your cluster.&lt;/p&gt;

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

&lt;p&gt;Thank you for reading. Hope this guide has been helpful for you to setup and play with multi-node Kubernetes cluster. If you have any corrections, suggestions, or feedback feel free to DM me on &lt;a href="https://twitter.com/yankexe"&gt;Twitter&lt;/a&gt; or comment below.&lt;/p&gt;

&lt;p&gt;Happy hacking! 🚀&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>docker</category>
    </item>
    <item>
      <title>Mastering Git Stash Workflow</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Sun, 23 Aug 2020 12:03:10 +0000</pubDate>
      <link>https://dev.to/yankee/mastering-git-stash-workflow-223</link>
      <guid>https://dev.to/yankee/mastering-git-stash-workflow-223</guid>
      <description>&lt;p&gt;Git is a powerful tool that makes up for a lot of use cases on our development workflow. One such case is to isolate the changes of a certain branch to itself. Let me elaborate.&lt;/p&gt;

&lt;p&gt;Suppose you are working on a branch called &lt;code&gt;admin-dashboard&lt;/code&gt; implementing ,well, an administrative dashboard. But you are not done yet, and the project manager wants a quickfix for the login implementation. Now you want to switch to the &lt;code&gt;login&lt;/code&gt; branch and fix the issue but don’t want to carry the changes you are doing on the &lt;code&gt;admin-dashboard&lt;/code&gt; branch. Well this is where git stash comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Git stash what?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Git stash allows you to quickly put aside your modified changes to a LIFO (Last In First Out) stack and re-apply them when feasible. We will be doing a rough walkthrough to see this in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Git stash walkthrough&lt;/strong&gt; 🚶‍♂️
&lt;/h2&gt;

&lt;p&gt;Initiate git on an empty directory. Add a file named &lt;code&gt;add.py&lt;/code&gt; and put the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# add.py 
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s add the file to git and commit it .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add add.py &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next let’s create and checkout to a new branch called &lt;code&gt;mul&lt;/code&gt; and create a file called &lt;code&gt;mul.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; mul
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code to the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# mul.py 
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the file to git and commit it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add mul &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Mul function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose, we need to update the mul function to take in a third argument and you just edited the function like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# mul.py&lt;/span&gt;

def mul&lt;span class="o"&gt;(&lt;/span&gt;a, b, c&lt;span class="o"&gt;)&lt;/span&gt;: 
    &lt;span class="k"&gt;return &lt;/span&gt;a &lt;span class="k"&gt;*&lt;/span&gt; b 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take note that, we still haven’t updated the return value with &lt;code&gt;c&lt;/code&gt;. While we were making our changes, the project manager called-in to update the &lt;code&gt;add&lt;/code&gt; function immediately with a third argument. Now you can’t waste a second on the &lt;code&gt;mul&lt;/code&gt; function which you haven’t completed. &lt;strong&gt;What are you going to do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you try to checkout to master where add function resides, git won’t let you because you have unfinished changes that hasn’t been committed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9M0Vcx2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2ASm1VcF-XIR9CZKJRrd9V0w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9M0Vcx2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2ASm1VcF-XIR9CZKJRrd9V0w.gif" alt="" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Stashing Changes&lt;/strong&gt; 📤
&lt;/h3&gt;

&lt;p&gt;Well this is the situation you should be using the &lt;code&gt;git stash&lt;/code&gt; command. We want to put away the changes on our current branch so that we can come back to it later.&lt;/p&gt;

&lt;p&gt;Stash the file with a message on the &lt;code&gt;mul&lt;/code&gt; branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash save &lt;span class="s2"&gt;"Multiply function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you &lt;code&gt;git status&lt;/code&gt;, the working directory will be clean and you can jump into the master branch for the changes. We can view the items in our stash using &lt;code&gt;git stash list&lt;/code&gt;. We can view the diff of the items on our stack using &lt;code&gt;git stash show&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x9rhmLFx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2A1w-UUFmluedhcbGROyvi2A.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x9rhmLFx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2A1w-UUFmluedhcbGROyvi2A.gif" alt="" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you are in &lt;code&gt;master&lt;/code&gt; branch modifying the &lt;code&gt;add&lt;/code&gt; function, and comes an even higher priority job to include a &lt;code&gt;subtraction&lt;/code&gt; function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;br&gt;
Project Managers in real life doesn’t put forward tasks on this manner.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your &lt;code&gt;add&lt;/code&gt; function looks pretty much like the &lt;code&gt;mul&lt;/code&gt; function now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# add.py 
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;   &lt;span class="c1"&gt;# couldn't include `c` due to a priority task.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stash it with a message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash save &lt;span class="s2"&gt;"Add function third argument"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rb5Ub2mS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AJPNqrbe449Konsoxrdg3-g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rb5Ub2mS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AJPNqrbe449Konsoxrdg3-g.gif" alt="" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s suppose we have completed our task for &lt;code&gt;subtraction&lt;/code&gt; branch and we want to continue working on other branches.&lt;/p&gt;

&lt;p&gt;Let’s move to the &lt;code&gt;master&lt;/code&gt; branch first to complete our changes for addition.&lt;/p&gt;

&lt;p&gt;There are two ways we can re-apply those changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git stash pop&lt;/code&gt;&lt;br&gt;
applies the top most change stored on the stack and removes it from the stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git stash apply &amp;lt;item-id&amp;gt;&lt;/code&gt; &lt;br&gt;
applies the stash based on the index provided, keeps the applied item intact on the stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Popping stashed changes&lt;/strong&gt; 🍾
&lt;/h3&gt;

&lt;p&gt;Like I mentioned earlier, stash follows the LIFO convention. The latest item we save are always on the top. And when we use &lt;code&gt;pop&lt;/code&gt;, always the top most change is applied to the current branch. Run the following command on &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git stash pop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7hyHIm0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2ArL3Sk-m74A8v-GYGbxKkOg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7hyHIm0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2ArL3Sk-m74A8v-GYGbxKkOg.gif" alt="" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complete the &lt;code&gt;add&lt;/code&gt; function and commit it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Applying stashed changes&lt;/strong&gt; 📥
&lt;/h3&gt;

&lt;p&gt;Next, checkout &lt;code&gt;mul&lt;/code&gt; branch. We can use &lt;code&gt;pop&lt;/code&gt; here as well since there is only one item remaining on the stack. But let’s see how &lt;code&gt;git stash apply&lt;/code&gt; works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash apply stash@&lt;span class="o"&gt;{&lt;/span&gt;0&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DTbH72OU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AVI7FJ2kNfy4_KWZCQ5WGVA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DTbH72OU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AVI7FJ2kNfy4_KWZCQ5WGVA.gif" alt="" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we apply from the stash, the item still remains on the stack. &lt;br&gt;
Complete the changes here and commit it.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Create a new branch with stashed changes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s do something fun. Let’s say we want to add a &lt;code&gt;divide&lt;/code&gt; function on a new branch. Well it is kind of similar to our &lt;code&gt;multiple&lt;/code&gt; function so why not utilize the item in stash and create a &lt;code&gt;divide&lt;/code&gt; function with it?&lt;/p&gt;

&lt;p&gt;We can do that with the &lt;code&gt;git stash branch&lt;/code&gt; command. It takes the &lt;code&gt;&amp;lt;item-id&amp;gt;&lt;/code&gt; and a branch name, then &lt;strong&gt;&lt;em&gt;applies&lt;/em&gt;&lt;/strong&gt; those changes to that branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash branch &amp;lt;branch-name&amp;gt; &amp;lt;item-id&amp;gt;

git stash branch divide stash@&lt;span class="o"&gt;{&lt;/span&gt;0&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UxpCw3TH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AROehknP7W7-a8v6Rdtr_sQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UxpCw3TH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AROehknP7W7-a8v6Rdtr_sQ.gif" alt="" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can rename the file and change the function to perform division.&lt;/p&gt;

&lt;h3&gt;
  
  
  Viewing the stashed changes
&lt;/h3&gt;

&lt;p&gt;Sometimes we tend to forget what changes we stashed. What we forget can range from which files were stashed to what changes on the files were stashed. &lt;/p&gt;

&lt;p&gt;To view a list of files that were stashed, we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# EXAMPLE:&lt;/span&gt;
&lt;span class="c"&gt;# git stash show stash@{&amp;lt;stash-id&amp;gt;}&lt;/span&gt;

git stash show stash@&lt;span class="o"&gt;{&lt;/span&gt;2&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get a diff view of changes on the files that were stashed, we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# EXAMPLE:&lt;/span&gt;
&lt;span class="c"&gt;# git stash show -p stash@{&amp;lt;stash-id&amp;gt;}&lt;/span&gt;

git stash show &lt;span class="nt"&gt;-p&lt;/span&gt; stash@&lt;span class="o"&gt;{&lt;/span&gt;2&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Clearing the stack&lt;/strong&gt; 🧹
&lt;/h3&gt;

&lt;p&gt;Now that the stash has served its purpose, we can clear it. There is again two ways of doing it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git stash clear&lt;/code&gt;&lt;br&gt;
wipes the whole stack clean.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git stash drop &amp;lt;item-id&amp;gt;&lt;/code&gt;&lt;br&gt;
removes the item from stack based on provided id.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt; 🚀
&lt;/h3&gt;

&lt;p&gt;Git stash is a powerful tool that comes handy in many situations. Hope this article helped you in understanding and implementing the concept in your project. If you have any suggestions or feedback, let’s talk on the comment section or you can &lt;a href="https://twitter.com/yankexe"&gt;@ me on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://github.com/yankeexe"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Deploy your Serverless Python function locally with OpenFaas in Kubernetes</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Sat, 15 Aug 2020 10:27:36 +0000</pubDate>
      <link>https://dev.to/yankee/deploy-your-serverless-python-function-locally-with-openfaas-in-kubernetes-18jf</link>
      <guid>https://dev.to/yankee/deploy-your-serverless-python-function-locally-with-openfaas-in-kubernetes-18jf</guid>
      <description>&lt;p&gt;We have come a long way in building distributed applications. From monoliths to Microservices we have been able to decouple and scale our applications with optimal use of the underlying hardware resources. But now we are moving towards more lightweight approach to deploy our applications; &lt;strong&gt;Serverless&lt;/strong&gt;! With the inception of Function as a Service (FaaS), application modularization has been taking an ascent in the world of cloud computing.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/3JpnyF0agxY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this blog, we will be exploring development to deployment of our Serverless function locally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The beauty of OpenFaas and KinD is that you don’t need to deploy your functions to cloud to test them, you can run them locally!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisite&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;You just need to have &lt;strong&gt;Docker&lt;/strong&gt; installed on your machine. The rest we will setup as we go along. We will be installing a few tools so bear with me. 🐻&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.openfaas.com/"&gt;OpenFaas&lt;/a&gt;?&lt;/strong&gt; 🐬
&lt;/h3&gt;

&lt;p&gt;OpenFaas is an awesome tool/framework developed by &lt;a href="https://github.com/sponsors/alexellis"&gt;Alex Ellis&lt;/a&gt; with the Open Source community that helps to deploy burstable functions and microservices to Kubernetes without repetitive, boiler-plate coding.&lt;/p&gt;

&lt;p&gt;It was built with developer experience in mind creating a low barrier of entry to the Kubernetes ecosystem. It comes with it’s own cli-tool called the &lt;code&gt;faas-cli&lt;/code&gt; which makes a clever use of templates and makes pushing docker images and deployment of containers a breeze. And once deployed it takes care of auto-scaling and auto-provisioning based on the network traffic.&lt;/p&gt;

&lt;p&gt;With all the overhead being handled by OpenFaas, all you have to do is focus on writing your function. But in our case we have some setting up to do 👨‍🏭&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Properties of functions&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Here are few things to keep in mind when you are creating a function.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A rule of thumb is to make your function stateless.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Function should be atomic (single responsibility).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It should be idempotent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger to the function could be TCP or event, however effect must be an event.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Let’s get started!&lt;/strong&gt; 🚀
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install arkade&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/alexellis/arkade"&gt;arkade&lt;/a&gt; will be our one stop tool to install and deploy apps and services to Kubernetes. Think of this tool as a package manager like &lt;code&gt;apt&lt;/code&gt; or &lt;code&gt;pacman&lt;/code&gt;. We will be needing a bunch of CLI utilities to get up and running.&lt;/p&gt;

&lt;p&gt;Make sure you install this if you have never set up a Kubernetes tooling in your system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-sLS&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;https://dl.get-arkade.dev]&lt;span class="o"&gt;(&lt;/span&gt;https://dl.get-arkade.dev&lt;span class="o"&gt;)&lt;/span&gt; | &lt;span class="nb"&gt;sudo &lt;/span&gt;sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Just to make things clear:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;use arkade get to download cli tools and applications related to Kubernetes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use arkade install to install Kubernetes applications using &lt;a href="https://helm.sh/docs/topics/charts/"&gt;helm charts&lt;/a&gt; or vanilla &lt;code&gt;yaml&lt;/code&gt; files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install kubectl&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/kubectl/overview/"&gt;kubectl&lt;/a&gt; is a command line tool that talks to the Kubernetes Master Controller API for performing actions on our cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;arkade get kubectl

&lt;span class="c"&gt;# follow the instructions on the screen.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Creating a local Kubernetes cluster&lt;/strong&gt; 🧱
&lt;/h2&gt;

&lt;p&gt;We will be deploying our function on a local Kubernetes cluster so let’s set that up. We will be using a tool called &lt;strong&gt;KinD&lt;/strong&gt;(Kubernetes in Docker) for this.&lt;/p&gt;

&lt;p&gt;Unlike &lt;a href="https://github.com/kubernetes/minikube"&gt;Minikube&lt;/a&gt; which requires VM; KinD utilizes Docker container to deploy your cluster. It is comparatively faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install KinD&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our goal is to keep everything local so we will be creating a local Docker registry (&lt;a href="https://hub.docker.com/"&gt;Dockerhub&lt;/a&gt; for your local machine). KinD provides a &lt;a href="https://kind.sigs.k8s.io/docs/user/local-registry/"&gt;shell script&lt;/a&gt; to create a Kubernetes cluster along with local Docker registry enabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; errexit

&lt;span class="c"&gt;# create registry container unless it already exists&lt;/span&gt;
&lt;span class="nv"&gt;reg_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kind-registry'&lt;/span&gt;
&lt;span class="nv"&gt;reg_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'5000'&lt;/span&gt;
&lt;span class="nv"&gt;running&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker inspect &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s1"&gt;'{{.State.Running}}'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;running&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;docker run &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_port&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:5000"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    registry:2
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# create a cluster with the local registry enabled in containerd&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_port&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"]
    endpoint = ["http://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_port&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"]
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# connect the registry to the cluster network&lt;/span&gt;
docker network connect &lt;span class="s2"&gt;"kind"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# tell https://tilt.dev to use the registry&lt;/span&gt;
&lt;span class="c"&gt;# https://docs.tilt.dev/choosing_clusters.html#discovering-the-registry&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;node &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;kind get nodes&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;kubectl annotate node &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"kind.x-k8s.io/registry=localhost:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;reg_port&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;kind-with-registry.sh from &lt;a href="https://kind.sigs.k8s.io/docs/user/local-registry/"&gt;KinD website&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have the file on your local machine. Run the following command to make it executable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x kind-with-registry.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run the script to create your local Kubernetes cluster with local Docker registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./kind-with-registry.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure the kubectl context is set to the newly created cluster; run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl config current-context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the result is not &lt;code&gt;kind-kind&lt;/code&gt;; then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl config use kind-kind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure your cluster is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl cluster-info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure Docker registry is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; kind-registry
OR 
&lt;span class="nv"&gt;$ &lt;/span&gt;docker ps &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Deploying OpenFaas to KinD cluster&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that we have our local Kubernetes cluster up and running lets deploy our OpenFaas services to support our functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;arkade &lt;span class="nb"&gt;install &lt;/span&gt;openfaas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure OpenFaas is deployed. It might take a minute or two.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; openfaas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://docs.openfaas.com/cli/templates/#templates"&gt;Templates&lt;/a&gt;&lt;/strong&gt;📂
&lt;/h3&gt;

&lt;p&gt;Before we move to creating our function, it is essential to understand the concept of templates in OpenFaas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are templates?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Templates are basically a wrapper for your functions. Same template can be used for multiple functions.&lt;/p&gt;

&lt;p&gt;OpenFaas already provides a variety of templates for different programming languages to start with.&lt;/p&gt;

&lt;p&gt;There are two type of templates based on the webserver :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;classic watchdog&lt;/strong&gt; which uses template format from &lt;a href="https://github.com/openfaas/templates"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;of-watchdog&lt;/strong&gt; which uses template format from &lt;a href="https://github.com/openfaas-incubator?q=template&amp;amp;type=&amp;amp;language="&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Watchdogs are basically webservers to proxy request to our functions.&lt;/p&gt;

&lt;p&gt;We will be using the templates that supports the latest &lt;code&gt;of-watchdog&lt;/code&gt;. You can read more about &lt;a href="https://docs.openfaas.com/architecture/watchdog/"&gt;OpenFaas watchdog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most important piece in the templates directory is the Dockerfile, it drives everything from your watchdog to how and where your function gets placed in the template. You can also create your own template based on the need of your function.&lt;/p&gt;

&lt;p&gt;Pull the template from store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# list all the templates &lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli template store list

&lt;span class="c"&gt;# pull python3-flask template from store&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli template store pull python3-flask
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will pull all the templates for python from OpenFaas store to your &lt;strong&gt;template&lt;/strong&gt; directory of your project folder. We will be using the &lt;a href="https://github.com/openfaas-incubator/python-flask-template/tree/master/template/python3-flask-debian"&gt;python3-flask-debian&lt;/a&gt; template. You can ignore rest of the templates or delete them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7-PiCOl4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2726/1%2AS-eT29RL_snrWai59dry6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7-PiCOl4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2726/1%2AS-eT29RL_snrWai59dry6g.png" alt="Openfaas template structure." width="800" height="462"&gt;&lt;/a&gt;&lt;em&gt;Openfaas template structure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Shown above is the basic template structure for all languages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Template structure explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;index.py&lt;/code&gt; is an entrypoint to our Flask application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;requirements.txt&lt;/code&gt; on the root project directory contains dependencies for our Flask application. It contains &lt;a href="https://flask.palletsprojects.com/en/1.1.x/"&gt;Flask&lt;/a&gt; and &lt;a href="https://docs.pylonsproject.org/projects/waitress/en/latest/"&gt;waitress&lt;/a&gt; (WSGI).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;template.yml&lt;/code&gt; contains the deployment specific configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;requirements.txt&lt;/code&gt; inside of the function directory is for the function specific dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt; contains the instructions to build image for our function.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Building our function&lt;/strong&gt; 🔨
&lt;/h2&gt;

&lt;p&gt;Now it’s time to create our Serverless function.&lt;/p&gt;

&lt;p&gt;We’ll keep the scope really small and build a simple dictionary function that returns the meaning of words you query. For this we will be using the &lt;a href="https://pypi.org/project/PyDictionary/"&gt;PyDictionary&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;Since we have our template in place, we can utilize it to scaffold our function. You may have noticed the &lt;strong&gt;function&lt;/strong&gt; directory and &lt;strong&gt;template.yml&lt;/strong&gt; file inside our &lt;code&gt;python3-flask-debian&lt;/code&gt; template folder earlier. We can leverage that to create our new function using the &lt;code&gt;faas-cli&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli new &amp;lt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nt"&gt;-name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;--lang&lt;/span&gt; &amp;lt;template-name&amp;gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli new pydict &lt;span class="nt"&gt;--lang&lt;/span&gt; python3-flask-debian
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a folder with the function name(pydict) along with the contents we saw earlier inside the templates function folder, plus a &lt;code&gt;yaml&lt;/code&gt; file with the function name(pydict).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bjTLem4m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A4kwHYzSifJlsqmqIIHzMCg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bjTLem4m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A4kwHYzSifJlsqmqIIHzMCg.png" alt="" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s add our dependency to the requirements.txt file of function folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PyDictionary==2.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the &lt;code&gt;handler.py&lt;/code&gt; with the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PyDictionary&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PyDictionary&lt;/span&gt;

&lt;span class="n"&gt;dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PyDictionary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;     
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;meaning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our function is complete. ✔&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Openfaas YAML configuration&lt;/strong&gt; 📄
&lt;/h3&gt;

&lt;p&gt;A Kubernetes guide won’t be complete without talking about YAML files. They are necessary to describe the state of our deployments. &lt;code&gt;faas-cli&lt;/code&gt; has already created a yaml file for our function, namely, &lt;code&gt;pydict.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This file will tell the &lt;code&gt;faas-cli&lt;/code&gt; about the functions and images we want to deploy, language templates we want to use, scaling factor, and other configurations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xmRmciJx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2180/1%2A6ZDh8rEB2abV6eQqZuJlhQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmRmciJx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2180/1%2A6ZDh8rEB2abV6eQqZuJlhQ.png" alt="contents of pydict.yml" width="800" height="427"&gt;&lt;/a&gt;&lt;em&gt;contents of pydict.yml&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;YAML file breakdown&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;gateway&lt;/code&gt;: determines the IP address to connect to the OpenFaas service. Since we are testing it locally the gateway provided by default is fine. &lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; if we were deploying on managed cloud: we will take the IP address of &lt;code&gt;gateway-external&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under &lt;code&gt;functions&lt;/code&gt;: we can register different Serverless functions we want to deploy along with their configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;lang&lt;/code&gt;: name of the language template the function uses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;handler&lt;/code&gt;: location of our Serverless function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;image&lt;/code&gt;: fully qualified docker registry URL along with image name and tag.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since we are using Local registry we have to change the image tag to incorporate it. Change value of image to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7wEEZGE0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2180/1%2Aex99mjBGUJ048DIHpkyBMw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7wEEZGE0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2180/1%2Aex99mjBGUJ048DIHpkyBMw.png" alt="Change image tag to use local container registry" width="800" height="427"&gt;&lt;/a&gt;&lt;em&gt;Change image tag to use local container registry&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Port-forward to Localhost&lt;/strong&gt; ⏩
&lt;/h3&gt;

&lt;p&gt;Now, we need to port-forward the OpenFaas gateway service to our localhost port. Remember the gateway on our yaml file?&lt;/p&gt;

&lt;p&gt;To check the gateway of OpenFaas service; run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get service &lt;span class="nt"&gt;-n&lt;/span&gt; openfaas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3YLpiGyC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2180/1%2Auj9C0YMr_2_dc7a3_mcy-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3YLpiGyC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2180/1%2Auj9C0YMr_2_dc7a3_mcy-Q.png" alt="" width="800" height="427"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl port-forward &lt;span class="nt"&gt;-n&lt;/span&gt; openfaas svc/gateway 8080:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although the the cluster is deployed locally, internally Kubernetes manages it’s own IP addresses. We are port forwarding to access the service inside the Kubernetes cluster from our local machine. Once that is done, open a new terminal window, and prepare for take off!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Build ➡Push ➡Deploy&lt;/strong&gt; 🚀
&lt;/h2&gt;

&lt;p&gt;We have most of the setup ready; now we can build our image, push it to the registry, and deploy it to Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build our image&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli build &lt;span class="nt"&gt;-f&lt;/span&gt; pydict.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Push our image to the local registry&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli push &lt;span class="nt"&gt;-f&lt;/span&gt; pydict.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to deploy the function to the cluster; we need to login to &lt;code&gt;faas-cli&lt;/code&gt; Let’s generate credentials for authentication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate password:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret &lt;span class="nt"&gt;-n&lt;/span&gt; openfaas basic-auth &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.basic-auth-password}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check if password exists:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, login to &lt;code&gt;faas-cli&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$PASSWORD&lt;/span&gt; | faas-cli login &lt;span class="nt"&gt;--username&lt;/span&gt; admin &lt;span class="nt"&gt;--password-stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time for deployment:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;faas-cli deploy &lt;span class="nt"&gt;-f&lt;/span&gt; pydict.yml &lt;span class="nt"&gt;-g&lt;/span&gt; http://127.0.0.1:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check if our deployment has been successful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; openfaas-fn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Testing our function&lt;/strong&gt; 👨‍🔬
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Test using CLI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We can invoke our function from CL I to get the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"brevity"&lt;/span&gt; | faas-cli invoke pydict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D9XPd0re--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AT_A_aLiJ65CPOCqd5y0d1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D9XPd0re--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AT_A_aLiJ65CPOCqd5y0d1A.png" alt="" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Test using Openfaas Portal&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;OpenFaas also comes with a neat UI portal to invoke our function.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;localhost:8080&lt;/code&gt; in your browser. A prompt will ask you for username and password. Use &lt;strong&gt;admin&lt;/strong&gt; for &lt;em&gt;username&lt;/em&gt; and for &lt;em&gt;password&lt;/em&gt; check the password we generated earlier. In case you forgot, you can always repeat the earlier command, i.e.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret &lt;span class="nt"&gt;-n&lt;/span&gt; openfaas basic-auth &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.data.basic-auth-password}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sX_34k7T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3840/1%2ApSG_9cokxgEucPhJW6ZdAQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sX_34k7T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3840/1%2ApSG_9cokxgEucPhJW6ZdAQ.png" alt="OpenFaas UI" width="800" height="429"&gt;&lt;/a&gt;&lt;em&gt;OpenFaas UI&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Build more functions&lt;/strong&gt; 🔨
&lt;/h3&gt;

&lt;p&gt;Now that you have your cluster deployed with OpenFaas, you can create function with ease and deploy them. If you want to create a new function, all you have to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;scaffold a new function using &lt;code&gt;faas-cli new&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;write your function&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;faas-cli up -f &amp;lt;config-yaml-file&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;faas-cli up&lt;/code&gt; is a shortcut for &lt;code&gt;build, push and deploy&lt;/code&gt; command.&lt;/p&gt;

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

&lt;p&gt;Hope this has been a helpful guide in learning how to use OpenFaas for Serverless deployment. If you have any queries or suggestions, let’s talk in the comment section or you can &lt;a href="https://twitter.com/yankexe"&gt;DM me on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Check out example &lt;a href="https://github.com/yankeexe/openfaas-functions"&gt;functions on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>serverless</category>
      <category>openfaas</category>
      <category>kubernetes</category>
      <category>python</category>
    </item>
    <item>
      <title>Understanding Callable in Python</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Tue, 11 Aug 2020 18:35:38 +0000</pubDate>
      <link>https://dev.to/yankee/understanding-callable-in-python-22k3</link>
      <guid>https://dev.to/yankee/understanding-callable-in-python-22k3</guid>
      <description>&lt;p&gt;Functions and classes are the most common things we use in our daily development. We invoke them, pass them around and yet never wonder what makes them so amazing. Well the short answer is &lt;strong&gt;callable protocol;&lt;/strong&gt; for the long answer keep reading!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Definition&lt;/strong&gt; 📢
&lt;/h3&gt;

&lt;p&gt;Objects defining the &lt;code&gt;__call__&lt;/code&gt; method is known as callable. Or basically callable is anything you can call using the parenthesis () and pass arguments to it. Yes I am basically talking about a function.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;__call__&lt;/code&gt; method&lt;/strong&gt; 🤙
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;__call__&lt;/code&gt; is one of the most interesting dunder method in Python. It is what most of the built-in functions make use of. If we peek into the type of some of these built-in functions then we often see the result as a class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;range&lt;/span&gt;&lt;span class="s"&gt;'&amp;gt;

&amp;gt;&amp;gt;&amp;gt; zip 
&amp;lt;class '&lt;/span&gt;&lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="s"&gt;'&amp;gt;

&amp;gt;&amp;gt;&amp;gt; int
&amp;lt;class '&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="s"&gt;'&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get the gist. But how is a class acting as a function? I mean you can just &lt;code&gt;zip(iterable1, iterable2)&lt;/code&gt; and you get your result without further invoking any other methods of the class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just imagine using zip like if it were a normal class.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Intel'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Ryzen'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Apple Silicon'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;zipped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;zipped&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This definitely isn’t intuitive to work with. So how does it work?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using &lt;code&gt;__call__&lt;/code&gt; method&lt;/strong&gt; 🔨
&lt;/h3&gt;

&lt;p&gt;Well behind the scenes it’s because of the &lt;code&gt;__call__&lt;/code&gt; method. This method is used in classes if we want the &lt;strong&gt;instance of the class&lt;/strong&gt; to be callable.&lt;/p&gt;

&lt;p&gt;What do I mean by that? Let’s take an example of a class that prints the square of a number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# create an instance 
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# invoke
&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is similar to executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But with the &lt;code&gt;__call__&lt;/code&gt; dunder method we don’t have to do that. We can directly invoke the instance like a normal function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may have noticed, we don’t need to use the &lt;code&gt;__init__&lt;/code&gt; constructor to pass the value. Since the class instance acts like a function, then it can take arguments like a function without a need of a constructor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Testing callable&lt;/strong&gt; 👨‍🔬
&lt;/h3&gt;

&lt;p&gt;A class or a function is callable by default; but the instance is callable with &lt;code&gt;__call__&lt;/code&gt; dunder method only. We can check this by using the &lt;code&gt;callable()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Take for example a class without a &lt;code&gt;__call__&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the contrary, let’s take our Square class from earlier example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt; 🚀
&lt;/h3&gt;

&lt;p&gt;Next time when you’re creating a class for something and it needs to return a value in an instant; you can make use of the &lt;code&gt;__call__&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;I hope this blog has been a help to understand an underlying concept involved in functions and classes. If you have any queries or suggestions, let’s discuss them in the comment section.&lt;/p&gt;

</description>
      <category>python</category>
      <category>codenewbie</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Faster Git workflow with Git Aliases</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Sat, 25 Jul 2020 15:39:06 +0000</pubDate>
      <link>https://dev.to/yankee/faster-git-workflow-with-git-aliases-4006</link>
      <guid>https://dev.to/yankee/faster-git-workflow-with-git-aliases-4006</guid>
      <description>&lt;p&gt;Git is an intricate part of our development workflow. There are handful of commands that you keep repeating day in and day out. I always relied on the command suggestions, or packages on top of my shell that gave access to handy git aliases. &lt;/p&gt;

&lt;p&gt;But usually you had to stick with the aliases decided by the package creators . Although most of the aliases included are unofficially globally accepted like &lt;code&gt;ga&lt;/code&gt; for &lt;code&gt;git add&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;But guess what? You don’t have to rely on any third party packages ; you can create your own with the aliases you prefer! &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;There are two ways of creating Git aliases: ✌&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;with the git config utility&lt;/strong&gt; 💻
&lt;/h3&gt;

&lt;p&gt;This is the preferred way of adding aliases as &lt;code&gt;git&lt;/code&gt; gives you an option to do so. &lt;/p&gt;

&lt;p&gt;Suppose you feel tired of repeating the &lt;strong&gt;commit&lt;/strong&gt; command every now and then. It would be nice if we could create an alias to write our commits faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Say no more! 🎉&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.c &lt;span class="s2"&gt;"commit -m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command follows the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.&amp;lt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;command&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use the &lt;code&gt;c&lt;/code&gt; alias to represent &lt;code&gt;commit -m&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git c &lt;span class="s2"&gt;"Update readme with social links"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;editing the .gitconfig file&lt;/strong&gt; 📝
&lt;/h3&gt;

&lt;p&gt;It would be tedious to add multiple aliases with the &lt;code&gt;git config&lt;/code&gt; command, so there’s an easier alternate approach.&lt;/p&gt;

&lt;p&gt;All the alias you create is saved to the &lt;code&gt;.gitconfig&lt;/code&gt; file sitting in your home directory. We can open the file and add our aliases following the &lt;a href="https://github.com/toml-lang/toml"&gt;TOML &lt;/a&gt;formatting. Make sure you do not modify anything in the file apart from adding the &lt;code&gt;[alias]&lt;/code&gt; table and its contents.&lt;/p&gt;

&lt;p&gt;Open the file using your favorite editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim ~/.gitconfig 
&lt;span class="c"&gt;# or&lt;/span&gt;
code ~/.gitconfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start adding your alias ✍️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="nn"&gt;[alias]&lt;/span&gt;
        &lt;span class="py"&gt;st&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="err"&gt;status&lt;/span&gt;
        &lt;span class="py"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="err"&gt;commit&lt;/span&gt; &lt;span class="err"&gt;-m&lt;/span&gt;
        &lt;span class="py"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="err"&gt;add&lt;/span&gt;
        &lt;span class="py"&gt;cb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="err"&gt;checkout&lt;/span&gt; &lt;span class="err"&gt;-b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use the above aliases as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git st &lt;span class="c"&gt;# git status&lt;/span&gt;
git c &lt;span class="s2"&gt;"hello world"&lt;/span&gt; &lt;span class="c"&gt;# git commit -m "hello world"&lt;/span&gt;
git a hallucination.py &lt;span class="c"&gt;# git add hallucination.py &lt;/span&gt;
git cb multi-stage-build &lt;span class="c"&gt;# git checkout -b multi-stage-build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s also a handy command: &lt;code&gt;git config --list&lt;/code&gt; to view the contents of the file including other git configurations. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Bonus&lt;/strong&gt; 🛸
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Git alias with parameters!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We can take our alias a step further by using shell script to add parameters. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where do we benefit from the parameters?&lt;/strong&gt; &lt;br&gt;
Let’s take an example of adding a git remote to our local repository. There are basically two variables in the command that I can pass as a parameter, namely, the &lt;strong&gt;remote name&lt;/strong&gt; and &lt;strong&gt;project name.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add &amp;lt;remote-name&amp;gt; git@github.com:yankeexe/&amp;lt;project-name&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can represent the above abstraction using an anonymous bash function &lt;code&gt;f()&lt;/code&gt;as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[alias]&lt;/span&gt;
        &lt;span class="py"&gt;ra&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"!f() { git remote add $1 git@github.com:yankeexe/$2.git; };f"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$1&lt;/code&gt; and &lt;code&gt;$2&lt;/code&gt; is the order in which the parameter will be used by the function. &lt;code&gt;!&lt;/code&gt; represents a shell script; our anonymous function is &lt;code&gt;f()&lt;/code&gt; which we have invoked immediately at the end.&lt;br&gt;
Let's use our alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git ra origin demo-project 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;strong&gt;origin&lt;/strong&gt; will be used in &lt;code&gt;$1&lt;/code&gt; since it’s the first parameter we are passing and &lt;code&gt;$2&lt;/code&gt; will be &lt;strong&gt;demo-project&lt;/strong&gt;. &lt;br&gt;
The above command will translate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin git@github.com:yankeexe/demo-project.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt; 🚀
&lt;/h3&gt;

&lt;p&gt;I hope this article has been of help in improving your Git workflow. If you have any queries or suggestions, let’s discuss in the comment section.&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Understanding Iterators and Iterables in Python</title>
      <dc:creator>Yankee Maharjan</dc:creator>
      <pubDate>Fri, 17 Jul 2020 03:06:57 +0000</pubDate>
      <link>https://dev.to/yankee/understanding-iterators-and-iterables-in-python-1oa1</link>
      <guid>https://dev.to/yankee/understanding-iterators-and-iterables-in-python-1oa1</guid>
      <description>&lt;p&gt;Iterator and Iterable are general terms that gets thrown around a lot in Python. But what do they mean? Are they the same? We will try to understand what these objects in Python are and debunk some misunderstandings. &lt;/p&gt;

&lt;p&gt;Along the line we will also see a high-level overview of how for loop and range function might be working under the hood. FYI these concepts as a whole is also known as the &lt;strong&gt;Iterator Protocol.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So let’s get started 🔨&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterable ➰
&lt;/h3&gt;

&lt;p&gt;In general terms, anything that we can loop over is an iterable. I think the name itself gives it away. Most of the data structures in Python is an iterable like List, Tuple, Dict and so on.&lt;/p&gt;

&lt;p&gt;You don’t have to believe me if I say a List is an iterable, you can see for yourself. We will be using the built-in &lt;code&gt;dir()&lt;/code&gt; function to analyze the properties and methods that a list object consists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'apple'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'banana'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'mango'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Create a list. 
&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# make sure it is a List object. :D
&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zV3211qi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2722/1%2AAZSzv6QKI_bR__eKICWddA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zV3211qi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2722/1%2AAZSzv6QKI_bR__eKICWddA.gif" alt="Checking for iter method in an object. 🔎" width="800" height="443"&gt;&lt;/a&gt;&lt;em&gt;Checking for iter method in an object. 🔎&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can find the &lt;code&gt;__iter__&lt;/code&gt; method in the list, which means it is an iterable. All the objects that are iterable has the method &lt;code&gt;__iter__&lt;/code&gt;. If you ever get confused, this handy knowledge might help you identify an iterable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterators ⏭
&lt;/h3&gt;

&lt;p&gt;Now that we know what iterables are and how to identify them, let’s get our feet wet with iterators.&lt;/p&gt;

&lt;p&gt;In general, iterator is an object that makes iteration possible. Sounds vague but let me explain. While iterables are the object that we can iterate over; iterator is the implementation that keeps track of the state of the iterable like what value has been returned, what value to return next and also returns the value accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So how do we use it ?&lt;/strong&gt;&lt;br&gt;
Remember the &lt;code&gt;__iter__&lt;/code&gt; method we analyzed in our iterable example? Well, if we invoke the &lt;code&gt;__iter__&lt;/code&gt; method of our iterable, it returns an iterator object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k93T-jEH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2A_GkGqTJK9Bs6lONV6Yn6RQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k93T-jEH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2A_GkGqTJK9Bs6lONV6Yn6RQ.gif" alt="Identifying  raw `iterator` endraw  type and its methods. 🔎" width="800" height="439"&gt;&lt;/a&gt;&lt;em&gt;Identifying &lt;code&gt;iterator&lt;/code&gt; type and its methods. 🔎&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'apple'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'banana'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'mango'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;fruity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, you don’t have to believe what I say, you can check for yourself if it is an iterator using the &lt;code&gt;dir()&lt;/code&gt; method. Like iterables, iterators can be identified using the &lt;code&gt;__next__&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fruity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;So what does &lt;strong&gt;next&lt;/strong&gt;_ do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next returns the item in a list, one at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Differences?
&lt;/h3&gt;

&lt;p&gt;You might have noticed the iterator also consists of the &lt;code&gt;__iter__&lt;/code&gt; method, so we can say that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every iterator is also an iterable but not every iterable is an iterator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hands on 🙌
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Implementing for loop manually
&lt;/h3&gt;

&lt;p&gt;For loop makes use of the concepts of iterator and iterables to return value. Let’s see how we can implement the for loop ourselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'apple'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'banana'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'mango'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;fruity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# alternative:  iter(fruits)
&lt;/span&gt;&lt;span class="n"&gt;fruity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__next__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# alternative: next(fruity)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may notice that our next method only returns a single value. What if we want the next item in the list? Well, you call the same method again.&lt;/p&gt;

&lt;p&gt;But did you notice, when calling the method again, it doesn’t return value from the start of the list, but carries on to return the next item? This is because iterator is maintaining the state of the items and knows exactly which item to return next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xzqpbvJ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2AcR3jN_bvqNQI1imOOsTQ7g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xzqpbvJ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2AcR3jN_bvqNQI1imOOsTQ7g.gif" alt="Manual implementation of  raw `for` endraw  loop ➿" width="800" height="439"&gt;&lt;/a&gt;&lt;em&gt;Manual implementation of &lt;code&gt;for&lt;/code&gt; loop ➿&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So in our example, we have to call the next function on our iterator object three times to return all the values in the list. But what if we run it four times? Well there is nothing to return as we have already exhausted our list by returning everything. So the iterator throws an &lt;code&gt;StopIteration&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;Well this was a bit redundant isn’t it? What if our list had 1000s of items? We already know the internals so let’s move ahead and automate the process. We are not going to invoke &lt;code&gt;next()&lt;/code&gt; for each item 🤷‍♂️.&lt;/p&gt;

&lt;p&gt;For that we can make use of class to implement them automatically. For this you need some knowledge of OOP, but I will try my best to explain it using code comments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abstracting for loop implementation using a class.📦
&lt;/h3&gt;

&lt;p&gt;We will create a class that will somewhat act like a for loop and return all the elements of an iterable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Loop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;some_iterable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# constructor
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_iterable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;some_iterable&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;  &lt;span class="c1"&gt;# next method is in the same class so return iterator here.
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__next__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_iterable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;some_iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pCnSa6ag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2Amso170Byz1ytbXx3X7PzJg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pCnSa6ag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2Amso170Byz1ytbXx3X7PzJg.gif" alt="Custom loop in action ⚡" width="800" height="439"&gt;&lt;/a&gt;&lt;em&gt;Custom loop in action ⚡&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since we are already peeking inside how loop works, lets see how we can implement the &lt;code&gt;range()&lt;/code&gt; function using these concepts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abstracting range() function implementation 🏹
&lt;/h3&gt;

&lt;p&gt;The concept is pretty similar, we need to print out a series of number one after another taking into consideration the steps to increase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__next__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;

                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7iaI6BmD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2Am1zLd32Z2TKkDU7RrubxJg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7iaI6BmD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/2748/1%2Am1zLd32Z2TKkDU7RrubxJg.gif" alt="Custom range in action ⚡" width="800" height="439"&gt;&lt;/a&gt;&lt;em&gt;Custom range in action ⚡&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion 🙏
&lt;/h3&gt;

&lt;p&gt;I hope this article has been of help to make things clear about Iterable and Iterator. If you have any suggestions or questions let’s talk in the comment section.&lt;/p&gt;

&lt;p&gt;Another implementation of Iterator protocol is the generator functions which we will cover in the future blog.&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>learning</category>
      <category>codenewbie</category>
    </item>
  </channel>
</rss>
