
網路是系統設計的地基。這篇從實際指令出發, 理解 DNS 解析、HTTP/HTTPS、TLS、Load Balancer、Proxy 的概念和 trade-off。

## DNS

### dig 指令

```bash
dig google.com
dig +short example.com
dig +short example.com CNAME
```

`dig` 是 DNS 查詢工具。`+short` 只顯示結果, 省略雜訊。

輸出解讀:

```
;; QUESTION SECTION:
;google.com.    IN    A          # query A Record (IP address)

;; ANSWER SECTION:
google.com.  300  IN  A  142.250.x.x   # TTL = 300 seconds
google.com.  300  IN  A  142.250.x.x
```

Google 回傳多個 IP, 是 Client-side Load Balancing — DNS 回傳多個 IP 讓客戶端自己選一個連。

### A Record vs CNAME

**A Record**: domain → IP (直接給地址)

```
example.com  →  1.2.3.4
```

**CNAME**: domain → 另一個 domain (別名, 再去查那個的 IP)

```
blog.example.com  →  user.github.io  # alias
user.github.io    →  140.82.x.x      # actual IP
```

### TTL

TTL (Time To Live) = DNS cache 的秒數。

- TTL 300 = 電腦 cache 這個結果 5 分鐘, 5 分鐘內不重新查詢
- 改了 DNS record 後, 要等 TTL 才會全面生效
- TTL 越短, 改動越快生效, 但 DNS server 負擔越大

### CNAME Flattening

根域名 (apex domain, 如 `example.com`) 技術上不能有 CNAME (DNS 標準限制)。Cloudflare 等 DNS 服務會自動把它壓平成 A Record 回傳, 稱為 CNAME Flattening。

Proxied 模式下, Cloudflare 不回傳真實的 CNAME 或 origin IP, 只回傳自己的 proxy IP。所以 `dig example.com CNAME` 可能回傳空的。

### DevOps 連結

- K8s 內部服務互相呼叫靠 **CoreDNS** (`kube-dns`)
- Pod 找其他 service: `service-name.namespace.svc.cluster.local`
- 部署新服務需要設定 domain 指向 Load Balancer IP

## HTTP / HTTPS / TLS

### curl -v 看連線過程

```bash
curl -v https://example.com 2>&1 | head -40
```

`-v` 顯示詳細資訊。`2>&1` 把 stderr 合併到 stdout, 讓 `head` 能同時截斷兩者。

實際輸出片段:

```
* Trying x.x.x.x:443...
* TLSv1.3 (OUT), TLS handshake, Client hello   # client proposes cipher suites
* TLSv1.3 (IN),  TLS handshake, Server hello   # server selects TLSv1.3
* TLSv1.3 (IN),  TLS handshake, Certificate    # server sends certificate
* TLSv1.3 (IN),  TLS handshake, Finished       # encrypted channel established
> GET / HTTP/2                                  # HTTP request (inside encrypted channel)
< HTTP/2 200                                    # response
```

### 連線順序

```
TCP 3-way handshake     (establish connection)
  SYN -> SYN-ACK -> ACK

TLS handshake           (establish encryption, on top of TCP)
  Client Hello -> Server Hello -> Certificate -> Verify -> Finished

HTTP request            (transmitted inside encrypted channel)
  GET / HTTP/2
```

**TCP 握手** 和 **TLS 握手** 是兩件不同的事, TCP 先完成才開始 TLS。

### 憑證資訊

```
subject: CN=example.com        # certificate issued for this domain
issuer: Google Trust Services  # certificate authority
expire date: ...               # expiry date (auto-renewed by Cloudflare)
```

### DevOps 連結

- 憑證到期 → 服務掛掉, 是常見的 incident
- `curl -v` 是排查 TLS 問題的基本工具
- Ingress Controller 做 TLS termination, 憑證設定在 Ingress 上, 後端 Pod 接收 plain HTTP

## Reverse Proxy vs Forward Proxy

### Forward Proxy

```
Client -> Proxy Server -> Target Website
```

代理**客戶端**對外的請求。目標網站看到 Proxy 的 IP, 不是你的 IP。

常見用途: 公司內網管控、VPN、隱藏真實 IP。Windows Network Manager 和瀏覽器設定的就是這個。

### Reverse Proxy

```
Client -> Reverse Proxy -> Your Server
```

代理**伺服器**接收請求。用戶看到 Proxy 的 IP, 不是伺服器的真實 IP。

常見用途: Cloudflare、Nginx、K8s Ingress Controller。

**記法**:
- Forward Proxy = 幫**客戶端**出去
- Reverse Proxy = 幫**伺服器**接進來

### Nginx 的雙重角色

Nginx 同時可以是:
- **Web Server**: 直接提供 HTML/CSS/圖片
- **Reverse Proxy**: 把請求轉發給後端應用程式

K8s 的 Nginx Ingress Controller 是第二種用法。

## Load Balancer

### 為什麼需要 Load Balancer

單一伺服器處理不了大量流量時, 需要跑多個 Pod。Load Balancer 站在前面, 把請求分散到後面的 Pod。

### L4 vs L7

