<?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: Denis AKPAGNONITE</title>
    <description>The latest articles on DEV Community by Denis AKPAGNONITE (@denisakp).</description>
    <link>https://dev.to/denisakp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1143824%2F82e99ca3-6952-4e01-b1b2-5c997711db9c.jpeg</url>
      <title>DEV Community: Denis AKPAGNONITE</title>
      <link>https://dev.to/denisakp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/denisakp"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Denis AKPAGNONITE</dc:creator>
      <pubDate>Sun, 13 Apr 2025 21:00:39 +0000</pubDate>
      <link>https://dev.to/denisakp/-38ok</link>
      <guid>https://dev.to/denisakp/-38ok</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/denisakp/how-a-job-interview-led-me-to-create-obscura-a-password-generator-with-real-entropy-3poh" class="crayons-story__hidden-navigation-link"&gt;How a job interview led me to create Obscura - A password generator with real entropy&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/denisakp" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1143824%2F82e99ca3-6952-4e01-b1b2-5c997711db9c.jpeg" alt="denisakp profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/denisakp" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Denis AKPAGNONITE
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Denis AKPAGNONITE
                
              
              &lt;div id="story-author-preview-content-2404543" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/denisakp" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1143824%2F82e99ca3-6952-4e01-b1b2-5c997711db9c.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Denis AKPAGNONITE&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/denisakp/how-a-job-interview-led-me-to-create-obscura-a-password-generator-with-real-entropy-3poh" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 13 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/denisakp/how-a-job-interview-led-me-to-create-obscura-a-password-generator-with-real-entropy-3poh" id="article-link-2404543"&gt;
          How a job interview led me to create Obscura - A password generator with real entropy
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/privacy"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;privacy&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/interview"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;interview&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/denisakp/how-a-job-interview-led-me-to-create-obscura-a-password-generator-with-real-entropy-3poh#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>security</category>
      <category>privacy</category>
      <category>opensource</category>
      <category>interview</category>
    </item>
    <item>
      <title>How a job interview led me to create Obscura - A password generator with real entropy</title>
      <dc:creator>Denis AKPAGNONITE</dc:creator>
      <pubDate>Sun, 13 Apr 2025 20:57:54 +0000</pubDate>
      <link>https://dev.to/denisakp/how-a-job-interview-led-me-to-create-obscura-a-password-generator-with-real-entropy-3poh</link>
      <guid>https://dev.to/denisakp/how-a-job-interview-led-me-to-create-obscura-a-password-generator-with-real-entropy-3poh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;During a recent interview for a Security Software Engineer position, I was given a challenge: create a secure password generator that takes into account real entropy. The interviewer wanted to see how I would approach the problem, and I was excited to take on the challenge.&lt;/p&gt;

&lt;p&gt;At first, I thought it would be a simple task. I had used password generators before (with Math.Random stuffs), and I assumed it would be easy to create one that was secure. But the conversation quickly steered away from superficial implementations and into deeper, often overlooked topic: entropy—and how most so-called generators don't handle it properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The challenge
&lt;/h2&gt;

&lt;p&gt;The interviewer insisted on entropy being measurable, adjustable, and predictable based on user choice. He wasn't looking for a simple tool that just throws random characters together; he wanted a password generator that would :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quantify the information entropy of the generated password,&lt;/li&gt;
&lt;li&gt;adapt based on character pool constraints (like avoiding duplicates or special characters),&lt;/li&gt;
&lt;li&gt;prevent common patterns and sequences (e.g., "123" or "qwerty" or "abc"),&lt;/li&gt;
&lt;li&gt;and still generate passwords that are straightforward to use and robust against brute-force attacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That got me thinking about how most password generators out there are just glorified random characters generators.&lt;/p&gt;

&lt;h2&gt;
  
  
  My thought process: understanding entropy
&lt;/h2&gt;

&lt;p&gt;I started by asking him about the definition of entropy in the context of password generation.&lt;/p&gt;

&lt;p&gt;He explained that entropy is a measure of uncertainty or randomness in a system. In the case of passwords, it refers to the unpredictability of the password itself.&lt;br&gt;
The more unpredictable a password is, the higher its entropy, and the more secure it is against brute-force attacks. (I said to my-self: come on man, you were supposed to make understand the concept not complicate it 🙁? because I don't know how to measure it, and I don't know how to calculate it).&lt;/p&gt;

&lt;p&gt;After a few minutes of discussion, I was given the entropy formula which was quite simple but powerful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E = log2(P^L)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E is the entropy in bits&lt;/li&gt;
&lt;li&gt;P is the size of the character pool (e.g., 26 for lowercase letters, 10 for digits, etc.)&lt;/li&gt;
&lt;li&gt;L is the length of the password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here is the example of the entropy calculation he gave me:&lt;br&gt;
For a password using 26 chars of lowercase letters and a length of 8:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E = log2(26^8) = 8 * log2(26) ≈ 37.6 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strong passwords should have at least 80 bits of entropy, so I needed to ensure that my generator increases the entropy by using :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A larger character pool (e.g., uppercase and lowercase letters, digits, special characters)&lt;/li&gt;
&lt;li&gt;A longer password length&lt;/li&gt;
&lt;li&gt;True randomness in character selection (not just pseudo-randomness)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After all these details, I understand two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The larger the character pool and the longer the password, the stronger the password.&lt;/li&gt;
&lt;li&gt;Entropy is measured in bits, and more bits means more possible combinations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if we exclude similar characters, enforce uniqueness, and start with specific characters, the pool shrinks—reducing entropy. So we need to calculate entropy dynamically based on current user choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution: Build a real password generator
&lt;/h2&gt;

&lt;p&gt;I wrote the first version of the password generator in TypeScript, focused purely on logic. It supports options like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;include/exclude uppercase, lowercase, digits, special characters&lt;/li&gt;
&lt;li&gt;exclude similar characters (e.g., "l" and "1", "O" and "0")&lt;/li&gt;
&lt;li&gt;avoid duplicates and sequential patterns&lt;/li&gt;
&lt;li&gt;generate multiple passwords at once&lt;/li&gt;
&lt;li&gt;and most importantly: real time entropy calculation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Design approach
&lt;/h3&gt;

&lt;p&gt;My implementation follows a modular approach centered around the core &lt;code&gt;generatePassword&lt;/code&gt; function. I defined a clear &lt;code&gt;PasswordOptions&lt;/code&gt; interface to make the code more readable and type-safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PasswordOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;includeLowercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;includeUppercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;includeDigits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;includeSymbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;excludeSimilarCharacters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;noDuplicateCharacters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;noSequentialCharacters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;beginWithLetter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
  &lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Character Pool generation
