• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Zero-Downtime Blue-Green Deployment Pipelines for Ruby Applications on DigitalOcean

Zero-Downtime Blue-Green Deployment Pipelines for Ruby Applications on DigitalOcean

Understanding the Blue-Green Deployment Pattern

The Blue-Green deployment strategy is a technique for releasing new versions of software with zero downtime. It involves maintaining two identical production environments, referred to as “Blue” and “Green.” At any given time, one environment (e.g., Blue) is running the current production version, while the other (Green) is idle or running a previous version. To deploy a new version, we provision the idle environment (Green) with the new code, test it thoroughly, and then switch the traffic from the Blue environment to the Green environment. The Blue environment then becomes the idle environment, ready for the next deployment.

Leveraging DigitalOcean Load Balancers and Droplets

For this setup on DigitalOcean, we’ll utilize Load Balancers to direct traffic and multiple Droplets to host our Ruby application. The core idea is to have two distinct sets of Droplets, each capable of running the full application stack. The Load Balancer will be configured to point to one of these sets. During a deployment, we’ll update the *other* set of Droplets and then reconfigure the Load Balancer to switch traffic.

Infrastructure Setup: Two Application Stacks

We need two identical sets of Droplets. For simplicity, let’s assume a basic Rails application with a web server (e.g., Nginx) and a database. In a production scenario, you’d likely have multiple Droplets per environment for high availability, but for this example, we’ll focus on the traffic switching mechanism.

Environment Blue:

  • Droplet 1 (Web Server/App): `app-blue-1`
  • Droplet 2 (Web Server/App): `app-blue-2`

Environment Green:

  • Droplet 1 (Web Server/App): `app-green-1`
  • Droplet 2 (Web Server/App): `app-green-2`

A single managed DigitalOcean Database instance will serve both environments. This simplifies database management but requires careful consideration during schema migrations.

Configuring the DigitalOcean Load Balancer

We’ll create a Load Balancer that initially points to the “Blue” Droplets. The health check is crucial for ensuring traffic is only sent to healthy instances.

Load Balancer Configuration (Conceptual):

  • Frontend: Port 80 (HTTP), Port 443 (HTTPS)
  • Backend Pool: Target Droplets `app-blue-1`, `app-blue-2`
  • Health Check: HTTP GET request to `/health` endpoint on port 3000 (or your app’s port). Timeout: 5s, Interval: 10s, Healthy Threshold: 2, Unhealthy Threshold: 3.

The Load Balancer’s IP address will be the public-facing endpoint for your application.

Automating Deployments with Capistrano

Capistrano is a powerful tool for automating application deployment. We’ll configure it to deploy to either the Blue or Green environment based on a variable. This requires a slightly modified Capistrano setup.

First, ensure you have a `Capfile` and `deploy.rb` in your Rails application’s root directory. We’ll add a task to switch the target environment.

Capistrano `deploy.rb` Modifications

We’ll introduce a variable, `target_environment`, which can be set to `:blue` or `:green`. Capistrano will then use the appropriate server definitions.

# deploy.rb

# ... other configurations ...

set :application, 'my_ruby_app'
set :repo_url, '[email protected]:your_username/my_ruby_app.git'

# Define target environment: :blue or :green
# This can be set via an environment variable or command-line argument
set :target_environment, ENV.fetch('TARGET_ENV', :blue).to_sym

# Define server roles based on the target environment
set :servers, []
if fetch(:target_environment) == :blue
  set :servers, [
    { host: 'app-blue-1.your_domain.com', roles: %w{app web} },
    { host: 'app-blue-2.your_domain.com', roles: %w{app web} }
  ]
else # :green
  set :servers, [
    { host: 'app-green-1.your_domain.com', roles: %w{app web} },
    { host: 'app-green-2.your_domain.com', roles: %w{app web} }
  ]
end

# ... other Capistrano configurations (e.g., linked_dirs, linked_files) ...

