Networking / Load balancers
Load balancers
Spread incoming traffic across virtual machines with VPC-native and appliance load balancers.
What a load balancer is
A load balancer takes incoming connections and distributes them across several virtual machines, its targets, so traffic keeps flowing when one of them is busy or down for maintenance.
Pantech offers two kinds of load balancers:
- VPC-native (
vpc_native): for virtual machines in a VPC subnet. It takes a static IP reserved for load balancing and spreads connections to one public port across targets in that subnet. - Appliance (
appliance): for standard virtual machines in a security group zone. It is a load balancer VM with its own public IP address, created for you and billed as that VM, and it spreads one TCP port across targets in the same zone.
Two architectures
| Feature | VPC-native (vpc_native) | Appliance (appliance) |
|---|---|---|
| Zone | VPC-enabled zone (af-abj-2) | Standard security group zone (af-abj-1) |
| Address | You reserve a static IP with purpose load_balancer | Automatically allocated by the platform |
| Protocols | tcp | tcp |
| Firewall / Security | Subnet network ACL | Security groups |
| Network | Bound to one VPC subnet | Standard public/guest network |
| Ports | One public port to one target port | Configured public to target ports |
Set one up
Option A: Set up a VPC-native load balancer
You need a VPC with a subnet, and the machines to balance across already running in that subnet.
1. Reserve a static IP for load balancing
On Static IPs, press Reserve static IP, choose the VPC, and choose Load balancer as its use. Wait for the address to be ready. It can carry load balancers for any subnet of that VPC.
2. Create the load balancer
Go to Load balancers and press Create load balancer:
- Name: 1 to 63 characters, like
web. Press Generate if you want a random memorable name. - Kind: choose VPC-native.
- Static IP: an address reserved for load balancing.
- Subnet: the subnet your targets are in.
- Public port: the port clients connect to, like
443. No other load balancer on the address may use it. - Target port: the port your app listens on, on every target. It defaults to the public port.
- Algorithm: how a target is picked for each connection. See algorithms.
- Allowed sources (optional): up to 20 IPv4 blocks, like
203.0.113.0/24, that may connect. Leave it empty for anywhere. - Targets: the VMs in the subnet to send traffic to. You can add them later.
Confirm. The load balancer's page follows the change, and shows each target as active once it receives traffic.
3. Let the traffic into the subnet
The subnet's network ACL still decides what reaches the machines. Add an inbound rule that allows TCP on the target port:
| # | Action | Direction | Protocol | Ports | Source |
|---|---|---|---|---|---|
| 200 | Allow | Inbound | TCP | 8443 | 0.0.0.0/0 |
Without it, the load balancer is in place but connections never reach your app. To limit who can connect, use the load balancer's allowed sources.
Option B: Set up an application (appliance) load balancer
For virtual machines running in a standard security group zone:
- Go to Load balancers and press Create load balancer.
- Name: 1 to 63 characters, or press Generate.
- Kind: choose Appliance.
- Zone: choose the standard zone (
af-abj-1). - Protocol: choose
http,https, ortcp. - Public port and Target port: the port clients connect to and the port your app listens on.
- Algorithm: choose
roundrobin,leastconn, orsource. - Targets: choose the running virtual machines in the zone.
Confirm. The platform allocates a dedicated public IP address and provisions the appliance. Inbound connections to the assigned public IP will be routed to your backend machines according to the chosen algorithm. Ensure that target machines allow inbound traffic from the appliance in their security group.
Algorithms
| Algorithm | How it picks a target | Good for |
|---|---|---|
Round robin (roundrobin, the default) | Each in turn | Targets of the same size serving short requests, like most web apps |
Least connections (leastconn) | The one with the fewest open connections | Long or uneven connections, like WebSockets, uploads or database proxies |
Source (source) | Always the same one for the same client address, while the targets stay the same | Apps that keep a session on the machine rather than in a shared store |
You can change the algorithm at any time; it applies to new connections.
Change the targets
On the load balancer's page, under Targets, add or remove VMs. Every target must be in the load balancer's subnet (for VPC-native) or zone (for appliance), and there can be at most 50. A removed VM keeps running; it just stops getting new connections from the load balancer.
To take a machine down for maintenance, remove it from the targets first, then add it back when it is ready.
You can also rename a load balancer. Everything else is fixed: see limits.
Limits
- Up to 50 targets, all in the load balancer's subnet or zone.
- Up to 20 allowed sources, as IPv4 blocks.
- Fixed once created: the zone, kind, static IP, subnet, ports and allowed sources. To change any of them, create a new load balancer and delete the old one.
- Changeable: the name, the algorithm and the targets.
Deleting, and what it blocks
Delete a load balancer from its page. Traffic to its port stops once it is gone. For VPC-native load balancers, the targets and the static IP stay in your account.
While a load balancer exists, two things are refused:
- Destroying a VM that is one of its targets. Remove it from the targets first. The API answers
409 INSTANCE_BEHIND_LOAD_BALANCER. - Releasing its static IP. Delete the address's load balancers first. The API answers
409 PUBLIC_IP_HAS_LOAD_BALANCERS.
Billing
- VPC-native load balancers: There is no extra charge for the load balancer itself. The static IP it uses is billed like any other static IP, monthly, whether it carries one load balancer or several. The targets are billed as the machines they are.
- Appliance load balancers: The appliance VM and public IP are billed as standard compute and network resources while active. Target virtual machines are billed as their own plans.
With the CLI
With the CLI, and the subnet's id in place of snet_…:
$ pantech public-ips create --network main --purpose load_balancer$ pantech load-balancers create --name web --public-ip 102.211.122.80 --subnet snet_… \ --port 443 --private-port 8443 --target web-1,web-2$ pantech load-balancers update web --targets web-1,web-2,web-3$ pantech load-balancers get web$ pantech load-balancers delete web--algorithm takes roundrobin (the default), leastconn or source, and --allow limits the source ranges. update --targets replaces the whole set; --no-targets removes them all. The subnet's network ACL must still allow the target port.
With the API
Every step is in the load balancers API. Using the pt and wait_op helpers from the API examples, with a VPC in $NET, its subnet in $SUBNET and two VMs in it in $VM1 and $VM2:
source pantech.sh
# 1. A static IP for load balancing. It takes no instance.
OP=$(pt POST /public-ips "$(jq -n --arg n "$NET" '{network_id: $n, purpose: "load_balancer"}')")
PIP=$(echo "$OP" | jq -r .resource_id); wait_op "$(echo "$OP" | jq -r .operation_id)"
# 2. The load balancer: 443 on the address to 8443 on each target (VPC-native).
OP=$(pt POST /load-balancers "$(jq -n --arg p "$PIP" --arg s "$SUBNET" --arg a "$VM1" --arg b "$VM2" \
'{name: "web", kind: "vpc_native", public_ip_id: $p, subnet_id: $s, public_port: 443, private_port: 8443,
algorithm: "roundrobin", instance_ids: [$a, $b]}')")
LB=$(echo "$OP" | jq -r .resource_id); wait_op "$(echo "$OP" | jq -r .operation_id)"
# Or create an application load balancer in a standard zone:
OP_APP=$(pt POST /load-balancers "$(jq -n --arg z "af-abj-1" --arg a "$VM1" \
'{name: "app-lb", kind: "appliance", zone_id: $z, public_port: 80, private_port: 80,
algorithm: "roundrobin", instance_ids: [$a]}')")
LB_APP=$(echo "$OP_APP" | jq -r .resource_id); wait_op "$(echo "$OP_APP" | jq -r .operation_id)"
# 3. Let the target port into the subnet.
OP=$(pt POST "/subnets/$SUBNET/firewall-rules" \
'{"number": 200, "protocol": "tcp", "port_start": 8443, "cidr": "0.0.0.0/0"}')
wait_op "$(echo "$OP" | jq -r .operation_id)"
pt GET "/load-balancers/$LB" | jq '{address: .public_ip_address, observed_state, members}'To change the targets, send the whole new set; leaving instance_ids out keeps them as they are, and [] removes them all:
OP=$(pt PATCH "/load-balancers/$LB" "$(jq -n --arg a "$VM1" '{instance_ids: [$a]}')")
OPID=$(echo "$OP" | jq -r .operation_id)
[ -n "$OPID" ] && wait_op "$OPID" # an empty operation_id means nothing changedThe refusals to expect: 409 PUBLIC_IP_NOT_FOR_LOAD_BALANCER (the address is not an active one reserved for load balancing), 409 PORT_IN_USE (another load balancer on the address has that port), 409 LOAD_BALANCER_NOT_CHANGEABLE (it is being deleted, or has failed), and 422 VALIDATION_FAILED naming the field, for example a target outside the subnet.
With Terraform
With the Terraform provider:
resource "pantechdynamics_network" "main" {
name = "main"
cidr = "10.0.0.0/16"
}
resource "pantechdynamics_subnet" "web" {
network_id = pantechdynamics_network.main.id
name = "web"
cidr = "10.0.1.0/24"
}
resource "pantechdynamics_instance" "web" {
count = 2
name = "web-${count.index + 1}"
plan_slug = "individual"
image_slug = "ubuntu-24-04"
ssh_key_id = pantechdynamics_ssh_key.admin.id
subnet_id = pantechdynamics_subnet.web.id
}
# An address for load balancing takes no instance.
resource "pantechdynamics_public_ip" "lb" {
network_id = pantechdynamics_network.main.id
purpose = "load_balancer"
}
# The subnet's network ACL must let the target port in.
resource "pantechdynamics_firewall_rule" "app" {
subnet_id = pantechdynamics_subnet.web.id
number = 200
protocol = "tcp"
port_start = 8443
cidr = "0.0.0.0/0"
}
resource "pantechdynamics_load_balancer" "web" {
name = "web"
public_ip_id = pantechdynamics_public_ip.lb.id
subnet_id = pantechdynamics_subnet.web.id
public_port = 443
private_port = 8443 # defaults to public_port
algorithm = "roundrobin" # or "leastconn", "source"
# cidr_list = ["203.0.113.0/24"] # leave out for anywhere
instance_ids = pantechdynamics_instance.web[*].id
}
output "address" {
value = pantechdynamics_load_balancer.web.public_ip_address
}- Changing
name,algorithmorinstance_idsupdates the load balancer in place. - Changing
public_ip_id,subnet_id,public_port,private_portorcidr_listreplaces it: Terraform deletes it and creates a new one, and the port is closed in between. - Import one with its id:
terraform import pantechdynamics_load_balancer.web lb_06gk3x9tq7m2v8r4y1c5d0zp8w.