<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Saif Mahmud</title>
    <description>The latest articles on Forem by Saif Mahmud (@sikhlana).</description>
    <link>https://forem.com/sikhlana</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%2F1336439%2F566bd4bb-4a9d-4aa5-be3f-6e622b9dd075.jpeg</url>
      <title>Forem: Saif Mahmud</title>
      <link>https://forem.com/sikhlana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sikhlana"/>
    <language>en</language>
    <item>
      <title>A Little Bit of a Disaster, A Lot of Motivation: Building a CLI Secret Manager</title>
      <dc:creator>Saif Mahmud</dc:creator>
      <pubDate>Thu, 21 Nov 2024 02:23:15 +0000</pubDate>
      <link>https://forem.com/sikhlana/a-little-bit-of-a-disaster-a-lot-of-motivation-building-a-cli-secret-manager-2oh7</link>
      <guid>https://forem.com/sikhlana/a-little-bit-of-a-disaster-a-lot-of-motivation-building-a-cli-secret-manager-2oh7</guid>
      <description>&lt;p&gt;So, let's talk about a little mishap that turned into a major motivation. My shiny new Macbook Pro M3, fresh out of the box, decided to brick itself after a routine software update. &lt;em&gt;Cue dramatic music.&lt;/em&gt; And with it, went all my precious data, including those pesky secrets like API keys, SSH keys, and personal shell scripts. The worst part? A critical production deployment was looming just two days away.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Domino Effect of Lost Secrets
&lt;/h3&gt;

&lt;p&gt;With my secrets gone, I had to reach out to various teams and departments to obtain new ones. This process, unfortunately, took longer than expected in the corporate world. The delays in acquiring these essential keys ultimately led to the postponement of the deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a CLI Secret Manager?
&lt;/h3&gt;

&lt;p&gt;This incident forced me to rethink my secret management strategy. Sure, I could've just zipped up the secrets and tossed them onto Google Drive, OneDrive, or S3. But let's be real, that's a huge security risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unauthorized Access:&lt;/strong&gt; If someone gains access to your cloud storage account, they could potentially get their hands on your sensitive information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Breaches:&lt;/strong&gt; Cloud storage providers, while generally secure, aren't immune to data breaches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Password-protecting the archive is an option, but I'm too lazy to do that. Using a third-party service like LastPass is another possibility, but it requires manual updates and management; &lt;em&gt;again, lazy&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are also native applications that offer automatic syncing, but let's be honest, the free ones are either poorly maintained or have a bad user experience. And the paid ones? Pfft, please.&lt;/p&gt;

&lt;p&gt;Even if there is one that checks out all of my requirements, as a software engineer, I couldn't resist the urge to build my own; something that I could control and customize. &lt;em&gt;So, I decided to build my own CLI secret manager.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the Plan?
&lt;/h3&gt;

&lt;p&gt;I'm building a CLI application that will allow me to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Store:&lt;/strong&gt; Using strong encryption and secure storage mechanisms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve:&lt;/strong&gt; With simple commands to access the secrets I need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage:&lt;/strong&gt; Easily add, remove, and update secrets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync:&lt;/strong&gt; Ensure consistency across multiple machines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share:&lt;/strong&gt; Securely share secrets with others using asymmetric keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've chosen PHP and Laravel Zero as the technology stack for this project. Why PHP, you ask? Well, it's a language I love more than my ex, who I'm still kind of hung up on, &lt;em&gt;but at least I'm not hung up on Python&lt;/em&gt;. And Laravel is a rock-solid framework. To make the application accessible to a wider audience, I'll try to create a standalone binary using &lt;a href="https://github.com/crazywhalecc/static-php-cli?ref=saifmahmud.blog" rel="noopener noreferrer"&gt;static-php-cli&lt;/a&gt; and &lt;a href="https://github.com/box-project/box?ref=saifmahmud.blog" rel="noopener noreferrer"&gt;box-project&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Stay Tuned for More&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;I'll be sharing regular updates on the development process, including challenges, solutions, and best practices. I'll also be releasing the project on GitHub once it's complete, so you can contribute or use it yourself.&lt;/p&gt;

&lt;p&gt;So, buckle up and join me on this exciting journey as I build a powerful(?) and secure CLI secret manager.&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%2F8d83rbo8tuwbmgizhj06.gif" 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%2F8d83rbo8tuwbmgizhj06.gif" alt="Can We Build It? Yes We Can!" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>php</category>
      <category>laravel</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Level Up Your Dev Workflow: Branch-Specific Data Volumes with Docker Compose</title>
      <dc:creator>Saif Mahmud</dc:creator>
      <pubDate>Sun, 03 Nov 2024 20:08:15 +0000</pubDate>
      <link>https://forem.com/sikhlana/level-up-your-dev-workflow-branch-specific-data-volumes-with-docker-compose-1fl2</link>
      <guid>https://forem.com/sikhlana/level-up-your-dev-workflow-branch-specific-data-volumes-with-docker-compose-1fl2</guid>
      <description>&lt;p&gt;Imagine this: you're working on a new feature and you're deep into it, only to be suddenly interrupted by a critical bug in production. You want to switch to a new branch to work on the bug fix, but your local database is still a work-in-progress with changes from your feature branch, hindering you from being able to test any changes for the bug fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yikes!&lt;/strong&gt; If only there was a way to do this without pulling your hair out 🤔&lt;/p&gt;

&lt;p&gt;One approach to solve this problem is using branch-specific volumes in Docker. This blog post will guide you through a script that leverages Docker Compose to spin up services with branch-specific data volumes, streamlining your development process. &lt;/p&gt;

&lt;p&gt;With branch-specific data volumes, each branch gets its own isolated data, preventing such conflicts. &lt;strong&gt;No more fear of breaking your main development environment or other branches!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Benefits of Using Docker Compose for Development:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Environments:&lt;/strong&gt; Docker Compose ensures your development environment is consistent across different machines and setups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Setup:&lt;/strong&gt; Define and manage multiple services in a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development:&lt;/strong&gt; Quickly spin up and tear down development environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Collaboration:&lt;/strong&gt; Share your development environment with ease.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Challenge with Default Docker Compose Volume Behavior
&lt;/h3&gt;

&lt;p&gt;A common limitation of Docker Compose is that a single instance of a volume, defined within a Docker Compose file, exists for the entire project. This can be problematic when working with multiple branches, as each branch might require its own isolated data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Dynamic Volume Creation
&lt;/h2&gt;

&lt;p&gt;To overcome these limitations, we'll use a script to dynamically create and manage branch-specific data volumes. Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detect the Current Branch and Calculate a Hash:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;CURRENT_BRANCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git symbolic-ref &lt;span class="nt"&gt;--short&lt;/span&gt; HEAD&lt;span class="si"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;CURRENT_BRANCH_HASH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_BRANCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-c8&lt;/span&gt; | hexdump &lt;span class="nt"&gt;-n4&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'"%08x"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define Volume Names Based on the Branch or Hash:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_BRANCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"master"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
       &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MYSQL_VOLUME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_NAME&lt;/span&gt;&lt;span class="s2"&gt;-mysql-master-data"&lt;/span&gt;
       &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REDIS_VOLUME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_NAME&lt;/span&gt;&lt;span class="s2"&gt;-redis-master-data"&lt;/span&gt;
       &lt;span class="c"&gt;# ... other volumes&lt;/span&gt;
   &lt;span class="k"&gt;else
       &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MYSQL_VOLUME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_NAME&lt;/span&gt;&lt;span class="s2"&gt;-mysql-&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_BRANCH_HASH&lt;/span&gt;&lt;span class="s2"&gt;-data"&lt;/span&gt;
       &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REDIS_VOLUME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APP_NAME&lt;/span&gt;&lt;span class="s2"&gt;-redis-&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_BRANCH_HASH&lt;/span&gt;&lt;span class="s2"&gt;-data"&lt;/span&gt;
       &lt;span class="c"&gt;# ... other volumes&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;

   &lt;span class="c"&gt;# Note that the '$APP_NAME' variable has been defined earlier&lt;/span&gt;
   &lt;span class="c"&gt;# which is basically the project name for the docker compose manifest.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create Volumes and Copy Data from &lt;code&gt;master&lt;/code&gt; if Necessary:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;VOLUMES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;MYSQL_VOLUME REDIS_VOLUME ...&lt;span class="o"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;for &lt;/span&gt;VOLUME &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VOLUMES&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
       if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker volume &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&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;then
           &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating volume: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
           docker volume create &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_BRANCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"master"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
               &lt;/span&gt;&lt;span class="nv"&gt;MASTER_VOLUME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"s/(.*?)-&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_BRANCH_HASH&lt;/span&gt;&lt;span class="s2"&gt;-(.*?)/&lt;/span&gt;&lt;span class="se"&gt;\1&lt;/span&gt;&lt;span class="s2"&gt;-master-&lt;/span&gt;&lt;span class="se"&gt;\2&lt;/span&gt;&lt;span class="s2"&gt;/g"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

               &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker volume &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MASTER_VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&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;then
                   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Master volume not found: &lt;/span&gt;&lt;span class="nv"&gt;$MASTER_VOLUME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                   docker volume &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
                   &lt;span class="nb"&gt;exit &lt;/span&gt;1
               &lt;span class="k"&gt;fi

               &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying data from master volume..."&lt;/span&gt;
               docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MASTER_VOLUME&lt;/span&gt;&lt;span class="s2"&gt;:/from"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:/to"&lt;/span&gt; busybox sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cd /from; cp -a . /to"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
           &lt;span class="k"&gt;fi
       fi
   done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Docker Compose:&lt;/strong&gt;
You can use the defined volume names as environment variables in your &lt;code&gt;docker-compose.yml&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;   &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:latest&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;mysql-data:/var/lib/mysql&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;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
               &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my_database&lt;/span&gt;
       &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:latest&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;redis-data:/data&lt;/span&gt;
       &lt;span class="c1"&gt;# ... other services&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;mysql-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MYSQL_VOLUME}&lt;/span&gt;
           &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
       &lt;span class="na"&gt;redis-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${REDIS_VOLUME}&lt;/span&gt;
           &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
       &lt;span class="c1"&gt;# ... other volumes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By dynamically creating volumes based on the branch hash, we ensure that each branch has its own isolated data, even if the branch name contains invalid characters for Docker volume names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Level Up Your Workflow
&lt;/h3&gt;

&lt;p&gt;By incorporating this script and Docker Compose into your development process, you'll enjoy a smoother, more efficient, and less stressful development experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For a full working example, check out this GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/sikhlana/laravel-template/blob/master/bin/run" rel="noopener noreferrer"&gt;https://github.com/sikhlana/laravel-template/blob/master/bin/run&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>docker</category>
      <category>git</category>
      <category>development</category>
    </item>
  </channel>
</rss>
