<?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: Shan Desai</title>
    <description>The latest articles on DEV Community by Shan Desai (@shandesai).</description>
    <link>https://dev.to/shandesai</link>
    <image>
      <url>https://res.cloudinary.com/practicaldev/image/fetch/s--4x8gqxNf--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/603350/4080e5a0-5888-4f95-b2e3-281fea92a137.jpeg</url>
      <title>DEV Community: Shan Desai</title>
      <link>https://dev.to/shandesai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shandesai"/>
    <language>en</language>
    <item>
      <title>Exploring the Marshland of Docker Compose Versions with single quotes, special characters and environment variables</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Fri, 15 Jul 2022 16:06:41 +0000</pubDate>
      <link>https://dev.to/shandesai/exploring-the-marshland-of-docker-compose-versions-with-single-quotes-special-characters-and-environment-variables-236f</link>
      <guid>https://dev.to/shandesai/exploring-the-marshland-of-docker-compose-versions-with-single-quotes-special-characters-and-environment-variables-236f</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Since &lt;a href="https://www.docker.com/blog/announcing-compose-v2-general-availability/"&gt;Docker's Compose V2 General Availability&lt;/a&gt; announcement, a lot of things have changed which might lead to &lt;br&gt;
Incompatibility in your currently running application stacks.&lt;/p&gt;
&lt;h3&gt;
  
  
  Compose V2: what changes?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;instead of &lt;code&gt;docker-compose&lt;/code&gt; the syntax will be &lt;code&gt;docker compose&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker-compose&lt;/code&gt; (v1) was written in Python, &lt;code&gt;docker compose&lt;/code&gt; (v2) is in Go&lt;/li&gt;
&lt;li&gt;Compose V1 is official EOL (End Of Life) aka. Deprecated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are lot of fine things in Compose V2 but this post isn't about it. This write-up takes you through the murky &lt;br&gt;
marshland between Compose V1 and Compose V2 and how things might start you break when you decide to jump to the &lt;br&gt;
&lt;em&gt;cool V2&lt;/em&gt; vers without doing some thorough checks in your stack application&lt;/p&gt;
&lt;h2&gt;
  
  
  Swiss Knife for the Exploration
&lt;/h2&gt;

&lt;p&gt;Tools you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hashicorp Vagrant&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ansible&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Different versions of Docker Compose (v1 as well as v2)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Vagrant
&lt;/h3&gt;

&lt;p&gt;Instead of setting up a pain-staking Virtual Machine, we will leverage a bit simplified and inexpensive Vagrant Machine&lt;br&gt;
with &lt;strong&gt;Ubuntu 20.04 (focal amd64) base image&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Within this image we will install the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Engine &lt;code&gt;20.10.17&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Docker Compose v1: &lt;code&gt;v1.25.4 build 8d51620a&lt;/code&gt; and &lt;code&gt;v1.29.2 build 5b3cea4c&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Docker Compose v2: &lt;code&gt;2.6.0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Ansible
&lt;/h3&gt;

