K8s kümesinde yük dengeleme sonrası istek kaynak IP'sini nasıl koruyabiliriz
Categories:
Giriş
Uygulama dağıtımı her zaman basit bir yükleme ve çalıştırma olmayabilir, bazen ağ sorunlarını da dikkate almak gerekir. Bu makale, k8s kümesinde hizmetin isteğin kaynak IP’sine erişmesini nasıl sağlayacağınızı anlatacaktır.
Uygulamalar hizmet sağlarken genellikle giriş bilgilerine dayanır, giriş bilgileri beşli gruba (kaynak IP, kaynak port, hedef IP, hedef port, protokol) bağlı değilse, bu hizmet ağ bağımlılığı düşük olur ve ağ detaylarını umursamaz.
Bu nedenle, çoğu kişi için bu makaleyi okumanıza gerek yoktur, eğer ağa ilgi duyuyorsanız veya ufuklarınızı genişletmek istiyorsanız, aşağıdaki metni okumaya devam edebilir, daha fazla hizmet senaryosu öğrenebilirsiniz.
Bu makale k8s v1.29.4 tabanlıdır, metinde pod ve endpoint karışık kullanılmıştır, bu senaryoda eşdeğer olarak kabul edilebilir.
Hata varsa, düzeltme için lütfen belirtin, zamanında düzelteceğim.
Neden kaynak IP bilgisi kaybolur?
Öncelikle kaynak IP’nin ne olduğunu netleştirelim, A’dan B’ye istek gönderildiğinde, B isteği C’ye yönlendirirse, C’nin gördüğü IP protokolünün kaynak IP’si B’nin IP’si olsa da, bu makalede A’nın IP’si kaynak IP olarak kabul edilir.
Kaynak bilgi kaybına yol açan iki ana davranış vardır:
- Ağ Adres Çevirisi (NAT), amacı IPv4 kamu IP’lerini tasarruflu kullanmak, yük dengeleme vb. Bu, sunucunun gördüğü kaynak IP’nin NAT cihazının IP’si olmasını sağlar, gerçek kaynak IP değil.
- Vekil (Proxy), Ters Vekil (RP, Reverse Proxy) ve Yük Dengeleyici (LB, Load Balancer) bu kategoriye girer, aşağıda vekil sunucu olarak adlandırılır. Bu tür vekil hizmetler isteği arka uç hizmete yönlendirir, ancak kaynak IP’yi kendi IP’si ile değiştirir.
- NAT basitçe port alanı ile IP alanı değiştirme olarak özetlenebilir, IPv4 adresleri sınırlıdır, bir IP adresi 65535 portu eşleyebilir, çoğu zaman bu portlar tükenmez, bu nedenle birden fazla alt ağ IP’si bir kamu IP’sini paylaşabilir, portlarda farklı hizmetleri ayırt eder. Kullanım biçimi:
kamu IP:kamu port -> özel IP_1:özel port, daha fazla içerik için lütfen Ağ Adres Çevirisi’ni kendiniz okuyun - Vekil hizmetler gizleme veya maruz bırakma içindir, vekil hizmet isteği arka uç hizmete yönlendirir, aynı zamanda kaynak IP’yi kendi IP’si ile değiştirerek arka uç hizmetin gerçek IP’sini gizler, arka uç hizmetin güvenliğini korur. Vekil hizmet kullanım biçimi:
istemci IP -> vekil IP -> sunucu IP, daha fazla içerik için lütfen Vekil‘i kendiniz okuyun
NAT ve vekil sunucular çok yaygındır, çoğu hizmet isteğin kaynak IP’sini alamaz.
Bu, kaynak IP’yi değiştiren yaygın iki yol, başkaları varsa lütfen ekleyin.
Kaynak IP’yi nasıl koruyabiliriz?
Aşağıda bir HTTP isteği örneği:
| Alan | Uzunluk (bayt) | Bit Ofseti | Açıklama |
|---|---|---|---|
| IP Başlığı | |||
Kaynak IP |
4 | 0-31 | Gönderenin IP adresi |
| Hedef IP | 4 | 32-63 | Alıcının IP adresi |
| TCP Başlığı | |||
| Kaynak Port | 2 | 0-15 | Gönderen port numarası |
| Hedef Port | 2 | 16-31 | Alıcı port numarası |
| Sıra Numarası | 4 | 32-63 | Gönderenin gönderdiği veri bayt akışını tanımlamak için kullanılır |
| Onay Numarası | 4 | 64-95 | ACK bayrağı ayarlanmışsa, bir sonraki beklenen sıra numarası |
| Veri Ofseti | 4 | 96-103 | Veri başlangıç konumunun TCP başlığına göre bayt sayısı |
| Ayrılmış | 4 | 104-111 | Ayrılmış alan, kullanılmaz, 0 olarak ayarlanır |
| Bayrak Bitleri | 2 | 112-127 | Çeşitli kontrol bayrakları, SYN, ACK, FIN vb. |
| Pencere Boyutu | 2 | 128-143 | Alıcının alabileceği veri miktarı |
| Kontrol Toplamı | 2 | 144-159 | Verinin iletim sırasında hata olup olmadığını tespit etmek için |
| Acil İşaretçi | 2 | 160-175 | Gönderenin alıcının en hızlı işleyeceği acil verinin konumu |
| Seçenekler | Değişken | 176-… | Zaman damgası, maksimum segment uzunluğu vb. içerebilir |
| HTTP Başlığı | |||
| İstek Satırı | Değişken | …-… | İstek yöntemi, URI ve HTTP sürümü içerir |
Başlık Alanları |
Değişken | …-… | Host, User-Agent vb. çeşitli başlık alanları içerir |
| Boş Satır | 2 | …-… | Başlık ve gövde kısmını ayırmak için kullanılır |
| Gövde | Değişken | …-… | İsteğe bağlı istek veya yanıt gövdesi |
Yukarıdaki HTTP istek yapısını inceleyin, TCP seçenekleri, istek satırı, başlık alanları, gövde değişkendir, TCP seçenekleri alanı sınırlıdır, genellikle kaynak IP taşımak için kullanılmaz, istek satırı sabit bilgi taşır genişletilemez, HTTP gövdesi şifrelendikten sonra değiştirilemez, sadece HTTP başlık alanları kaynak IP taşımak için genişletmeye uygundur.
HTTP header’ına X-REAL-IP alanı eklenebilir, kaynak IP taşımak için, bu işlem genellikle vekil sunucuda yapılır, sonra vekil sunucu isteği arka uç hizmete gönderir, arka uç hizmet bu alan üzerinden kaynak IP bilgisini alabilir.
Dikkat, vekil sunucunun NAT cihazından önce olduğundan emin olun, böylece gerçek isteğin kaynak kimliğini alabilir. Alibaba Cloud ürünlerinde Yük Dengeleyici adlı ayrı bir ürün kategorisi görebilirsiniz, ağdaki konumu sıradan uygulama sunucularından farklıdır.
K8S İşlem Kılavuzu
whoami projesi örneğiyle dağıtım yapalım.
Deployment Oluşturma
Önce hizmeti oluşturun:
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
Bu adım bir Deployment oluşturur, içinde 3 Pod bulunur, her pod bir konteyner içerir, bu konteyner whoami hizmetini çalıştırır.
Service Oluşturma
NodePort veya LoadBalancer tipi hizmet oluşturabilirsiniz, dış erişimi destekler, veya ClusterIP tipi hizmet oluşturup yalnızca küme içi erişimi destekler, sonra Ingress hizmeti ekleyerek dış erişimi açığa çıkarır.
NodePort hem NodeIP:NodePort ile hem de Ingress hizmeti ile erişilebilir, test için uygundur, bu bölümde NodePort hizmeti kullanılır.
apiVersion: v1
kind: Service
metadata:
name: whoami-service
spec:
type: NodePort
selector:
app: whoami
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30002
Hizmet oluşturulduktan sonra, curl whoami.example.com:30002 ile erişin, dönen IP’nin NodeIP olduğunu göreceksiniz, isteğin kaynak whoami değil.
Dikkat, bu doğru istemci IP’si değildir, bunlar kümenin iç IP’leridir. Olan şu:
- İstemci veri paketini node2:nodePort’a gönderir
- node2 veri paketinin kaynak IP adresini kendi IP adresi ile değiştirir (SNAT)
- node2 veri paketindeki hedef IP’yi Pod IP ile değiştirir
- Veri paketi node1’e yönlendirilir, sonra uç noktaya
- Pod’un yanıtı node2’ye geri yönlendirilir
- Pod’un yanıtı istemciye geri gönderilir
Şekille ifade edelim:

externalTrafficPolicy: Local Yapılandırma
Bunu önlemek için, Kubernetes bir özellik sunar ki istemci kaynak IP’sini korur. service.spec.externalTrafficPolicy’yi Local olarak ayarlarsanız, kube-proxy yalnızca yerel uç noktaları proxy’ler, trafiği diğer düğümlere yönlendirmez.
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
curl whoami.example.com:30002 ile test edin, whoami.example.com kümedeki birden fazla node’un IP’sine eşlendiğinde, belirli bir oranda erişilemezlik olur. Alan adı kaydının yalnızca endpoint(pod) bulunduğu node( düğüm) IP’sini içerdiğinden emin olun.
Bu yapılandırmanın maliyeti vardır, küme içi yük dengeleme yeteneğini kaybedersiniz, istemci yalnızca endpoint dağıtılan node’a erişirse yanıt alır.

İstemci Node 2’ye eriştiğinde yanıt olmaz.
Ingress Oluşturma
Çoğu hizmet kullanıcılara http/https olarak sunulur, https://ip:port biçimi kullanıcılara yabancı gelebilir. Genellikle Ingress ile yukarıdaki NodePort hizmetini bir alan adının 80/443 portuna yük dengeleyin.
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
Uygulandıktan sonra, curl whoami.example.com ile test edin, ClientIP’nin her zaman endpoint bulunduğu düğümdeki Ingress Controller Pod IP’si olduğunu göreceksiniz.
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>
Ingress ile NodePort hizmetini ters vekil olarak kullanmak, endpoint önünde iki katman service eklemek gibidir, aşağıdaki şekil ikisinin farkını gösterir.
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]
Yol 1’de, dış erişim Ingress’e geldiğinde, trafiğin ilk ulaştığı endpoint Ingress Controller olur, sonra whoami endpoint’ine ulaşır.
Ingress Controller esasen bir LoadBalancer hizmetidir,
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
Bu nedenle, yukarıda bahsedilen externalTrafficPolicy‘yi Ingress Controller’a ayarlayarak kaynak IP korunabilir.
Aynı zamanda ingress-nginx-controller‘ın configmap‘indeki use-forwarded-headers‘ı true olarak ayarlamak gerekir, böylece Ingress Controller X-Forwarded-For veya X-REAL-IP alanlarını tanıyabilir.
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
NodePort hizmeti ile ingress-nginx-controller hizmetinin farkı esasen, NodePort‘un arkasının genellikle her node’da dağıtılmaması, ingress-nginx-controller‘ın arkasının ise genellikle her dışa açık node’da dağıtılmasıdır.
NodePort hizmetinde externalTrafficPolicy ayarlanması düğümler arası isteklerin yanıtsız kalmasına yol açarken, Ingress istekleri önce HEADER ayarlayıp sonra vekil olarak yönlendirebilir, kaynak IP koruma ve yük dengeleme yeteneklerini gerçekleştirir.
Özet
- Adres Çevirisi (NAT), Vekil (Proxy), Ters Vekil (Reverse Proxy), Yük Dengeleme (Load Balance) kaynak IP kaybına yol açar.
- Kaynak IP kaybını önlemek için, vekil sunucu yönlendirirken gerçek IP’yi HTTP başlık alanı
X-REAL-IP‘de ayarlayabilir, vekil hizmet üzerinden iletir. Çok katmanlı vekil kullanırsanız,X-Forwarded-Foralanını kullanabilirsiniz, bu alan yığın şeklinde kaynak IP ve vekil yolunun IP listesini kaydeder. - Küme NodePort hizmetinde
externalTrafficPolicy: Localayarlayarak kaynak IP korunabilir, ancak yük dengeleme yeteneği kaybolur. - ingress-nginx-controller daemonset şeklinde tüm loadbalancer rolü node’lara dağıtıldığında,
externalTrafficPolicy: Localayarlayarak kaynak IP korunabilir ve yük dengeleme yeteneği korunur.