&lt;/h3&gt;

&lt;p&gt;The foundation of my code is the character pool selection. I defined constant of character sets and wrote a helper function to build customized pool based on user preferences:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCharacterPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PasswordOptions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includeLowercase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;LOWERCASE&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includeUppercase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;UPPERCASE&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includeDigits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;DIGITS&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includeSymbols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;SYMBOLS&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excludeSimilarCharacters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&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="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;SIMILAR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach gives users fine-grained control over the character set, which is directly impacting the entropy calculation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security considerations
&lt;/h3&gt;

&lt;p&gt;I implemented several security features to ensure strong password generation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cryptographically secure randomness&lt;/strong&gt;: instead of using &lt;code&gt;Math.random()&lt;/code&gt;, I used the
Web Crypto API &lt;code&gt;crypto.getRandomValues()&lt;/code&gt; for true randomness:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;     &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getRandomChar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;randomIndex&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sequential character detection&lt;/strong&gt;: to prevent weak pattens like "abc" or "123", I added a
function to check for sequential characters:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hasSequentialCharacters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&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="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input validation&lt;/strong&gt;: The code prevents impossible combinations, like requiring unique characters in a password longer than the available character pool:&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Password generation logic
&lt;/h3&gt;

&lt;p&gt;The core algorithm uses a retry mechanism to ensure all constraints are satisfied:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;generate teh first character (optionally a letter)&lt;/li&gt;
&lt;li&gt;build the rest of the password character by character&lt;/li&gt;
&lt;li&gt;validate against all constraints (uniqueness, sequential patterns, etc.)&lt;/li&gt;
&lt;li&gt;if any constraint fails, retry the entire password generation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach ensures that every generated password meets all security requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final output
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;generatePassword&lt;/code&gt; function ties everything together, enforcing sensible limits(8–64 characters) and generating the requested quantity of passwords:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generatePasswords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PasswordOptions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safeLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passwords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;passwords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;generatePassword&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;safeLength&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;passwords&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation balances security, usability, and performance, resulting in a robust password generator suitable for real-world applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matter
&lt;/h2&gt;

&lt;p&gt;I learned a lot from this interview challenge, and I realized that most password generators out there are just glorified random character generators. They don't take into account the real entropy. Good password hygiene is crucial—and we've all reused passwords at some point. Tools like Obscura give users confidence and control without compromising on privacy.&lt;/p&gt;

&lt;p&gt;Here are few tips for better password security:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;always use unique passwords for each account&lt;/li&gt;
&lt;li&gt;prefer longer passwords (16+ characters)&lt;/li&gt;
&lt;li&gt;avoid predictable pattens or using personal information (like birthdays or names)&lt;/li&gt;
&lt;li&gt;use a password manager (Obscura is great for generating strong password to store there)&lt;/li&gt;
&lt;li&gt;never, and ever share your passwords with anyone&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  My journey experience
&lt;/h2&gt;

&lt;p&gt;Unfortunately, my journey with the company didn't go further than the technical interview step. According to their feedback, they're specifically looking for someone with experience in software engineering and formal security certifications like CISSP, CLSSP, COMPTIA Security+, etc.&lt;/p&gt;

&lt;p&gt;My background is primarily in software engineering in distributed systems, with a focus on Kubernetes and DevSecOps practices. While I have experience with security aspects like SAST/DAST code analysis, dependency vulnerability scanning, container security, IaC security reviews, and IAM/secrets management, they were looking for someone with a more specialized security background.&lt;/p&gt;

&lt;p&gt;Despite not getting the position, I thoroughly enjoyed the interview process and learned a lot from the challenge. I decided to take the opportunity to build something useful out of it, and that's how I ended up creating Obscura.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, Fork it, Share it or Contribute
&lt;/h2&gt;

&lt;p&gt;You can try obscura at &lt;a href="https://obscura.denisakp.me" rel="noopener noreferrer"&gt;obscura.denisakp.me&lt;/a&gt; and check the code on &lt;a href="https://github.com/denisakp/obscura" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. I would love to hear your feedback, suggestions, or contributions. This project is open-source, and I welcome any improvements or new features you might want to add.&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>opensource</category>
      <category>interview</category>
    </item>
    <item>
      <title>Backup and Restore MongoDB in a Docker Environment</title>
      <dc:creator>Denis AKPAGNONITE</dc:creator>
      <pubDate>Sun, 21 Jul 2024 16:26:48 +0000</pubDate>
      <link>https://dev.to/denisakp/backup-and-restore-mongodb-in-a-docker-environment-1ebb</link>
      <guid>https://dev.to/denisakp/backup-and-restore-mongodb-in-a-docker-environment-1ebb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In a previous post, we discussed how to run a MongoDB database in a Docker container. And we learned how to create a 3-node replica set using Docker Compose. If you missed it, you can check it out &lt;a href="https://dev.to/denisakp/setting-up-a-3-node-mongodb-replica-set-cluster-with-docker-compose-50kn"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post, we'll cover an essential topic: &lt;strong&gt;Backup and Restore MongoDB in a Docker Environment&lt;/strong&gt;. I'll walk you through the process of creating a full backup of a MongoDB database running in a Docker container and restoring the backup to a new MongoDB container.&lt;/p&gt;

&lt;h2&gt;
  
  
  The importance of Backups in a Containerized Environment
&lt;/h2&gt;

&lt;p&gt;Containers are designed to be ephemeral, meaning they can be created, destroyed and recreated at any time. While this offers flexibility, it also means that any data stored within a container is at risk of being lost when the container is removed, or lost due to corruption or other issues. Therefore, it's crucial to have a robust backup and restore strategy to protect your data from loss or corruption and ensure data availability and business continuity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why backups matter
&lt;/h2&gt;

&lt;p&gt;1- &lt;strong&gt;Data Loss Prevention&lt;/strong&gt;: Backups are essential for preventing data loss due to accidental deletion, corruption, or hardware failure, or other unexpected events. Having a backup ensures that you can recover your data in case of any such event.&lt;/p&gt;

&lt;p&gt;2- &lt;strong&gt;Business Continuity&lt;/strong&gt;: Backups are crucial for maintaining business continuity in the event of data loss. Having a reliable backup strategy ensures that you can quickly recover your data and resume operations without significant downtime, especially in containerized environments.&lt;/p&gt;

&lt;p&gt;3- &lt;strong&gt;Disaster Recovery&lt;/strong&gt;: Backups are an essential part of any disaster recovery plan. Having a reliable backup strategy ensures that you can quickly recover your data and resume operations in the event of a disaster.&lt;/p&gt;

