• 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 C++ Applications on DigitalOcean

Zero-Downtime Blue-Green Deployment Pipelines for C++ Applications on DigitalOcean

Understanding the Blue-Green Deployment Pattern

The blue-green deployment strategy is a method for releasing software that minimizes downtime and risk. 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 live version of the application, while the other (Green) is idle. To deploy a new version, we deploy it to the idle environment (Green), test it thoroughly, and then switch the router to direct all incoming traffic to the Green environment. The Blue environment then becomes idle and can be used for the next deployment. This approach ensures that if any issues arise with the new deployment, we can instantly roll back by switching traffic back to the Blue environment.

Prerequisites for C++ Blue-Green on DigitalOcean

Before implementing blue-green deployments for your C++ application on DigitalOcean, ensure you have the following in place:

  • DigitalOcean Account: With sufficient credits or a subscription.
  • Droplets: At least two identical Droplets for each environment (Blue and Green). These should be configured with the same operating system, installed dependencies, and network settings.
  • Load Balancer: A DigitalOcean Load Balancer to manage traffic routing between the Blue and Green environments.
  • CI/CD Pipeline: A robust Continuous Integration and Continuous Deployment pipeline. We’ll use GitLab CI/CD for this example, but Jenkins, GitHub Actions, or CircleCI are also viable.
  • Build Artifacts: A mechanism to store and retrieve your compiled C++ application binaries. This could be a private Git repository, an artifact repository like Nexus or Artifactory, or even a simple object storage solution like DigitalOcean Spaces.
  • Configuration Management: Tools like Ansible or Chef to ensure consistent setup across all Droplets.
  • Health Checks: A defined health check endpoint in your C++ application that the load balancer can query.

Setting Up the DigitalOcean Infrastructure

We’ll need two sets of Droplets, one for the Blue environment and one for the Green. For simplicity, let’s assume we’re using Ubuntu 22.04 LTS. We’ll also set up a DigitalOcean Load Balancer.

1. Provisioning Droplets:

You can provision Droplets manually via the DigitalOcean control panel or, more practically for infrastructure as code, using Terraform or the DigitalOcean API. For this example, let’s assume you have two Droplets tagged as ‘blue-app-01’ and ‘blue-app-02’ for the Blue environment, and ‘green-app-01’ and ‘green-app-02’ for the Green environment. These Droplets should have a common tag, e.g., ‘cpp-app-server’.

2. Configuring the Load Balancer:

Create a DigitalOcean Load Balancer. Configure it to forward traffic on port 80 (or your application’s port) to your application servers. Initially, you’ll add the Droplets from one environment (e.g., Blue) to the load balancer’s target pool. We’ll define health checks to ensure traffic is only sent to healthy instances.

Example Load Balancer configuration (conceptual, actual configuration is via DO UI/API):

Target Pool Name: cpp-app-pool

Protocol: HTTP

Port: 80

Health Check:

  • Protocol: HTTP
  • Port: 80
  • Path: /healthz (assuming your C++ app exposes this endpoint)
  • Check Interval: 10 seconds
  • Response Timeout: 5 seconds
  • Healthy Threshold: 2
  • Unhealthy Threshold: 3

Initially, add the IP addresses of your Blue environment Droplets to this target pool.

C++ Application Structure and Health Check

Your C++ application needs to be designed to run as a service and expose a health check endpoint. For this example, let’s assume a simple HTTP server using `libmicrohttpd` or a similar lightweight library.

Example Health Check Endpoint (Conceptual C++):

#include <microhttpd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define PORT 8080 // Or whatever port your app uses internally

