Skip to main content
Updated Feb 23, 2026

Cloud Load Balancer & DNS

In Docker Desktop Kubernetes (Lesson 5 of Chapter 50), you used NodePort services to access your applications from outside the cluster. NodePort worked because Docker Desktop simulates external access on your laptop. But NodePort has limitations: you access services on high port numbers (30000-32767), and there's no real load balancer distributing traffic.

On a real cloud provider, you get something better: LoadBalancer services that provision actual cloud load balancers. When you create a LoadBalancer service on DigitalOcean, Kubernetes talks to the DigitalOcean API and creates a real load balancer with a public IP address. Your service becomes accessible at standard ports (80, 443) without any port mapping tricks.

This lesson covers how LoadBalancer services work differently in the cloud, how to watch external IP provisioning, how to configure DNS to point your domain at your service, and what this costs.


LoadBalancer vs NodePort: The Cloud Difference

In Chapter 50, you learned three Service types: ClusterIP (internal), NodePort (external via high ports), and LoadBalancer (external via cloud LB). On Docker Desktop, LoadBalancer services behave like NodePort because there's no cloud provider to provision a real load balancer.

On DigitalOcean DOKS (or any cloud Kubernetes), the LoadBalancer type triggers cloud provider integration:

AspectNodePortLoadBalancer (Cloud)
Access Port30000-32767Standard ports (80, 443)
External IPNode IP + nodePortDedicated public IP
Traffic PathClient -> Node -> PodClient -> LB -> Node -> Pod
Load BalancingNone (client picks node)Cloud LB distributes traffic
CostFree (uses nodes)Additional (~$12/month on DigitalOcean)
Production ReadyDevelopment onlyYes

The key insight: LoadBalancer is the production pattern because it provides a stable public IP, handles traffic distribution, and works with standard ports.


Creating a LoadBalancer Service

Here's a LoadBalancer service for your Task API:

apiVersion: v1
kind: Service
metadata:
name: task-api
namespace: default
spec:
type: LoadBalancer
selector:
app: task-api
ports:
- name: http
port: 80
targetPort: 8000
protocol: TCP

Save this as task-api-lb.yaml and apply it:

kubectl apply -f task-api-lb.yaml

Output:

service/task-api created

Watching External IP Provisioning

When you create a LoadBalancer service on a cloud cluster, the external IP doesn't appear immediately. Kubernetes requests a load balancer from the cloud provider, and provisioning takes 30-60 seconds.

Watch the service to see the transition:

kubectl get svc task-api -w

Output (initial state):

NAME       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
task-api LoadBalancer 10.245.0.100 <pending> 80:31234/TCP 10s

The <pending> status means Kubernetes has requested a load balancer from DigitalOcean, but it's still being provisioned. Keep watching:

Output (after ~45 seconds):

NAME       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
task-api LoadBalancer 10.245.0.100 143.198.x.x 80:31234/TCP 55s

The EXTERNAL-IP column now shows a real public IP address. Your service is accessible at http://143.198.x.x (your actual IP will differ).

Press Ctrl+C to stop watching.

What Happened Behind the Scenes

When you created the LoadBalancer service:

  1. Kubernetes detected LoadBalancer type and contacted the DigitalOcean cloud controller
  2. Cloud controller called DigitalOcean API to create a load balancer
  3. DigitalOcean provisioned the LB with a public IP and configured it to forward traffic to your cluster nodes
  4. Cloud controller updated the Service with the external IP
  5. Kubernetes updated the Endpoints to route traffic to your Pods

This integration is automatic. You don't manage the load balancer directly—Kubernetes does it for you.

Verify the Load Balancer Exists

You can see the load balancer in the DigitalOcean console (Control Panel -> Networking -> Load Balancers) or via doctl:

doctl compute load-balancer list

Output:

ID          Name                              IP               Status    Created At
abc123... k8s-lb-task-api-abcd1234... 143.198.x.x active 2025-01-15T10:30:00Z

The load balancer was automatically created and named based on your service.


Cost Implications

Each LoadBalancer service creates a separate cloud load balancer. On DigitalOcean, regional HTTP load balancers cost $12 per month per node (starting with 1 node). This adds up quickly:

Number of LoadBalancer ServicesMonthly Cost
1$12
3$36
5$60
10$120

For a single service, $12/month is reasonable. But if you have 10 microservices each with a LoadBalancer, you're paying $120/month just for load balancers—often more than your compute costs.

The Ingress Solution

In production, teams use Ingress controllers (covered in later chapters) to expose multiple services through a single load balancer:

                   Single LB ($12/mo)

┌────┴────┐
│ Ingress │
└────┬────┘
┌─────────────┼─────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Service A │ │ Service B │ │ Service C │
│ ClusterIP │ │ ClusterIP │ │ ClusterIP │
└───────────┘ └───────────┘ └───────────┘

Instead of 3 LoadBalancers ($36/mo), you have 1 LoadBalancer with an Ingress routing to 3 ClusterIP services ($12/mo).

For this chapter, you'll use a LoadBalancer for simplicity. Just remember: production deployments typically use Ingress to consolidate costs.


DNS Configuration Options

Your LoadBalancer has a public IP (e.g., 143.198.x.x), but users access applications via domain names, not IP addresses. You need DNS to map your domain to the external IP.

Option 1: Real Domain with A-Record

If you own a domain (e.g., example.com), create an A-record pointing to your LoadBalancer IP:

  1. Log into your DNS provider (DigitalOcean, Cloudflare, Route53, GoDaddy, etc.)

  2. Create an A-record:

    • Type: A
    • Name: api (or task-api, or @ for root)
    • Value: 143.198.x.x (your LoadBalancer IP)
    • TTL: 300 (5 minutes, good for testing)
  3. Result: api.example.com resolves to 143.198.x.x