namespace :deploy do
  desc 'Switch the Load Balancer to the Green environment'
  task :switch_to_green do
    on roles(:app) do
      # This is a placeholder. Actual implementation depends on DigitalOcean API client.
      # Example: execute("doctl loadbalancer update #{lb_id} --forwarding-rules '{\"entry_points\": [{\"protocol\": \"http\", \"port\": 80, \"targets\": [{\"port\": 80, \"service_name\": \"app-green-pool\"}]}]}'")
      puts "--- Switching Load Balancer to GREEN environment ---"
      puts "NOTE: This is a placeholder. Implement actual DO API call here."
    end
  end

  desc 'Switch the Load Balancer to the Blue environment'
  task :switch_to_blue do
    on roles(:app) do
      # This is a placeholder. Actual implementation depends on DigitalOcean API client.
      # Example: execute("doctl loadbalancer update #{lb_id} --forwarding-rules '{\"entry_points\": [{\"protocol\": \"http\", \"port\": 80, \"targets\": [{\"port\": 80, \"service_name\": \"app-blue-pool\"}]}]}'")
      puts "--- Switching Load Balancer to BLUE environment ---"
      puts "NOTE: This is a placeholder. Implement actual DO API call here."
    end
  end

  # Override the default deploy task to include switching logic
  # This is a simplified example. A more robust solution would involve
  # a separate task to deploy to the *inactive* environment first.
  # For this example, we assume the inactive environment is already updated.
  task :perform_deployment do
    # Deploy to the current target environment
    invoke 'deploy:updating'
    invoke 'deploy:published'
  end
end

# Add a task to deploy to the *inactive* environment
namespace :deploy do
  desc 'Deploy to the inactive environment (for blue-green switch)'
  task :deploy_inactive do
    # Determine the inactive environment
    inactive_env = fetch(:target_environment) == :blue ? :green : :blue

    puts "--- Deploying to INACTIVE environment: #{inactive_env.to_s.upcase} ---"

    # Temporarily switch Capistrano's target to the inactive environment
    original_servers = fetch(:servers)
    original_target_env = fetch(:target_environment)

    set :target_environment, inactive_env
    if fetch(:target_environment) == :blue
      set :servers, [
        { host: 'app-blue-1.your_domain.com', roles: %w{app web} },
        { host: 'app-blue-2.your_domain.com', roles: %w{app web} }
      ]
    else # :green
      set :servers, [
        { host: 'app-green-1.your_domain.com', roles: %w{app web} },
        { host: 'app-green-2.your_domain.com', roles: %w{app web} }
      ]
    end

    # Perform the deployment to the inactive environment
    invoke 'deploy:updating'
    invoke 'deploy:published'

    # Restore original settings
    set :servers, original_servers
    set :target_environment, original_target_env
    puts "--- Deployment to inactive environment complete ---"
  end
end



DigitalOcean API Integration for Load Balancer Switching

The `switch_to_green` and `switch_to_blue` tasks are placeholders. You'll need to integrate with the DigitalOcean API to actually modify the Load Balancer's forwarding rules. This typically involves using the `doctl` CLI tool or a Ruby SDK.

First, ensure you have `doctl` installed and authenticated:

# Install doctl (example for macOS)
brew install doctl

# Authenticate
doctl auth init

You'll need the ID of your Load Balancer and the names of your backend pools (e.g., `app-blue-pool`, `app-green-pool`). You can find these using `doctl compute loadbalancer list` and `doctl compute loadbalancer get <lb-id>`.

Here's how you might implement the switching tasks using `doctl`:

# deploy.rb (continued)

# Replace with your actual Load Balancer ID and pool names
set :do_lb_id, 'YOUR_LOAD_BALANCER_ID'
set :do_blue_pool_name, 'app-blue-pool' # Or the actual name of your blue backend pool
set :do_green_pool_name, 'app-green-pool' # Or the actual name of your green backend pool