&lt;p&gt;4- &lt;strong&gt;Compliance and Legal Requirements&lt;/strong&gt;: Many industries have strict compliance and legal requirements regarding data.&lt;/p&gt;

&lt;p&gt;5- &lt;strong&gt;Peace of Mind&lt;/strong&gt;: Having a reliable backup strategy in place gives you peace of mind knowing that your data is protected and can be recovered in case of any event.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backup strategies for MongoDB
&lt;/h2&gt;

&lt;p&gt;MongoDB provides several options for backing up your data, including incremental backups, full backups, and differential backups.&lt;/p&gt;

&lt;p&gt;1- &lt;strong&gt;Incremental Backups&lt;/strong&gt;: Incremental backups capture only the changes made since the last backup, reducing the amount of data that needs to be backed up and speeding up the backup process, but can be complex to manage and restore.&lt;/p&gt;

&lt;p&gt;2- &lt;strong&gt;Full Backups&lt;/strong&gt;: Full backups capture the entire database, including all data and indexes. While full backups are more time-consuming and resource-intensive than incremental backups, they provide a complete snapshot of the database that can be used to restore the database to a specific point in time.&lt;/p&gt;

&lt;p&gt;3- &lt;strong&gt;Differential Backups&lt;/strong&gt;: Differential backups capture only the changes made since the last full backup, reducing the amount of data that needs to be backed up compared to a full backup. This can be a good compromise between full and incremental backups, but can be also complex.&lt;/p&gt;

&lt;p&gt;In this post, we'll focus on the full backup strategy as it's the simplest and most reliable method for backing up your database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performing a Full Backup of MongoDB
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;1- &lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; installed on your system.&lt;br&gt;
2- Basic knowledge of Docker concepts such as &lt;a href="https://docs.docker.com/storage/volumes/" rel="noopener noreferrer"&gt;volumes&lt;/a&gt;.&lt;br&gt;
3- Time to complete the tutorial: 6 to 10 minutes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Start a MongoDB container
&lt;/h3&gt;

&lt;p&gt;First, we'll pull the MongoDB image from Docker Hub and start a MongoDB 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 volume create mongo-data &lt;span class="c"&gt;# Create a volume to persist the MongoDB data&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; mongo &lt;span class="nt"&gt;-v&lt;/span&gt; mongo-data:/data/db &lt;span class="nt"&gt;-p&lt;/span&gt; 27017:27017 mongo:7.0-jammy &lt;span class="c"&gt;# Start a MongoDB container&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Run the mongodump command
&lt;/h3&gt;

&lt;p&gt;To create a full backup of your MongoDB database, you'll use the &lt;a href="https://www.mongodb.com/docs/database-tools/mongodump/" rel="noopener noreferrer"&gt;mongodump command&lt;/a&gt;, which is an utility provided by MongoDB. This command will create a binary export of your database that can be used to restore the data later.&lt;/p&gt;

&lt;p&gt;Run the following from your host machine to create a full backup of your MongoDB database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mongo mongodump &lt;span class="nt"&gt;--uri&lt;/span&gt; mongodb://localhost:27017/test &lt;span class="nt"&gt;--gzip&lt;/span&gt; &lt;span class="nt"&gt;--archive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test.archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example my container is named &lt;code&gt;mongo&lt;/code&gt;, and my database is named &lt;code&gt;test&lt;/code&gt;. Also, notice the &lt;code&gt;--gzip&lt;/code&gt; flag, which compresses the backup file to save disk space. My test database contains almost 7000 documents and is about 18MB, and the backup file is about 627KB which represent a significant reduction in size.&lt;/p&gt;

&lt;p&gt;Another important thing is the &lt;code&gt;--uri&lt;/code&gt; flag, which specifies the connection string to the MongoDB database. In this example, we're connecting to the MongoDB database exposed on &lt;code&gt;localhost&lt;/code&gt; on port &lt;code&gt;27017&lt;/code&gt;. If you followed my &lt;a href="https://dev.to/denisakp/setting-up-a-3-node-mongodb-replica-set-cluster-with-docker-compose-50kn"&gt;previous post&lt;/a&gt;, you may have a replica set running on &lt;code&gt;localhost:27017,localhost:27018,localhost:27019&lt;/code&gt;. In this case, you should replace the connection string with the appropriate one: &lt;code&gt;mongodb://localhost:27017,locahost:27018,localhost:27019/test?replicaSet=rs0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And if everything goes well, you should see a message indicating that the backup was successful. Something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farhdihi8m6d3cm98ekvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farhdihi8m6d3cm98ekvg.png" alt="Successful backup of MongoDB" width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Copy the backup file to your host machine
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;mongodump&lt;/code&gt; command will create a backup file inside the container. But we need to copy it to our host machine because the container is ephemeral and can be destroyed at any time.&lt;/p&gt;

&lt;p&gt;Run the following command to copy the backup file to your 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;docker &lt;span class="nb"&gt;cp &lt;/span&gt;mongo:/test.archive /path/to/backup/yourdatabase.archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Replace &lt;code&gt;/path/to/backup/yourdatabase.archive&lt;/code&gt; with the path where you want to store the backup file on your host machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If everything goes well, you should see a message indicating that the file was copied successfully. Something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvdn1pla4yrw3puxuty3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvdn1pla4yrw3puxuty3.png" alt="Successful copied archive" width="800" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You've successfully created a full backup of your MongoDB database. You can now store this backup file in a safe location and use it to restore your data if needed. When I say safe location, I mean a location different from your local machine because, if your local machine or server fails, you will lose both the database and the backup.&lt;/p&gt;

&lt;p&gt;Another option is to use a cloud storage service like AWS S3, Google Cloud Storage, Azure Blob Storage, or MinIo to store your backups. This way, your backups will be safe even if your local machine or server fails. You may also take care of the security of your backups by encrypting them before storing them in the cloud. This ensure the backup integrity and confidentiality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performing a MongoDB Restore
&lt;/h2&gt;

&lt;p&gt;Just as important as creating backups is the ability to restore them when needed. The &lt;a href="https://www.mongodb.com/docs/database-tools/mongorestore/" rel="noopener noreferrer"&gt;mongorestore command&lt;/a&gt; is used to restore a MongoDB backup created with &lt;code&gt;mongodump&lt;/code&gt;. In this section, I'll walk you through the process of restoring a MongoDB backup in a Docker environment.&lt;/p&gt;

&lt;p&gt;We'll assume that our MongoDB container has been deleted unintentionally 😏, and the attached volume has gone with it. We'll use the backup file we created earlier to restore the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Start a new MongoDB container
&lt;/h3&gt;