Example in DigitalOcean DNS:

Type    Name       Value           TTL
A api 143.198.x.x 300

Option 2: Wildcard DNS for Testing (nip.io / sslip.io)

If you don't have a domain or want quick testing, use wildcard DNS services. These services resolve any hostname containing an IP address back to that IP:

ServicePatternExample
nip.io<anything>.<ip>.nip.ioapi.143.198.1.2.nip.io -> 143.198.1.2
sslip.io<anything>.<ip>.sslip.iotask-api.143.198.1.2.sslip.io -> 143.198.1.2

With your LoadBalancer IP 143.198.x.x, you can immediately access:

curl http://task-api.143.198.x.x.nip.io/health

No DNS configuration required. The nip.io service extracts the IP from the hostname and returns it.

Limitations of wildcard DNS:

  • Not suitable for production (depends on third-party service)
  • No HTTPS without additional configuration
  • Looks unprofessional in URLs

Use nip.io/sslip.io for testing. Use real domains for production.


Verifying DNS Propagation

After creating DNS records, verify they propagate correctly using dig or nslookup.

Using dig

dig api.example.com

Output:

;; QUESTION SECTION:
;api.example.com. IN A

;; ANSWER SECTION:
api.example.com. 300 IN A 143.198.x.x

;; Query time: 45 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)

The ANSWER SECTION shows your A-record resolving to the LoadBalancer IP.

Using nslookup

nslookup api.example.com

Output:

Server:		8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
Name: api.example.com
Address: 143.198.x.x

Troubleshooting DNS

If DNS doesn't resolve immediately:

  1. Wait for propagation: DNS changes can take up to TTL seconds (plus caching). With TTL 300, wait 5 minutes.

  2. Flush local DNS cache:

    # macOS
    sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

    # Linux
    sudo systemd-resolve --flush-caches

    # Windows
    ipconfig /flushdns
  3. Check with a public DNS server:

    dig @8.8.8.8 api.example.com
  4. Verify the record exists at your DNS provider using their control panel.


Complete Workflow: LoadBalancer to DNS

Here's the full sequence for making your Task API accessible at a real domain:

Step 1: Apply LoadBalancer Service

kubectl apply -f task-api-lb.yaml

Step 2: Wait for External IP

kubectl get svc task-api -w

Wait until EXTERNAL-IP shows a real IP (not <pending>).

Step 3: Create DNS Record

In your DNS provider, create:

Type: A
Name: api
Value: <your-external-ip>
TTL: 300

Step 4: Verify DNS

dig api.yourdomain.com

Confirm it resolves to your LoadBalancer IP.

Step 5: Test Access

curl http://api.yourdomain.com/health

Output:

{"status": "healthy"}

Your Task API is now accessible via a real domain name.


Try With AI

You've learned how LoadBalancer services provision cloud load balancers and how DNS connects domains to IPs. Now practice with your AI companion.

Prompt 1: Diagnose EXTERNAL-IP Stuck on Pending

My LoadBalancer service has been stuck on EXTERNAL-IP <pending> for 5 minutes.
The cluster is on DigitalOcean DOKS. Help me debug this.
What should I check first? What are the common causes?

What you're learning: Systematic debugging of cloud controller integration issues—permissions, quotas, and cloud provider errors.

Prompt 2: Calculate Multi-Service Costs

I'm planning a microservices deployment with 8 services that need external access.
If I use one LoadBalancer per service at $12/month each, that's $96/month.
Help me design an alternative using Ingress. What would the architecture look like?
What's the cost difference? What are the tradeoffs?

What you're learning: Cost-aware architecture design. Understanding when to consolidate load balancers vs when dedicated LBs make sense.

Prompt 3: DNS for Multiple Environments

I need DNS configuration for three environments:
- dev.api.example.com -> development cluster
- staging.api.example.com -> staging cluster
- api.example.com -> production cluster

Each environment has its own LoadBalancer IP. Show me the DNS records I need
and explain how to manage this at scale.

What you're learning: Multi-environment DNS patterns and the operational considerations for managing multiple cluster endpoints.

Safety Note

When configuring DNS, remember that changes propagate globally. Use low TTL values (300 seconds) during initial setup so you can fix mistakes quickly. For production, increase TTL to reduce DNS query load.


Reflect on Your Skill

Test your multi-cloud-deployer skill with what you learned about LoadBalancer services and DNS.

Test Your Skill

Using my multi-cloud-deployer skill, explain the difference between NodePort
and LoadBalancer services. Does my skill include the PENDING to IP transition?
Does it explain the cost implications of LoadBalancer services?

Identify Gaps

Ask yourself:

  • Does my skill explain how cloud LoadBalancer provisioning works (the cloud controller integration)?
  • Does it include DNS configuration steps (A-records, TTL, verification with dig)?
  • Does it warn about per-LoadBalancer costs and suggest Ingress as an alternative?
  • Does it cover wildcard DNS services (nip.io/sslip.io) for testing?

Improve Your Skill

If you found gaps:

My multi-cloud-deployer skill is missing LoadBalancer and DNS patterns.
Update it to include:
- The PENDING to external IP transition and how to watch it
- Cost implications (~$12/month per LB on DigitalOcean)
- DNS A-record configuration steps
- Wildcard DNS alternatives (nip.io, sslip.io) for testing
- DNS verification using dig and nslookup

By the end of this chapter, your skill will be a comprehensive cloud deployment reference.