namespace :deploy do
  desc 'Switch the Load Balancer to the Green environment'
  task :switch_to_green do
    on roles(:app) do # This task doesn't strictly need to run on app roles, but it's a common place
      puts "--- Switching Load Balancer to GREEN environment ---"
      # Get current LB config
      lb_config = JSON.parse(`doctl compute loadbalancer get #{fetch(:do_lb_id)} --format JSON`)

      # Find and update the forwarding rule for HTTP (port 80)
      # This assumes a single HTTP forwarding rule. Adjust if you have multiple.
      lb_config['forwarding_rules'].each do |rule|
        if rule['entry_points'].any? { |ep| ep['protocol'] == 'http' && ep['port'] == 80 }
          rule['targets'].first['service_name'] = fetch(:do_green_pool_name)
          break
        end
      end

      # Update the Load Balancer
      # We need to pass the entire updated config as a JSON string.
      # This requires careful JSON serialization and escaping.
      # A simpler approach might be to use individual doctl commands if available for specific rule updates.
      # For demonstration, we'll simulate the update command.
      # In a real scenario, you'd construct the JSON payload carefully.
      puts "Simulating: doctl compute loadbalancer update #{fetch(:do_lb_id)} --forwarding-rules '#{JSON.dump(lb_config['forwarding_rules'])}'"
      # execute("doctl compute loadbalancer update #{fetch(:do_lb_id)} --forwarding-rules '#{JSON.dump(lb_config['forwarding_rules'])}'")
    end
  end

  desc 'Switch the Load Balancer to the Blue environment'
  task :switch_to_blue do
    on roles(:app) do
      puts "--- Switching Load Balancer to BLUE environment ---"
      lb_config = JSON.parse(`doctl compute loadbalancer get #{fetch(:do_lb_id)} --format JSON`)

      lb_config['forwarding_rules'].each do |rule|
        if rule['entry_points'].any? { |ep| ep['protocol'] == 'http' && ep['port'] == 80 }
          rule['targets'].first['service_name'] = fetch(:do_blue_pool_name)
          break
        end
      end

      puts "Simulating: doctl compute loadbalancer update #{fetch(:do_lb_id)} --forwarding-rules '#{JSON.dump(lb_config['forwarding_rules'])}'"
      # execute("doctl compute loadbalancer update #{fetch(:do_lb_id)} --forwarding-rules '#{JSON.dump(lb_config['forwarding_rules'])}'")
    end
  end
end



The Zero-Downtime Deployment Workflow

With the infrastructure and Capistrano setup, the deployment workflow becomes a sequence of automated steps:

Step 1: Deploy to the Inactive Environment

First, we deploy the new version of the application to the environment that is *not* currently receiving live traffic. If Blue is live, we deploy to Green. If Green is live, we deploy to Blue.

# Assuming Blue is currently live, deploy to Green
TARGET_ENV=green bundle exec cap production deploy:deploy_inactive

This command uses Capistrano to deploy the code to the Droplets designated as the "Green" environment. The `deploy_inactive` task temporarily tells Capistrano to target the Green servers.

Step 2: Run Smoke Tests and Health Checks

After the deployment to the inactive environment is complete, it's crucial to verify its health and functionality. This can involve:

  • Automated integration tests against the inactive environment's IP address or a staging URL.
  • Manual verification by QA or development teams.
  • Checking application logs for errors.
  • Ensuring the `/health` endpoint on the inactive environment returns a 200 OK status.

If any checks fail, you can immediately roll back by simply not switching the traffic. The currently live environment remains unaffected.

Step 3: Switch Traffic with the Load Balancer

Once you're confident the new version is stable, you switch the traffic. This is the critical step where the Load Balancer is reconfigured to point to the newly deployed environment.

# Assuming we just deployed to Green and Green is now ready to go live
bundle exec cap production deploy:switch_to_green

This command executes the `switch_to_green` task, which uses `doctl` to update the Load Balancer's forwarding rules. Traffic will now be directed to the Green Droplets. The switch is typically instantaneous or takes only a few seconds, depending on the Load Balancer's configuration.

Step 4: Monitor and Rollback (if necessary)

After the switch, closely monitor your application's performance, error rates, and user feedback. If critical issues arise, you can quickly roll back by switching the traffic back to the previous environment.

# If issues are found with Green, switch back to Blue
bundle exec cap production deploy:switch_to_blue

Handling Database Migrations

