Zero-Downtime Blue-Green Deployment Pipelines for WordPress Applications on Linode
Understanding the Blue-Green Deployment Model
Blue-Green deployment is a strategy that minimizes downtime and risk by running two identical production environments, referred to as “Blue” and “Green.” At any given time, only one environment is live, serving all production traffic. The other environment is idle, used for deployment and testing. Once the new version is deployed and validated in the idle environment, traffic is switched over, making the previously live environment the idle one for the next deployment.
Prerequisites for Linode WordPress Blue-Green Deployments
To implement this strategy effectively on Linode, you’ll need:
- Two identical Linode Compute Instances (or Kubernetes clusters, for more advanced setups). These instances will host your WordPress application.
- A load balancer capable of directing traffic to one of the two environments. Linode’s NodeBalancers are a suitable choice.
- A mechanism for synchronizing your WordPress database and media files between the Blue and Green environments.
- A robust deployment script or CI/CD pipeline to automate the deployment process.
- SSH access to your Linode instances.
Infrastructure Setup on Linode
Let’s assume you have two Linode Compute Instances, `wp-blue.example.com` and `wp-green.example.com`, both running a standard LAMP/LEMP stack. For simplicity, we’ll focus on a single-server setup per environment, but this can be scaled horizontally.
Database Synchronization Strategy
Database consistency is paramount. Several approaches exist:
- Master-Replica with Read-Only Writes to Blue: The primary database is on the “Blue” environment. The “Green” environment connects as a read replica. During deployment, you temporarily halt writes to Blue, wait for Green to catch up, deploy to Green, test, and then switch traffic. This is complex and can still involve a brief write freeze.
- Shared Database (with caution): Both environments connect to a single, external database instance. This simplifies synchronization but introduces a single point of failure and potential performance bottlenecks. It’s generally not recommended for true blue-green isolation.
- Database Snapshot and Restore: The most robust for isolation. Before deploying to Green, take a snapshot of the Blue database, restore it to a new database instance for Green, and then deploy. This ensures complete isolation but requires careful management of database credentials and connection strings.
- Replication Plugin (e.g., WP Migrate DB Pro with replication add-on): For more dynamic synchronization, tools like WP Migrate DB Pro can be configured for replication, pushing changes from Blue to Green.
For this guide, we’ll assume a Database Snapshot and Restore approach for maximum isolation, managed via a deployment script. This involves a dedicated database server or managed database service that both environments can connect to, but the data is snapshotted and restored per environment.
Media File Synchronization
WordPress media files (uploads) must also be consistent. Options include:
- rsync: Periodically rsync the
wp-content/uploadsdirectory from Blue to Green. - Object Storage (AWS S3, Linode Object Storage): Configure WordPress to use an object storage service for uploads. Both environments will then read from and write to the same central storage, eliminating synchronization issues. This is the preferred method for scalability and ease of management.
We’ll assume Object Storage is configured for media. If not, rsync would be a viable alternative, executed as part of the deployment script.
Load Balancer Configuration (Linode NodeBalancer)
A Linode NodeBalancer will sit in front of your two WordPress instances. It will manage SSL termination and distribute traffic. Initially, it will point exclusively to the “Blue” environment.
NodeBalancer Setup:
- Create a NodeBalancer in your Linode Cloud Manager.
- Add a NodeBalancer Listener on port 443 (HTTPS) with your domain’s SSL certificate.
- Add a Backend Node for your “Blue” instance (e.g.,
wp-blue.example.comon port 80). - Configure health checks (e.g., HTTP check on
/with expected status 200).
The NodeBalancer’s IP address will be your public-facing IP. DNS records for your domain should point to this IP.
Automating Deployments with Bash and WP-CLI
We’ll use a Bash script leveraging wp-cli for WordPress-specific tasks and standard Linux utilities for file management and server configuration.
Deployment Script Structure
Create a script, e.g., deploy.sh, on a separate deployment server or a management instance. This script will orchestrate the entire process.
#!/bin/bash # --- Configuration --- CURRENT_LIVE_ENV="blue" # 'blue' or 'green' TARGET_ENV="green" # The environment to deploy to BLUE_SERVER="[email protected]" GREEN_SERVER="[email protected]" DB_SNAPSHOT_PATH="/path/to/db_backups/wordpress_snapshot.sql.gz" # Path on deployment server DB_USER="wp_user" DB_PASS="wp_password" DB_NAME="wordpress_db" DB_HOST_BLUE="db_host_for_blue" # e.g., a separate DB server IP or managed DB endpoint DB_HOST_GREEN="db_host_for_green" # e.g., a separate DB server IP or managed DB endpoint WP_PATH="/var/www/html" # WordPress root on target server # --- Functions --- # Function to execute commands on a remote server remote_exec() { local server="$1" shift ssh "$server" "$@" } # Function to deploy code to the target environment deploy_code() { echo "Deploying code to $TARGET_ENV environment..." # Example: rsync your theme, plugin, and core files # Ensure you have a clean build artifact or Git checkout on the deployment server rsync -avz --delete ./build/ "$TARGET_ENV":"$WP_PATH/" --exclude 'wp-content/uploads' echo "Code deployment complete." } # Function to update database for the target environment update_database() { echo "Updating database for $TARGET_ENV environment..." # 1. Snapshot current live DB (if not using external snapshot) # For this example, we assume DB_SNAPSHOT_PATH is pre-populated. # If not, you'd add: # echo "Taking snapshot of $CURRENT_LIVE_ENV database..." # remote_exec $CURRENT_LIVE_ENV "wp db export --allow-root $WP_PATH/db_backup.sql" # scp $CURRENT_LIVE_ENV:$WP_PATH/db_backup.sql /tmp/db_backup.sql # gzip /tmp/db_backup.sql # DB_SNAPSHOT_PATH="/tmp/db_backup.sql.gz" # 2. Restore snapshot to target environment's DB echo "Restoring snapshot to $TARGET_ENV database..." # Ensure the target DB server is accessible and credentials are correct # This command assumes the target DB server is accessible from the target server # If DB_HOST_GREEN is different from the server itself, you'll need to adjust wp-cli config or use a remote DB tool remote_exec $TARGET_ENV "wp db import --allow-root $DB_SNAPSHOT_PATH --user=$DB_USER --password=$DB_PASS --database=$DB_NAME --host=$DB_HOST_GREEN" echo "Database restore complete." # 3. Perform any necessary WP-CLI updates (e.g., search-replace for URLs if needed) # Example: If your DB_HOST_GREEN is different and requires URL changes # remote_exec $TARGET_ENV "wp search-replace 'old.db.host' 'new.db.host' --all-tables --allow-root" echo "Running WP-CLI database updates..." remote_exec $TARGET_ENV "wp cache flush --allow-root" echo "Database updates complete." } # Function to perform health checks on the target environment health_check() { echo "Performing health checks on $TARGET_ENV..." # Basic check: curl the homepage and check for HTTP 200 local target_ip=$(dig +short $TARGET_ENV | head -n 1) # Get IP of target server if [ -z "$target_ip" ]; then echo "Error: Could not resolve IP for $TARGET_ENV." exit 1 fi # If using NodeBalancer, you'd check the NodeBalancer's IP or a specific health endpoint # For simplicity, we'll curl the server directly. In production, use NodeBalancer health checks. if curl --silent --fail http://$target_ip &>/dev/null; then echo "$TARGET_ENV is healthy." return 0 else echo "$TARGET_ENV failed health check." return 1 fi } # Function to switch traffic via NodeBalancer API (requires Linode API token) switch_traffic() { echo "Switching traffic to $TARGET_ENV..." # This is a placeholder. You'd use the Linode API or CLI to update NodeBalancer backend configurations. # Example using linode-cli (install with: pip install linode-cli) # NODEBALANCER_ID="your-nodebalancer-id" # BLUE_NODE_ID="your-blue-node-id" # GREEN_NODE_ID="your-green-node-id" # # echo "Disabling Blue Node..." # linode-cli nodebalancers configs update $NODEBALANCER_ID --configs $(linode-cli nodebalancers configs list $NODEBALANCER_ID --json | jq '.[] | select(.label=="Default Config") | .id') --nodes $(linode-cli nodebalancers configs nodes list $NODEBALANCER_ID --configs $(linode-cli nodebalancers configs list $NODEBALANCER_ID --json | jq '.[] | select(.label=="Default Config") | .id') --json | jq --argjson green_id $GREEN_NODE_ID '.[] | select(.id != $green_id)' ) # # echo "Enabling Green Node..." # linode-cli nodebalancers configs update $NODEBALANCER_ID --configs $(linode-cli nodebalancers configs list $NODEBALANCER_ID --json | jq '.[] | select(.label=="Default Config") | .id') --nodes $(linode-cli nodebalancers configs nodes list $NODEBALANCER_ID --configs $(linode-cli nodebalancers configs list $NODEBALANCER_ID --json | jq '.[] | select(.label=="Default Config") | .id') --json | jq --argjson green_id $GREEN_NODE_ID '.[] | select(.id == $green_id)' ) # # For manual switching: echo "Manual traffic switch required: Update NodeBalancer configuration to point to $TARGET_ENV." echo "Once confirmed, update CURRENT_LIVE_ENV and TARGET_ENV in this script for the next deployment." } # --- Main Deployment Flow --- echo "Starting Blue-Green Deployment..." echo "Current Live Environment: $CURRENT_LIVE_ENV" echo "Target Deployment Environment: $TARGET_ENV" # 1. Deploy Code deploy_code # 2. Update Database update_database # 3. Health Check if health_check; then # 4. Switch Traffic (Automated or Manual) switch_traffic echo "Deployment to $TARGET_ENV successful!" echo "Remember to update the CURRENT_LIVE_ENV and TARGET_ENV variables in deploy.sh for the next cycle." else echo "Deployment failed health checks. No traffic switched." exit 1 fi exit 0
Explanation of the Script:
- Configuration Variables: Define your server IPs, SSH users, database credentials, and paths. Crucially,
CURRENT_LIVE_ENVandTARGET_ENVdictate the flow. remote_exec: A helper function to run commands over SSH.deploy_code: Usesrsyncto push your application code (themes, plugins, core files) to the target server. Excludewp-content/uploadsif using object storage.update_database: This is the most critical part. It assumes you have a database snapshot (.sql.gz) ready. It then useswp-clito import this snapshot into the target environment’s database, specifying the correct host and credentials. It also flushes the cache.health_check: A basic check to see if the target server is responding. In a production scenario, you’d want more comprehensive checks (e.g., checking specific admin pages, API endpoints, or relying on the NodeBalancer’s built-in health checks).switch_traffic: This is a placeholder for interacting with the Linode API to update the NodeBalancer. The example shows how you might uselinode-cli. For manual deployments, you’d instruct the user to perform this step via the Linode Cloud Manager.
Manual Deployment Workflow Example
Let’s walk through a manual deployment from Blue to Green:
- Initial State: NodeBalancer directs all traffic to
wp-blue.example.com.CURRENT_LIVE_ENV="blue",TARGET_ENV="green"indeploy.sh. - Prepare Green Environment: Ensure
wp-green.example.comis set up identically to Blue (same WordPress version, plugins, themes). - Take Database Snapshot: On the Blue server (or via your DB management tool), export the database:
ssh [email protected] "wp db export --allow-root /var/www/html/db_backup_$(date +%Y%m%d%H%M%S).sql"
Then, download this snapshot to your deployment server:scp [email protected]:/var/www/html/db_backup_*.sql.gz /path/to/db_backups/
UpdateDB_SNAPSHOT_PATHindeploy.shto point to this new snapshot. - Run Deployment Script: Execute the script:
./deploy.sh
This will:- rsync code to
wp-green.example.com. - Import the database snapshot into the Green environment’s database.
- Perform basic health checks on
wp-green.example.com.
- rsync code to
- Manual Traffic Switch: If health checks pass, log into your Linode Cloud Manager. Navigate to your NodeBalancer. Edit the backend configuration to disable the “Blue” node and enable the “Green” node.
- Post-Switch Verification: Browse your website, test critical functionalities, and check the WordPress admin area on the Green environment.
- Update Script Variables: Once confident, SSH into your deployment server and edit
deploy.sh:- Change
CURRENT_LIVE_ENV="green" - Change
TARGET_ENV="blue"
- Change
- Next Deployment: The next time you run
deploy.sh, it will deploy to “Blue,” and you’ll switch traffic back.
Advanced Considerations and Enhancements
CI/CD Integration
Integrate this script into a CI/CD pipeline (e.g., GitLab CI, GitHub Actions, Jenkins). The pipeline would trigger on code commits, build artifacts, run tests, and then execute the deploy.sh script. The traffic switching step might require API tokens for automated NodeBalancer manipulation.
Database Schema Migrations
For database schema changes, you need a strategy that works across both environments during the transition. Tools like:
- WP Migrate DB Pro with Schema Add-on: Can handle schema diffs and migrations.
- Custom Migration Scripts: Execute SQL scripts via
wp-clion the target environment after the data import but *before* traffic switch.
Ensure your migration process is idempotent and tested thoroughly.
Rollback Strategy
A rollback is essentially performing the deployment script again, but targeting the previously live environment. If the new “Green” deployment fails after traffic switch, you would:
- Update
deploy.shto target “Blue” again (TARGET_ENV="blue"). - Ensure the “Blue” database is reverted to its state before the failed deployment (this is where having isolated DB snapshots is crucial). You might need to restore an older snapshot to Blue.
- Run
deploy.sh. - Switch traffic back to “Blue” via the NodeBalancer.
WordPress Multisite
For Multisite, the complexity increases. Database snapshots and restores become more involved. Ensure your wp-cli commands and sync strategies account for the entire network.
Kubernetes and Managed Services
For larger-scale WordPress deployments, consider using Linode Kubernetes Engine (LKE). Blue-Green deployments can be implemented using Kubernetes Ingress controllers (like Nginx Ingress or Traefik) and manipulating service weights or deployment strategies. Database management would typically involve managed database services or robust stateful set configurations with backup/restore automation.