Documentation

esc
    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

    FeatureVPC-native (vpc_native)Appliance (appliance)
    ZoneVPC-enabled zone (af-abj-2)Standard security group zone (af-abj-1)
    AddressYou reserve a static IP with purpose load_balancerAutomatically allocated by the platform
    Protocolstcptcp
    Firewall / SecuritySubnet network ACLSecurity groups
    NetworkBound to one VPC subnetStandard public/guest network
    PortsOne public port to one target portConfigured 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:

    1. Name: 1 to 63 characters, like web. Press Generate if you want a random memorable name.
    2. Kind: choose VPC-native.
    3. Static IP: an address reserved for load balancing.
    4. Subnet: the subnet your targets are in.
    5. Public port: the port clients connect to, like 443. No other load balancer on the address may use it.
    6. Target port: the port your app listens on, on every target. It defaults to the public port.
    7. Algorithm: how a target is picked for each connection. See algorithms.
    8. Allowed sources (optional): up to 20 IPv4 blocks, like 203.0.113.0/24, that may connect. Leave it empty for anywhere.
    9. 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:

    #ActionDirectionProtocolPortsSource
    200AllowInboundTCP84430.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:

    1. Go to Load balancers and press Create load balancer.
    2. Name: 1 to 63 characters, or press Generate.
    3. Kind: choose Appliance.
    4. Zone: choose the standard zone (af-abj-1).
    5. Protocol: choose http, https, or tcp.
    6. Public port and Target port: the port clients connect to and the port your app listens on.
    7. Algorithm: choose roundrobin, leastconn, or source.
    8. 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

    AlgorithmHow it picks a targetGood for
    Round robin (roundrobin, the default)Each in turnTargets of the same size serving short requests, like most web apps
    Least connections (leastconn)The one with the fewest open connectionsLong 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 sameApps 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_…:

    Terminal
    $ 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:

    Shell
    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:

    Shell
    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 changed

    The 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:

    main.tf
    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, algorithm or instance_ids updates the load balancer in place.
    • Changing public_ip_id, subnet_id, public_port, private_port or cidr_list replaces 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.

    Was this page helpful?

    Updated