Orchestrating High Availability via Pulumi Load Balancer Architectures

The transition from a single-server deployment to a distributed, high-availability architecture represents a critical evolution in the lifecycle of any professional application. A single server serves as a catastrophic single point of failure; if the underlying hardware fails, the operating system crashes, or a software bug triggers a kernel panic, the entire application goes offline immediately. Furthermore, a lone server possesses a finite ceiling for resource consumption, meaning that sudden traffic spikes lead to latency degradation or complete service outages. The architectural remedy for these vulnerabilities is the implementation of a Load Balancer. A Load Balancer acts as the intelligent entry point for all incoming network traffic, distributing requests across a pool of multiple backend application servers. This ensures that no single server is overwhelmed and that the failure of an individual node does not result in application downtime. When integrated with Infrastructure as Code (IaC) tools like Pulumi, the deployment of these complex network topologies becomes repeatable, version-controlled, and programmable across various cloud providers including Hetzner Cloud, AWS, and Azure.

Infrastructure Requirements for Load Balanced Environments

Before deploying a load balancer via Pulumi, a specific set of environment prerequisites must be established to ensure the toolchain can communicate with the cloud provider and execute the desired state.

For those deploying specifically within the Hetzner Cloud ecosystem using TypeScript, the following technical requirements are mandatory:

  • Node.js 18 or later: This provides the necessary runtime environment for executing TypeScript code and managing the Pulumi SDK.
  • Pulumi CLI: The command-line interface must be installed and authenticated to the desired backend.
  • Pulumi Login: Local authentication must be performed using the pulumi login --local command to manage state files on the local machine.
  • Hetzner Cloud API Token: A valid secret token is required to authorize Pulumi to provision resources within the Hetzner account.

Hetzner Cloud Load Balancer Topology and Private Networking

A professional load balancer implementation does not simply place servers on the open internet. Instead, it utilizes a layered security approach combining public gateways with isolated private networks to minimize the attack surface.

The Private Network Architecture

In a secure Hetzner configuration, the load balancer and the application servers are connected via a dedicated private network. This ensures that the communication between the distributor (the Load Balancer) and the workers (the App Servers) never traverses the public internet, reducing latency and increasing security.

The network configuration typically follows a specific CIDR (Classless Inter-Domain Routing) structure to organize IP address allocation:

Resource IP Address / Value Purpose
Network CIDR 10.44.0.0/16 The broad address space for the entire VPC/Network
Private Subnet 10.44.10.0/24 The specific segment where the LB and servers reside
Load Balancer Private IP 10.44.10.10 The internal identity of the balancer
App Server 1 Private IP 10.44.10.11 Internal IP for the first application node
App Server 2 Private IP 10.44.10.12 Internal IP for the second application node
Location nbg1 The physical data center region (e.g., Nuremberg)
Server Type cx23 The specific compute profile for the app servers
OS Image ubuntu-24.04 The standardized operating system across the fleet

Security and Firewalling Strategy

One of the most critical aspects of this architecture is the "Locked Down" server model. While the application servers may be assigned public IP addresses for administrative purposes (such as SSH access), the firewall must be configured to block all incoming HTTP traffic from the open internet.

The security logic operates as follows:

  • External Traffic: The only way for a user to reach the application is through the Load Balancer's public IP (e.g., 203.0.113.1).
  • Internal Traffic: The Load Balancer receives the request and forwards it to the app servers over the private network (10.44.10.0/24).
  • Firewall Rules: The application servers are configured to accept HTTP traffic exclusively from the Load Balancer's private IP. Any attempt to hit the app server directly via its public IP on port 80 or 443 is rejected by the firewall.

Operationalizing the Deployment with Pulumi

The deployment process using Pulumi involves defining the desired state in code and then applying that state to the cloud environment. This replaces manual clicking in a web console with a deterministic script.

Deployment Lifecycle

To initiate the deployment of a load balancer and two app servers, the following workflow is executed:

  1. Environment Setup: Load the necessary environment variables.
    set -a && source .env && set +a
  2. State Preview: Run a preview to see exactly which resources Pulumi intends to create.
    pulumi preview
  3. Execution: Apply the changes to the cloud.
    pulumi up