static int
handle_request (void *cls, struct MHD_Connection *connection,
                const char *url, const char *method, const char *version,
                const char *upload_data, size_t *upload_data_size, void **con_cls)
{
    if (strcmp (url, "/healthz") == 0) {
        const char *response_string = "OK";
        struct MHD_Response *response;
        int ret;

        response = MHD_create_response_from_buffer (strlen (response_string),
                                                    (void *) response_string, MHD_RESPMem_PERSISTENT);
        if (!response)
            return MHD_NO;

        ret = MHD_queue_basic_auth_response (connection, "200", "OK", NULL, NULL, NULL, NULL);
        if (ret != MHD_YES) {
            MHD_destroy_response (response);
            return MHD_NO;
        }
        ret = MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain");
        if (ret != MHD_YES) {
            MHD_destroy_response (response);
            return MHD_NO;
        }

        ret = MHD_queue_response (connection, 200, response);
        MHD_destroy_response (response); // response is queued, MHD takes ownership
        return ret;
    }

    // Handle other requests...
    const char *response_string = "Not Found";
    struct MHD_Response *response;
    int ret;

    response = MHD_create_response_from_buffer (strlen (response_string),
                                                (void *) response_string, MHD_RESPMem_PERSISTENT);
    if (!response)
        return MHD_NO;

    ret = MHD_queue_basic_auth_response (connection, "404", "Not Found", NULL, NULL, NULL, NULL);
    if (ret != MHD_YES) {
        MHD_destroy_response (response);
        return MHD_NO;
    }
    ret = MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain");
    if (ret != MHD_YES) {
        MHD_destroy_response (response);
        return MHD_NO;
    }

    ret = MHD_queue_response (connection, 404, response);
    MHD_destroy_response (response);
    return ret;
}

int main (void)
{
    struct MHD_Daemon *daemon;

    daemon = MHD_start_daemon (MHD_NO_OPTS, PORT, NULL, NULL,
                               &handle_request, NULL, MHD_OPTION_END);
    if (daemon == NULL)
        return 1;

    printf("Server started on port %d\n", PORT);

    // Keep the server running...
    getchar ();

    MHD_stop_daemon (daemon);

    return 0;
}

This C++ code snippet demonstrates a basic HTTP server that responds with “OK” to requests on the /healthz path. You would compile this and ensure it runs on your Droplets, listening on the port configured in your load balancer (e.g., 80).

CI/CD Pipeline with GitLab CI/CD

We’ll use GitLab CI/CD to automate the build, test, and deployment process. The pipeline will handle building the C++ application, pushing artifacts, and orchestrating the blue-green switch.

1. GitLab CI/CD Configuration (.gitlab-ci.yml):

variables:
  APP_NAME: my-cpp-app
  DO_TOKEN: $DIGITALOCEAN_TOKEN # GitLab CI/CD variable for DigitalOcean API token
  DO_SSH_KEY: $DIGITALOCEAN_SSH_KEY # GitLab CI/CD variable for SSH private key
  DO_SSH_USER: root
  BUILD_DIR: build
  ARTIFACT_PATH: /opt/artifacts/${CI_COMMIT_REF_SLUG}/${CI_COMMIT_SHA}/${APP_NAME}
  BLUE_SERVERS: "192.168.1.10,192.168.1.11" # Replace with actual IPs or use DO tags
  GREEN_SERVERS: "192.168.2.10,192.168.2.11" # Replace with actual IPs or use DO tags
  HEALTH_CHECK_PORT: 80 # Application port, not SSH port
  HEALTH_CHECK_PATH: "/healthz"

stages:
  - build
  - deploy_green
  - test_green
  - promote_green
  - rollback # Optional, for manual rollback

.build_template: &build_template
  stage: build
  image: ubuntu:22.04 # Or a custom Docker image with your C++ toolchain
  script:
    - apt-get update -y && apt-get install -y build-essential cmake git openssh-client
    - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
    - cmake ..
    - make
    - cd ..
    - echo "Build successful. Artifacts are in ${BUILD_DIR}"
    # In a real scenario, you'd package this artifact (e.g., tar.gz)
    # and upload it to an artifact repository or DO Spaces.
    # For simplicity, we'll assume direct deployment via SSH for now.
  artifacts:
    paths:
      - ${BUILD_DIR}/${APP_NAME} # Assuming your executable is named APP_NAME