&lt;p&gt;I have Ansible installed on my host machine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible &lt;span class="nt"&gt;--version&lt;/span&gt;
ansible &lt;span class="o"&gt;[&lt;/span&gt;core 2.13.1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ansible will install all the spicy Compose versions into the Vagrant Machine for us&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are we doing this?
&lt;/h2&gt;

&lt;p&gt;If you have containers that require passwords at rest e.g. in &lt;code&gt;.env&lt;/code&gt; environment files to be encrypted and with &lt;br&gt;
special characters like the &lt;code&gt;$&lt;/code&gt; in them, we are going for ride which will make you want to bookmark this write-up.&lt;/p&gt;

&lt;p&gt;It turns out, I had a system running Compose v1 (&lt;code&gt;v1.25.4&lt;/code&gt;) and upon upgrading to Compose v2 (&lt;code&gt;2.6.0&lt;/code&gt;) I wasn't able&lt;br&gt;
to login to my Node-RED container which had authentication setup already.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node-RED Container
&lt;/h3&gt;

&lt;p&gt;Node-RED requires that the administrator password must be encrypted in &lt;code&gt;bcrypt&lt;/code&gt; type scheme and the password looks&lt;br&gt;
something like your dog walked over your keyboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks fairly okay, but the menace is the &lt;code&gt;$&lt;/code&gt; characters in them.&lt;/p&gt;

&lt;p&gt;Let's dive deep shall we!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Vagrantfile&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I am using a Linux Machine with Virtual Box as a provider&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# -*- mode: ruby -*-
# vi: set ft=ruby :


Vagrant.configure("2") do |config|

  # Use Ubuntu 20.04 as base
  config.vm.box = "ubuntu/focal64"

  config.vm.box_check_update =false

  # Synchronize all the docker-compose related file to `/vagrant` dir in VM
  config.vm.synced_folder ".", "/vagrant"

  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
  end

  # Setup the VM with all the different variants of Docker Compose in them
  config.vm.provision "ansible" do |a|
    a.verbose = "v"
    a.playbook = "./docker-compose-playbook.yml"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ansible Playbook: &lt;code&gt;docker-compose-playbook.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We will let Ansible install all the required Docker Compose versions for us in the VM through the playbook.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Compose v1.25.4 will be available in the VM as CLI &lt;code&gt;docker-compose-125&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Docker Compose v1.29.2 will be available in the VM as CLI &lt;code&gt;docker-compose-129&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Docker Compose v2.6.0 will be available in the VM as CLI &lt;code&gt;docker compose&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;install prerequisites&lt;/span&gt;
      &lt;span class="na"&gt;apt&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="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-transport-https&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ca-certificates&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gnupg-agent&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;software-properties-common&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&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;add apt-key&lt;/span&gt;
      &lt;span class="na"&gt;apt_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://download.docker.com/linux/ubuntu/gpg&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;add docker repo&lt;/span&gt;
      &lt;span class="na"&gt;apt_repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deb https://download.docker.com/linux/ubuntu focal stable&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;install docker&lt;/span&gt;
      &lt;span class="na"&gt;apt&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="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-ce&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-ce-cli&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;containerd.io&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose-plugin&lt;/span&gt;
        &lt;span class="na"&gt;update_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&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;add userpermissions&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usermod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-aG&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;docker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vagrant"&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;Install docker-compose v1.29.2 from official github repo&lt;/span&gt;
      &lt;span class="na"&gt;get_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;url &lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/docker-compose-129&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;u+x,g+x'&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;change compose v1.29.2 user permissions&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+x&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/docker-compose-129"&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;Install docker-compose v1.25.4 from official github repo&lt;/span&gt;
      &lt;span class="na"&gt;get_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/docker/compose/releases/download/1.25.4/docker-compose-Linux-x86_64&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/docker-compose-125&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;u+x,g+x'&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;change compose v1.25.4 user permissions&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chmod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+x&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/docker-compose-125"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Files for reproduction of incompatibility
&lt;/h3&gt;

&lt;p&gt;We wont be spinning to much complex stuff so a simple compose file and the relevant &lt;code&gt;.env.node-red&lt;/code&gt;&lt;br&gt;
file with the encrypted password should suffice&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&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;nodered/node-red:2.2.2&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env.node-red&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.env.node-red&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Encrypting plain-text password with value `password` with bcyrpt
NODERED_ADMIN_PASSWORD=$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Compatibility Checks
&lt;/h2&gt;

&lt;p&gt;Let's bring the Vagrant Machine up using:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;this will download the base ubuntu image if you previously don't have it on your host machine,&lt;br&gt;
provision it with all the docker compose versions in it.&lt;/p&gt;

&lt;p&gt;Login into the Machine:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Once into the Machine head to the &lt;code&gt;/vagrant&lt;/code&gt; directory, and just to be safe we check if all the &lt;br&gt;
required compose versions are available or not.&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;cd&lt;/span&gt; /vagrant

&lt;span class="nv"&gt;$ &lt;/span&gt;docker-compose-125 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker-compose-129 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Checks: Password not encloses in Single Quotes
&lt;/h3&gt;

&lt;p&gt;As the &lt;code&gt;.env.node-red&lt;/code&gt; file currently shows that my encrypted password is not enclosed in single quotes&lt;/p&gt;

&lt;p&gt;Let's understand what Compose thinks of the value of the environment variable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compose v1.25.4 (without single quotes)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose-125 config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODERED_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$2a$$08$$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.&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;nodered/node-red:2.2.2&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NO Problem! My dollar characters are escaped by docker-compose. I can login with password &lt;code&gt;password&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Compose v1.29.2 (without single quotes)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose-129 config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODERED_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$2a$$08$$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.&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;nodered/node-red:2.2.2&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NO Problem! My dollar characters are escaped by docker-compose. I can login with password &lt;code&gt;password&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Compose v2 without single quotes)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-red-app&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODERED_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;a$$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.&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;nodered/node-red:2.2.2&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;null&lt;/span&gt;
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&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;node-red-app_default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Oh NO! What happened here? Password looks eaten up. The YAML file looks different too!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Checks: Password enclosed in single quotes
&lt;/h3&gt;

&lt;p&gt;Now let's enclose our encrypted password between single quotes, so our &lt;code&gt;.env.node-red&lt;/code&gt; file&lt;br&gt;
should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NODERED_ADMIN_PASSWORD=$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Compose v1.25.4 (with single quotes)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose-125 config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODERED_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$$2a$$08$$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.'&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&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;nodered/node-red:2.2.2&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Oh NO! Why are there more single quotes than expected. This is not going to let me login!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Compose v1.29.2 (with single quotes)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose-129 config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODERED_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$2a$$08$$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.&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;nodered/node-red:2.2.2&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NO problem! here this will work fine as the dollar characters are escaped safely by compose&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Compose v2 (with single quotes)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-red-app&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-nodered&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODERED_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$2a$$08$$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.&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;nodered/node-red:2.2.2&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;null&lt;/span&gt;
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&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;node-red-app_default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NO Problem! Phew ! This will work just fine ! &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Result: Compose Compatibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Compose Version / Values&lt;/th&gt;
&lt;th&gt;&lt;code&gt;1.25.4&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;1.29.2&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;2.6.0&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;with Single Quotes&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;without Single Quotes&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What did we learn today, kids?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No Single Quotes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Compose v1.25.4 was able to resolve special characters without having enclose them in single quotes&lt;/li&gt;
&lt;li&gt;Docker Compose v1.29.2 will also work just fine for values not enclosed in single quotes&lt;/li&gt;
&lt;li&gt;Docker Compose v2 will try go hay-wire (try to resolve the value after the &lt;code&gt;$&lt;/code&gt; sign) if you do not use things in single quotes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With Single Quotes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Docker Compose v1.25.4 will &lt;em&gt;literally&lt;/em&gt; take things enclosed in single quotes as part of your environment variable and will&lt;br&gt;
break your Container's Login logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker Compose v1.29.2 will work well&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker Compose v2 will work well&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a nutshell&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DON'T JUMP THE GUN, when moving from different V1 to V2 in Compose. Do some throrough research as well as experiments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since Compose V1 is now deprecated, when transitioning to Compose V2 check all your environment variable files and if they require&lt;br&gt;
special characters to be either enclosed in single quotes or not. Estimate your downtimes and conduct isolated tests when required.&lt;/p&gt;

&lt;p&gt;Rule of thumb from Compose V2 onwards: &lt;em&gt;if it got some special char in them password, pack em between single quotes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;but to each their own!&lt;/p&gt;

&lt;h3&gt;
  
  
  Github Gist
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/shantanoo-desai/b5d971c533509fdf978f9e97e584b0d0"&gt;GitHub Gist available publicly&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>vagrant</category>
      <category>ansible</category>
    </item>
    <item>
      <title>Multi-Image Docker Images: Using COPY with Images directly from registries</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Fri, 24 Jun 2022 20:10:18 +0000</pubDate>
      <link>https://dev.to/shandesai/multi-image-docker-images-using-copy-with-images-directly-from-registries-50ed</link>
      <guid>https://dev.to/shandesai/multi-image-docker-images-using-copy-with-images-directly-from-registries-50ed</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I was on the lookout for a solution to a problem in Docker that needed to do the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a Docker Image for a bunch of compiled ASP.NET &lt;code&gt;.dll&lt;/code&gt; files and try reducing the &lt;br&gt;
container footprint&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds simple, right? But it turned out to be a bit more &lt;em&gt;messy&lt;/em&gt; than I imagined. To top it off,&lt;br&gt;
I have &lt;strong&gt;NEVER&lt;/strong&gt; even programmed in .NET so I was feeling like a visually impaired person made to &lt;br&gt;
navigate his way through a dark room with furniture scattered all over!&lt;/p&gt;
&lt;h2&gt;
  
  
  Thousand Leagues under the Container Sea!
&lt;/h2&gt;

&lt;p&gt;Keeping the whole Maritime theme alive with Docker (and Kubernetes), I jumped into the sea of &lt;br&gt;
Docker Hub with millions of containers and found out that Microsoft hosts all the .NET related &lt;br&gt;
container images as &lt;a href="https://hub.docker.com/_/microsoft-dotnet"&gt;.NET by Microsoft registry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Gentle reminder that I have never even thought of .NET before in my life, so just trying to figure out&lt;br&gt;
whether I need an one or more of the following images:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SDK&lt;/li&gt;
&lt;li&gt;ASP.NET Core Runtime&lt;/li&gt;
&lt;li&gt;.NET Runtime&lt;/li&gt;
&lt;li&gt;.NET Runtime Dependencies&lt;/li&gt;
&lt;li&gt;.NET Monitor Tool&lt;/li&gt;
&lt;li&gt;.NET Samples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;was a side-mission in its own right.&lt;/p&gt;
&lt;h3&gt;
  
  
  Side-Mission
&lt;/h3&gt;

&lt;p&gt;A quick deep-dive into &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/docker/building-net-docker-images?view=aspnetcore-6.0"&gt;Microsoft's Docker .NET Docs&lt;/a&gt; made me think I only need the following docker image: &lt;br&gt;
&lt;code&gt;mcr.microsoft.com/dotnet/aspnet:6.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So packing everything in a simple &lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:6.0-focal&lt;/span&gt;


&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /DotNetVoyage&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./appsettings.json /DotNetVoyage/Server-Files/&lt;/span&gt;

&lt;span class="c"&gt;# Copy every '.dll' file I was handed &lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./* /DotNetVoyage/Server-Files/&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "dotnet", "Server-Files/Server.dll" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building it locally and accessing the App initially on the dedicated ports seemed to work just fine and I thought &lt;br&gt;
I was getting off work a bit early today. I jinxed myself.&lt;/p&gt;

&lt;p&gt;Upon some API testing of the image I started seems some logs that were strange to my &lt;em&gt;non .NETian brain&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The specified framework can be found at:
It was not possible to find any compatible framework version
The framework 'Microsoft.AspNetCore.App', version '5.0.0' (x64) was not found.
 - The following frameworks were found:
    6.0.6 at [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
You can resolve the problem by installing the specified framework and/or SDK.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was head scratching as to how I can make my runtime which is &lt;code&gt;6.0.0&lt;/code&gt; potentially have an SDK version that must &lt;br&gt;
have &lt;code&gt;5.0.0&lt;/code&gt; SDK on it. It got worse, I found out I needed the now &lt;em&gt;defunct and not supported&lt;/em&gt; &lt;code&gt;2.1&lt;/code&gt; version of the SDK&lt;br&gt;
too! &lt;/p&gt;
&lt;h3&gt;
  
  
  Build everything from scratch?
&lt;/h3&gt;

&lt;p&gt;Unaware if there was a way to introduce the different SDKs into the already slimmed container image, I had lost hope &lt;br&gt;
and decided to build an image with maybe &lt;code&gt;debian&lt;/code&gt; or &lt;code&gt;ubuntu&lt;/code&gt; or &lt;code&gt;alpine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, upon asking the Slack Community and rummaging through some StackExchange queries, I traced out a plan that was&lt;br&gt;
pretty familiar to me: &lt;strong&gt;Using Multi-Stage Docker Builds&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Charting towards a Destination
&lt;/h2&gt;

&lt;p&gt;I use Multi-Stage Docker builds almost everyday for work and so I decided to design my container image as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stage 1: pull SDK 2.1
  1.1: find out which directory do the SDK Files persist

Stage 2: pull SDK 5.1
  2.1: find out which directory do the SDK Files persist

Stage Prod: Pull the 6.0.0 Runtime
  Prod.1: copy all the SDK Files (from Stage 1 and Stage 2) to the same directory here in Prod Stage
  Prod.2: copy all the DLL files from host and run the dedicated DLL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where art thou SDKs?
&lt;/h3&gt;

&lt;p&gt;A quick pull:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull mcr.microsoft.com/dotnet/sdk:2.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and check within the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sdk21-check mcr.microsoft.com/dotnet/sdk:2.1 dotnet &lt;span class="nt"&gt;--list-sdks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resulted in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2.1.818 &lt;span class="o"&gt;[&lt;/span&gt;/usr/share/dotnet/sdk]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gotcha! the directory for the SDKs is &lt;code&gt;/usr/share/dotnet/&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Image Image
&lt;/h3&gt;

&lt;p&gt;what I mean by this is whether Docker is smart enough to directly pull an image either using &lt;code&gt;COPY&lt;/code&gt; or &lt;code&gt;ADD&lt;/code&gt;&lt;br&gt;
instructions without me having to create &lt;code&gt;Stage 1&lt;/code&gt; and &lt;code&gt;Stage 2&lt;/code&gt; using syntax such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:2.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base21&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:5.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It turns out that &lt;code&gt;COPY&lt;/code&gt; is extremely flexible! with the &lt;code&gt;COPY --from&lt;/code&gt; instruction in the &lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
is completely capable of pull the image from a registry and the dedicated directories can be copied easily!&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Final Checks for &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:6.0-focal&lt;/span&gt;

&lt;span class="c"&gt;# Add those missing SDKs here&lt;/span&gt;
&lt;span class="c"&gt;## Syntax: COPY --from=&amp;lt;registry/image:version&amp;gt; image_directory ProdStage__dest_directory&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=mcr.microsoft.com/dotnet/sdk:2.1 /usr/share/dotnet /usr/share/dotnet/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=mcr.microsoft.com/dotnet/sdk:5.1 /usr/share/dotnet /usr/share/dotnet&lt;/span&gt;

&lt;span class="c"&gt;# List all the SDKs / Runtimes available in the container&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "--list-sdks", "dotnet", "--list-runtimes"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;build the image and run it and the output will be similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft.AspNetCore.All 2.1.30 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.30 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.17 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.6 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.30 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.17 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.6 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilá ! Runtimes &lt;code&gt;v6.0&lt;/code&gt;, &lt;code&gt;v5.0&lt;/code&gt;, &lt;code&gt;v2.1&lt;/code&gt; all in the same container !!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:6.0-focal&lt;/span&gt;

&lt;span class="c"&gt;# Add those missing SDKs here&lt;/span&gt;
&lt;span class="c"&gt;## Syntax: COPY --from=&amp;lt;registry/image:version&amp;gt; image_directory ProdStage__dest_directory&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=mcr.microsoft.com/dotnet/sdk:2.1 /usr/share/dotnet /usr/share/dotnet/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=mcr.microsoft.com/dotnet/sdk:5.1 /usr/share/dotnet /usr/share/dotnet&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /DotNetVoyage&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./appsettings.json /DotNetVoyage/Server-Files/&lt;/span&gt;

&lt;span class="c"&gt;# Copy every '.dll' file I was handed &lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./* /DotNetVoyage/Server-Files/&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "dotnet", "Server-Files/Server.dll" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Dedicated &lt;a href="https://stackoverflow.com/a/72745810/4851126"&gt;StackOverflow Query I created and answered&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just another day on the decks with Docker !!&lt;/p&gt;

&lt;p&gt;Get in touch if you feel like dropping on suggestions, feedbacks or criticism!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>dotnet</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Use htpasswd to secure your node-RED Container</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Thu, 09 Jun 2022 21:10:01 +0000</pubDate>
      <link>https://dev.to/shandesai/use-htpasswd-to-secure-your-node-red-container-15cl</link>
      <guid>https://dev.to/shandesai/use-htpasswd-to-secure-your-node-red-container-15cl</guid>
      <description>&lt;h2&gt;
  
  
  Securing Node-RED
&lt;/h2&gt;

&lt;p&gt;node-RED containers can be made secure when using Admin Authorization features&lt;br&gt;
using its &lt;a href="https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js"&gt;&lt;code&gt;settings.js&lt;/code&gt; file&lt;/a&gt; and mounting it to the container. Sounds quite simple,&lt;br&gt;
however unlike other containers that let your configure their environments via environment&lt;br&gt;
variables whereby the stored credentials are in plaintext, node-RED passwords typically are&lt;br&gt;
stored in encrypted format i.e., &lt;a href="https://en.wikipedia.org/wiki/Bcrypt"&gt;bcrypt&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Automation: Encrypted Passwords
&lt;/h2&gt;

&lt;p&gt;There is a possibility of obtaining the hashed (encrypted) password using an ephemeral container&lt;br&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;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; /bin/bash nodered/node-red:2.2.2-12-minima
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One in the container use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash-5.0&lt;span class="nv"&gt;$ &lt;/span&gt;node-red-admin hash-pw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which will prompt you to enter the password and the resultant hash password will be available for you&lt;br&gt;
to use.&lt;/p&gt;

&lt;p&gt;This is however, a bit more of manual work and in case where you wish to perform more easy, automated&lt;br&gt;
setups we might need to find a different way.&lt;/p&gt;
&lt;h3&gt;
  
  
  Automation Script via &lt;code&gt;htpasswd&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Apache provide a great CLI tool called &lt;code&gt;htpasswd&lt;/code&gt; that can encrypt our plaintext passwords&lt;br&gt;
into the required &lt;code&gt;bcrypt&lt;/code&gt; hashed format which the node-RED UI and Admin Auth backend will decrypt.&lt;/p&gt;

&lt;p&gt;For most of the distributions the package name is &lt;code&gt;apache2-utils&lt;/code&gt; so for Ubuntu/Debian you can install&lt;br&gt;
&lt;code&gt;htpasswd&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="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;apache2-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Jumping right into it!
&lt;/h3&gt;

&lt;p&gt;You can go through the &lt;code&gt;man&lt;/code&gt; pages of &lt;code&gt;htpasswd&lt;/code&gt; to find how it might suit for your needs. I am cutting &lt;br&gt;
to the chase as to how I used it.&lt;/p&gt;

&lt;p&gt;In order to generate my hashed password that will be compatible with node-RED's decryption backend, I had&lt;br&gt;
to find the total Computation Cost (rounds) needed, which I found out the value was &lt;code&gt;8&lt;/code&gt; based on some &lt;br&gt;
code diving using &lt;a href="https://github.com/node-red/node-red-admin/blob/master/lib/commands/hash.js#L28"&gt;node-red-admin&lt;/a&gt; repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;htpasswd &lt;span class="nt"&gt;-nb&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; 8 admin testpassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will produce the following result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;admin:&lt;span class="nv"&gt;$2y$08$JTOJDi&lt;/span&gt;/whZxz8qwsdwCkfedhVOhh00QiKHICdHLImGS8XM2v.fng2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating an Environment Variable Template file for node-RED Docker Container
&lt;/h3&gt;

&lt;p&gt;we will make the automation a bit more easier for us, whereby we can use &lt;code&gt;envsubst&lt;/code&gt; commandline to fill&lt;br&gt;
and environment variable called &lt;code&gt;NODERED_AUTH_ADMIN&lt;/code&gt; in a file called &lt;code&gt;node-red.env&lt;/code&gt;. But in order leverage&lt;br&gt;
the power of &lt;code&gt;envsubst&lt;/code&gt; we will create a template file called &lt;code&gt;node-red.tpl.env&lt;/code&gt; which has the following &lt;br&gt;
content:&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;cat &lt;/span&gt;node-red.tpl.env
&lt;span class="nv"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'${NODERED_AUTH_ADMIN}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create simple bash script which will do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accept a plaintext password as an argument to the script&lt;/li&gt;
&lt;li&gt;use this plaintext password and hash it with &lt;code&gt;htpasswd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;export the variable which has the result of &lt;code&gt;htpasswd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;use the exported variable to replace the &lt;code&gt;node-red.tpl.env&lt;/code&gt; file to &lt;code&gt;node-red.env&lt;/code&gt; with the value&lt;/li&gt;
&lt;li&gt;unset variable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The script is 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;&lt;span class="nb"&gt;cat &lt;/span&gt;nodeREDPwgen.sh
&lt;span class="c"&gt;#!/bin/env bash&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;nodeREDPW &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# 1st argument to this script is plaintext password&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;htpasswd &lt;span class="nt"&gt;-nb&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; 8 admin &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;export &lt;/span&gt;NODERED_AUTH_ADMIN
    &lt;span class="nb"&gt;touch &lt;/span&gt;node-red.env
    envsubst &lt;span class="s1"&gt;'${NODERED_AUTH_ADMIN}'&lt;/span&gt; &amp;lt; node-red.tpl.env &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node-red.env
    &lt;span class="nb"&gt;unset &lt;/span&gt;NODERED_AUTH_ADMIN 
&lt;span class="o"&gt;}&lt;/span&gt;

nodeREDPW &lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example Usage:&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;chmod&lt;/span&gt; +x nodeREDPwgen.sh

./nodeREDPWgen.sh testpasswd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will produce a &lt;code&gt;node-red.env&lt;/code&gt; file after successful execution with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NODERED_AUTH_ADMIN='admin:$2y$08$/8NVmF2gJ3JDrmv0tX2ud.P7S9gqvB0ds2cRByhnZcRdZOWhTnPN.'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a &lt;code&gt;settings.js&lt;/code&gt; file for Node-RED Container
&lt;/h3&gt;

&lt;p&gt;copy the &lt;a href="https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js"&gt;&lt;code&gt;settings.js&lt;/code&gt;&lt;/a&gt; file from the node-red repository and adapt the &lt;code&gt;adminAuth&lt;/code&gt; object&lt;br&gt;
as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="nx"&gt;adminAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;credentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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="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;h3&gt;
  
  
  Creating a &lt;code&gt;docker-compose.yml&lt;/code&gt; file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-red&lt;/span&gt;&lt;span class="pi"&gt;:&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;nodered/node-red:2.2.2-12-minimal&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secure_nodered&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./node-red.env&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1880:1880"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./settings.js:/data/settings.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;bring the container up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI is available at &lt;code&gt;http://localhost:1880&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;If you try to login in by typing &lt;code&gt;testpassword&lt;/code&gt; in the Admin UI, you will get Login Failed! But Why?&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigations
&lt;/h3&gt;

&lt;p&gt;It turns out that the password generated by &lt;code&gt;htpasswd&lt;/code&gt; produces a variant of bcrypt &lt;code&gt;$2y&lt;/code&gt; where as,&lt;br&gt;
if we were to generate the password using &lt;code&gt;node-red-admin hash-pw&lt;/code&gt; and added &lt;code&gt;testpassword&lt;/code&gt; it would&lt;br&gt;
generate a completely different looking password with the variant &lt;code&gt;$2b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example: &lt;code&gt;$2b$08$sfPlvPNDVVz/duAbAC2bbuNEVuvrwmU01x7plOAQIem6H187Xxq9G&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;It turns out that the &lt;code&gt;$2y&lt;/code&gt; variant of bcrypt has compatibiltity and we could simply try and replace&lt;br&gt;
&lt;code&gt;$2y&lt;/code&gt; to &lt;code&gt;$2b&lt;/code&gt; in our &lt;code&gt;settings.js&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// .. removed for brewity&lt;/span&gt;
  &lt;span class="na"&gt;adminAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;credentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODERED_AUTH_ADMIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$2y$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$2b$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// removed for brewity&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;notice the &lt;code&gt;.replace("$2y", "$2b")&lt;/code&gt; at the end of &lt;code&gt;password&lt;/code&gt; key.&lt;/p&gt;

&lt;p&gt;Let's spin the container up again using &lt;code&gt;docker compose up -d&lt;/code&gt; and try to login with &lt;code&gt;testpassword&lt;/code&gt; et Voila!!&lt;/p&gt;

&lt;p&gt;We are able to login into Node-RED!&lt;/p&gt;

&lt;p&gt;I found that &lt;strong&gt;Nick O'Leary&lt;/strong&gt; (founder of Node-RED and the great guy that he is..) already did &lt;a href="https://github.com/node-red/node-red-docker/issues/109"&gt;some research on this&lt;/a&gt;,&lt;br&gt;
I just had to bring this all together.&lt;/p&gt;

&lt;p&gt;If you have some suggestions, critiques than please get in touch with me and I would be happy to help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/shantanoo-desai/0d5fbc51518f6cdd1e04cbeab8d63c13"&gt;GitHub Gist of the files&lt;/a&gt; for the impatient ones!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>security</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>Set the hostname of a Docker Container same as that of your host machine</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Wed, 08 Jun 2022 19:02:30 +0000</pubDate>
      <link>https://dev.to/shandesai/set-the-hostname-of-a-docker-container-same-as-that-of-your-host-machine-26h5</link>
      <guid>https://dev.to/shandesai/set-the-hostname-of-a-docker-container-same-as-that-of-your-host-machine-26h5</guid>
      <description>&lt;h2&gt;
  
  
  Setting Container Hostname to be same as your Host Machine
&lt;/h2&gt;

&lt;p&gt;Sounds trivial, but it turns out you need to do some tweaks in order to set the hostname&lt;br&gt;
to be the same as that of Host Machine.&lt;/p&gt;
&lt;h3&gt;
  
  
  Scenario
&lt;/h3&gt;

&lt;p&gt;I had a requirement at work, where I needed to set the hostname of a specific container&lt;br&gt;
to be that of the Machine it was supposed to run on.&lt;/p&gt;

&lt;p&gt;The Linux Distribution under consideration was &lt;strong&gt;Ubuntu 20.04 LTS&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Ubuntu's mysterious &lt;code&gt;HOST&lt;/code&gt; and &lt;code&gt;HOSTNAME&lt;/code&gt; environment variables
&lt;/h3&gt;

&lt;p&gt;If you are on an Ubuntu machine right now, try &lt;code&gt;echo $HOS&lt;/code&gt; and press the TAB key to let the bash completion fill out. High chances that you will see &lt;code&gt;HOST&lt;/code&gt; and &lt;code&gt;HOSTNAME&lt;/code&gt;&lt;br&gt;
as available Environment Variables already available to your bash shell's session.&lt;/p&gt;

&lt;p&gt;Fairly Simple, you could simply use either one of them in your Compose file as an environment variable to the &lt;code&gt;hostname&lt;/code&gt; key and should work out of the box! Not quite!&lt;/p&gt;
&lt;h3&gt;
  
  
  Investigation via a simple Example
&lt;/h3&gt;

&lt;p&gt;Take the following &lt;code&gt;docker-compose.yml&lt;/code&gt; 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="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&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;alpine:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostname-tester&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine-${HOST}&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hostname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following &lt;code&gt;test&lt;/code&gt; service should be able to retrieve the &lt;code&gt;HOST&lt;/code&gt; variable value and set it as the hostname of the alpine container. The &lt;code&gt;command&lt;/code&gt; should be able to print something like &lt;code&gt;alpine-my-ubuntu&lt;/code&gt; as an example.&lt;/p&gt;

&lt;p&gt;Let's see what happens when we run &lt;code&gt;docker compose up&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;WARN[0000] The &lt;span class="s2"&gt;"HOST"&lt;/span&gt; variable is not set. Defaulting to a blank string. 
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 1/1
 ⠿ Container hostname-tester  Recreated                                    0.1s
Attaching to hostname-tester
hostname-tester  | alpine-
hostname-tester exited with code 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see the &lt;code&gt;HOST&lt;/code&gt; variable although available to the shell is not available within the &lt;br&gt;
Compose file.&lt;/p&gt;

&lt;p&gt;Most of the shell environment variables are visible via using &lt;code&gt;printenv&lt;/code&gt; on the host machine, so a quick search for &lt;code&gt;HOST&lt;/code&gt; or &lt;code&gt;HOSTNAME&lt;/code&gt; reveals that these specific environment variables are not in the &lt;code&gt;env&lt;/code&gt; of the shell&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;printenv&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"host"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;The most standard way to make a variable available for a shell session is by exporting it.&lt;/p&gt;

&lt;p&gt;Let's export &lt;code&gt;HOST&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="nb"&gt;export &lt;/span&gt;HOST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try bringing the container back up again and see if it picks up the variable values&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;export &lt;/span&gt;HOST
❯ docker compose up
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 1/0
 ⠿ Container hostname-tester  Recreated                                    0.0s
Attaching to hostname-tester
hostname-tester  | alpine-shan-pc
hostname-tester exited with code 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for my machine (&lt;strong&gt;Manjaro Linux (Rolling)&lt;/strong&gt;) I could now set the hostname of the container to be the same as that of the Host Machine.&lt;/p&gt;

&lt;p&gt;Sure enough searching through &lt;code&gt;printenv&lt;/code&gt; again you will find the export &lt;code&gt;HOST&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;If you have on-prem servers or cloud images where you might need such a configuration a solution would be to add &lt;code&gt;export HOST&lt;/code&gt; to your user's &lt;code&gt;~/.bashrc&lt;/code&gt; or &lt;code&gt;~/.zshrc&lt;/code&gt; (if using ZSH)&lt;br&gt;
and the value will be available when bringing the corresponding Compose Stack up.&lt;/p&gt;

&lt;p&gt;Hope this information helps people trying to find a similar solutions when it comes to Docker and Docker Compose based environments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>No Setup Development: Productivity Experience with Docker</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Sun, 08 May 2022 09:13:47 +0000</pubDate>
      <link>https://dev.to/shandesai/no-setup-development-productivity-experience-with-docker-2pbf</link>
      <guid>https://dev.to/shandesai/no-setup-development-productivity-experience-with-docker-2pbf</guid>
      <description>&lt;h2&gt;
  
  
  Why I stopped worrying about setting up environments!
&lt;/h2&gt;

&lt;p&gt;If Stanley Kubrick were a Software Engineer, he would have named this post&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dr. Nosetup: How I Stopped Worrying About Setting Up and Love the Development&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(I'll see myself out with that pun!)&lt;/p&gt;

&lt;p&gt;I tried contributing to an open-source project without actually setting up the&lt;br&gt;
complete programming language tools, and it felt like worth documenting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem: So much to download, and setup before getting to work
&lt;/h3&gt;

&lt;p&gt;I tried sending a feature to the &lt;a href="https://github.com/node-red/node-red/pull/3599"&gt;node-red GitHub Repository with a new TOML configuration node&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, I didn't want to &lt;em&gt;taint&lt;/em&gt; (pardon me for using the word) my personal laptop by installing&lt;br&gt;
&lt;code&gt;node.js&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One particular reason being, is that I have less time now to continue with Web Development stuff,&lt;br&gt;
and &lt;code&gt;node.js&lt;/code&gt; isn't my preferred language anyways. I want my host laptop to be as minimal as possible.&lt;/p&gt;

&lt;p&gt;But I wanted to send the feature patch upstream because I was &lt;em&gt;in the zone&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Docker encapsulated Environment
&lt;/h3&gt;

&lt;p&gt;Since I have been heavily using &lt;code&gt;docker&lt;/code&gt; for a while now, I asked myself&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What do I need to send a patch upstream?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A: Only relevant files&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does &lt;code&gt;docker&lt;/code&gt; provide me a &lt;code&gt;node.js&lt;/code&gt; environment?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A: Yes, certainly it does. Not just &lt;code&gt;node.js&lt;/code&gt; but for all possible programming languages&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do I avoid doing &lt;em&gt;manual copy-paste&lt;/em&gt; labour for files between the container and my laptop?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A: &lt;strong&gt;Volume-Mounts&lt;/strong&gt;. Any changes within the containe get reflected back to the host laptop and vice-versa&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting it Up!
&lt;/h2&gt;

&lt;p&gt;All I really needed was &lt;code&gt;docker&lt;/code&gt; on my machine and we are ready to go!&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;clone the repository to dedicated directory on my host laptop&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Visit &lt;strong&gt;Docker Hub&lt;/strong&gt; and find the &lt;code&gt;node-js&lt;/code&gt; Image repository&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find the Long-Term-Support (LTS) version image tag. In my case it was &lt;code&gt;16.15.0&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So we almost have everything we want!&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveats
&lt;/h3&gt;

&lt;p&gt;Remember that Docker Containers are their own &lt;em&gt;ephemeral&lt;/em&gt; worlds all together.&lt;/p&gt;

&lt;p&gt;If the containers are designed to with &lt;code&gt;root&lt;/code&gt; users, your files may change ownership, or might have&lt;br&gt;
different owners. You could check this using &lt;code&gt;ls -la&lt;/code&gt; in your directory.&lt;/p&gt;

&lt;p&gt;I really want to avoid such scenarios, such ownership issues might affect your filesystem as well as&lt;br&gt;
the upstream code. But no issues, &lt;code&gt;docker&lt;/code&gt; CLI provides way to control the user and group settings &lt;br&gt;
before bringing the container up.&lt;/p&gt;

&lt;p&gt;It is also worth mentioning that, the container environments also produce files that should be not be&lt;br&gt;
reflected in your commits upstream. In the case of &lt;code&gt;node-red&lt;/code&gt; the &lt;code&gt;package-lock.json&lt;/code&gt; is a file created&lt;br&gt;
within the container that will be mapped to the host machine.&lt;/p&gt;

&lt;p&gt;It might be wise to keep such files into &lt;code&gt;.gitignore&lt;/code&gt; as well as &lt;code&gt;.dockerignore&lt;/code&gt; files within the development&lt;br&gt;
repository to avoid accidently committing them upstream or bringing them within the container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker CLI
&lt;/h3&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="c"&gt;# assuming your are in the development repository&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node-red-TOML &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/usr/src/app &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-p&lt;/span&gt; 1880:1880 &lt;span class="se"&gt;\&lt;/span&gt;
     node:16.15.0 &lt;span class="se"&gt;\&lt;/span&gt;
     /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-u&lt;/code&gt; parameter maps your current user id and group to the container, avoiding any &lt;code&gt;root&lt;/code&gt; ownership&lt;br&gt;
conflicts.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;-v&lt;/code&gt; parameter is the volume mount that will map the codebase to the &lt;code&gt;/usr/src/app&lt;/code&gt; directory in the&lt;br&gt;
container.&lt;/p&gt;

&lt;p&gt;There you have it ! A node-js environment without having to download and setup the tool on the host!&lt;/p&gt;

&lt;p&gt;You can now code everything with ease with your Editor of your choice with the container running.&lt;/p&gt;

&lt;p&gt;Any changes, either on the host or within the container will be reflected to your editor.&lt;/p&gt;

&lt;p&gt;Just make sure to run the execution commands in the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;This worked out well for me! I was able to get the codebase up and running in no time, without having to&lt;br&gt;
worry about incompatibility issues.&lt;/p&gt;

&lt;p&gt;Changes made in my editor (new files, refactored files) are available in the container to use and execute.&lt;/p&gt;

&lt;p&gt;Running the commands within the container makes it easier to know what happens and all of this is &lt;em&gt;ephemeral&lt;/em&gt;&lt;br&gt;
so I don't have to do a lot of cleanup afterwards.&lt;/p&gt;

&lt;p&gt;Just remove the container and commit the code!&lt;/p&gt;

&lt;p&gt;On a side-note, the &lt;a href="https://github.com/node-red/node-red/pull/3599"&gt;feature patch upstream&lt;/a&gt; wasn't required by the core team :(, but I could use the &lt;br&gt;
same development environment pattern to create a &lt;code&gt;node-red-contrib&lt;/code&gt; node. So nothing does to waste!&lt;/p&gt;

&lt;p&gt;Hope this helps, get in touch if you would like to provide some suggestions, criticisms!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Create a custom Node-Red Docker Image and performance Integration Tests and CI/CD Pipelines</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Sun, 10 Apr 2022 11:48:15 +0000</pubDate>
      <link>https://dev.to/shandesai/create-a-custom-node-red-docker-image-and-performance-integration-tests-and-cicd-pipelines-56b5</link>
      <guid>https://dev.to/shandesai/create-a-custom-node-red-docker-image-and-performance-integration-tests-and-cicd-pipelines-56b5</guid>
      <description>&lt;h2&gt;
  
  
  Pre-Requisites
&lt;/h2&gt;

&lt;p&gt;This post assumes that the reader has an understanding about &lt;a href="https://nodered.org/"&gt;Node-Red&lt;/a&gt; Flow&lt;br&gt;
Programming tool and wishes to work with a custom Docker Images for it.&lt;/p&gt;

&lt;p&gt;This post also assumes the readers are familiar with python programming.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;Since Node-Red provides a &lt;em&gt;visual&lt;/em&gt; way of connecting many components through Flows,&lt;br&gt;
we might be interested in using it for our own personal stack.&lt;/p&gt;

&lt;p&gt;If you haven't tried it out, &lt;a href="https://nodered.org/docs/getting-started/docker"&gt;Node-Red Documentation for Docker&lt;/a&gt; provides some nice&lt;br&gt;
ways to getting started.&lt;/p&gt;

&lt;p&gt;Since the Flows are rendered to a web-browser, we might want to take into consideration &lt;br&gt;
testing our custom Node-Red container when it might be integrated with other containers &lt;br&gt;
within a stack deployment.&lt;/p&gt;

&lt;p&gt;This guide will provide a concise way of joining the dots between creating your custom&lt;br&gt;
Node-Red container and testing its reachability within a &lt;code&gt;docker-compose&lt;/code&gt; file using &lt;br&gt;
the &lt;a href="https://pypi.org/project/pytest-docker-compose/"&gt;&lt;code&gt;pytest-docker-compose&lt;/code&gt; suite&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Follow Along
&lt;/h2&gt;

&lt;p&gt;Please refer to the &lt;a href="https://github.com/shantanoo-desai/node-red-slim"&gt;GitHub Repository&lt;/a&gt; for&lt;br&gt;
the code structure and file content&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom Node-Red Docker Container Creation
&lt;/h2&gt;

&lt;p&gt;Diving into the deep-end straight, we want to create a Node-Red custom container with &lt;br&gt;
just the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;node-red&lt;/code&gt; runtime-engine&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node-red&lt;/code&gt; dashboard&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: for this post sake, we stick to basic things, please feel free to add more things &lt;br&gt;
      according to you needs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Adding Node-Red and its Dependencies
&lt;/h3&gt;

&lt;p&gt;Standard practice with Node-Red lets the user add dedicated flows and dependencies via the &lt;br&gt;
&lt;code&gt;npm install&lt;/code&gt; command-line. However within the &lt;a href="https://github.com/node-red/node-red-docker/wiki/Quick-Custom-Image"&gt;Node-Red-Docker Repo Wiki&lt;/a&gt;, you can also&lt;br&gt;
add these flows/dependencies via a dedicated &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's stick to this method and avoid adding things via CLI within the container.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node-red-slim-container"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A Slim Node-RED Docker Image running on Alpine Container"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"node-red"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=2.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"node-red-dashboard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS --userDir=/data"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving on to creating a &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Stage Dockerfile for a Slim Image
&lt;/h3&gt;

&lt;p&gt;We will be using a &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;Multi-Stage Docker build process&lt;/a&gt; to keep our image a bit &lt;em&gt;light&lt;/em&gt; on the &lt;br&gt;
size using &lt;code&gt;alpine&lt;/code&gt; based containers and the official &lt;code&gt;minimal&lt;/code&gt; image from Node-Red.&lt;/p&gt;

&lt;p&gt;We will use &lt;strong&gt;TWO-Stages&lt;/strong&gt; in our build process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;prepare a base Image with &lt;code&gt;alpine&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;nodered/node-red-minimal&lt;/code&gt; image to install the flows/deps and prepare the &lt;code&gt;node_modules&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We then use the base Image in step 1 as a production image and copy the &lt;code&gt;node_modules&lt;/code&gt; directory &lt;br&gt;
to this production image.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;Dockerfile&lt;/code&gt; looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:3.13 AS base&lt;/span&gt;


&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;            nodejs &lt;span class="se"&gt;\
&lt;/span&gt;            npm &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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/src/node-red /data &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser &lt;span class="nt"&gt;-h&lt;/span&gt; /usr/src/node-red &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; node-red &lt;span class="nt"&gt;-u&lt;/span&gt; 1000 &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;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; node-red:node-red /data 

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nodered/node-red:2.2.2-minimal AS build&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;        &lt;span class="nt"&gt;--unsafe-perm&lt;/span&gt; &lt;span class="nt"&gt;--no-update-notifier&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;
        --no-audit --only=production

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; base as prod&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build --chown=node-red:node-red /data/ /data/&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/node-red&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; settings.js /data/settings.js&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; flows.json  /data/flows.json&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build --chown=node-red:node-red /usr/src/node-red/  /usr/src/node-red/&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node-red&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start with the base image as &lt;code&gt;alpine:3.13&lt;/code&gt; and prepare it by adding &lt;code&gt;nodejs&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt;&lt;br&gt;
needing to run Node-Red. For security best-practices, we add a &lt;code&gt;node-red&lt;/code&gt; user and group as&lt;br&gt;
opposed to running everything as &lt;code&gt;root&lt;/code&gt;. This avoids any privilege escalation within the container,&lt;br&gt;
as well as misuse within the container.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;build&lt;/code&gt; stage will install all the NPM packages in our &lt;code&gt;package.json&lt;/code&gt; and then we copy the&lt;br&gt;
necessary &lt;code&gt;node_modules&lt;/code&gt; to our &lt;code&gt;prod&lt;/code&gt; image. In the end, we will run the command as &lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can build this image locally using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; node-red-slim:latest &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add a Healthcheck API in Node-Red
&lt;/h3&gt;

&lt;p&gt;You can refer to this &lt;a href="https://discourse.nodered.org/t/is-there-an-http-api-where-i-can-ask-for-pings-for-integration-tests/59707"&gt;Discussion Thread on Node-Red Forum&lt;/a&gt; to create the flow, or use the following&lt;br&gt;
&lt;a href="https://github.com/shantanoo-desai/node-red-slim/blob/main/flows.json"&gt;&lt;code&gt;flows.json&lt;/code&gt;&lt;/a&gt; file&lt;/p&gt;

&lt;p&gt;We can check if the flow is working again but building the Docker Image and then try:&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;-XGET&lt;/span&gt; http://localhost:1880/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to set the port 1880 when running the docker image e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 1880:1880 node-red-slim:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that works, good job! now it is time to make an integration test with python&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration Test of your Node-Red Image
&lt;/h2&gt;

&lt;p&gt;One cool thing you can try out is the &lt;a href="https://pypi.org/project/pytest-docker-compose/"&gt;pytest-docker-compose&lt;/a&gt; which provides you a nice suite &lt;br&gt;
to do tests with &lt;code&gt;docker-compose&lt;/code&gt;. I won't dive too deep into it, but I relied on this&lt;br&gt;
&lt;a href="https://dev.to/xnuinside/integration-tests-for-bunch-of-services-with-pytest-docker-compose-j5i"&gt;Dev.To post by Iuliia Volkova&lt;/a&gt; for wrting a simple test that does a health check on our&lt;br&gt;
&lt;code&gt;/health&lt;/code&gt; API once the container is up and running.&lt;/p&gt;
&lt;h3&gt;
  
  
  Testing Files
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pytest-docker-compose&lt;/code&gt; is a plugin for &lt;code&gt;pytest&lt;/code&gt; testing suite. The structure of your test directory&lt;br&gt;
should be 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;&lt;span class="nb"&gt;.&lt;/span&gt;
├── README.md
├── requirements.dev.txt
├── scripts
│   ├── 00-build-test-env.sh
│   └── 01-run-tests.sh
├── test-docker-compose.yml
└── tests
    ├── conftest.py
    └── test_fixtures.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer to &lt;a href="https://github.com/shantanoo-desai/node-red-slim/tree/main/tests/integration"&gt;tests/integration&lt;/a&gt; directory for file contents&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;conftest.py&lt;/code&gt; is used to as fixture for the &lt;code&gt;test-docker-compose.yml&lt;/code&gt; to be used for the test stack.&lt;/p&gt;

&lt;p&gt;the &lt;code&gt;test_fixture.py&lt;/code&gt; contains the test fixture to ping the &lt;code&gt;/health&lt;/code&gt; API from our flow once the &lt;br&gt;
node-red container&lt;/p&gt;

&lt;p&gt;For our case, if the &lt;code&gt;/health&lt;/code&gt; API provides a HTTP 200 OK response, our test passes. You can add more &lt;br&gt;
tests depending on your requirements.&lt;/p&gt;

&lt;p&gt;We will leverage simple bash scripts in the &lt;code&gt;scripts&lt;/code&gt; directory to setup the python &lt;br&gt;
virtualenvironment as to bring the &lt;code&gt;test-docker-compose&lt;/code&gt; up and run the pytest&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional: using this setup in a CI/CD Pipeline using GitHub
&lt;/h3&gt;

&lt;p&gt;You can think of our steps we just went through as a CI/CD Pipeline. The steps are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build our custom &lt;strong&gt;Node-Red&lt;/strong&gt; Docker Image&lt;/li&gt;
&lt;li&gt;Test Integration using &lt;code&gt;pytest-docker-compose&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Push the image to Docker Hub, if test passes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the repository, I have setup a GitHub Workflow that pushes the docker image only &lt;br&gt;
when I push a Tag e.g. &lt;code&gt;v1.2.0&lt;/code&gt; etc.&lt;/p&gt;

&lt;p&gt;For this Workflow, you will need to setup the credentials of your Registry in your GitHub Secrets. &lt;br&gt;
For a sample of the YAML file, refer to this &lt;a href="https://github.com/shantanoo-desai/node-red-slim/blob/main/.github/workflows/deploy.yml"&gt;deploy.yml&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inference
&lt;/h2&gt;

&lt;p&gt;That's how you do custom node-red, docker, docker-compose and integration testing !&lt;/p&gt;

&lt;p&gt;I am not aware of conducting tests of the individual tests of the flows generated in Node-Red, but this &lt;br&gt;
test focuses on integrating node-red with some possible stacks where different Databases are part of the&lt;br&gt;
stack.&lt;/p&gt;

&lt;p&gt;If you have comments, criticisms, feedback please reach out to me and I will be happy to learn and help!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>pytest</category>
      <category>dockercompose</category>
      <category>devops</category>
    </item>
    <item>
      <title>Prepare your Docker-Compose Stack as a Tarball for Offline Installations</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Sat, 26 Mar 2022 13:52:49 +0000</pubDate>
      <link>https://dev.to/shandesai/prepare-your-docker-compose-stack-as-a-tarball-for-offline-installations-40cd</link>
      <guid>https://dev.to/shandesai/prepare-your-docker-compose-stack-as-a-tarball-for-offline-installations-40cd</guid>
      <description>&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;Many a times you might have requirement to run Docker on a Raspberry Pi or other SBCs that may have to do run some applications without any internet connections. You might have initially developed your application only by keeping in mind a Docker Artifact and was meant to run as complete stack using &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In almost all cases, bringing the stack up will pull the images from a registry through the Internet. But when you wish to deploy some SBCs into a space where there is no Internet to begin with you might have to either develop your code artifact as a package or binary bundle. If this application requires dependencies on some Databases then you will have to write tedious bash scripts to prepare the device&lt;br&gt;
for some pre-installtion.&lt;/p&gt;

&lt;p&gt;Seems like a lot of refactoring / re-thinking to do!&lt;/p&gt;

&lt;p&gt;Do not worry &lt;code&gt;docker&lt;/code&gt; has things sorted out, and provides &lt;code&gt;docker save&lt;/code&gt; and &lt;code&gt;docker load&lt;/code&gt; functionalities.&lt;/p&gt;
&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;Let's consider an Open-Source Stack &lt;a href="https://github.com/shantanoo-desai/tiguitto"&gt;tiguitto&lt;/a&gt; for IoT at Edge.&lt;/p&gt;

&lt;p&gt;It comprises of some standard apps like an &lt;strong&gt;MQTT Broker&lt;/strong&gt;, &lt;strong&gt;InfluxDB&lt;/strong&gt;, &lt;strong&gt;Telegraf&lt;/strong&gt;, &lt;strong&gt;Grafana&lt;/strong&gt;. All these&lt;br&gt;
components are combined through a &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now, as previously mentioned shipping the stack would have been easy, had we had Internet on the target node.&lt;br&gt;
Simply sending the compose file to the node would have done everything for us.&lt;/p&gt;

&lt;p&gt;For cases where we do not have Internet access, we have to ship two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Compressed Tar-Ball for services present in the compose file&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Usage Steps
&lt;/h3&gt;

&lt;p&gt;Assume we have our development machine with &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;docker-compose&lt;/code&gt; on them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We make sure to remove all not-used, unnecessary images are cleared from the machine and only the images 
of our application exists.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    docker images &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="c"&gt;# check existing images on dev machine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you wish to remove everything and only pull the required images do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    docker rmi &lt;span class="si"&gt;$(&lt;/span&gt;docker images | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s2"&gt;"NR&amp;gt;0 {print&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Pull the images with their dedicated tags using &lt;code&gt;docker pull &amp;lt;image_name&amp;gt;:&amp;lt;tag&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check using &lt;code&gt;docker images -a&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now leverage &lt;code&gt;docker save&lt;/code&gt; along with some format parsing using:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker save &lt;span class="nt"&gt;-o&lt;/span&gt; myStack.tar &lt;span class="si"&gt;$(&lt;/span&gt;docker images &lt;span class="nt"&gt;--format&lt;/span&gt; &lt;span class="s2"&gt;"{{.Repository}}:{{.Tag}}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;docker save&lt;/code&gt; combines the image into their respective Tar balls however we need to tell &lt;code&gt;docker&lt;/code&gt; that we need to combine all the images existing on the dev machine into a combined Tar ball. This is done through &lt;code&gt;--format "{{.Repository}}:{{.Tag}}"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should produce &lt;code&gt;myStack.tar&lt;/code&gt; in your directory&lt;/p&gt;

&lt;h2&gt;
  
  
  Unpack your Tarball and Test
&lt;/h2&gt;

&lt;p&gt;If you are doing this on a laptop or PC, try switching your network connection off now.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unpack your Tarball
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    docker load &lt;span class="nt"&gt;-i&lt;/span&gt; myStack.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Check with &lt;code&gt;docker images -a&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can now &lt;code&gt;docker-compose up&lt;/code&gt; and your application should work offline&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you use some other ways of using shipping your Docker and Compose applications, get in touch with me and would like to learn from you!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Use Docker Secret to set your Portainer Admin User's Password</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Sun, 13 Mar 2022 10:57:31 +0000</pubDate>
      <link>https://dev.to/shandesai/use-docker-secret-to-set-your-portainer-admin-users-password-ppc</link>
      <guid>https://dev.to/shandesai/use-docker-secret-to-set-your-portainer-admin-users-password-ppc</guid>
      <description>&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;I was deep-diving on creating a decent-sized &lt;code&gt;docker-compose&lt;/code&gt; stack with 5+ services in them. &lt;br&gt;
I was also on the look out for some Deployment Pattern where I didn't want to dump all my&lt;br&gt;
&lt;strong&gt;Environment Variables&lt;/strong&gt; into a giant &lt;code&gt;.env&lt;/code&gt; file, neither in Production nor in Development.&lt;br&gt;
I decided to create a structure where each service aka. component would have their own dedicated&lt;br&gt;
directory with their respective &lt;em&gt;secrets&lt;/em&gt; (credentials) and their configuration files all bundled&lt;br&gt;
together.&lt;/p&gt;

&lt;p&gt;I decided upon the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ComponentName
├── config.component
└── secrets
    └── .env.component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the &lt;code&gt;ComponentName&lt;/code&gt; could your favourite database, the &lt;code&gt;secrets&lt;/code&gt; directory within this directory&lt;br&gt;
would contain a &lt;code&gt;.env.database&lt;/code&gt; file with all necessary admin credentials for the initial stack configuration.&lt;br&gt;
The &lt;code&gt;config.component&lt;/code&gt; file is a dedicated configuration file (if needed)&lt;/p&gt;

&lt;p&gt;I think the structure would work &lt;em&gt;Okay&lt;/em&gt; since changes to a component's configuration would be reflected&lt;br&gt;
a bit better in the Git History / Logs&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;If you end up having a lot of containers in the stack, &lt;code&gt;docker-compose logs&lt;/code&gt; only takes ever so far! You might&lt;br&gt;
decide upon &lt;strong&gt;Portainer&lt;/strong&gt; to make the container management a bit easier through it's UI.&lt;/p&gt;

&lt;p&gt;One problem, Portainer doesn't support the &lt;strong&gt;Environment Variables&lt;/strong&gt; Configuration pattern as by many container&lt;br&gt;
based software applications.&lt;/p&gt;

&lt;p&gt;It relies on executing &lt;code&gt;command&lt;/code&gt; in your &lt;code&gt;docker-compose&lt;/code&gt; file to introduce an password into your Portainer's service.&lt;/p&gt;

&lt;p&gt;If you have a bit of Software OCD, you are going to hate it! One service not conforming to your dream stack deployment!&lt;/p&gt;
&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Here comes &lt;a href="https://docs.docker.com/engine/swarm/secrets/"&gt;&lt;code&gt;docker secret&lt;/code&gt;&lt;/a&gt; to the rescue!&lt;/p&gt;

&lt;p&gt;One massive Caveat, according to the documentation, &lt;code&gt;docker secret&lt;/code&gt; is only available for &lt;strong&gt;Swarm&lt;/strong&gt; Setting, or it ?!&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://blog.mikesir87.io/2017/05/using-docker-secrets-during-development/"&gt;blog post from Michael Irwin&lt;/a&gt; about using&lt;br&gt;
docker secrets in Development provides a way to trick docker into accepting files as a docker secret and use it into your&lt;br&gt;
service.&lt;/p&gt;

&lt;p&gt;Another thing when going through Portainer's Documentation is that, it accepts admin password also through a &lt;br&gt;
&lt;a href="https://docs.portainer.io/v/ce-2.11/advanced/cli#configuration-flags-available-at-the-command-line"&gt;password file&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We could see some Puzzle Pieces falling into place here!&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Let's start with our structure mentioned above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portainer
└── secrets
    └── portainer-admin-password
|- docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of an &lt;code&gt;.env&lt;/code&gt; we rename the file to &lt;code&gt;portainer-admin-password&lt;/code&gt; where you can set your password.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;docker-compose.yml&lt;/code&gt; will then look as follows:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.7'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;portainer&lt;/span&gt;&lt;span class="pi"&gt;:&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;portainer/portainer-ce:latest&lt;/span&gt;
      &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sys_portainer&lt;/span&gt;
      &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--admin-password-file=/run/secrets/portainer_admin_password'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--no-analytics'&lt;/span&gt;
      &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;some_network&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9000:9000"&lt;/span&gt;
      &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;portainer_admin_password&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;some_network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;portainer_admin_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./portainer/secrets/portainer_admin_password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Breaking it down functionally!
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;portainer_admin_password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./portainer/secrets/portainer_admin_password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mounts the file as a docker secret into the compose file. Since it is a file mount, it will be&lt;br&gt;
available in the following directory &lt;code&gt;/run/secrets/&amp;lt;KEY_NAME_IN_SECRETS_section&amp;gt;&lt;/code&gt; since our key&lt;br&gt;
is the same name as that of the file (in order to avoid any discrepancy), the content of the file&lt;br&gt;
will be consumed by the &lt;code&gt;--admin-password-file&lt;/code&gt; flag during the stack initialization.&lt;/p&gt;

&lt;p&gt;Voilá! You now have a similar structure without having to hardcode passwords or sensitive information&lt;br&gt;
into your &lt;code&gt;docker-compose.yml&lt;/code&gt; file&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>docker</category>
      <category>portainer</category>
      <category>devops</category>
    </item>
    <item>
      <title>Seed Your MongoDB Container with JSON data using Docker and Docker-Compose</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Tue, 09 Nov 2021 12:21:07 +0000</pubDate>
      <link>https://dev.to/shandesai/seed-your-mongodb-container-with-json-data-using-docker-and-docker-compose-5af1</link>
      <guid>https://dev.to/shandesai/seed-your-mongodb-container-with-json-data-using-docker-and-docker-compose-5af1</guid>
      <description>&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;A couple of years ago I made a frontend app which rendered JSON data stored in-memory. The App provided a &lt;em&gt;check-list&lt;/em&gt; for Quality Management called &lt;a href="https://github.com/shantanoo-desai/qualiexplore"&gt;QualiExplore&lt;/a&gt; (under &lt;strong&gt;Apache 2.0 License&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Nothing too fancy, but we needed to make the app a bit more flexible and decided to use &lt;em&gt;MongoDB&lt;/em&gt; to render the information &lt;br&gt;
as well as make it easy to introduce new information to the JSON data that previously persisted in the App.&lt;/p&gt;

&lt;p&gt;Fundamentally, the app should be &lt;em&gt;out-of-the-box&lt;/em&gt; usable for someone who wants to use it (with other additions currently on-going e.g., GraphQL backend + User authentication / authorization)&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;The JSON data, that previously persisted in the app needs to be &lt;em&gt;seeded&lt;/em&gt; into the MongoDB instance once the complete stack is &lt;br&gt;
brought up.&lt;/p&gt;

&lt;p&gt;Doesn't sound like a bit deal, should be possible to use volume mounts with docker, right? Yup, you guessed it but MongoDB doesn't&lt;br&gt;
just ingest data because one mounted a volume to a specific directory. To the rescue comes &lt;code&gt;mongoimport&lt;/code&gt; tool where one can load&lt;br&gt;
data via CLI. Seems like our problem is solved!&lt;/p&gt;

&lt;p&gt;Well it turns out I wanted to seed data into the MongoDB in a &lt;em&gt;litte more secure&lt;/em&gt; manner aka. maybe use a username and password and a dedicated initialized database where this imported data should persist under specific collections.&lt;/p&gt;

&lt;p&gt;Turns out, once you figure out the &lt;code&gt;mongoimport&lt;/code&gt; tool's Syntax, the next big headache was to figure out how to &lt;em&gt;securely&lt;/em&gt; pass this information to a docker image which will insert this information into Mongo.&lt;/p&gt;

&lt;p&gt;I generally have a stack design pattern where I try to keep changes into YAML files for an end-user minimum and let the changes reflect through the environment variables passed to the stack. So passing the environment variables to the respective docker containers shouldn't be a big hassle, right? &lt;em&gt;Oh! how wrong I was!&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;I decided to following the following sequential steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bring the MongoDB container up&lt;/li&gt;
&lt;li&gt;Create a docker container that is connected to the same network as MongoDB container as above that has &lt;code&gt;mongoimport&lt;/code&gt; on it&lt;/li&gt;
&lt;li&gt;Mount the JSON data into the container in step 2 and insert the data&lt;/li&gt;
&lt;li&gt;In order to make the ingestion of data bit more secure pass the information like the database's URI, credentials via environment variables&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the initial project setup is 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;&lt;span class="nb"&gt;.&lt;/span&gt;
├── docker-compose.yml
├── mongo_seed
│   ├── Dockerfile
│   ├── factors.json
│   └── filters.json
└── .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;mongo_seed&lt;/code&gt; is the directory with the data to be ingested as well as the &lt;code&gt;Dockerfile&lt;/code&gt; that will perform the necessary ingestion.&lt;/p&gt;

&lt;p&gt;The root of the directory contains the &lt;code&gt;docker-compose.yml&lt;/code&gt; for the stack and its respective &lt;code&gt;.env&lt;/code&gt; file for environment variables&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems Faced
&lt;/h3&gt;

&lt;p&gt;This requires a quick primer of Docker's &lt;code&gt;ARG&lt;/code&gt; and &lt;code&gt;ENV&lt;/code&gt; in context of &lt;code&gt;docker&lt;/code&gt;. A decent read-through I used can be found &lt;br&gt;
&lt;a href="https://vsupalov.com/docker-arg-env-variable-guide/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ARG&lt;/code&gt; is used during build-time i.e., when building a docker container. It's lifetime is short till the build is complete. Once the container&lt;br&gt;
is built, they are not available for further usage.&lt;br&gt;
&lt;code&gt;ENV&lt;/code&gt;, on the other hand, is available for the run-time of the container too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A common practice that a lot of container developers use is to declare an &lt;code&gt;ARG&lt;/code&gt; and then use the value of the incoming build-argument as an&lt;br&gt;
&lt;code&gt;ENV&lt;/code&gt; for further usage.&lt;/p&gt;

&lt;p&gt;so something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; database-uri&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATABASE_URI=$(database-uri)&lt;/span&gt;

&lt;span class="c"&gt;# Use `$DATABASE_URI` to insert database&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This wasn't the case since I ended facing problem which I documented on &lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/69886273/docker-compose-file-doesnt-pick-up-environment-variable-from-a-dedicated-env-fi"&gt;StackExchange&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem concisely, is the environment variables from &lt;code&gt;.env&lt;/code&gt; fille passed into the &lt;code&gt;mongo-seed&lt;/code&gt; container doesn't get set during run-time&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;After going through some StackExchange Queries, an answer from&lt;br&gt;
&lt;a href="https://stackoverflow.com/a/69173690/4851126"&gt;Zincfan on a Query regarding getting Env Variable in Dockerfile&lt;/a&gt; turned out to be the solution&lt;/p&gt;
&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Declare Same &lt;code&gt;ARG&lt;/code&gt; and &lt;code&gt;ENV&lt;/code&gt; of the same name as that of the environment variables&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get the information from the build-argument and store the information into the env. variable using the syntax:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```
ARG DATABASE_URI
ENV DATABASE_URI ${DATABASE_URI}
```
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use &lt;code&gt;${DATABASE_URI}&lt;/code&gt; in the run-time of the container&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;to pass the information from the &lt;code&gt;.env&lt;/code&gt; passed to the compose file should be in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;mongo-seed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URI=$DATABASE_URI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




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

&lt;h3&gt;
  
  
  Files
&lt;/h3&gt;

&lt;p&gt;So finally my &lt;code&gt;Dockerfile&lt;/code&gt; looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mongo:5.0&lt;/span&gt;
 &lt;span class="c"&gt;# Will be set through Environment Files&lt;/span&gt;
 ARG DATABASE_URI
 ARG USERNAME
 ARG PASSWORD

 ENV DATABASE_URI ${DATABASE_URI}
 ENV USERNAME ${USERNAME}
 ENV PASSWORD ${PASSWORD}

 COPY factors.json /factors.json

 COPY filters.json /filters.json

 CMD mongoimport --username ${USERNAME} --password ${PASSWORD} --uri ${DATABASE_URI} --collection factors --drop --file /factors.json &amp;amp;&amp;amp; \
     mongoimport --username ${USERNAME} --password ${PASSWORD} --uri ${DATABASE_URI} --collection filters --drop --file /filters.json


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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Good to Note&lt;/strong&gt;: Never split into two &lt;code&gt;CMD&lt;/code&gt; in the file, rather merge multiple commands into one &lt;code&gt;CMD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;my &lt;code&gt;docker-compose.yml&lt;/code&gt; file looks like the following:&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# MongoDB&lt;/span&gt;
    &lt;span class="na"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb&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;mongo:latest&lt;/span&gt;
        &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27017:27017"&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qualiexplore_net"&lt;/span&gt;

    &lt;span class="c1"&gt;# Initial Seed to QualiExplore Database&lt;/span&gt;
    &lt;span class="na"&gt;mongo-seed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./mongo_seed&lt;/span&gt;
            &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
            &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URI=$DATABASE_URI&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;USERNAME=$MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PASSWORD=$MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
        &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qualiexplore_net"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My &lt;code&gt;.env&lt;/code&gt; file is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=example
MONGO_INITDB_DATABASE=qualiexplore
DATABASE_URI=mongodb://mongodb:27017/qualiexplore?authSource=admin****
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Comments, Suggestions
&lt;/h2&gt;

&lt;p&gt;If you would like to suggest me some changes in my design or a better way to tackle this situation, I am all ears&lt;br&gt;
and would love to improve and discuss aspects. You can contact me on &lt;a href="https://linkedin.com/in/shantanoo-desai"&gt;LinkedIn&lt;/a&gt; or or leave a comment here&lt;/p&gt;

</description>
      <category>docker</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Setting up and running LF-Edge's Fledge (from source) on a Raspberry Pi 4</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Fri, 30 Jul 2021 10:03:35 +0000</pubDate>
      <link>https://dev.to/shandesai/setting-up-and-running-lf-edge-s-fledge-from-source-on-a-raspberry-pi-4-188o</link>
      <guid>https://dev.to/shandesai/setting-up-and-running-lf-edge-s-fledge-from-source-on-a-raspberry-pi-4-188o</guid>
      <description>&lt;h2&gt;
  
  
  Fledge
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Fledge is an open source framework and community for the industrial edge focused on critical operations, predictive maintenance, situational awareness and safety. Fledge is architected to integrate Industrial Internet of Things (IIoT), sensors and modern machines with the cloud and existing “brown field” systems like historians, DCS (Distributed Control Systems), PLC (Program Logic Controllers) and SCADA (Supervisory Control and Data Acquisition). All sharing a common set of administration and application APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wanted to give &lt;a href="https://github.com/fledge-iot"&gt;Fledge&lt;/a&gt; a try to see how one can bring an open-source IoT/IIoT Stack to a quick realization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Hands Dirty already!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hardware
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Device&lt;/strong&gt;: &lt;strong&gt;Raspberry Pi 4 Model B&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Spec&lt;/strong&gt;: 2GB RAM, 32GB Micro SD Card&lt;br&gt;
&lt;strong&gt;Operating System&lt;/strong&gt;: &lt;strong&gt;Ubuntu LTS 20.04.2&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;I am going to just clone stuff in my home directory&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the &lt;a href="https://github.com/fledge-iot/fledge"&gt;fledge Repository&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/fledge-iot/fledge.git &amp;amp;&amp;amp; cd fledge/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the Dependencies (in the root directory of fledge)&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ sudo ./requirements.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's install fledge on the Pi&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo make install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;grab something to munch on till the installation is complete&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The installation will add the files and binaries in to the following directory: &lt;code&gt;/usr/local/fledge/&lt;/code&gt;. You can export this path:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export FLEDGE=/usr/local/fledge
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;start Fledge and check the status using the following:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ $FLEDGE/bin/fledge start
$ $FLEDGE/bin/fledge status
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Checkout the Fledge UI by hitting the Pi's IP Address: &lt;code&gt;http://&amp;lt;IP_ADDRESS_of_PI&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point of time, Fledge is very &lt;em&gt;bare-metal&lt;/em&gt; which implies there are lot of plugins that are missing. We begin by installing a very basic &lt;em&gt;simulated&lt;/em&gt; plugin.&lt;/p&gt;
&lt;h3&gt;
  
  
  South-Plugin Installation
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Sinusoid
&lt;/h4&gt;

&lt;p&gt;Since we are doing things by source, we need to clone the plugin repository. We start with a very basic &lt;code&gt;sinusoidal&lt;/code&gt; South Plugin which will generate sine waves to the Fledge Core.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;clone the &lt;a href="https://github.com/fledge-iot/fledge-south-sinusoid"&gt;&lt;code&gt;fledge-south-sinusoid&lt;/code&gt; plugin repository&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd 
$ git clone https://github.com/fledge-iot/fledge-south-sinusoid.git &amp;amp;&amp;amp; cd fledge-south-sinusoid/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we just need to copy the source code of the sine-wave generator to the directory path of plugins for Fledge&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # we are currently in the root directory of fledge-south-sinusoid
$ sudo cp -r python/fledge/plugins/south/sinusoid $FLEDGE/python/fledge/plugins/south
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can refresh the UI and click on the &lt;strong&gt;South&lt;/strong&gt; Menu and you will be able to see &lt;code&gt;sinusoid&lt;/code&gt; as a &lt;strong&gt;South Plugin&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  CoAP
&lt;/h4&gt;

&lt;p&gt;Let's get one more Plugin into Fledge: CoAP plugin&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;clone the &lt;a href="https://github.com/fledge-iot/fledge-south-coap"&gt;&lt;code&gt;fledge-south-coap&lt;/code&gt; plugin repository&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd 
$ git clone https://github.com/fledge-iot/fledge-south-coap.git &amp;amp;&amp;amp; cd fledge-south-coap/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let's copy the plugin's code to Fledge as we did previously&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # we are currently in the root directory of fledge-south-coap
$ sudo cp -r python/fledge/plugins/south/coap $FLEDGE/python/fledge/plugins/south
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the python dependencies that are necessary to execute the plugin and install them:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo cp -r python/requirements-coap.txt $FLEDGE/python/
$ sudo pip3 - r $FLEDGE/python/requirements-coap.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Since the code is in the &lt;code&gt;/usr/local/&lt;/code&gt; directory we need to provide root privileges to the coap plugin for execution by the Fledge Core&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo chown -R root:root $FLEDGE/python/fledge/plugins/south/coap
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it ! Now you have we two South Plugins in our Fledge Application that can provide us some simulated data!&lt;/p&gt;

&lt;p&gt;Your UI &lt;strong&gt;South&lt;/strong&gt; Menu should look like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8cIGtZHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vm1f7kwbt9ohedh87hdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8cIGtZHx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vm1f7kwbt9ohedh87hdc.png" alt="Sinusoid &amp;amp; CoAP Plugins in the Fledge UI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup / Data Generation for Sinusoid Plugin
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Let's setup the Sine-Wave Generator by naming it &lt;code&gt;test-sine-south&lt;/code&gt; and click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ccthtDDp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4oc0bxiksywblr1mxf4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ccthtDDp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4oc0bxiksywblr1mxf4s.png" alt="Sinusoid Plugin Setup in Fledge UI. Step 1"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Name the &lt;strong&gt;Asset Name&lt;/strong&gt;. We name it &lt;code&gt;sine-wave-asset&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mHFLux-W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57fcmuvxxoi25h4xtbts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mHFLux-W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57fcmuvxxoi25h4xtbts.png" alt="Name the Asset in Fledge UI. Step 2"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure to enable the plugin by checking the &lt;strong&gt;Enabled&lt;/strong&gt; checkbox and finally click &lt;strong&gt;Done&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the UI you now see the Sinusoid Plugin Enabled with active readings being fed into the Fledge Core. You can click on the link &lt;code&gt;test-sine-south&lt;/code&gt; to change the configuration of the plugin / delete it or export readings to a file.&lt;/p&gt;

&lt;p&gt;You can click on &lt;strong&gt;Assets &amp;amp; Readings&lt;/strong&gt; Menu and click on the Graph Icon to get some visualization delete it or export readings to a file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n5P__VFU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uou30gkzoi27qev2s8sa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n5P__VFU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uou30gkzoi27qev2s8sa.png" alt="Assets &amp;amp; Readings of Sinusoid Wave"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there you have visualization of the data coming in from your South Plugin, a lovely sine wave. Not practical but you get to understand how the Fledge Architecture would work!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lNZNjUQw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9867eqjv08k8cq8infz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lNZNjUQw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9867eqjv08k8cq8infz.png" alt="Data Visualization of Sine Wave Asset"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click on the &lt;strong&gt;Summary&lt;/strong&gt; tab to get some basic statistics of the information&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup / Data Generation for CoAP Plugin
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Let's setup the CoAP South Plugin similarly to Sinusoid by clicking on the &lt;strong&gt;+ Add&lt;/strong&gt; button on the top-right of the Panel under &lt;strong&gt;South&lt;/strong&gt; Page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sy8Rj0YS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54qloscll9hnh1vgb63o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sy8Rj0YS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54qloscll9hnh1vgb63o.png" alt="Setting up CoAP South Plugin: Step 1"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Call the service &lt;code&gt;test-coap-south&lt;/code&gt; and click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P26p094U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cq2938t0y4171q0qnmp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P26p094U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cq2938t0y4171q0qnmp0.png" alt="Naming CoAP Service: Step 2"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the next step keep the configuration as it is for now i.e. Port as &lt;code&gt;5683&lt;/code&gt; and the URI as &lt;code&gt;sensor-values&lt;/code&gt; and click &lt;strong&gt;Next&lt;/strong&gt; and enable the plugin on the last setup.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should enable the CoAP Plugin for Fledge and it's time to generated some CoAP data from a simulated client to a CoAP Server running on the Pi.&lt;/p&gt;

&lt;p&gt;Fledge does provide some testing information for CoAP in the core directory under the the CLI called &lt;code&gt;fogbench&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's generate some CoAP data on the Pi.&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;$FLEDGE&lt;/span&gt;/bin/fogbench &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$FLEDGE&lt;/span&gt;/data/extras/fogbench/fogbench_sensor_coap.template.json &lt;span class="nt"&gt;-I&lt;/span&gt; 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;here &lt;code&gt;-t&lt;/code&gt; flag is for mentioning a template and we use a coap template provided by Fledge mentioned above. &lt;code&gt;-I&lt;/code&gt; is the time interval&lt;/p&gt;

&lt;p&gt;Upon executing the command on the Pi, you can check the UI which will generate the following output for the CoAP Plugin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2uoIAauX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xia5fphgrxxkftlm8oep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2uoIAauX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xia5fphgrxxkftlm8oep.png" alt="Assets for Fogbench CoAP Service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can explore the Assets and Visualization by going to &lt;strong&gt;Assets &amp;amp; Readings&lt;/strong&gt; and clicking on any of the asset you wish to observe. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: In order to visualize live-data you can run the &lt;code&gt;fogbench&lt;/code&gt; command above a couple of more times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OqhV1d-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1m30qkuk7v290t6xfnqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OqhV1d-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1m30qkuk7v290t6xfnqj.png" alt="Statistics for Luxometer Asset"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter Plugins in Fledge
&lt;/h2&gt;

&lt;p&gt;The sine wave isn't that cool to look at to so let's get some Frequency Domain Analysis on it with a &lt;strong&gt;Fast Fourier Transform&lt;/strong&gt; on it using Fledge's FFT filter plugin&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Let's clone the plugin in the home directory&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd 
$ git clone https://github.com/fledge-iot/fledge-filter-fft.git &amp;amp;&amp;amp; cd fledge-filter-fft/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This plugin is not python based so we need to do some tasks for installing it. We export a &lt;code&gt;FLEDGE_ROOT&lt;/code&gt; variable and create a &lt;code&gt;build&lt;/code&gt; directory in the root of the repo&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # we export the directory where we built Fledge for the filter plugin to use
$ export FLEDGE_ROOT=~/fledge/
$ # in the root of the `fledge-filter-fft` repo
$ mkdir build &amp;amp;&amp;amp; cd build/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compile the plugin&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cmake ..
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;install the plugin&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo make install
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you have the FFT plugin ready to be applied in Fledge&lt;/p&gt;

&lt;h3&gt;
  
  
  Applying FFT on the our Sine-Wave Asset
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Let's head back to the &lt;strong&gt;South&lt;/strong&gt; Plugins in the UI and click on the &lt;code&gt;test-sine-south&lt;/code&gt; service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the &lt;strong&gt;Applications&lt;/strong&gt; menu for the Service &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3oZLtNj8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnkcabc64w9tmspti7ul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3oZLtNj8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnkcabc64w9tmspti7ul.png" alt="UI for test-sine-south Service"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &lt;code&gt;fft&lt;/code&gt; from the available plugins and name the service &lt;code&gt;test-fft-sine&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--58hmRLEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aon94xjylbxsosal3btk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--58hmRLEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aon94xjylbxsosal3btk.png" alt="Name the FFT filter Plugin Service"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup the Service to conduct filtering on the asset called &lt;code&gt;sine-wave-asset&lt;/code&gt; (See steps to setup Sinusoid Plugin) and other parameters as shown below (no fine tuning done here). Don't forget to click the &lt;strong&gt;Enabled&lt;/strong&gt; checkbox and finally &lt;strong&gt;Done&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dPfM1DLn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yleb6l3yo1ln7vxv7gru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dPfM1DLn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yleb6l3yo1ln7vxv7gru.png" alt="Configuring FFT Filter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Fast Fourier Transform might take some time to show up but you can head to &lt;strong&gt;Assets &amp;amp; Readings&lt;/strong&gt; and click on the &lt;code&gt;sine-wave-asset FFT&lt;/code&gt;'s Graph Icon to see some visualizations. This is what mine look like&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QhA_ckes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dncghkughxwtg5or1ytr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QhA_ckes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dncghkughxwtg5or1ytr.png" alt="FFT of the sine-wave-asset"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great stuff. Imagine having vibration sensors and you need to conduct FFT analyses on it! Fledge makes it nifty!!&lt;/p&gt;

</description>
      <category>iot</category>
      <category>raspberrypi4</category>
      <category>iiot</category>
      <category>edgecomputing</category>
    </item>
    <item>
      <title>How to (atleast) not get downvoted on StackExchange or anywhere: My Bug/Query Template</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Thu, 15 Jul 2021 16:36:57 +0000</pubDate>
      <link>https://dev.to/shandesai/how-to-atleast-not-get-downvoted-on-stackexchange-or-anywhere-my-bug-query-template-23d2</link>
      <guid>https://dev.to/shandesai/how-to-atleast-not-get-downvoted-on-stackexchange-or-anywhere-my-bug-query-template-23d2</guid>
      <description>&lt;p&gt;(Originally posted on my personal Blog)&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;Everything mentioned in the blog are my own findings / discoveries to survive the often times &lt;em&gt;brutal&lt;/em&gt; down-voting of &lt;br&gt;
StackExchange / StackOverflow Queries. Please feel free to ignore any or all of this if you have a better way of documenting errors / bug reports.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;For someone who does not have an education in Software Engineering but yet loves writing Software, I frequently, if not always, rely on the community of Software Developers / Engineers to help me figure out my problems with programming languages or software suites.&lt;/p&gt;

&lt;p&gt;One of the major problems when I started working with code-bases / stacks (in 2015, not so old as I want to make it sound!) was the lack of coherence in trying to frame my problem which I faced whilst working on something. The frustration that mounts on when you are deep-diving into something and hitting a temporary barrier is sometimes baffling.&lt;/p&gt;

&lt;p&gt;Now after 6 years of working with software and &lt;a href="https://meta.stackoverflow.com/users/4851126/shan-desai?tab=profile"&gt;2.4k Reputations on StackExchange&lt;/a&gt; later, I looked back at why some of my posts keep getting me up-votes even though they were posted a while back!&lt;/p&gt;
&lt;h2&gt;
  
  
  Bragging Time
&lt;/h2&gt;

&lt;p&gt;At the time of writing this blog, I checked my reputations and I am ranked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Top 11% for this year&lt;/strong&gt; on StackExchange&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top 7% Overall&lt;/strong&gt; on Internet of Things Beta Community&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top 9% Overall&lt;/strong&gt; on Rasbperry Pi StackExchange Community&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top 26% Overall&lt;/strong&gt; on Unix Linux StackExchange Community&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One might be tempted to think, that these numbers are weak and do not amount to anything which is absolutely fair to assume. However, please do realize that for someone not with hardcore software background, surviving the &lt;em&gt;down-votes&lt;/em&gt; on such communities is an achievement in itself.&lt;/p&gt;
&lt;h2&gt;
  
  
  Analyses
&lt;/h2&gt;

&lt;p&gt;These are some of the things that have helped me over the years in obtaining answers to queries on forums and also a positive reputation&lt;/p&gt;
&lt;h3&gt;
  
  
  Mark (this) Down
&lt;/h3&gt;

&lt;p&gt;This is a rather software &lt;em&gt;philosophy&lt;/em&gt; that one can debate till the end of time or till the end of a project!&lt;/p&gt;

&lt;p&gt;Documentation is not for everyone ! I hardly have met someone who is as much in love with &lt;strong&gt;Markdown&lt;/strong&gt; as I am at this point of my professional career. Don't believe me ? I am writing this blog post in &lt;strong&gt;Markdown&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;I am mentioning Markdown because it is exceptionally handy to work with. From a blog post such as this, to StackExchange, to different community websites and even Reddit support it in some form or another. Not to mention how minimal it is compared to terrible HTML tags !&lt;/p&gt;

&lt;p&gt;It also has some of the lowest learning curves for any Markup Language to my knowledge. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;May it be opening an Issue on GitHub, or writing a blog post, or an opinionated post on your favourite subreddit - Markdown is always there to help you transfer your thoughts for you without having to click on that fancy editor buttons ! &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Start a project with a NOTES.md
&lt;/h3&gt;

&lt;p&gt;you can ignore this file in your software development and use this &lt;code&gt;NOTES.md&lt;/code&gt; as a scribbling markdown file for all things you did/ you want / you will need to do in order to get something up and running.&lt;/p&gt;

&lt;p&gt;Great thing about making this a markdown file is the flexibility of copying / pasting commands and code snippets that are suspicious.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;CTRL + C&lt;/strong&gt;  and &lt;strong&gt;CTRL + V&lt;/strong&gt; is way comfortable that a million &lt;strong&gt;CTRL + Z&lt;/strong&gt; a lot of times ! &lt;/p&gt;
&lt;h3&gt;
  
  
  Being Concise
&lt;/h3&gt;

&lt;p&gt;This is the hardest thing I had to adapt. In a frustrating bout with some code or a stack, I would have just loved to dump everything that has been through at my screen on a forum and wait for someone to catch my attention. However, life isn't like that and so is software troubleshooting!&lt;/p&gt;

&lt;p&gt;Things that can help be concise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep a small notebook to help keep track of basic Command-Lines executed (better yet use &lt;code&gt;history&lt;/code&gt; command to know what was done)&lt;/li&gt;
&lt;li&gt;If you don't care about jotting things down, try keeping a mindful state when developing in order to trace back some vital steps which may lead to failure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Depending on your jotting down skills / recollection of your mind's memory you can use this information to summarize what lead you to the problem / bug in the first place and place those information in your &lt;code&gt;NOTES.md&lt;/code&gt; for posterity&lt;/p&gt;
&lt;h3&gt;
  
  
  Document your working system
&lt;/h3&gt;

&lt;p&gt;Not everyone has the same computer / server etc. as yours ! So it is definitely worth keeping track of which OS you have (which build, distribution, etc.) to make it clear to someone that things may be a bit different.&lt;/p&gt;

&lt;p&gt;Same logic goes for your programming languages. Each programming language's compiler, interpretor keeps updating itself and it is wise to provide someone willing to help you out with a bit more precise information on how you got started with your work.&lt;/p&gt;

&lt;p&gt;Same logic should go for your Dependencies. A lot of programming environments provide a file that keeps track of all your dependencies, and although some are uglier than another (looking at your Java's &lt;code&gt;pom.xml&lt;/code&gt; or other &lt;code&gt;.xml&lt;/code&gt; files), it is worth mentioning the dependencies that you might have added recently that you suspect might have broken your code&lt;/p&gt;

&lt;p&gt;Maybe a &lt;code&gt;git diff&lt;/code&gt; can help you get an idea of what was recently added or changed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Copy / Paste all your URLs
&lt;/h3&gt;

&lt;p&gt;Seems harsh but, if you browsed through some handy tutorial / blog / StackExchange Response, copy the URL in your &lt;code&gt;NOTES.md&lt;/code&gt; or bookmark it!&lt;/p&gt;

&lt;p&gt;We all suffer from the StackOverflow Copy/Paste Syndrome and in a frustrating event don't realize where and why we changed a bit of our work just get things up and running!&lt;/p&gt;

&lt;p&gt;Adding URLs also is extremely beneficially for posterity when someone who wishes to pursue something similar to your work can benefit from it!&lt;/p&gt;
&lt;h3&gt;
  
  
  Do not write massive paragraphs
&lt;/h3&gt;

&lt;p&gt;My observations over the years is that a lot of communities don't care about a &lt;em&gt;Shakesperean&lt;/em&gt; Description of your problems you face ! Instead they prefer to read shorter sentences since they too want to get to the bottom of the mystery that you have posted on.&lt;/p&gt;

&lt;p&gt;Granted, this strategy does not always work however it gets the ball rolling and further information can be requested in the comments sections.&lt;/p&gt;
&lt;h3&gt;
  
  
  Do not Paste your massive code snippet
&lt;/h3&gt;

&lt;p&gt;Let's be honest, not even your QA manager wants to dive deep into your 1000+ lines of code. There is most certainly a certain block of code you feel is the culprit and this can be pasted in the query in order for the readers to only focus on the things that are causing a problem.&lt;/p&gt;
&lt;h3&gt;
  
  
  An Updated Query Provides More Context
&lt;/h3&gt;

&lt;p&gt;Apropos, if someone asks you to provide more information for your query then a better way to address the additional information is writing it under a new section. A lot of forums provide an &lt;strong&gt;Edited View&lt;/strong&gt; on the query but a lot of times I find them to be let intuitive about the added information.&lt;/p&gt;
&lt;h2&gt;
  
  
  What got me the Up-Votes?
&lt;/h2&gt;

&lt;p&gt;At this point, you might be like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yeah, Yeah ! Show me something substantial and enough with the words already!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well here is a template I think might help people (new-comers/ beginners) out!&lt;/p&gt;

&lt;p&gt;Click on the code snippet below which is already in markdown and add the information accordingly.&lt;/p&gt;

&lt;p&gt;Please feel free to add / remove any other information that you might find useful (Let me know so I can improve myself too!)&lt;/p&gt;
&lt;h3&gt;
  
  
  Template
&lt;/h3&gt;

&lt;p&gt;This is how I have gotten around to structure my queries mostly!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Host System&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Mention Operating System
&lt;span class="p"&gt;    -&lt;/span&gt; Mention Build Version / Kernel Version / Distribution

&lt;span class="gu"&gt;## Programming Language / Software Suite / Software Tool Environment Information&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Compiler / Interpretor Version (mostly available via &lt;span class="sb"&gt;`--version`&lt;/span&gt; flag or &lt;span class="sb"&gt;`version`&lt;/span&gt; parameter)

&lt;span class="gu"&gt;## Dependencies Graph&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Provide a list of changed dependencies (if any that you think might be the culprit)

&lt;span class="gu"&gt;## Problem Description / Scenario&lt;/span&gt;

Provide the following:
&lt;span class="p"&gt;
-&lt;/span&gt; I want to --INSERT Intent HERE--
&lt;span class="p"&gt;-&lt;/span&gt; Upon following the step (mentioned below) I end up with
    --- PASTE ERROR LOGS here ---

&lt;span class="gu"&gt;### Provide a repo overview (if necessary)&lt;/span&gt;

Sometimes the repository structure may be helpful to get a better picture 
(Calling modules from different directories etc.)
&lt;span class="p"&gt;
-&lt;/span&gt; Use &lt;span class="sb"&gt;`tree`&lt;/span&gt; command-line to provide a necessary structure of your repository

&lt;span class="gu"&gt;### Code Snippets (If any, else use Reproduction Steps)&lt;/span&gt;

Remember not to dump all the 700 Line code here. 

Add a particular part of the code that you think may be the culprit

Add a note in the end or as a comment in the code snippet &lt;span class="sb"&gt;`// removed code for brevity`&lt;/span&gt; 
to let the reader know that you are focussing on what you think is causing a problem

&lt;span class="gu"&gt;### Reproduction Steps&lt;/span&gt;

Here you can actually make a list of all the command lines
you have executed in order to provide a better context.

A lot of times the error might lie in some of the steps executed here (missing flags etc.)

&lt;span class="gu"&gt;## Queries / Requirements&lt;/span&gt;

Add a list of questions you think you are unable to figure out from the problem 
or a list of requirementst that your code should be able to achieve.

Do not add a massive amount of information here, try to be concise as much as you can.

&lt;span class="gu"&gt;## Edit (only necessary if requested)&lt;/span&gt;

Add a list of updated information here, only if the community requests its.

It is easier to add information here than
rummaging through the comments under the query.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  For Posterity and beyond
&lt;/h2&gt;

&lt;p&gt;I am aware that not a lot of my code will be super helpful to people however in terms of &lt;strong&gt;Technical Debt&lt;/strong&gt;, I understand that finding a solution to a problem is not an easy task, however an even harder task is to take the effort for documenting it and making it available for others!&lt;br&gt;
How great does it feel when, you stumble across a query that is very similar to what you are facing and there is an Accepted answer for it!&lt;/p&gt;

&lt;p&gt;What also works incredibly well is to easily address the query and the solution in your Software code. You do not have write the complete bug description and the decision to solve the bug would already be mentioned in the URL of the Query. The URLs also work great for a company's Knowledge Base / CMS.&lt;/p&gt;

&lt;p&gt;What also works well for me is going back to a particular bug I had previously documented on StackOverflow / StackExchange is quite easy. A few clicks from my user account and voila! I land up to the solution as well as related queries to the topic in no time.&lt;/p&gt;

&lt;p&gt;Last but not the least, to be honest, everyone would love to have a quick Dopamine fix when they see an upvoted query or an answer !&lt;/p&gt;

&lt;h2&gt;
  
  
  Show and Tell
&lt;/h2&gt;

&lt;p&gt;After all this, do I have something to back my claims?&lt;/p&gt;

&lt;p&gt;Yes I do!&lt;/p&gt;

&lt;p&gt;Here is a list of all the Queries and Answers that have gotten me a lot of upvotes over the years and stick more or less to the template mentioned above:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;StackOverflow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/50436413/write-a-recipe-in-yocto-for-a-python-application/52643185#52643185"&gt;Write a Recipe in Yocto for Python Application&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/57589183/passing-node-env-into-the-npm-script-for-windows-10"&gt;Passing NODE_ENV into npm script for Windows 10&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/52928799/editing-an-already-existing-patch-file"&gt;Editing an already existing patch file&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/57313080/perform-nested-query-in-python-graphene-with-distinct-types-in-schema/57326796#57326796"&gt;Perform Nested Query in Python Graphene&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Internet of Things (Beta)&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://iot.stackexchange.com/questions/3592/make-embedded-board-ntp-server-for-arduino-boards-in-the-subnet"&gt;Make Embedded Board NTP Server for Arduino Boards in the subnet&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Raspberry Pi&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://raspberrypi.stackexchange.com/questions/61699/which-model-raspberry-pi-i-am-running"&gt;Which Model Raspberry Pi am I running&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Unix / Linux&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://unix.stackexchange.com/questions/444363/systemd-service-does-not-trigger-the-tmux-command-upon-reboot/444390#444390"&gt;systemd service does not trigger tmux command&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://unix.stackexchange.com/questions/354673/is-it-possible-to-use-commands-like-fg-in-a-shell-script"&gt;Is it possible to use commands like &lt;code&gt;fg&lt;/code&gt; in a shell-script&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you have tips that you feel I might have overseen or something that needs to be corrected than let me know! I am all about improving!&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Provision your Raspberry Pi 4 Cluster with Ansible</title>
      <dc:creator>Shan Desai</dc:creator>
      <pubDate>Sat, 08 May 2021 11:50:23 +0000</pubDate>
      <link>https://dev.to/shandesai/provision-your-raspberry-pi-4-cluster-with-ansible-2j8m</link>
      <guid>https://dev.to/shandesai/provision-your-raspberry-pi-4-cluster-with-ansible-2j8m</guid>
      <description>&lt;p&gt;Originally written on my &lt;a href="https://shantanoo-desai.github.io/posts/technology/edge_cluster_provisioning_ansible/"&gt;GitHub Pages Blog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I have &lt;strong&gt;eight&lt;/strong&gt; Raspberry Pi 4 8GB and wanted to setup them up to be a High Availablity (HA) Kubernetes Cluster for some projects that comprise of &lt;strong&gt;Edge&lt;/strong&gt;, &lt;strong&gt;Fog&lt;/strong&gt; Computing.&lt;/p&gt;

&lt;p&gt;The Problem is redundancy of setting these Pis up with pretty much the same thing.&lt;/p&gt;

&lt;p&gt;Think of installing something but doing it 8 times in total! Sounds more of an hassle!&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;ansible&lt;/code&gt; we can setup a number of Pis in the cluster without having to repeat anything!&lt;/p&gt;

&lt;h2&gt;
  
  
  Network
&lt;/h2&gt;

&lt;p&gt;This is what my network look like:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jeaZxlS1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6t98bn51k39qr84frkah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jeaZxlS1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6t98bn51k39qr84frkah.png" alt="Network Diagram consisting of 8 Raspberry Pi 4 8GBs connected to a Gigabit Ethernet Switch and WLAN Router"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Component Description
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WLAN Router&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;DHCP Server / Entry for user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gigabit Switch&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;High-Speed Networking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi-4 8GB RAM&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Control / Worker Nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64 GB SD Cards&lt;/td&gt;
&lt;td&gt;8+&lt;/td&gt;
&lt;td&gt;For Operating System / Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cat6e Ethernet cables&lt;/td&gt;
&lt;td&gt;8+&lt;/td&gt;
&lt;td&gt;For connecting to Switch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating System&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Ubuntu 20.04 - LTS&lt;/strong&gt; on Pis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: SD Cards are not the best choice, since they wear-out over longer usage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A possible solution is to by USB3.1 based storage disks which can be used to store information&lt;br&gt;
and boot the Raspberry Pi Up.&lt;/p&gt;

&lt;p&gt;For the time-being, the SD Cards will do just fine.&lt;/p&gt;
&lt;h4&gt;
  
  
  Fixed IP Address Allocation
&lt;/h4&gt;

&lt;p&gt;Either use &lt;strong&gt;DHCP Address Allocation&lt;/strong&gt; on your WLAN Router to dedicate a fixed IP address to the MAC Address of your Raspberry Pi 4s or configure your Operating System for your Pis with static IP Addresses. I chose the former method, since mapping the MAC Addresses with defined IP addresses using your WLAN router's UI is way easier. Also I wasn't aware what the MAC Address of each of the Pi was beforehand, so the UI was able to show it to me easily.&lt;/p&gt;
&lt;h3&gt;
  
  
  Node Roles
&lt;/h3&gt;

&lt;p&gt;Each Raspberry Pi 4 has a function to perform, we split them into 2 major roles.&lt;/p&gt;
&lt;h4&gt;
  
  
  Control Nodes
&lt;/h4&gt;

&lt;p&gt;As described in the figure, I will pick 3 Pis as Control nodes. They will be able to &lt;em&gt;control&lt;/em&gt;&lt;br&gt;
the worker nodes and also be a bit more fault-tolerant as compared to having just one node control the whole cluster.&lt;/p&gt;

&lt;p&gt;Out of these 3 nodes, I will pick on to be the entry-point and main node that I will use to work with and provision my cluster (&lt;code&gt;control01&lt;/code&gt; Pi with &lt;code&gt;192.168.0.108&lt;/code&gt;)&lt;/p&gt;
&lt;h4&gt;
  
  
  Worker Nodes
&lt;/h4&gt;

&lt;p&gt;The are the real MVPs here. These nodes will do all the heavy lifting for us.&lt;/p&gt;
&lt;h2&gt;
  
  
  Initial Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download the &lt;a href="https://ubuntu.com/download/raspberry-pi/thank-you?version=20.04.2&amp;amp;architecture=server-arm64+raspi"&gt;Ubuntu Server 20.04 LTS 64-bit OS Image&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the instructions of burning the image on to the SD Cards&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Setup your Pis by inserting the SD Cards, connecting the Pis to the Switch and powering them up (Note: make sure to provide a minimum of &lt;strong&gt;3A&lt;/strong&gt; current to the Pis or else you might face &lt;em&gt;brown-outs&lt;/em&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect the WLAN Router to the Switch and use the router's UI to provide fixed/static IPs to each of the Pis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect to the WLAN network and, login into the Pi with address &lt;code&gt;192.168.0.108&lt;/code&gt; using &lt;code&gt;ssh&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -l ubuntu 192.168.0.108
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note: all the Pis will have the username &lt;code&gt;ubuntu&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Hard Part
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Be a nice developer / administrator for once and log into each Pi and change the passwords to something safe. &lt;em&gt;Just this one time&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As it is, Ubuntu will insist you on changing the password for the &lt;code&gt;ubuntu&lt;/code&gt; user on the very first SSH Login. Might as well begin with good security practices!&lt;/p&gt;

&lt;p&gt;For the sake of simplicity, you can keep the same password for each Pi (but preferably you would use some form of password generator for distinct passwords for each Pi)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I promise, this is the only time you will have to login these Pis individually!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can change the passwords for the user &lt;code&gt;ubuntu&lt;/code&gt; and &lt;code&gt;root&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="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"changing root password"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;passwd

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"changing user Ubuntu's password"&lt;/span&gt;
passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting Up the Cluster
&lt;/h3&gt;

&lt;p&gt;on the Pi with &lt;code&gt;192.168.0.108&lt;/code&gt; you are currently logged into change the &lt;code&gt;/etc/hosts&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We map the names of the Pis to their respective IP addresses and use the &lt;code&gt;.local&lt;/code&gt; mdns FQDN for ease of access&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;127.0.0.1 localhost &lt;span class="c"&gt;# This is me, hello!&lt;/span&gt;


&lt;span class="c"&gt;## This can be adapted according to Your Needs!!&lt;/span&gt;
&lt;span class="c"&gt;## Cluster Lab Hosts&lt;/span&gt;
&lt;span class="c"&gt;### Control Nodes&lt;/span&gt;
192.168.0.108 control01 control01.local
192.168.0.107 control02 control02.local
192.168.0.106 control03 control03.local

&lt;span class="c"&gt;### Worker Nodes&lt;/span&gt;
192.168.0.101 worker01 worker01.local
192.168.0.102 worker02 worker02.local
192.168.0.103 worker03 worker03.local
192.168.0.104 worker04 worker04.local
192.168.0.105 worker05 worker05.local

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Checking Connectivity
&lt;/h3&gt;

&lt;p&gt;we can use &lt;code&gt;nmap&lt;/code&gt; on the pi to ping the sub-network and see if all the Pis are reachable&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;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nmap

&lt;span class="nv"&gt;$ &lt;/span&gt;nmap &lt;span class="nt"&gt;-sP&lt;/span&gt; 192.168.0.100-120 &lt;span class="c"&gt;# the IP range for the network&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should yield:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Starting Nmap 7.80 &lt;span class="o"&gt;(&lt;/span&gt; https://nmap.org &lt;span class="o"&gt;)&lt;/span&gt; at 2021-05-05 14:44 UTC
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;worker01 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.101&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00073s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;worker02 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.102&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00060s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;worker03 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.103&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00051s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;worker04 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.104&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00046s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;worker05 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.105&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00041s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;control03 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.106&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00034s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;control02 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.107&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00029s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap scan report &lt;span class="k"&gt;for &lt;/span&gt;control01 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.108&lt;span class="o"&gt;)&lt;/span&gt;
Host is up &lt;span class="o"&gt;(&lt;/span&gt;0.00024s latency&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Nmap &lt;span class="k"&gt;done&lt;/span&gt;: 21 IP addresses &lt;span class="o"&gt;(&lt;/span&gt;8 hosts up&lt;span class="o"&gt;)&lt;/span&gt; scanned &lt;span class="k"&gt;in &lt;/span&gt;1.41 seconds

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

&lt;/div&gt;



&lt;p&gt;Looks good and well-connected!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduce Ansible to your Pi Fleet
&lt;/h2&gt;

&lt;p&gt;First and foremost install &lt;code&gt;ansible&lt;/code&gt; on the Pi with Address &lt;code&gt;192.168.0.108&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install -y ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Change the Hosts file for ansible as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/ansible/hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Cluster Lab Settings&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;control]
&lt;span class="c"&gt;## all the "control" nodes go here&lt;/span&gt;
&lt;span class="c"&gt;# keep control01 as local but other nodes can be reached via ssh&lt;/span&gt;
control01  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;local  &lt;/span&gt;&lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;control01
control02  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh    &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;control02
control03  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh    &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;control03

&lt;span class="o"&gt;[&lt;/span&gt;workers]
&lt;span class="c"&gt;## all the "worker" nodes go here&lt;/span&gt;
worker01  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh  &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;worker01
worker02  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh  &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;worker02
worker03  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh  &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;worker03
worker04  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh  &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;worker04
worker05  &lt;span class="nv"&gt;ansible_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh  &lt;span class="nv"&gt;var_hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;worker05

&lt;span class="c"&gt;## The complete group of pis here is called a "cluster"&lt;/span&gt;
&lt;span class="c"&gt;## which comprises of "control" and "workers"&lt;/span&gt;
&lt;span class="c"&gt;## You can however name the group however you like!&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;cluster:children]
control
workers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that at this point of time we haven't even changed the names of the hosts on each Pis,&lt;br&gt;
we have just mapped the IP Addresses to a name! But we will &lt;em&gt;automate&lt;/em&gt; such changes via &lt;code&gt;ansible&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Passwordless logins via SSH
&lt;/h4&gt;

&lt;p&gt;In the configuration for the ansible hosts, you could see &lt;code&gt;ansible_connection=ssh&lt;/code&gt; in all but one nodes. This is achieved by generating an SSH key from the present Pi and shared to all other pis&lt;/p&gt;

&lt;p&gt;Okay! I lied before about just the one time doing the redundant task on all Pis. Here you might have to share the SSH Public Key to all other Pis &lt;em&gt;One Last Time&lt;/em&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="c"&gt;# On cluster01&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.ssh &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/.ssh
&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa
&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# Copy the Key to each node in the cluster&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_rsa.pub ubuntu@control02 &lt;span class="c"&gt;# control03, worker01-worker05 ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connectivity via &lt;code&gt;ansible&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let me show you why I am blow away by &lt;code&gt;ansible&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ping all the nodes 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;&lt;span class="c"&gt;# cluster is the name of the group mentioned in the `/etc/ansible/hosts` file&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ansible cluster &lt;span class="nt"&gt;-m&lt;/span&gt; ping &lt;span class="c"&gt;# here -m is module which is &amp;lt;ping&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And surely you get pings from all the nodes thanks to ansible&lt;/p&gt;

&lt;p&gt;You can ping just the &lt;code&gt;control&lt;/code&gt; nodes 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;ansible control &lt;span class="nt"&gt;-m&lt;/span&gt; ping
&lt;span class="nv"&gt;$ &lt;/span&gt;ansible workers &lt;span class="nt"&gt;-m&lt;/span&gt; ping &lt;span class="c"&gt;# say hello to the Workers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change the &lt;code&gt;hostname&lt;/code&gt; for each Pi via &lt;code&gt;ansible&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now, remember each Pi on the network is still called &lt;code&gt;ubuntu@ubuntu&lt;/code&gt; where &lt;code&gt;ubuntu&lt;/code&gt; is also the hostname. To do it manually would comprise of executing the following command in each Pi&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hostnamectl set-hostname &amp;lt;desired_hostname_for_pi&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;in the &lt;code&gt;/etc/ansible/hosts&lt;/code&gt; file we declared &lt;code&gt;var_hostname=...&lt;/code&gt; which will set the names up in a single command line instruction&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;ansible cluster &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; shell &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"hostnamectl set-hostname {{ var_hostname }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And Voila! this will be done for all Pis. To check the name changes execute:&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;ansible cluster &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; shell &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"hostnamectl status | get hostname"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and all the Pis should have the designated hostnames&lt;/p&gt;

&lt;h3&gt;
  
  
  Changing Configuration for Containers
&lt;/h3&gt;

&lt;p&gt;you need &lt;code&gt;cgroup&lt;/code&gt; enabled in the Pi to do fun stuff with containers (docker, kaniko etc.) in the&lt;br&gt;
&lt;code&gt;/boot/firmware/cmdline.txt&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Do this via &lt;code&gt;ansible&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;ansible cluster &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; shell &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"sed -i '&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="s2"&gt;s/&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="s2"&gt; cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 swapaccount=1/' /boot/firmware/cmdline.txt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install &lt;code&gt;microk8s&lt;/code&gt; on the cluster
&lt;/h3&gt;

&lt;p&gt;You can install &lt;a href="http://microk8s.io"&gt;&lt;code&gt;microk8s&lt;/code&gt;&lt;/a&gt; on each pi using &lt;strong&gt;Snap&lt;/strong&gt; from Canonical 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;ansible cluster &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; snap &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"name=microk8s classic=true channel=1.21"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will install &lt;code&gt;microk8s v1.21/stable&lt;/code&gt; on each Pi&lt;/p&gt;

&lt;p&gt;To check the status using &lt;code&gt;ansible&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;ansible cluster &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; shell &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"snap list | grep microk8s"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Reboot
&lt;/h3&gt;

&lt;p&gt;Since you have made changes if might be better to reboot the Pis you can do this based on the subgroups&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;ansible control02 &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; reboot
&lt;span class="nv"&gt;$ &lt;/span&gt;ansible control03 &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; reboot
&lt;span class="nv"&gt;$ &lt;/span&gt;ansible workers &lt;span class="nt"&gt;--become&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally reboot the current Pi &lt;code&gt;cluster01&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="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Concluding Remarks
&lt;/h2&gt;

&lt;p&gt;I am honestly blown away by &lt;code&gt;ansible&lt;/code&gt; as tool and planning to learn it and other aspects like the &lt;strong&gt;Playbooks&lt;/strong&gt; where you can configure the fleet using files!!&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>edgecomputing</category>
      <category>cluster</category>
      <category>microk8s</category>
    </item>
  </channel>
</rss>