&lt;p&gt;First, create a new volume, and start a new MongoDB container attached to the newly created volume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create mongo-data 
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; mongo &lt;span class="nt"&gt;-v&lt;/span&gt; mongo-data:/data/db &lt;span class="nt"&gt;-p&lt;/span&gt; 27017:27017 mongo:7.0-jammy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Copy the backup file to the new container
&lt;/h3&gt;

&lt;p&gt;Next, copy the backup file from your host machine or get it from the cloud storage to the new MongoDB container. For this example, we will use the backup file we created earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;cp&lt;/span&gt; /path/to/backup/test.archive mongo:/test.archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Replace &lt;code&gt;/path/to/backup/test.archive&lt;/code&gt; with the path to the backup file on your host machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Run the mongorestore command
&lt;/h3&gt;

&lt;p&gt;Finally, use the &lt;code&gt;mongorestore&lt;/code&gt; command to restore the backup file to the new MongoDB 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 &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mongo mongorestore &lt;span class="nt"&gt;--uri&lt;/span&gt; mongodb://localhost:27017 &lt;span class="nt"&gt;--gzip&lt;/span&gt; &lt;span class="nt"&gt;--archive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;test.archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will restore the data from the backup file to the MongoDB database running in the new container. Notice that we don't need to specify the database name because it's included in the backup file. The &lt;code&gt;--gzip&lt;/code&gt; flag is used to tell &lt;code&gt;mongorestore&lt;/code&gt; that the backup file is compressed. &lt;/p&gt;

&lt;p&gt;If everything goes well, you should see a message indicating that the restore was successful. Something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8c7zhmr49yuh599i7en.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8c7zhmr49yuh599i7en.png" alt="Successful restored backup" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for MongoDB Backups in a Containerized Environment
&lt;/h2&gt;

&lt;p&gt;1- &lt;strong&gt;Use Volumes&lt;/strong&gt;: Store your MongoDB data on a volume to persist it even if the container is destroyed. This ensures that your data is safe and can be easily backed up and restored. &lt;/p&gt;

&lt;p&gt;2- &lt;strong&gt;Regular Backups&lt;/strong&gt;: Schedule regular backups of your MongoDB database to ensure that your data is always up-to-date and can be quickly restored in case of any event. Depending on your data, you may need to back up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily&lt;/strong&gt;: ideal for databases with frequent changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;weekly&lt;/strong&gt;: suitable for moderately active databases; with less frequent changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;monthly&lt;/strong&gt;: for databases with infrequent changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3- &lt;strong&gt;Offsite Backups&lt;/strong&gt;: Store your backups in an offsite location, such as a cloud storage service, to ensure that your data is safe even if your local machine or server fails. Remember to treat your database backups as sensitive data, meaning you should encrypt them before storing them in the cloud, and restrict access to them to authorized staff only.&lt;/p&gt;

&lt;p&gt;3- &lt;strong&gt;Automate Backups&lt;/strong&gt;: Set up automated backup jobs to run at regular intervals to ensure that your data is backed up regularly and consistently. &lt;/p&gt;

&lt;p&gt;4- &lt;strong&gt;Test Restores&lt;/strong&gt;: Regularly test your backup and restore process to ensure that your backups are valid and can be restored successfully. This will help you identify any issues with your backup strategy and make the necessary adjustments.&lt;/p&gt;

&lt;p&gt;After a backup, you should test the restore process in a sandbox environment to ensure that the backup is valid and can be restored successfully. And one more important thing, you should document the restore process, to ensure that any authorized staff can restore the database in case of any event.&lt;/p&gt;

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

&lt;p&gt;In this article, we've covered the importance of backups in a Docker environment and walked you through the process of creating a full backup of a MongoDB database running in a Docker container. I've also shown you how to restore the backup to a new MongoDB container. By following these steps and best practices, you can ensure that your MongoDB data is safe, secure, and always available, even in the event of data loss or corruption. &lt;strong&gt;Remember, having a backup is essential, but being able to restore it is even more important&lt;/strong&gt;. So, make sure to test your backup and restore processes regularly to ensure that your data is protected and can be recovered when needed.&lt;/p&gt;

&lt;p&gt;In a future post, we'll cover an interesting topic: &lt;strong&gt;Automating MongoDB Backups in a Containerized Environment&lt;/strong&gt;. I'm pretty sure you'll love it, because it will save you time and effort. Stay tuned! &lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/manual/core/backups/" rel="noopener noreferrer"&gt;MongoDB Backup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/database-tools/mongorestore/" rel="noopener noreferrer"&gt;MongoDB Restore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/storage/volumes/" rel="noopener noreferrer"&gt;Docker Volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/reference/commandline/cp/" rel="noopener noreferrer"&gt;Docker Copy Command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/reference/commandline/exec/" rel="noopener noreferrer"&gt;Docker Exec Command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/_/mongo" rel="noopener noreferrer"&gt;Docker MongoDB Image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Setting Up a 3-Node MongoDB Replica Set Cluster with Docker Compose</title>
      <dc:creator>Denis AKPAGNONITE</dc:creator>
      <pubDate>Fri, 19 Jul 2024 13:51:06 +0000</pubDate>
      <link>https://dev.to/denisakp/setting-up-a-3-node-mongodb-replica-set-cluster-with-docker-compose-50kn</link>
      <guid>https://dev.to/denisakp/setting-up-a-3-node-mongodb-replica-set-cluster-with-docker-compose-50kn</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog post, I'll walk you through setting up a 3-node MongoDB replica set cluster using Docker Compose. This guide will assume you're familiar with basic Docker concepts such as Docker Compose, volumes, networks, and health checks, as well as MongoDB concepts like replica sets. So, if you're ready, let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a MongoDB Replica Set?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fmanual%2Fimages%2Freplica-set-read-write-operations-primary.bakedsvg.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fmanual%2Fimages%2Freplica-set-read-write-operations-primary.bakedsvg.svg" alt="MongoDB Replica set!" width="620" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A mongoDB replica set is a group of mongoDB instances that host the same data set. In a replica set, one node is the primary node that receives all write operations. All other nodes, known as secondary nodes, apply operations from the primary so that they have the same data set.&lt;/p&gt;

&lt;p&gt;MongoDB replica sets offer redundancy and high availability, keeping the database operational even if one or more nodes die. They replicate data across multiple nodes to ensure integrity and availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use a MongoDB Replica Set?
&lt;/h3&gt;