build_app:
  <<: *build_template
  script:
    - apt-get update -y && apt-get install -y build-essential cmake git openssh-client
    - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
    - cmake ..
    - make
    - cd ..
    - echo "Build successful. Artifacts are in ${BUILD_DIR}/${APP_NAME}"
    # Package the executable for deployment
    - tar -czvf ${APP_NAME}.tar.gz ${BUILD_DIR}/${APP_NAME}
  artifacts:
    paths:
      - ${APP_NAME}.tar.gz

.deploy_template: &deploy_template
  stage: deploy_green # Default to deploy_green, can be overridden
  image: ubuntu:22.04
  before_script:
    - apt-get update -y && apt-get install -y openssh-client tar
    - eval $(ssh-agent -s)
    - echo "$DO_SSH_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "Host *\n  StrictHostKeyChecking no\n  IdentityFile ~/.ssh/id_rsa" >> ~/.ssh/config
    - ssh-keyscan digitalocean.com >> ~/.ssh/known_hosts # Or specific IPs
  script:
    - echo "Deploying to $TARGET_SERVERS"
    - IFS=',' read -ra SERVERS <<< "$TARGET_SERVERS"
    - for server in "${SERVERS[@]}"; do
        echo "Deploying to $server..."
        # Ensure target directory exists
        ssh ${DO_SSH_USER}@$server "mkdir -p ${ARTIFACT_PATH}"
        # Transfer artifact
        scp ${APP_NAME}.tar.gz ${DO_SSH_USER}@$server:${ARTIFACT_PATH}/
        # Extract and replace old binary
        ssh ${DO_SSH_USER}@$server "tar -xzf ${ARTIFACT_PATH}/${APP_NAME}.tar.gz -C ${ARTIFACT_PATH} && mv ${ARTIFACT_PATH}/${APP_NAME} /usr/local/bin/${APP_NAME} && rm -rf ${ARTIFACT_PATH}"
        # Ensure the new binary is executable and restart the service
        ssh ${DO_SSH_USER}@$server "chmod +x /usr/local/bin/${APP_NAME} && systemctl restart ${APP_NAME}"
      done

deploy_green:
  <<: *deploy_template
  stage: deploy_green
  variables:
    TARGET_SERVERS: $GREEN_SERVERS
  only:
    - main # Or your deployment branch

.health_check_template: &health_check_template
  stage: test_green
  image: curlimages/curl:latest
  script:
    - echo "Checking health of Green environment on $TARGET_SERVERS"
    - IFS=',' read -ra SERVERS <<< "$TARGET_SERVERS"
    - for server in "${SERVERS[@]}"; do
        # Construct the health check URL. Assumes app is accessible via LB or directly.
        # If using LB, this check should target the LB's IP/hostname.
        # For direct server checks, you'd need to know the server's public IP.
        # For simplicity, we'll assume direct check to server IP on the app port.
        HEALTH_URL="http://${server}:${HEALTH_CHECK_PORT}${HEALTH_CHECK_PATH}"
        echo "Checking ${HEALTH_URL}..."
        # Retry mechanism for health check
        for i in {1..10}; do
          curl -s --fail "$HEALTH_URL" && echo "Health check passed for $server." && break
          echo "Health check failed for $server. Retrying in 5s... ($i/10)"
          sleep 5
          if [ $i -eq 10 ]; then
            echo "Health check failed for $server after multiple retries. Failing pipeline."
            exit 1
          fi
        done
      done

check_green_health:
  <<: *health_check_template
  variables:
    TARGET_SERVERS: $GREEN_SERVERS
  needs:
    - deploy_green
  allow_failure: false # Pipeline fails if health check fails