| | L4 Load Balancer | L7 Load Balancer |
|---|---|---|
| 運作層 | Transport (TCP/UDP) | Application (HTTP) |
| 看得到 | IP + Port | URL, Headers, Cookies |
| 路由依據 | IP/Port | URL path, hostname, cookie |
| 速度 | 快 (封包檢查少) | 較慢 (需解析 HTTP) |
| 適合 | WebSocket, 持久連線 | HTTP API, path-based routing |

**K8s 對應**:
- ClusterIP Service ≈ L4 (TCP 轉發, 不看 HTTP 內容)
- Ingress ≈ L7 (根據 URL 路由, 由 Traefik 或 Nginx 實作)

### Load Balancing 演算法

**Round Robin**: 依序輪流

```
request 1 -> Pod 1
request 2 -> Pod 2
request 3 -> Pod 3
request 4 -> Pod 1  # back to the first
```

適合: 請求處理時間相近的 REST API。LB 幾乎不需要額外計算, 效能最高。

**Least Connections**: 發給目前連線數最少的 Pod

```
Pod 1: 100 connections
Pod 2:  20 connections  # next request goes here
Pod 3:  80 connections
```

適合: 請求處理時間差異大的服務 (如影片轉檔)。代價是 LB 需要持續追蹤每個 Pod 的連線數, 高流量下 LB 本身有額外負擔。

**IP Hash**: 同一個 IP 永遠打到同一台 Pod

適合: 需要 sticky session 的舊系統 (session 存在特定 server 記憶體裡)。現代系統通常把 session 存 Redis, 不需要 IP Hash。

### K8s Ingress vs Ingress Controller

Ingress 分兩層:

**Ingress Resource (YAML)** = 路由規格, 本身不執行任何事

```yaml
rules:
  - path: /api
    backend: go-api-service
  - path: /web
    backend: frontend-service
```

**Ingress Controller** = 真正執行路由的程式, 需要另外安裝或由雲端提供

| Ingress Controller | 說明 |
|---|---|
| Nginx Ingress Controller | 最普遍, 自己安裝 |
| Traefik | k3s 預設內建 |
| GKE Ingress | GKE 預設, 用 Google Cloud LB |
| AGIC | AKS 選項, 用 Azure App Gateway |

```bash
kubectl get svc -n kube-system  # check installed ingress controller
kubectl get ingress -A          # check routing rules
```

## WebSocket 與 L4 LB 的關係

### HTTP vs WebSocket

HTTP 是請求-回應模型, 每個請求獨立, 伺服器無法主動推資料。

WebSocket 建立一次連線後持續保持, 伺服器可以隨時主動推資料給客戶端。

```
HTTP (polling):
Client -> Server: "any new messages?"
Server -> Client: "no"
Client -> Server: "any new messages?"
Server -> Client: "yes, here it is"

WebSocket:
Client <-> Server: (connection established, kept open)
Server -> Client: "new message!"
Server -> Client: "another message!"
```

### 為什麼 WebSocket 需要 L4

L7 LB 可能把同一個用戶的不同封包發到不同 Pod, 導致 WebSocket session 斷裂。

L4 LB 在 TCP 層運作, 建立連線後整個 session 黏在同一台 Pod, WebSocket 正常運作。

### 適合 WebSocket 的情境

- 即時客服對話框
- 線上遊戲
- 股票即時報價
- IoT 設備控制 (如智慧插座, 燈泡)

## Linux CLI 補充

### stderr, stdout, 重新導向

```
0 = stdin   (input)
1 = stdout  (normal output)
2 = stderr  (error output)
```

```bash
command > file.log        # redirect stdout to file
command 2>/dev/null       # discard stderr
command 2>&1              # merge stderr into stdout
command > file.log 2>&1   # redirect both stdout and stderr to file
```

`| head -40` 只截斷進入 pipe 的 stdout。stderr 不進 pipe, 所以不受 `head` 限制。加上 `2>&1` 才能讓 `head` 同時截斷兩者。

### 常用網路診斷工具

| 工具 | 用途 |
|---|---|
| `dig` / `nslookup` | DNS 查詢, 排查 domain 解析問題 |
| `curl -v` | HTTP/HTTPS 測試, 看 TLS 憑證和 headers |
| `ping` | 測試基本連通性 |
| `traceroute` | 看封包走哪條路徑 |
| `netstat` / `ss` | 看目前的連線狀態 |

## References

- [DNS - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Glossary/DNS)
- [How HTTPS works - curl documentation](https://curl.se/docs/sslcerts.html)
- [TLS Handshake - Cloudflare Learning](https://www.cloudflare.com/learning/ssl/what-happens-in-a-tls-handshake/)
- [CNAME Flattening - Cloudflare Docs](https://developers.cloudflare.com/dns/cname-flattening/)
- [WebSocket - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
- [Kubernetes Ingress - Official Docs](https://kubernetes.io/docs/concepts/services-networking/ingress/)
- [Nginx Ingress Controller](https://kubernetes.github.io/ingress-nginx/)
- [Traefik on k3s](https://docs.k3s.io/networking/networking-services#traefik-ingress-controller)