&lt;p&gt;1- &lt;strong&gt;High Availability&lt;/strong&gt;: If the primary node fails, a secondary node can be elected as the new primary, ensuring that the database remains available.&lt;/p&gt;

&lt;p&gt;2- &lt;strong&gt;Data Redundancy&lt;/strong&gt;: Data is replicated across multiple nodes, ensuring data integrity and availability.&lt;/p&gt;

&lt;p&gt;3- &lt;strong&gt;Read Scalability&lt;/strong&gt;: Secondary nodes can serve read operations, distributing the read load across multiple nodes.&lt;/p&gt;

&lt;p&gt;4- &lt;strong&gt;Automatic Failover&lt;/strong&gt;: If the primary node fails, a secondary node is automatically elected as the new primary node.&lt;/p&gt;

&lt;p&gt;For further reading about MongoDB replication, check out the official MongoDB documentation on &lt;a href="https://docs.mongodb.com/manual/replication/" rel="noopener noreferrer"&gt;replica sets&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a 3-Node MongoDB Replica Set Cluster with Docker Compose
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;In this guide, we'll use Docker Compose to set up a 3-node MongoDB replica set cluster. Before you start, make sure you have Docker and Docker Compose installed on your machine. If you don't have them installed, you can download them from the official &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may also need to have a basic understanding of MongoDB and mongo shell commands. If you're new to MongoDB, you can check out the official MongoDB documentation on &lt;a href="https://docs.mongodb.com/manual/crud/" rel="noopener noreferrer"&gt;MongoDB CRUD Operations&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Docker Compose File
&lt;/h3&gt;

&lt;p&gt;Begin by creating a &lt;code&gt;docker-compose.yml&lt;/code&gt; file in a new directory. This file will define the services for the MongoDB containers. We'll create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;three services: &lt;code&gt;mongo1&lt;/code&gt;, &lt;code&gt;mongo2&lt;/code&gt;, and &lt;code&gt;mongo3&lt;/code&gt;; &lt;/li&gt;
&lt;li&gt;a network called &lt;code&gt;mongo-cluster&lt;/code&gt;; and&lt;/li&gt;
&lt;li&gt;three volumes: &lt;code&gt;mongo1-data&lt;/code&gt;, &lt;code&gt;mongo2-data&lt;/code&gt;, and &lt;code&gt;mongo3-data&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dot it:&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;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo-cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo1-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo2-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongo3-data&lt;/span&gt;&lt;span class="pi"&gt;:&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;mongo1&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;mongo_rs0&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:7.0-jammy&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;mongo1&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--replSet"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rs0"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--bind_ip"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1,mongo1"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--port"&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"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--keyFile"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/etc/mongodb/pki/keyfile"&lt;/span&gt;&lt;span class="pi"&gt;]&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;mongo1-data:/data/db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$PWD/scripts/mongo/rs_keyfile:/etc/mongodb/pki/keyfile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$PWD/scripts/mongo/init.js:/docker-entrypoint-initdb.d/init-mongo.js&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="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="s"&gt;mongo-cluster&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&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="s"&gt;echo "try {rs.status()} catch(err) {rs.initiate({_id:'rs0',members:[{_id:0,host:'mongo1:27017',priority:1},{_id:1,host:'mongo2:27018',priority:0.5},{_id:2,host:'mongo3:27019',priority:0.5}]})}" | mongosh --port 27017 -u '${MONGO_ADMIN_USER:-admin}' -p '${MONGO_ADMIN_PASSWD:-veryStringPassword}' --authenticationDatabase admin --quiet&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&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;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${MONGO_ADMIN_USER:-admin}'&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_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;${MONGO_ADMIN_PASSWD:-veryStringPassword}'&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${DB_NAME:-test}'&lt;/span&gt;
      &lt;span class="na"&gt;DB_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_USERNAME:-myuser}&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_PASSWORD:-mypassword}&lt;/span&gt;
  &lt;span class="na"&gt;mongo2&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;mongo_rs1&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:7.0-jammy&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;mongo2&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--replSet"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rs0"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--bind_ip"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1,mongo2"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--port"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27018"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--keyFile"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/etc/mongodb/pki/keyfile"&lt;/span&gt;&lt;span class="pi"&gt;]&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;mongo2-data:/data/db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$PWD/scripts/mongo/rs_keyfile:/etc/mongodb/pki/keyfile&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="s"&gt;27018: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="s"&gt;mongo-cluster&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;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${MONGO_ADMIN_USER:-admin}'&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_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;${MONGO_ADMIN_PASSWD:-veryStringPassword}'&lt;/span&gt;
  &lt;span class="na"&gt;mongo3&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;mongo_rs2&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:7.0-jammy&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;mongo3&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--replSet"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rs0"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--bind_ip"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1,mongo3"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--port"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27019"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--keyFile"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/etc/mongodb/pki/keyfile"&lt;/span&gt;&lt;span class="pi"&gt;]&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;mongo3-data:/data/db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$PWD/scripts/mongo/rs_keyfile:/etc/mongodb/pki/keyfile&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="s"&gt;27019: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="s"&gt;mongo-cluster&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;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${MONGO_ADMIN_USER:-admin}'&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_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;${MONGO_ADMIN_PASSWD:-veryStringPassword}'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Let's break down the &lt;code&gt;docker-compose.yml&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We define a network called &lt;code&gt;mongo-cluster&lt;/code&gt; that will be used by all the MongoDB containers. This ensures that the
