Achieve Zero-Downtime Deployments with DigitalOcean and GitHub
Building a Scalable Infrastructure
DigitalOcean is a popular platform that provides developers with a robust infrastructure to host their applications. In this guide, we’ll explore how to leverage DigitalOcean, GitHub, and Docker to achieve zero-downtime deployments, ensuring your services remain available even during updates.
Infrastructure Overview
Our demo infrastructure consists of two $5/month droplets, one $10/month load balancer, and a free container registry. DigitalOcean charges by the hour, so you can create and tear down the infrastructure without incurring significant costs.
Deployment Timeline
Here’s a high-level overview of the deployment process:
- Two service instances (API 1 and API 2) run V1 of the codebase.
- The load balancer sends health checks to both instances.
- When a deployment occurs, the shutdown endpoint is called, and the health checks fail.
- The instance is removed from the load balancer, updated with V2 of the codebase, and brought back up.
- The load balancer starts routing requests to the updated instance.
Key Takeaways
- There’s always at least one instance available to handle requests.
- An instance can serve responses while requests are being routed to it.
Getting Started
To follow along, create a DigitalOcean account and a GitHub account if you don’t already have one. Since I’m a Node.js developer, this guide uses a basic Node.js service (Docker), but you can adapt it to your preferred platform.
Create Tokens and SSH Keys
Generate two DigitalOcean API tokens: “GitHub Actions” and “Droplet Registry Pull.” Create an SSH key for secure communication with your droplets.
Create Droplets and Load Balancer
Using the DigitalOcean interface, create two droplets with Debian 10 and a Basic $5/month plan. Create a load balancer with a Small $10/month plan, ensuring it’s in the same region as your droplets.
Create Container Registry and GitHub Repository
Create a container registry using the DigitalOcean UI. Set up a new GitHub repository and configure a local directory to point to it.
Configure GitHub Actions and Deployment
Create a .github/workflows/main-deploy.yml
file to describe the deployment process. This file contains three jobs: build, deploy-api-1, and deploy-api-2. The build job builds the Docker container and pushes it to the container registry. The deploy-api-1 and deploy-api-2 jobs connect to your droplets, pull the new Docker image, shut down the service, and wait for the health checks to fail.
Run Your First Deploy
Merge the file changes to the GitHub main branch, and the deployment process should kick off. Monitor the deployment process in the GitHub Actions tab.
Troubleshooting and Monitoring
If you encounter issues, modify the previous steps and commit the changes again to the main branch. Monitor the application health using DigitalOcean graphs, which display the health of the application over time.
Achieving Zero-Downtime Deployments
With this setup, you’ve successfully achieved zero-downtime deployments. The load balancer ensures that requests are routed to available instances, even during deployments. Make a load-balanced request to verify that the application is running in a redundant manner.
Productionalizing Your Infrastructure
While this guide provides a solid foundation, there are additional steps you should take to make your infrastructure more secure, such as:
- Exposing the shutdown endpoint on a different port
- Renaming the healthcheck endpoint
- Forwarding HTTPS requests from the load balancer to HTTP on the APIs
- Using a non-root account on the droplets
By following these steps, you’ll have a scalable and secure infrastructure that ensures zero-downtime deployments.