.promote_template: &promote_template
  stage: promote_green
  image: ubuntu:22.04
  script:
    - echo "Switching traffic to Green environment..."
    # This step requires interaction with DigitalOcean Load Balancer API.
    # You'd use `doctl` or a custom script with the DO API.
    # Example using doctl (requires doctl to be installed and configured):
    # 1. Get LB ID
    # 2. Get current target pool ID
    # 3. Get Green target pool ID (or create one if not pre-configured)
    # 4. Update LB to use Green target pool
    # For simplicity, we'll simulate this with a manual step or a placeholder.
    - echo "Manual step: Update DigitalOcean Load Balancer to point to Green servers ($GREEN_SERVERS)."
    - echo "Once confirmed, manually trigger the next job or merge."
    # Example conceptual doctl commands (replace with actual IDs and logic):
    # LB_ID=$(doctl compute load-balancer list --format ID --no-header)
    # GREEN_POOL_ID=$(doctl compute load-balancer target-pool list $LB_ID --format ID --no-header | grep "green-pool") # Assuming a pre-configured green pool
    # doctl compute load-balancer update $LB_ID --target-pools $GREEN_POOL_ID
    - echo "Traffic switched to Green."
  when: manual # Requires manual trigger to prevent accidental promotion

promote_to_green:
  <<: *promote_template
  needs:
    - check_green_health

# Optional: Rollback job
rollback_to_blue:
  stage: rollback
  image: ubuntu:22.04
  script:
    - echo "Rolling back traffic to Blue environment..."
    # Similar to promote, this involves updating the LB to point back to Blue.
    - echo "Manual step: Update DigitalOcean Load Balancer to point to Blue servers ($BLUE_SERVERS)."
    - echo "Once confirmed, manually trigger the next job or merge."
  when: manual

Explanation of the GitLab CI/CD Pipeline:

  • Variables: Define application name, DigitalOcean credentials (stored as protected CI/CD variables), server IPs, and artifact paths.
  • Stages: The pipeline is divided into logical stages: build, deploy to the new environment (Green), test the new environment, and promote it to production.
  • Build Stage: Compiles the C++ application using CMake and Make. It then packages the executable into a tarball. In a production setup, this artifact would be uploaded to a dedicated artifact repository.
  • Deploy Stage (deploy_green): This job uses SSH to connect to the Green environment Droplets. It transfers the compiled artifact, extracts it, replaces the existing binary (if any), makes it executable, and restarts the application service (assuming you have a systemd service file for your C++ app).
  • Health Check Stage (check_green_health): This job uses curl to ping the /healthz endpoint on each server in the Green environment. It includes a retry mechanism to account for brief startup delays. If any health check fails after multiple retries, the pipeline fails, preventing promotion.
  • Promote Stage (promote_to_green): This is a manual job. It's designed to be triggered by a human operator after verifying the Green environment is healthy. This job would interact with the DigitalOcean Load Balancer API (e.g., using doctl or a custom script) to switch traffic from the Blue environment to the Green environment.
  • Rollback Stage (rollback_to_blue): Another manual job, intended for emergency rollbacks. It would reverse the load balancer configuration to point back to the Blue environment.

Orchestrating the Blue-Green Switch

The critical part of the blue-green deployment is the traffic switch. This is managed by the DigitalOcean Load Balancer. The pipeline needs to interact with the Load Balancer's API to update its target pools.

1. Using doctl:

The DigitalOcean command-line interface (doctl) is a convenient tool for this. You'll need to install doctl on your GitLab Runner and configure it with your DigitalOcean API token.

Prerequisites for doctl:

  • Install doctl on your GitLab Runner.
  • Generate a DigitalOcean API token with read/write permissions.
  • Configure doctl on the runner: doctl auth init.

Conceptual doctl commands for switching traffic:

# Assume LB_ID is known or fetched
LB_ID="your-load-balancer-id"

# --- To switch to Green ---
# 1. Get the ID of the target pool associated with the Green environment.
#    This assumes you have pre-configured target pools for Blue and Green,
#    or you dynamically create/update them.
GREEN_POOL_ID=$(doctl compute load-balancer target-pool list $LB_ID --format ID --no-header | grep "green-pool-identifier") # Adjust grep pattern