containers can communicate with each other through the hostnames &lt;code&gt;mongo1&lt;/code&gt;, &lt;code&gt;mongo2&lt;/code&gt;, and &lt;code&gt;mongo3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We define three volumes: &lt;code&gt;mongo1-data&lt;/code&gt;, &lt;code&gt;mongo2-data&lt;/code&gt;, and &lt;code&gt;mongo3-data&lt;/code&gt; to persist the data for each MongoDB
container.&lt;/li&gt;
&lt;li&gt;We define three services: &lt;code&gt;mongo1&lt;/code&gt;, &lt;code&gt;mongo2&lt;/code&gt;, and &lt;code&gt;mongo3&lt;/code&gt;. Each service runs a MongoDB container with the
&lt;code&gt;mongo:7.0-jammy&lt;/code&gt; image. We specify the &lt;code&gt;--replSet&lt;/code&gt; option to set the replica set name to &lt;code&gt;rs0&lt;/code&gt;. We also specify the
&lt;code&gt;--bind_ip&lt;/code&gt; option to bind the container to the hostnames &lt;code&gt;mongo1&lt;/code&gt;, &lt;code&gt;mongo2&lt;/code&gt;, and &lt;code&gt;mongo3&lt;/code&gt;. We mount the volumes to
persist the data and the keyfile for authentication. We expose the ports &lt;code&gt;27017&lt;/code&gt;, &lt;code&gt;27018&lt;/code&gt;, and &lt;code&gt;27019&lt;/code&gt; for the MongoDB
containers. We define a health check for the &lt;code&gt;mongo1&lt;/code&gt; service to check the status of the replica set and initiate it
if it's not already initiated.  After the healthcheck is successful, the replica set is initiated with the primary node
&lt;code&gt;mongo1&lt;/code&gt; and secondary nodes &lt;code&gt;mongo2&lt;/code&gt; and &lt;code&gt;mongo3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We set the environment variables &lt;code&gt;MONGO_INITDB_ROOT_USERNAME&lt;/code&gt;, &lt;code&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/code&gt;, &lt;code&gt;MONGO_INITDB_DATABASE&lt;/code&gt;,
&lt;code&gt;DB_USERNAME&lt;/code&gt;, and &lt;code&gt;DB_PASSWORD&lt;/code&gt; for each service to configure the MongoDB authentication. We're using interpolation
to make sure the default values are used if the environment variables are not set.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Create a Keyfile for Authentication
&lt;/h3&gt;

&lt;p&gt;MongoDB uses keyfiles for internal authentication between members of the replica set. In a certain scenario where credentials are not set, we would not need it. But for the sake of this guide, we need to create a keyfile and mount it to the MongoDB containers, since we're using authentication.&lt;/p&gt;

&lt;p&gt;To create a keyfile, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 756 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; scripts/mongo/rs_keyfile &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;400 scripts/mongo/rs_keyfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command generates a random 756-byte key and saves it to the &lt;code&gt;scripts/mongo/rs_keyfile&lt;/code&gt; file. We then set the file permissions to &lt;code&gt;400&lt;/code&gt; to ensure that only the owner &lt;code&gt;mongodb:mongodb&lt;/code&gt; can read and write to the file. You can read more about keyfiles in the &lt;a href="https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set-with-keyfile-access-control/" rel="noopener noreferrer"&gt;MongoDB documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: the keyfile is used for internal authentication between members of the replica set. It's important to keep the keyfile secure and not expose it to unauthorized users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Create an Initialization Script
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, we'll set up an initial database, username and password for the MongoDB replica set. To do so we'll use an initialization script that will be executed when the MongoDB container starts. Now, create a file called &lt;code&gt;init.js&lt;/code&gt; in the &lt;code&gt;scripts/mongo&lt;/code&gt; directory with the following content:&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;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSiblingDB&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;MONGO_INITDB_DATABASE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;user&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;DB_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pwd&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;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;readWrite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;db&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;MONGO_INITDB_DATABASE&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="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;majority&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;wtimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Let's break down the &lt;code&gt;init.js&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We connect to the database specified by the &lt;code&gt;MONGO_INITDB_DATABASE&lt;/code&gt; environment variable.&lt;/li&gt;
&lt;li&gt;We create a user specified by the &lt;code&gt;DB_USERNAME&lt;/code&gt; and &lt;code&gt;DB_PASSWORD&lt;/code&gt; environment variables with the &lt;code&gt;readWrite&lt;/code&gt; role on the
database.&lt;/li&gt;
&lt;li&gt;We set the write concern to &lt;code&gt;majority&lt;/code&gt; with a timeout of &lt;code&gt;5000&lt;/code&gt; milliseconds. This ensures that the write operation is
acknowledged by the majority of the replica set members.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This script will be executed when the MongoDB container starts, creating the initial database and user for the replica set. Note that the script part is not mandatory, and you could use hardcoded values. However, according to the &lt;a href="https://12factor.net/config" rel="noopener noreferrer"&gt;section III of the 12-factor app&lt;/a&gt;, it's better to use environment variables to store secrets or anything that may vary between deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Start the MongoDB Replica Set Cluster
&lt;/h3&gt;

&lt;p&gt;Now that we have everything set up, we can start the MongoDB replica set cluster using Docker Compose by running the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: The &lt;code&gt;-d&lt;/code&gt; flag runs the containers in detached mode, which means they will run in the background.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 5: Verify the MongoDB Replica Set
&lt;/h3&gt;

&lt;p&gt;To verify that the MongoDB replica set is running correctly, you can use the &lt;code&gt;mongo&lt;/code&gt; shell to connect to the primary node and check the status of the replica set. Run the following command to connect to the primary node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mongo_rs0 mongosh &lt;span class="nt"&gt;-u&lt;/span&gt; admin &lt;span class="nt"&gt;-p&lt;/span&gt; veryStringPassword &lt;span class="nt"&gt;--authenticationDatabase&lt;/span&gt; admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: Replace &lt;code&gt;veryStringPassword&lt;/code&gt; with the password you set for the &lt;code&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/code&gt; environment variable. If you didn't set it, use &lt;code&gt;veryStringPassword&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once connected, run the following command to check the status of the replica set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rs.status&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the status of the replica set with the primary node &lt;code&gt;mongo1&lt;/code&gt; and the secondary nodes &lt;code&gt;mongo2&lt;/code&gt; and &lt;code&gt;mongo3&lt;/code&gt;. The output should like:&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="err"&gt;members:&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;span class="err"&gt;_id:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'mongo&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27017&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;health:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;state:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;stateStr:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'PRIMARY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;uptime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;478&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;electionTime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Timestamp(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;t:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1721354075&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;i:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;electionDate:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ISODate('&lt;/span&gt;&lt;span class="mi"&gt;2024-07-19&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;35.000&lt;/span&gt;&lt;span class="err"&gt;Z')&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;_id:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'mongo&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27018&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;health:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;state:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;stateStr:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'SECONDARY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;uptime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;471&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;syncSourceHost:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'mongo&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27017&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;_id:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'mongo&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27019&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;health:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;state:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;stateStr:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'SECONDARY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;uptime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;471&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;syncSourceHost:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'mongo&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27017&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&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="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;ok:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'$clusterTime':&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="err"&gt;clusterTime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Timestamp(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;t:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1721354536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;i:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;signature:&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="err"&gt;hash:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Binary.createFromBase&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="err"&gt;('&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;KKPt/SmHkhGZDH&lt;/span&gt;&lt;span class="mi"&gt;299&lt;/span&gt;&lt;span class="err"&gt;+yq&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;j&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;i&lt;/span&gt;&lt;span class="mi"&gt;04&lt;/span&gt;&lt;span class="err"&gt;='&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;keyId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Long('&lt;/span&gt;&lt;span class="mi"&gt;7393159456961331205&lt;/span&gt;&lt;span class="err"&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="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: This is a truncated output, and it may vary depending on the version of MongoDB you're using.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bonus: Add Mongo-Express for Web-based Administration
&lt;/h2&gt;

&lt;p&gt;Let's add a web-based administration tool for MongoDB, by using &lt;code&gt;mongo-express&lt;/code&gt;. To add &lt;code&gt;mongo-express&lt;/code&gt; to the Docker Compose file, add the following service definition:&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;mongo-express&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;mongo-express&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-express&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="s"&gt;8081:8081&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;mongo-cluster&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;ME_CONFIG_BASICAUTH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;ME_CONFIG_MONGODB_ENABLE_ADMIN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;ME_CONFIG_MONGODB_ADMINUSERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${MONGO_ADMIN_USER}'&lt;/span&gt;
      &lt;span class="na"&gt;ME_CONFIG_MONGODB_ADMINPASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${MONGO_ADMIN_PASSWD}'&lt;/span&gt;
      &lt;span class="na"&gt;ME_CONFIG_MONGODB_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb://${DB_USERNAME}:${DB_PASSWORD}@mongo1:27017,mongo2:27018,mongo3:27019/${DB_NAME}?replicaSet=rs0&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;mongo1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: The &lt;code&gt;mongo-express&lt;/code&gt; service depends on the &lt;code&gt;mongo1&lt;/code&gt; service being healthy. This ensures that the replica set is up and running before starting the &lt;code&gt;mongo-express&lt;/code&gt; service.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can access &lt;code&gt;mongo-express&lt;/code&gt; at &lt;code&gt;http://localhost:8081&lt;/code&gt; in your browser, and have something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz7tefhf98q0d1derbd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz7tefhf98q0d1derbd5.png" alt="Mongo express in action" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: To connect your application to the MongoDB replica set, you can use the connection string &lt;code&gt;mongodb://${DB_USERNAME:-myuser}:${DB_PASSWORD:-veryStringPassword}@mongo1:27017,mongo2:27018,mongo3:27019/${DB_NAME}?replicaSet=rs0&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If everything is set up correctly, you should have something like this in your docker desktop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ty70wluswu5xxz0mfm9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ty70wluswu5xxz0mfm9.png" alt="Docker desktop result" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this article, I walked you through setting up a 3-node MongoDB replica set cluster using Docker Compose. We covered the basics of MongoDB replica sets, the prerequisites for setting up a replica set, and the steps to create a Docker Compose file to set up the replica set. I also showed you how to verify the replica set and add a web-based administration tool using &lt;code&gt;mongo-express&lt;/code&gt;. I hope this guide helps you get started with MongoDB replica sets and Docker Compose.&lt;/p&gt;

&lt;p&gt;In a future post, I'll talk about something more important: how to back up, and restore a MongoDB database in a Docker environment. You may have heard that Docker containers are ephemeral, so it's important to have a backup strategy in place to avoid data loss. Stay tuned for that!&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, feel free to reach out to me. &lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/manual/replication/" rel="noopener noreferrer"&gt;MongoDB Replica Set Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/manual/crud/" rel="noopener noreferrer"&gt;MongoDB CRUD Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/storage/volumes/" rel="noopener noreferrer"&gt;Docker Volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/network/" rel="noopener noreferrer"&gt;Docker Networks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/reference/builder/#healthcheck" rel="noopener noreferrer"&gt;Docker Health Checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mongo-express/mongo-express" rel="noopener noreferrer"&gt;Mongo-Express&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post has been originally posted on my &lt;a href="https://denisakp.me/blog/devops/set-up-mongodb-replica-with-docker" rel="noopener noreferrer"&gt;website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>mongodb</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unlocking the Cloud: My Journey to AWS Cloud Practitioner Certification</title>
      <dc:creator>Denis AKPAGNONITE</dc:creator>
      <pubDate>Thu, 09 Nov 2023 13:07:22 +0000</pubDate>
      <link>https://dev.to/denisakp/unlocking-the-cloud-my-journey-to-aws-cloud-practitioner-certification-47lo</link>
      <guid>https://dev.to/denisakp/unlocking-the-cloud-my-journey-to-aws-cloud-practitioner-certification-47lo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;After weeks of dedicated study and hard work, I'm thrilled to announce that I've recently achieved a major milestone in&lt;br&gt;
my career. I'm now an AWS Certified Cloud Practitioner! This certification has opened up a world of opportunities in the&lt;br&gt;
cloud computing industry, and I'm excited to share my journey and insights with you.&lt;/p&gt;

&lt;p&gt;View my &lt;a href="https://www.credly.com/badges/1a490efa-6214-427a-964a-eca1e6898685/public_url" rel="noopener noreferrer"&gt;verified achievement&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Amazon Web Services (AWS)
&lt;/h2&gt;

&lt;p&gt;Do you wonder why AWS? It all began with my intense fascination with cloud computing and the rising need in the labor market for cloud experts. Amazon Web Services has revolutionized the way we think about computing, storage, and&lt;br&gt;
scalability.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive services portfolio&lt;/strong&gt;&lt;br&gt;
With the widest range of cloud services available, AWS is the best option for companies of all sizes and sectors. It offers everything from compute, network, storage, databases, to machine learning and more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global Presence&lt;/strong&gt;&lt;br&gt;
AWS offers low latency and high availability to customers and organizations globally, with data centers and regions located all over the world, ensuring redundancy and expanding applications require this worldwide reach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reliability and Security&lt;/strong&gt;&lt;br&gt;
AWS has a track record of reliability and security. From healthcare to financial services, it drives some of the most important workloads in the world. AWS is a reliable option because of its strong security features and compliance certifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Strong Community and Support&lt;/strong&gt;&lt;br&gt;
The AWS community is vast and vibrant, offering a wealth of resources, forums, and documentation. You can find support and solutions to your cloud challenges.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In summary, AWS is not just a cloud provider; it's a leader in the industry, offering the most comprehensive, reliable,&lt;br&gt;
and innovative cloud solutions. Choosing AWS is a strategic move that can propel your career and business to new heights&lt;br&gt;
in the world of cloud computing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cloud Practitioner Certification Objectives
&lt;/h2&gt;

&lt;p&gt;The AWS Certified Cloud Practitioner (CLF-C02) exam is intended for individuals who can effectively demonstrate overall knowledge of the AWS Cloud, independent of a specific job role. The exam validates a candidate’s ability to complete the following tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explain the value of the AWS Cloud.&lt;/li&gt;
&lt;li&gt;Understand and explain the AWS shared responsibility model.&lt;/li&gt;
&lt;li&gt;Understand security best practices.&lt;/li&gt;
&lt;li&gt;Understand AWS Cloud costs, economics, and billing practices.&lt;/li&gt;
&lt;li&gt;Describe and position the core AWS services, including compute, network, database, and storage services.&lt;/li&gt;
&lt;li&gt;Identify AWS services for common use cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The AWS Cloud Practitioner Curriculum
&lt;/h3&gt;

&lt;p&gt;The Exam curriculum covers up to four domains which are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloud Concepts&lt;/strong&gt; (24% of scored content)&lt;br&gt;
It is necessary to have a fundamental understanding of cloud computing concepts to pass the AWS Cloud Practitioner exam. This domain covers a wide range of subjects, including elasticity, scalability, fault tolerance, and high availability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security and compliance&lt;/strong&gt; (30% of scored content)&lt;br&gt;
Another crucial subject for candidates to AWS Cloud Practitioner exam is security. This domain covers a range of&lt;br&gt;
issues with security, compliance, and accountable management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloud Technology and Services&lt;/strong&gt; (34% of scored content)&lt;br&gt;
This domain is the most important of the AWS Certified Cloud Practitioner Exam. To be proficient in this part, you need to be familiar with the primary AWS services such as EC2, RDS, EC2, S3, Lambda&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Billing, Pricing, and Support&lt;/strong&gt; (12% of scored content)&lt;br&gt;
You must have a basic understanding of AWS Cloud economics, AWS Billing and Cost Management, AWS support plans, the types of charges, billing processes and how services are billed, the consolidated billing and more.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Study resources
&lt;/h2&gt;

&lt;p&gt;Preparing for the AWS Cloud Practitioner exam involves setting a study schedule, breaking down the topics, and setting&lt;br&gt;
goals. Consistency is key, and I recommend dedicating time each day to study. In addition, make use of AWS white papers&lt;br&gt;
and documentation to deepen your knowledge. One of the key factors that contributed to my success was the availability&lt;br&gt;
of excellent study resources. Here are some of the resources I used:&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Training lessons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Cloud Practitioner Essentials&lt;/strong&gt;: This course is for anyone who seeks an overall understanding of the Amazon Web
Services Cloud. You will learn about AWS Cloud concepts, AWS services, security, architecture, pricing, and support to build your AWS Cloud knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Technical Essentials&lt;/strong&gt;: This course introduces you to essential Amazon Web Services and common solutions. It covers the fundamental AWS concepts related to compute, database, storage, networking, monitoring, and security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Cloud Quest: Cloud Practitioner&lt;/strong&gt;: AWS Cloud Quest is a role-playing game to help you build in-demand AWS Cloud skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KodeKloud AWS Cloud Practitioner (CLF-C02)&lt;/strong&gt;: This course was well-structured, and I gained valuable insights. The Billing &amp;amp; Pricing module was particularly enlightening, offering a concise view of AWS cost management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Get Familiar with AWS: AWS Free tier
&lt;/h3&gt;

&lt;p&gt;AWS Free Tier is a program offered by Amazon Web Services that provides new AWS users with a limited amount of free access to a variety of AWS services for 12 months. It allows you to explore and experiment with AWS cloud services without incurring any charges, making it an excellent starting point for beginners and those looking to get hands-on experience with AWS. AWS Free Tier is a great way to get started with AWS services.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Cloud Practitioner Free Practice test
&lt;/h3&gt;

&lt;p&gt;The greatest way to assess your exam readiness and knowledge is to take practice exams. You should take advantage of the&lt;br&gt;
free AWS Certified Cloud Practitioner practice exam if you want to achieve high scores. The format and substance of&lt;br&gt;
these tests are intended to closely mimic the real exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Exam booking and the Exam day
&lt;/h2&gt;

&lt;p&gt;To initiate the exam process, I had to book a time slot through the Pearson VUE website. The booking process was&lt;br&gt;
straightforward, allowing me to choose a date and time that suited my schedule. Additionally, I needed to purchase an&lt;br&gt;
exam voucher, which costs $100 USD. It's essential to note that the voucher price covers the exam cost.&lt;/p&gt;

&lt;p&gt;There were a few crucial decisions to make, including the method of examination and the logistics of booking. I opted to&lt;br&gt;
take the exam at a Pearson VUE test center, mainly because I wanted a controlled and focused environment. While the option of a proctored exam from the comfort of home is available, I saw it as potentially distracting. The center offered a quiet space dedicated to the exam, ensuring minimal disruptions.&lt;/p&gt;

&lt;p&gt;The AWS Cloud Practitioner exam consists of 65 multiple-choice questions, and achieving a minimum score of 700 out of 1000 is required to pass. The questions cover a range of topics relevant to foundational AWS Cloud concepts. Upon completing the exam, the results were available immediately. The instant feedback provided a sense of closure to the exam experience, as the screen revealed whether I had passed or not.&lt;/p&gt;

&lt;p&gt;Three days after successfully passing the exam, I received my digital badge on Creedly, a tangible symbol of my accomplishment. Accompanying the badge was a congratulatory email containing valuable instructions and information on&lt;br&gt;
the next steps in my AWS certification journey. This swift response from AWS added a personal touch to the certification&lt;br&gt;
process, emphasizing their commitment to recognizing and celebrating the achievements of candidates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;If you're considering pursuing an AWS certification, especially the AWS Cloud Practitioner, remember that you're not alone in this journey. Feel free to reach out with any questions or for guidance. The world of AWS and cloud computing is filled with endless possibilities, and I can't wait to see where it takes you.&lt;/p&gt;

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

&lt;p&gt;Finally, for anyone interested in cloud technology, the AWS Cloud Practitioner certification is a great place to start.&lt;br&gt;
It gives you the fundamental information you need and provides access to a variety of career options in the cloud computing area. As I rejoice in my accomplishment, I'm already actively preparing for the AWS Solutions Architect Associate certification, a step I plan to take within the next six months. This ongoing commitment to learning and growth reflects my dedication to staying at the forefront of cloud technology and furthering my expertise in the AWS ecosystem.&lt;/p&gt;

&lt;p&gt;I hope that my experience has motivated you to get your AWS certification. I wish you well and the realization of your&lt;br&gt;
cloud computing goals.&lt;/p&gt;

&lt;p&gt;This post has been originally posted on my personal web site &lt;a href="https://www.denisakp.me/blog/aws/how-i-passed-clf-exam" rel="noopener noreferrer"&gt;Dev Life&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloudpractitioner</category>
    </item>
  </channel>
</rss>