Upon execution, a comprehensive set of nine resources is typically provisioned to support the architecture:

  • Network: The overarching private network.
  • Subnet: The specific IP range for the cluster.
  • SSH Key: For secure administrative access to servers.
  • Firewall: To enforce the "LB-only" traffic rule.
  • Two Servers: The backend application nodes.
  • Load Balancer: The public-facing distributor.
  • LB Network Attachment: Connects the Load Balancer to the private network.
  • LB Targets: Defines which servers the Load Balancer should send traffic to.
  • LB Service: Defines the ports and protocols (e.g., HTTP on port 80).

Verification and Testing

Once the deployment is complete, Pulumi provides the resulting infrastructure data via stack outputs.

  • Application URL: Accessed via pulumi stack output appUrl, which typically returns http://<LB_IP>/.
  • Health URL: Accessed via pulumi stack output healthUrl, which returns http://<LB_IP>/health.

Testing the distribution can be performed using a simple curl command:
curl "$(pulumi stack output appUrl)"

When this command is run repeatedly, the responses will alternate between "app-1" and "app-2", proving that the Load Balancer is successfully distributing traffic across the server pool.

Health Monitoring and Traffic Management

A Load Balancer is only as effective as its ability to detect failure. This is achieved through a process called Health Checking.

Health Check Mechanics

The Load Balancer is configured to poll a specific endpoint on each backend server—in this case, the /health path—every 10 seconds. This creates a continuous heartbeat monitoring system:

  • Healthy State: If the server responds with a 200 OK status code, it is considered healthy and remains in the active rotation.
  • Failure Detection: If a server fails to respond or returns an error code, the Load Balancer marks it as suspect.
  • Removal from Rotation: After 3 consecutive failures, the Load Balancer automatically stops sending traffic to that specific server.
  • Recovery: The Load Balancer continues to poll the failed server. Once it begins responding with 200 OK again, it is automatically reintroduced into the traffic rotation.

This mechanism ensures that users never encounter a "502 Bad Gateway" or a timeout page if one of the application servers crashes, as the traffic is seamlessly routed to the remaining healthy nodes.

TLS Termination and HTTPS Security

Standard HTTP traffic is transmitted in plain text, making it vulnerable to interception. For production environments, Transport Layer Security (TLS) is mandatory.

The Concept of TLS Termination

TLS termination is the process where the Load Balancer handles the encrypted HTTPS connection from the client. The Load Balancer possesses the SSL/TLS certificate and performs the decryption. Once the traffic is decrypted, the Load Balancer forwards the request as plain HTTP to the backend servers over the private network.

This architecture provides several benefits:

  • Reduced Server Load: The application servers do not have to spend CPU cycles on the computationally expensive process of encrypting and decrypting traffic.
  • Centralized Certificate Management: Certificates are managed at the Load Balancer level (using Hetzner managed certificates) rather than having to install and renew certificates on every single single backend server.
  • Simplified Internal Routing: Internal traffic remains simple and fast over the private network while the external perimeter remains secure.

Multi-Cloud Load Balancing Implementation

While Hetzner provides a streamlined approach, Pulumi allows for similar patterns across other major cloud providers like AWS and Azure, though the resource naming and specific APIs differ.

AWS Load Balancer Integration

In AWS, Pulumi interacts with the Elastic Load Balancing (ELB) service. A typical deployment involving an Application Load Balancer (ALB) requires the creation of several interlocking components:

  • Target Groups: These define the group of instances that will receive traffic.
  • Load Balancer: The actual AWS ALB resource.
  • Target Group Attachments: The link between a specific EC2 instance and a target group.
  • Listeners: Rules that define how the LB handles requests (e.g., listening on port 80 and forwarding to a target group).

Pulumi provides data sources to retrieve existing load balancer information, which is useful for modular architectures. For example, if a module needs to find the security groups associated with an existing LB, the aws.lb.getLoadBalancer function is used.

TypeScript Example for AWS LB Lookup:
typescript import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; const config = new pulumi.Config(); const lbArn = config.get("lbArn") || ""; const lbName = config.get("lbName") || ""; const test = aws.lb.getLoadBalancer({ arn: lbArn, name: lbName, });