# 2. Update the load balancer to use the Green target pool.
#    This command might vary based on how your LB is configured (e.g., multiple pools).
#    If you have a single pool, you might replace the existing one.
#    If you have multiple pools, you might update the 'forwarding rules'.
doctl compute load-balancer update $LB_ID --target-pools $GREEN_POOL_ID

# --- To switch back to Blue (Rollback) ---
# 1. Get the ID of the target pool associated with the Blue environment.
BLUE_POOL_ID=$(doctl compute load-balancer target-pool list $LB_ID --format ID --no-header | grep "blue-pool-identifier") # Adjust grep pattern

# 2. Update the load balancer to use the Blue target pool.
doctl compute load-balancer update $LB_ID --target-pools $BLUE_POOL_ID

You would integrate these doctl commands into your promote_to_green and rollback_to_blue jobs in the .gitlab-ci.yml file. Remember to handle the retrieval of LB_ID and the correct POOL_IDs dynamically or through configuration.

Managing C++ Service Lifecycle

For seamless deployments, your C++ application must be managed as a system service. This allows for easy starting, stopping, and restarting during deployments.

Example Systemd Service File (/etc/systemd/system/my-cpp-app.service):

[Unit]
Description=My C++ Application Service
After=network.target

[Service]
User=your_app_user # Recommended to run as a non-root user
Group=your_app_group
WorkingDirectory=/usr/local/bin/
ExecStart=/usr/local/bin/my-cpp-app --port 80 # Your application executable and arguments
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

After creating this file on your Droplets, you would use systemctl enable my-cpp-app to start it on boot and systemctl restart my-cpp-app to restart it during deployment. The CI/CD pipeline script includes these commands.

Advanced Considerations and Best Practices

1. Database Migrations: Handling database schema changes during blue-green deployments requires careful planning. A common strategy is to ensure backward compatibility: deploy the new application code that can work with the old schema, perform the migration, and then deploy the new application code that relies on the new schema. Alternatively, use a phased migration approach where the database schema is updated before the application code.

2. Configuration Management: Use tools like Ansible to provision and configure your Droplets consistently. This ensures that both Blue and Green environments are identical, reducing the risk of deployment failures due to configuration drift.

3. Canary Releases: For even lower risk, consider a canary release strategy. After deploying to Green and testing, instead of switching 100% of traffic, gradually shift a small percentage (e.g., 1%, 5%, 10%) to the Green environment. Monitor performance and error rates closely. If all looks good, increase the percentage until 100% of traffic is on Green.

4. Automated Testing: Beyond basic health checks, implement comprehensive automated tests (unit, integration, end-to-end) that run against the Green environment before promotion. This significantly increases confidence in the new release.

5. Infrastructure as Code (IaC): Manage your DigitalOcean infrastructure (Droplets, Load Balancers) using tools like Terraform. This allows you to version control your infrastructure, making it reproducible and easier to manage.

6. Artifact Management: Instead of directly SCP'ing binaries, use a dedicated artifact repository (e.g., Nexus, Artifactory, or even DigitalOcean Spaces with proper versioning). This provides better traceability and management of your build artifacts.

By implementing these strategies, you can achieve robust, zero-downtime blue-green deployments for your C++ applications on DigitalOcean, enabling a more agile and reliable release process.

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

  • How to securely integrate ActiveCampaign automation API endpoints into WordPress custom plugins using WordPress Settings API
  • Debugging and Resolving complex REST API CORS authorization failures issues during heavy concurrent database traffic
  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to online course lessons
  • WordPress Development Recipe: Staggered database writes for high-volume custom form fields using Cron API (wp_schedule_event)
  • Step-by-Step Guide: Offloading high-frequency knowledge base document categories metadata writes to a Redis KV store

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (42)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (116)
  • WordPress Plugin Development (126)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • How to securely integrate ActiveCampaign automation API endpoints into WordPress custom plugins using WordPress Settings API
  • Debugging and Resolving complex REST API CORS authorization failures issues during heavy concurrent database traffic
  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to online course lessons

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala