# Cloud Load Balancer & DNS (/docs/deploying-agent-factories-in-the-cloud/90-real-cloud-deployment/04-cloud-load-balancer-dns)

---
type: Document
title: "Cloud Load Balancer & DNS"
description: "Understand how cloud LoadBalancer services differ from local NodePort and configure DNS for real domains"
status: stable
order: 9004
chapter: 90
lesson: 4
duration_minutes: 25
generated:
  by: ag-archive/0.1.0
  at: 2026-08-26T00:00:00Z
ksor:
  audience: [public]
  approval:
    by: ag-archive/0.1.0
    at: 2026-08-26T00:00:00Z
trust_tier: unverified
build_id: sha256:c8912c3008ae345a7fdc33ace656531ad74f37c065177057c390c7d759f1e970
source_commit: dad4758bb59919c7b9130444778ade062a2dce3e
ksor_version: 0.0.47
---

In Docker Desktop Kubernetes (Lesson 5 of Chapter 80), 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 80, 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:

| Aspect | NodePort | LoadBalancer (Cloud) |
|--------|----------|---------------------|
| **Access Port** | 30000-32767 | Standard ports (80, 443) |
| **External IP** | Node IP + nodePort | Dedicated public IP |
| **Traffic Path** | Client -> Node -> Pod | Client -> LB -> Node -> Pod |
| **Load Balancing** | None (client picks node) | Cloud LB distributes traffic |
| **Cost** | Free (uses nodes) | Additional (~$12/month on DigitalOcean) |
| **Production Ready** | Development only | Yes |

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:

```yaml
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:

```bash
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:

```bash
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:

```bash
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 Services | Monthly 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:

| Service | Pattern | Example |
|---------|---------|---------|
| **nip.io** | `<anything>.<ip>.nip.io` | `api.143.198.1.2.nip.io` -> `143.198.1.2` |
| **sslip.io** | `<anything>.<ip>.sslip.io` | `task-api.143.198.1.2.sslip.io` -> `143.198.1.2` |

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

```bash
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

```bash
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

```bash
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**:
   ```bash
   # macOS
   sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

   # Linux
   sudo systemd-resolve --flush-caches

   # Windows
   ipconfig /flushdns
   ```

3. **Check with a public DNS server**:
   ```bash
   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

```bash
kubectl apply -f task-api-lb.yaml
```

### Step 2: Wait for External IP

```bash
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

```bash
dig api.yourdomain.com
```

Confirm it resolves to your LoadBalancer IP.

### Step 5: Test Access

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

**Output:**

```json
{"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.