Python Example for AWS LB Lookup:
python import pulumi import pulumi_aws as aws config = pulumi.Config() lb_arn = config.get("lbArn") if lb_arn is None: lb_arn = "" lb_name = config.get("lbName") if lb_name is None: lb_name = "" test = aws.lb.get_load_balancer(arn=lb_arn, name=lb_name)

Go Example for AWS LB Lookup:
go package main import ( "github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lb" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config" ) func main() { pulumi.Run(func(ctx *pulumi.Context) error { cfg := config.New(ctx, "") lbArn := "" if param := cfg.Get("lbArn"); param != "" { lbArn = param } lbName := "" if param := cfg.Get("lbName"); param != "" { lbName = param } _, err := lb.LookupLoadBalancer(ctx, &lb.LookupLoadBalancerArgs{ Arn: pulumi.StringRef(lbArn), Name: pulumi.StringRef(lbName), }, nil) if err != nil { return err } return nil }) }

Azure and Cloudflare Geo-Steered Architectures

For global-scale applications, a combination of Azure Kubernetes Service (AKS) and Cloudflare Load Balancers is often employed to achieve zero-downtime deployments and geo-steering.

In this advanced pattern:
- Remote Backends: Pulumi state is stored in a remote backend to ensure consistency across CI/CD pipeline runs.
- Containerization: Application images are built and published via the same pipeline, with Kubernetes deployments updated using Helm or Kustomize.
- Cloudflare Tunnels: These create secure connections between the Cloudflare edge and the Azure Kubernetes clusters, eliminating the need to expose cluster IPs to the public internet.
- Geo-Steering: The Cloudflare Load Balancer directs users to the nearest healthy cluster, reducing latency.

Advanced Monitoring and Scaling Strategies

Deploying a load balancer is the first step; maintaining it requires a robust observability stack to handle the increased complexity of a distributed system.

System Monitoring

With multiple nodes and a distributor, monitoring must move from "server-centric" to "service-centric."

  • Infrastructure Metrics: Azure Monitor or Prometheus are used to track cluster health, CPU usage, and node status.
  • Network Metrics: Cloudflare logs provide critical data on load balancer health check success rates, tunnel connectivity status, and request latency.
  • Alerting: Automated alerts must be configured to notify engineers the moment a cluster or tunnel becomes unhealthy. Because the Load Balancer handles failover automatically, these alerts become operational tasks rather than emergency outages.

Scaling the Architecture

The beauty of the Pulumi-based approach is the ease of horizontal scaling. To expand the system to more regions or increase capacity:

  • Additional Regions: A new Pulumi resource group and cluster can be defined in a different geographic region.
  • Connectivity: A new Cloudflare tunnel and DNS record are created for the new region.
  • Pool Expansion: The corresponding pool is added to the Load Balancer configuration, and Pulumi handles the propagation of these changes across the infrastructure.

Conclusion

The implementation of a Load Balancer via Pulumi transforms a fragile, single-point-of-failure setup into a resilient, enterprise-grade architecture. By leveraging private networking to isolate application servers and enforcing strict firewall rules that only allow traffic from the load balancer, developers can significantly harden their security posture. The integration of automated health checks—polling endpoints every 10 seconds and removing failed nodes after three misses—guarantees that the application remains available even during partial infrastructure collapse. Furthermore, the transition from plain HTTP to HTTPS via TLS termination at the balancer level ensures data integrity and security without overburdening the backend compute resources. Whether utilizing the straightforward server-based approach on Hetzner Cloud or the complex, geo-steered Kubernetes clusters on Azure and Cloudflare, the use of Infrastructure as Code via Pulumi ensures that these complex networks are deployable, scalable, and maintainable. The shift from managing servers to managing state allows engineering teams to treat their infrastructure as software, enabling rapid scaling and zero-downtime evolutions of the application ecosystem.

Sources

  1. Hetzner Community - Pulumi Load Balancer Two Servers
  2. Pulumi Registry - AWS LB getLoadBalancer
  3. Hetzner Community - Pulumi Load Balancer TLS Termination
  4. Pulumi AWS Workshop - Adding a Load Balancer
  5. Alex Rocks - Zero Downtime Azure K8s Cloudflare LB

Related Posts