Database schema changes are the trickiest part of Blue-Green deployments. Since both environments share a single database instance, you cannot have incompatible schema versions running simultaneously. The standard approach is:

  • No Schema Changes: Deploy code that does not require database schema changes.
  • Backward-Compatible Schema Changes: Deploy a database migration that adds new columns or tables, or makes non-breaking changes. The new application code (deployed to the inactive environment) can then use these new structures. The old application code (still running on the live environment) will simply ignore the new columns/tables.
  • Deploy New Code: Deploy the application code that *uses* the new schema elements.
  • Remove Old Schema Elements: Once traffic is fully switched and you are confident, deploy a migration to remove old columns or tables. This migration should be deployed *after* the application code that relies on them has been deployed and is live.

This phased approach ensures that at no point is the database schema incompatible with the running application code in either the Blue or Green environment.

Considerations for Production

  • Database Backups: Always ensure robust database backup and recovery strategies are in place before any deployment.
  • Stateful Applications: If your application maintains state on the application servers (e.g., file uploads not stored in S3), ensure this state is managed or replicated across instances in both environments.
  • Session Management: Use a shared session store (like Redis or Memcached) if user sessions need to persist across traffic switches.
  • CI/CD Integration: Integrate these Capistrano tasks into your CI/CD pipeline (e.g., GitLab CI, GitHub Actions, Jenkins) for fully automated deployments.
  • Configuration Management: Use tools like Ansible or Chef to provision and configure your Droplets consistently for both Blue and Green environments.
  • Monitoring and Alerting: Implement comprehensive monitoring for both environments and the Load Balancer itself.
  • Rollback Strategy: Have a well-defined and tested rollback procedure.

By carefully orchestrating your infrastructure and deployment process, you can achieve reliable zero-downtime deployments for your Ruby applications on DigitalOcean.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 100 SEO and Schema Markup Plugins for Headless Decoupled Sites for Independent Web Developers and Indie Hackers
  • Top 5 SEO Growth Tactics to Explode Search Engine Visibility for SaaS to Boost Organic Search Growth by 200%
  • Top 100 Premium Newsletter and Subscription Business Models for Devs to Scale to $10,000 Monthly Recurring Revenue (MRR)

Categories

  • apache (1)
  • Business & Monetization (377)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (484)
  • DevOps (7)
  • DevOps & Cloud Scaling (918)
  • Django (1)
  • Migration & Architecture (66)
  • MySQL (1)
  • Performance & Optimization (626)
  • PHP (5)
  • Plugins & Themes (88)
  • Security & Compliance (524)
  • SEO & Growth (421)
  • Server (23)
  • Ubuntu (9)
  • WordPress (22)
  • WordPress Plugin Development (7)

Recent Posts

  • Top 100 Developer Tooling and Productivity SaaS Ideas to Launch in 2026 to Boost Organic Search Growth by 200%
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Minimize Server Costs and Load Overhead
  • Top 100 SEO and Schema Markup Plugins for Headless Decoupled Sites for Independent Web Developers and Indie Hackers
  • Top 5 SEO Growth Tactics to Explode Search Engine Visibility for SaaS to Boost Organic Search Growth by 200%
  • Top 100 Premium Newsletter and Subscription Business Models for Devs to Scale to $10,000 Monthly Recurring Revenue (MRR)
  • Top 100 Headless Decoupled Web App Ideas Built on Laravel API Backends in Highly Competitive Technical Niches

Top Categories

  • DevOps & Cloud Scaling (918)
  • Performance & Optimization (626)
  • Security & Compliance (524)
  • Debugging & Troubleshooting (484)
  • SEO & Growth (421)
  • Business & Monetization (377)

Our Products

  • School Management & Student Administration System
  • Integrated Hospital & Clinic Management System
  • Real Estate Directory & Agent Portal
  • Restaurant POS & Table Booking System
  • Retail Inventory POS & Billing System
  • Pharmacy Inventory & Clinic Billing System

Our Services

  • Vibe Engineering & AI Code Auditing Services
  • Prompt Engineering & "Vibe Coding" Workflow Consulting
  • AI-Augmented "Vibe Coding" & Rapid MVP Development
  • Figma to Shopify Liquid Theme Customization
  • Figma to WooCommerce Frontend Development
  • Figma to Magento 2 Theme Development

Copyright © 2026 · Vinay Vengala