K8s Kluster Bagaimana Mempertahankan IP Sumber Setelah Load Balancing
Categories:
Pengantar
应用部署 tidak selalu sederhana 安装 dan 运行, terkadang perlu mempertimbangkan 网络 masalah. Artikel ini akan menjelaskan bagaimana layanan dapat memperoleh IP sumber permintaan di kluster K8s.
Layanan aplikasi umumnya bergantung pada informasi input, jika informasi input tidak bergantung lima elemen (source IP, source port, destination port, destination port, protocol), maka layanan tersebut memiliki ketergantungan jaringan rendah dan tidak perlu memikirkan detail jaringan.
Oleh karena itu, bagi mayoritas orang, tidak ada kebutuhan membaca artikel ini. Jika Anda tertarik dengan jaringan, atau ingin memperluas wawasan, Anda bisa melanjutkan membaca artikel ini untuk memahami lebih banyak skenario layanan.
Artikel ini berdasarkan K8s v1.29.4, sebagian narasi di dalamnya mengacu pada pod dan endpoint, di artikel ini dapat dianggap setara.
Jika ada kesalahan, silakan sampaikan, saya akan segera memperbaiknya.
Mengapa Informasi IP Sumber Hilang?
Kita pertama kali memahami apa itu IP sumber. Ketika A mengirim permintaan ke B, B akan memforward permintaan ke C, meskipun C melihat alamat IP sumber protokol adalah IP B, namun artikel ini menganggap A的IP sebagai IP sumber.
Ada dua jenis perilaku yang utama menyebabkan informasi sumber hilang:
- 网络地址转换(NAT), tujuannya untuk menghemat IPv4 publik, 负载均衡, dll. Ini akan menyebabkan IP sumber yang dilihat oleh layanan adalah NAT perangkat, bukan IP sumber asli.
- 代理(Proxy), 反向代理(RP, Reverse Proxy) dan 负载均衡(LB, Load Balancer) termasuk dalam kategori ini, disebut sebagai 代理服务器 dalam artikel ini. Layanan proxy ini akan memforward permintaan ke layanan backend, tetapi akan mengganti IP sumber dengan IP sendiri.
- NAT sederhana adalah mengganti ruang port dengan ruang IP, alamat IPv4 terbatas, satu alamat IP dapat memetakan 65535 port, kebanyakan waktu port tersebut tidak habis, sehingga banyak subnet IP dapat berbagi satu IP publik,区分 pada port. Forma penggunaannya adalah:
public IP:public port -> private IP_1:private port, lebih banyak konten silakan cari sendiri Network Address Translation - Layanan proxy dilakukan untuk menyembunyikan atau mengekspos, layanan proxy akan memforward permintaan ke layanan backend, sambil mengganti IP sumber dengan IP sendiri, untuk menyembunyikan IP sumber asli layanan backend, melindungi keamanan layanan backend. Forma penggunaan proxy adalah:
client IP -> proxy IP -> server IP, lebih banyak konten silakan cari sendiri Proxy
NAT dan 代理服务器 sangat umum, kebanyakan layanan tidak dapat memperoleh IP permintaan asli.
ini adalah dua cara umum mengubah IP sumber, jika ada yang lain silakan tambahkan.
Cara Mempertahankan IP Sumber?
Berikut adalah contoh HTTP permintaan:
| 字段 | 长度(字节) | 位偏移 | 描述 |
|---|---|---|---|
| IP 首部 | |||
源 IP | 4 | 0-31 | 发送方的 IP 地址 |
| 目的 IP | 4 | 32-63 | 接收方的 IP 地址 |
| TCP 首部 | |||
| 源端口 | 2 | 0-15 | 发送端口号 |
| 目的端口 | 2 | 16-31 | 接收端口号 |
| 序列号 | 4 | 32-63 | 用于标识发送方发送的数据的字节流 |
| 确认号 | 4 | 64-95 | 如果设置了 ACK 标志,则为下一个期望收到的序列号 |
| 数据偏移 | 4 | 96-103 | 数据起始位置相对于 TCP 首部的字节数 |
| 保留 | 4 | 104-111 | 保留字段,未使用,设置为 0 |
| 标志位 | 2 | 112-127 | 各种控制标志,如 SYN、ACK、FIN 等 |
| 窗口大小 | 2 | 128-143 | 接收方可以接收的数据量 |
| 检验和 | 2 | 144-159 | 用于检测数据是否在传输过程中发生了错误 |
| 紧急指针 | 2 | 160-175 | 发送方希望接收方尽快处理的紧急数据的位置 |
| 选项 | 可变 | 176-… | 可能包括时间戳、最大报文段长度等 |
| HTTP 首部 | |||
| 请求行 | 可变 | …-… | 包括请求方法、URI dan HTTP 版本 |
头部字段 | 可变 | …-… | 包含 berbagai bidang header, seperti Host、User-Agent 等 |
| 空行 | 2 | …-… | Digunakan untuk memisahkan header dan bagian badan |
| 主体 | 可变 | …-… | Badan permintaan atau respons opsional |
Tes di atas struktur permintaan HTTP, dapat ditemukan, ada TCP选项, request line, header fields, body yang variabel, di mana TCP options ruang terbatas, umumnya tidak digunakan untuk mentransfer IP sumber, request line membawa informasi tetap tidak dapat diperluas, HTTP body setelah dienkripsi tidak dapat dimodifikasi, hanya HTTP header fields cocok untuk memperluas mentransfer IP sumber.
HTTP header dapat menambah X-REAL-IP field, digunakan untuk mentransfer IP sumber, operasi ini biasanya ditempatkan di proxy server, lalu proxy server akan mengirim permintaan ke layanan backend, layanan backend kemudian dapat melalui field ini memperoleh informasi IP sumber.
Perlu dicatat, perlu memastikan proxy server berada di NAT device sebelumnya, sehingga dapat memperoleh IP sumber asli. Kita bisa di produk 阿里云 melihat 负载均衡器 ini kategori produk terpisah, posisinya di jaringan berbeda dari layanan aplikasi umum.
Panduan Operasi K8S
Menggunakan proyek whoami sebagai contoh untuk melakukan deployment.
Membuat Deployment
Pertama buat layanan:
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-deployment
spec:
replicas: 3
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: docker.io/traefik/whoami:latest
ports:
- containerPort: 8080
Langkah ini akan membuat Deployment, yang berisi 3 Pod, setiap Pod berisi satu kontainer, kontainer tersebut akan menjalankan layanan whoami.
Membuat Service
Bisa buat NodePort atau LoadBalancer jenis layanan, mendukung akses eksternal, atau buat ClusterIP jenis layanan, hanya mendukung akses dalam kluster, lalu menambah Ingress layanan, melalui Ingress mengekspos akses eksternal.
NodePort bisa diakses melalui NodeIP:NodePort atau melalui Ingress layanan, nyaman untuk pengujian, bagian ini menggunakan NodePort layanan.
apiVersion: v1
kind: Service
metadata:
name: whoami-service
spec:
type: NodePort
selector:
app: whoami
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30002
Setelah membuat layanan, dengan curl whoami.example.com:30002 mengakses, dapat dilihat IP yang dikembalikan adalah NodeIP, bukan IP permintaan asli whoami.
Catatan, ini bukan IP klien yang benar, ini adalah IP internal kluster. Ini yang terjadi:
- Klien mengirim paket ke node:nodePort
- node2 menggunakan IP-nya sendiri untuk mengganti alamat IP sumber paket (SNAT)
- node2 mengganti tujuan IP paket menjadi IP Pod
- Paket diarahkan ke node1, lalu ke endpoint
- Balasan Pod diarahkan kembali ke node2
- Balasan Pod dikirim kembali ke klien
Ditampilkan sebagai gambar:

Konfigurasi externalTrafficPolicy: Local
Untuk menghindari kasus ini, Kubernetes memiliki fitur dapat mempertahankan IP sumber klien. Jika menyetel service.spec.externalTrafficPolicy menjadi Local, kube-proxy hanya akan memproxy permintaan ke endpoint lokal, bukan memforward aliran ke node lain.
apiVersion: v1
kind: Service
metadata:
name: whoami-service
spec:
type: NodePort
externalTrafficPolicy: Local
selector:
app: whoami
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30002
Menggunakan curl whoami.example.com:30002 untuk pengujian, ketika whoami.example.com dipetakan ke IP node kluster banyak, ada proporsi tertentu tidak dapat diakses. Perlu dikonfirmasi catatan domain hanya berisi endpoint (pod) yang ditempatkan di node (node) IP.
Konfigurasi ini mempunyai biaya, yaitu kehilangan kemampuan load balancing dalam kluster, pelanggan hanya dapat mengakses node yang telah ditempatkan endpoint untuk mendapatkan respons.

Ketika klien mengakses Node 2, tidak ada respons.
Membuat Ingress
Banyak layanan diberikan ke pengguna menggunakan format http/https, bentuk https://ip:port mungkin membuat pengguna merasa asing. Umumnya akan menggunakan Ingress mengubah layanan NodePort sebelumnya ke port 80/443 sebuah domain.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: whoami-ingress
namespace: default
spec:
ingressClassName: external-lb-default
rules:
- host: whoami.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: whoami-service
port:
number: 80
Setelah diterapkan, menggunakan curl whoami.example.com untuk pengujian, dapat dilihat ClientIP selalu IP Pod di node Ingress Controller.
root@client:~# curl whoami.example.com
...
RemoteAddr: 10.42.1.10:56482
...
root@worker:~# kubectl get -n ingress-nginx pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-c8f499cfc-xdrg7 1/1 Running 0 3d2h 10.42.1.10 k3s-agent-1 <none> <none>
Menggunakan Ingress reverse proxy NodePort layanan, artinya di endpoint sebelum dua lapis layanan, perbedaan ditunjukkan gambar di bawah.
graph LR
A[Client] -->|whoami.example.com:80| B(Ingress)
B -->|10.43.38.129:32123| C[Service]
C -->|10.42.1.1:8080| D[Endpoint]graph LR
A[Client] -->|whoami.example.com:30001| B(Service)
B -->|10.42.1.1:8080| C[Endpoint]Pada jalur 1, saat akses eksternal Ingress, aliran pertama mencapai endpoint adalah Ingress Controller, lalu mencapai endpoint whoami.
Ingress Controller secara essence adalah layanan LoadBalancer,
kubectl -n ingress-nginx get svc
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
default echoip-ingress nginx ip.example.com 172.16.0.57,2408:4005:3de:8500:4da1:169e:dc47:1707 80 18h
default whoami-ingress nginx whoami.example.com 172.16.0.57,2408:4005:3de:8500:4da1:169e:dc47:1707 80 16h
Oleh karena itu, dapat melalui penyesuaian externalTrafficPolicy yang disebutkan sebelumnya ke dalam Ingress Controller untuk mempertahankan IP sumber.
Sama sekali perlu menetapkan configmap ingress-nginx-controller di configmap di dalam use-forwarded-headers menjadi true, agar Ingress Controller dapat mengenali field X-Forwarded-For atau X-REAL-IP.
apiVersion: v1
data:
allow-snippet-annotations: "false"
compute-full-forwarded-for: "true"
use-forwarded-headers: "true"
enable-real-ip: "true"
forwarded-for-header: "X-Real-IP" # X-Real-IP or X-Forwarded-For
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.10.1
name: ingress-nginx-controller
namespace: ingress-nginx
Perbedaan utama antara NodePort layanan dan ingress-nginx-controller layanan terletak pada, NodePort backend umumnya tidak ditempatkan di setiap node, sedangkan ingress-nginx-controller backend umumnya ditempatkan di setiap node yang diekspos eksternal.
Dengan NodePort layanan menyetel externalTrafficPolicy akan menyebabkan permintaan lintas node tidak respons, sedangkan Ingress dapat men-set HEADER terlebih dahulu kemudian melakukan forward proxy, mengimplementasikan mempertahankan IP sumber dan kemampuan load balancing sekaligus.
Kesimpulan
- Alamat Jaringan (NAT), Proxy, Reverse Proxy, Load Balancer menyebabkan IP sumber hilang.
- Untuk mencegah IP sumber hilang, layanan proxy saat forward dapat menempatkan IP asli di field header HTTP X-REAL-IP, melalui layanan proxy ditransmisikan. Jika menggunakan banyak lapis proxy, dapat menggunakan field X-Forwarded-For, field ini dengan tumpukan merekam IP sumber serta daftar IP jalur proxy.
- Layanan NodePort kluster menyetel
externalTrafficPolicy: Localdapat mempertahankan IP sumber, namun kehilangan kemampuan load balancing. - ingress-nginx-controller ditempatkan dengan bentuk daemonset di semua node role loadbalancer, menyetel
externalTrafficPolicy: Localdapat mempertahankan IP sumber dan mempertahankan kemampuan load balancing.