Deploying a monolithic application isn’t about when you deploy, it’s about how you avoid becoming a single point of failure during the update.
Let’s look at how this plays out. Imagine you have a single, massive application running on a fleet of servers. Your users are hitting these servers constantly. You need to push a new version, but a botched deployment means downtime, angry customers, and probably a late night for you.
Here’s a simplified view of your current setup:
+-----------------+ +-----------------+ +-----------------+
| User Traffic | --> | Load Balancer| --> | App Server 1 |
+-----------------+ +-----------------+ +-----------------+
| +-----------------+
| -->| App Server 2 |
| +-----------------+
| +-----------------+
| -->| App Server 3 |
+-----------------+
You’ve got three app servers behind a load balancer. Traffic is distributed evenly.
Rolling Deployments: The Gradual Handover
The core idea of a rolling deployment is to update your application one server at a time, or in small batches, while the rest of the fleet continues to serve traffic.
How it works:
- Take one server out: The load balancer stops sending traffic to a single app server.
- Update it: You deploy the new version of your application to that server.
- Test it (briefly): You might run a quick health check or a few basic tests against this newly updated server.
- Put it back in: Once you’re reasonably confident, you tell the load balancer to start sending traffic to it again.
- Repeat: You pick the next server and repeat the process.
Example Scenario:
Let’s say you have 10 app servers (app-01 through app-10) behind a load balancer.
- Step 1: You start with
app-01. The load balancer removes it from the rotation. - Step 2: You deploy version
1.1.0toapp-01. - Step 3:
app-01passes its health checks. - Step 4:
app-01is added back to the load balancer’s rotation. - Step 5: You then take
app-02out, deploy1.1.0to it, health check, and add it back. - This continues until all 10 servers are running
1.1.0.
What this looks like in practice (conceptually, using a tool like Ansible or a CI/CD pipeline):
# Pseudocode for a rolling update
SERVERS="app-01 app-02 app-03 app-04 app-05" # Your fleet
NEW_VERSION="1.1.0"
for SERVER in $SERVERS; do
echo "Taking $SERVER out of rotation..."
# Command to tell your load balancer to stop sending traffic to $SERVER
# e.g., aws elb deregister-targets --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-tg/abcdef1234567890 --targets Id=$SERVER
echo "Deploying $NEW_VERSION to $SERVER..."
# Command to deploy your new application artifact to $SERVER
# e.g., scp myapp-$NEW_VERSION.tar.gz user@$SERVER:/opt/myapp/
# ssh user@$SERVER "tar xzf /opt/myapp/myapp-$NEW_VERSION.tar.gz -C /opt/myapp/ && rm /opt/myapp/current && ln -s /opt/myapp/$NEW_VERSION /opt/myapp/current && systemctl restart myapp.service"
echo "Performing health checks on $SERVER..."
# Command to check if the application on $SERVER is healthy
# e.g., curl -s http://$SERVER:8080/health | grep OK
if [ $? -eq 0 ]; then
echo "$SERVER is healthy. Adding back to rotation..."
# Command to tell your load balancer to add $SERVER back
# e.g., aws elb register-targets --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-tg/abcdef1234567890 --targets Id=$SERVER
else
echo "ERROR: $SERVER failed health checks! Manual intervention required."
# Potentially stop the deployment and revert the previous server
exit 1
fi
sleep 5 # Give the system a moment to stabilize
done
echo "Rolling deployment complete. All servers running $NEW_VERSION."
The magic: At any given moment, you have a mix of old and new versions running. If the new version has a critical bug, only a fraction of your users are affected. You can quickly roll back by repeating the process with the old version.
Blue-Green Deployments: The Instant Switchover
Blue-Green is a strategy where you maintain two identical production environments, "Blue" and "Green." At any time, one environment is live (serving user traffic), and the other is idle.
How it works:
- The Setup: You have your current production environment (let’s call it "Blue") serving all live traffic. You also have an identical, but currently idle, environment ("Green").
- Deploy to Idle: You deploy your new application version to the "Green" environment.
- Test: You thoroughly test the "Green" environment. Since it’s not serving live traffic, you can be more aggressive with your testing.
- The Switch: When you’re ready, you simply redirect all incoming traffic from the "Blue" environment to the "Green" environment. This is usually done at the load balancer or DNS level.
- Rollback: If something goes wrong, you simply redirect traffic back to the "Blue" environment. The "Green" environment remains untouched with the new version, ready to be reverted to if needed.
Example Scenario:
- Initial State: All user traffic goes to the "Blue" environment (servers
blue-01,blue-02,blue-03). The "Green" environment (green-01,green-02,green-03) is idle. - Deployment: You deploy version
1.1.0togreen-01,green-02, andgreen-03. - Testing: You run extensive integration tests, performance tests, and user acceptance tests against the "Green" environment.
- The Switch: You configure your load balancer (or DNS) to send all new incoming traffic to the "Green" environment. Now, users are hitting
green-01,green-02,green-03. - Post-Switch: The "Blue" environment (
blue-01,blue-02,blue-03) is now idle but still running the old version (1.0.0). You can keep it around for a while as an immediate rollback target. If you’re confident, you can then tear down or update the "Blue" environment to prepare for the next deployment.
What this looks like in practice (conceptually, using a load balancer with distinct target groups):
+-----------------+ +-----------------+
| User Traffic | --> | Load Balancer|
+-----------------+ +-----------------+
/ \
/ \
/ \
(Active) (Idle/Staging)
+---------+ +---------+
| Blue | | Green |
| Env | | Env |
+---------+ +---------+
| blue-01 | | green-01|
| blue-02 | | green-02|
| blue-03 | | green-03|
+---------+ +---------+
The magic: This offers the fastest possible rollback. It’s a near-instantaneous cutover. The downside is that you need to maintain two full sets of infrastructure, which doubles your resource costs (though often this is offset by reduced downtime risk and faster deployment cycles).
The "One Thing" Most People Don’t Know
While both strategies aim to minimize downtime and risk, many teams overlook the critical importance of stateful services. If your application relies on a database, cache, or message queue, simply switching application versions isn’t enough. You need a strategy for migrating the data and ensuring backward compatibility of your data schema. A rolling deployment might allow for a gradual database schema migration, but a blue-green deployment typically requires the new application version to be backward compatible with the existing data and the old application version to be forward compatible with the new data state (or vice versa, depending on your migration path). This is often the hardest part of any deployment strategy.
With rolling deployments, you’ll eventually hit a point where all servers are updated. With blue-green, your next step is often deciding what to do with the now-idle "Blue" environment – either tear it down or prepare it for the next "Green" deployment.