4 minute read

# Blueprint: Mastering Multi-Environment CI/CD with Traditional Git Flow and Immutable Containers

πŸ“ Introduction

  • The Core Challenge: Managing software configurations across multiple environments (Development, Staging, Production) often leads to configuration drift, security vulnerabilities, or the anti-pattern of building separate artifacts for different environments.
  • The Goal: Establish a robust, production-grade automated pipeline using Traditional Git Flow, Docker, Jenkins, and AWS EC2 that guarantees identical software behavior while seamlessly swapping environmental profiles.

πŸ—ΊοΈ Architectural Findings: The β€œBuild Once, Run Anywhere” Principle

The absolute cornerstone of modern DevOps engineering discovered during this deep-dive is the strict isolation of the Build Stage from the Deployment Stage.

[ Git Event Trigger ] ──► [ Build Neutral Image ] ──► [ Push to Docker Hub ]
                                                               β”‚
                                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                     β–Ό                         β–Ό                         β–Ό
                                     (Deploy to Dev)          (Deploy to Stage)          (Deploy to Prod)
                                     Inject: Mint Green       Inject: Amber Orange       Inject: Slate Blue

1. The Build Phase (Environment-Neutral Image)

  • The Finding: Docker images must be completely environment-agnostic. They should contain zero database endpoints, zero secret API tokens, and zero hardcoded configuration files.
  • Why it matters: Baking variables into images requires rebuilding the image for each environment. This violates the principle of artifact immutabilityβ€”meaning you are no longer truly testing the exact same code artifact in Staging that goes live to Production.

2. The Deployment Phase (Runtime Injection)

  • The Finding: Environment configurations must be applied at the container’s runtime initialization using execution flags (e.g., docker run -e VARIABLE=value).
  • Why it matters: This approach allows the identical, immutable binary image layer to run flawlessly across completely isolated network boundaries. It also dramatically speeds up deployments, as promotion becomes an instantaneous container restart rather than a multi-minute code recompilation.

🌳 Branching Strategy Breakdown: Traditional Git Flow

To manage the software development lifecycle safely, the architecture utilizes five distinct Git branches mapped explicitly to dedicated deployment infrastructure.

The 5 Essential Branches

  1. feature/* (Temporary): Isolated branches cut from develop where individual engineers write features. They run and test entirely within a local developer workspace.
  2. develop (Permanent): The primary integration zone. Merging code here fires automated linting/testing and instantly deploys to the Development EC2 Server using Mint Green (#1abc9c) visual flags.
  3. release/* (Temporary): The stabilization buffer branch cut directly from develop once a launch version is frozen. Pushing this branch initiates a rollout to the Staging/Pre-Prod EC2 Server using Amber Orange (#f39c12) visual flags.
  4. main / master (Permanent): The definitive history of live production-ready releases.
  5. hotfix/* (Temporary): The emergency fast-track channel cut directly from main to address active production crashes. It tests on Staging before deploying directly to the live environment, followed by a mandatory backward sync merge into develop.

πŸš€ The End-to-End Release Process: A Step-by-Step Walkthrough

[ develop ] ──► Create Branch ──► [ release/ ] ──► Deploys to Staging (Orange)
                                                           β”‚
                                                           β–Ό 
                                                    (QA Passes)Raise PR to [ main ] 
                                                           β”‚
                                                           β–Ό 
                    (Triggers Pre-Merge Prod Deployment)[ Production Gate ]  ◄── (Manual Sign-Off)
                                                                                        β”‚
                                                                                        β–Ό 
                                                                (Approved)[ Live Production ] ──► Auto-Merges to main & develop

Step 1: Feature Integration

  • Developers merge peer-reviewed code into develop.
  • Jenkins runs code-quality syntax pipelines, updates the neutral Docker image tag, and runs it on the Dev instance with dev parameters.

Step 2: Transitioning to the Release Track

  • Once features are stable on Dev, a release/<date> branch is cut from develop.
  • Jenkins builds the immutable image tag, pushes it to Docker Hub, connects via SSH to the Staging EC2 Instance, and boots the container with Staging environment parameters.

Step 3: Isolation of Stabilization Testing

  • The QA engineering team runs heavy integration testing on Staging.
  • Critical Pattern: Any bug found during this phase is patched directly on the release/* branch. This restarts the staging pipeline for re-validation, leaving the main develop branch completely open for engineers to keep working on future versions without stepping on the current launch cycle.

Step 4: Secure Production Elevation

  • Once QA gives a complete sign-off, a Pull Request is raised from release/* into main.
  • Advanced Practice: To avoid a permanent bad merge into main, the open PR itself triggers a temporary production deployment slot.
  • The pipeline encounters an explicit Jenkins Manual Approval Gate. Execution halts safely until a release manager reviews the release and clicks β€œApprove”.

Step 5: The Post-Approval Double Merge

  • Upon manual approval, Jenkins executes the production rollout, pointing live user traffic to the container running with Slate Blue (#2c3e50) Production variables.
  • Jenkins completes the automated merge into main to lock down the release history.
  • The Vital Sync: The release branch is then merged back into develop to ensure that all patches discovered during the staging QA cycle are permanently synchronized back into the foundational engineering stream.

πŸ”‘ Key Engineering Takeaways

  • Security Isolation: Production variables (like PROD_DB_PASS or API_KEYS) stay hidden inside the encrypted Jenkins Credentials Store and are only surfaced in-memory during the final production deploy stage. Lower environments remain entirely sandbox-isolated.
  • Visual Elements Matter: Utilizing a highly visible configuration variable like ENV_COLOR on internal headers/backgrounds serves as an immediate visual safety check for stakeholders to confirm exactly which environment they are testing.
  • Scale Limits: While this workflow is pristine for small to mid-market architectures, hyperscale enterprises like Spotify often pivot away from environment-based pipelines toward Trunk-Based Development and Feature Flags to support multi-thousand engineer daily code deployment velocities.