Kubernetes'te Giden Trafik ve Proxy: Sidecar, Egress ve NO_PROXY
Makale içeriği
- Temeller: kümede her şey neden farklı
- Derinlemesine inceleme: proxy'nin yaşadığı üç seviye
- Manifest'te ortam değişkenleri ve no_proxy'nin rolü
- Ortam değişkenlerini almayan bileşenler
- Sırlar: proxy kimlik bilgileri manifest'te değil secret'ta
- Sidecar yaklaşımı: ne zaman haklı çıkar ve ne sağlar
- Egress gateway: küme için sabit giden adres
- Kümede giden trafik teşhisi
- Kaçınılması gereken tipik hatalar
- Araçlar ve kaynaklar
- Vaka örnekleri ve sonuçlar
- Sss: mühendislerin sık soruları
- Sonuç: dağıtım kontrol listesini bir araya getirelim
Sıradan sunuculara alışkın bir mühendis Kubernetes'e gelir ve her zaman yaptığını yapar: HTTP_PROXY'yi ortama aktarır, süreci yeniden başlatır ve tüm giden trafiğin proxy'den geçmesini bekler. Bazen işe yarar. Çok daha sık olarak, kümenin yarısını bozar, diğer yarısı ise proxy'yi atlayarak doğrudan internete çıkmaya devam eder. Sonra en ilginç kısım başlar: neden bazı pod'lar değişkenleri alıyor, bazıları almıyor, servisler birbirini neden göremez hale geliyor ve neden healthcheck aniden güvenilir listesinde olmayan bir proxy sunucusundan geçiyor.
Bu makale, kümedeki giden trafiğin gerçekte nasıl çalıştığının ve proxy'nin nereye doğru şekilde yerleştirileceğinin ayrıntılı bir incelemesidir. Temel ortam değişkeni yapılandırmasını tekrar anlatmayacağız: bunu zaten biliyorsunuz. Konu, alışılmış yaklaşımların beklenmedik etkiler yarattığı Kubernetes'e özgü ayrıntılar olacak. Tüm örnekler gerçek manifest parçaları üzerinde verilmiştir ve proxy altyapısı rolünde Proxeon (proxeon.net) bulunmaktadır.
Temeller: kümede her şey neden farklı
Temelden başlayalım. Klasik bir sunucuda giden trafik kavramı basittir: bir ağ arayüzü, bir yönlendirme tablosu, sistem ortam değişkenleri vardır ve çalıştırdığınız neredeyse her şey bunları ebeveyn kabuğundan miras alır. Değişkeni profile'a aktardınız - tüm kullanıcı süreci onu görür.
Kubernetes'te böyle tek bir nokta yoktur. Burada pod vardır - bir veya daha fazla konteynerin içinde yaşadığı minimum dağıtım birimi. Pod'un kendi ağ namespace'i, kendi IP adresi, manifest tarafından tanımlanan kendi ortam değişkenleri kümesi vardır. Sürecin bir şeyi miras alabileceği kabuk yoktur. Ortam değişkeni konteynerde yalnızca pod spesifikasyonunda veya imajda açıkça bildirdiyseniz görünür.
Pod'un giden trafiği nedir
Konteyner harici bir adrese başvurduğunda, paket uzun bir yol kat eder. Önce konteynerin ağ namespace'inden sanal arayüz üzerinden çıkar. Sonra düğümün ağ yığınına girer, burada CNI eklentisi - küme ağından sorumlu bileşen - onunla ilgilenir. Ardından iptables veya eBPF kuralları, SNAT mekanizması (kaynak adres değiştirme) devreye girer ve paket düğümün ağ arayüzünden dış dünyaya çıkar.
Kilit nokta: harici bir servisin bakış açısından istek pod'un adresinden değil, küme düğümünün adresinden gelir. Pod adres dönüşümünün arkasına gizlenmiştir. Bu, IP beyaz listesine göre erişim yapılandırmaya çalışan yeni başlayanları şaşırtan ilk şeydir: listeye pod'un adresini eklerler ama trafik tamamen farklı bir adresten gelir.
İki tür giden trafik
En baştan iki temelde farklı akışı ayırmak önemlidir:
- Doğu-batı - küme içindeki servisler arası trafik. Bir pod diğerine servis, ClusterIP veya my-service.namespace.svc.cluster.local biçimindeki DNS adı üzerinden başvurur.
- Kuzey-güney - dışa doğru trafik: harici API'ler, veritabanları, iş ortağı servisleri, nesne depolama.
Proxy'ye neredeyse her zaman yalnızca kuzey-güney trafiği için ihtiyaç duyulur. En sık ve en acı verici hata ise, yanlış proxy yapılandırmasının kazara doğu-batı trafiğini de yakalaması ve iç iletişimi koparmasıdır. Bu yüzden hariç tutma listesi burada her yerde olduğundan daha önemlidir. Ama buna birazdan geleceğiz.
Derinlemesine inceleme: proxy'nin yaşadığı üç seviye
Bir pod'un giden yoluna proxy yerleştirmenin tam olarak üç mimari seviyesi vardır. Her biri sorunu kendi tarzında çözer, her birinin kendi bedeli vardır. Üçünü de dürüstçe, artıları ve eksileriyle ele alalım.
Seviye 1: konteynerin kendisi
Bu, konteyner içindeki uygulamanın proxy'yi kendisinin bilmesi durumudur. HTTP_PROXY ve HTTPS_PROXY ortam değişkenlerini okur veya kendi yapılandırmasında proxy bulunur ve HTTP isteklerini onun üzerinden yönlendirir. Proxy mantığı uygulamanın istemci kütüphanesine yerleştirilmiştir.
Artıları. Başlangıçta maksimum uygulama kolaylığı. Kümeye hiçbir şey eklemek gerekmez, ek bileşen yok. Belirli bir pod düzeyinde kontrol: hangi uygulamanın nereye gittiğini kesin olarak bilirsiniz.
Eksileri. Her uygulama bu değişkenleri okuyabilmelidir ki bunu pek azı yapabilir. Yapılandırma onlarca manifest'e yayılır. Proxy adresini güncellemek, tüm deployment'ları dolaşmak anlamına gelir. Bir servisi unutmak kolaydır ve o doğrudan çıkar. Merkezi politika yoktur.
Seviye 2: sidecar konteyner
Burada aynı pod'da ana konteynerin yanında ikinci bir konteyner - sidecar - çalıştırılır. Giden trafiği yakalar ve proxy üzerinden yönlendirir. Uygulama proxy'nin varlığından tamamen habersiz olabilir: istekleri her zamanki gibi gönderir, sidecar onları sessizce proxy'ler. Istio ve Linkerd gibi service mesh'ler bu şekilde çalışır ve aynı prensiple hafif bir yerel proxy ajanı da yerleştirilebilir.
Artıları. Uygulama için şeffaflık. Pod şablonu aracılığıyla tek politika. Proxy'lemenin ötesinde gözlemlenebilirlik ekleme imkanı: metrikler, izleme, yeniden denemeler, zaman aşımları. Sidecar pod içinde izole edilmiştir ve yaşam döngüsünü onunla paylaşır.
Eksileri. Ek yük: artık her pod için iki konteyner, yani daha fazla bellek ve CPU. Hata ayıklama karmaşıklaşır - zincirde fazladan bir halka belirir. Konteynerlerin başlatma sırası önemlidir: uygulama sidecar'dan önce başlarsa ilk istekler başarısız olabilir. Kubernetes 1.28+ sürümünde bu sorun native sidecar containers ile init konteynerler olarak restartPolicy Always politikasıyla çözülür.
Seviye 3: küme egress gateway'i
Bu, kümenin tüm giden trafiğinin zorla yönlendirildiği ayrılmış bir düğüm veya pod'dur. Paketler CNI araçlarıyla egress gateway'e yönlendirilir ve o, harici proxy ile iletişim kurar ya da kendisi sabit bir giden IP'ye sahip çıkış noktası olarak işlev görür.
Artıları. Tüm küme için tek kontrol noktası. Harici iş ortaklarının beyaz listesine eklemek için uygun, sabit ve öngörülebilir bir giden adres. Politikayı tek yerde değiştirirsiniz. Uygulamalar hiçbir şey bilmez.
Eksileri. Egress gateway kritik bir nokta haline gelir: düştüğünde tüm kuzey-güney durur. Yedeklilik ve izleme gerekir. Yapılandırma daha karmaşıktır ve CNI tarafından desteklenmesini gerektirir. Granülerlik daha düşüktür: ek kurallar olmadan farklı uygulamalar için farklı politika tanımlamak daha zordur.
Seviye nasıl seçilir
Deneyimden pratik rehber: harici proxy'ye ihtiyaç duyan birkaç servisli küçük bir proje - konteyner seviyesi. Onlarca servisli ve tek politika gereksinimi olan orta ölçekli küme - sidecar. Harici ortakların sabit giden IP ve tüm trafiğin denetimini talep ettiği büyük altyapı - egress gateway. Seviyeler sıklıkla birleştirilir: temel kontrol için egress gateway artı Proxeon üzerinden bireysel pod'ların ince ayarı için ortam değişkenleri.
Manifest'te ortam değişkenleri ve NO_PROXY'nin rolü
En hafife alınan ayrıntıya geçelim. HTTP_PROXY, HTTPS_PROXY ve NO_PROXY değişkenleri manifest'te konteyner spesifikasyonunun env bloğu aracılığıyla verilir. Klasik isimlerin küçük harfli kopyalarını vermek yaygındır, çünkü bazı kütüphaneler tam olarak küçük harfli varyantları okur.
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker
spec:
replicas: 2
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: app
image: registry.example.com/worker:1.4.0
env:
- name: HTTP_PROXY
value: "http://gate.proxeon.net:8080"
- name: HTTPS_PROXY
value: "http://gate.proxeon.net:8080"
- name: NO_PROXY
value: "localhost,127.0.0.1,10.0.0.0/8,.svc,.svc.cluster.local,.cluster.local,kubernetes.default"
- name: http_proxy
value: "http://gate.proxeon.net:8080"
- name: https_proxy
value: "http://gate.proxeon.net:8080"
- name: no_proxy
value: "localhost,127.0.0.1,10.0.0.0/8,.svc,.svc.cluster.local,.cluster.local,kubernetes.default"Doğru NO_PROXY olmadan küme neden dağılır
İşte sorunun özü. HTTP_PROXY'yi bildirdiğiniz anda, uygulamanın HTTP istemcisi kesinlikle tüm istekleri proxy üzerinden yönlendirmeye başlar; küme içindeki komşu servislere yapılan başvurular dahil. Ancak iç servisler yalnızca küme ağı içinde erişilebilir - harici proxy sunucusu fiziksel olarak onlara ulaşamaz. Sonuç: orders.default.svc.cluster.local adresine yapılan istek harici proxy'ye gider, o bu adı çözmeye çalışır, çözemez ve hata döndürür. İç iletişim anında kopar.
NO_PROXY, proxy'yi atlayıp doğrudan gönderilmesi gereken adreslerin ve alan adlarının listesidir. Sıradan bir sunucuda buraya localhost ve belki birkaç iç alt ağ konur. Kubernetes'te bu liste kritik hale gelir, çünkü kümenin tüm iç topolojisini kapsamalıdır. Bir sonek bile atlarsanız, servisler arası trafiğin bir kısmı harici proxy'den geçer.
NO_PROXY'de mutlaka bulunması gerekenler
- localhost ve 127.0.0.1 - pod'un kendi içindeki başvurular.
- Pod CIDR aralığı - pod'lara adres atanan alt ağ, örneğin 10.0.0.0/8 veya kümenizin belirli aralığı.
- Service CIDR aralığı - servis ClusterIP'lerinin alt ağı, genellikle 10.96.0.0/12.
- Küme DNS sonekleri - .svc, .svc.cluster.local, .cluster.local. Tam olarak bunlar tüm iç servis DNS adlarını kapsar.
- kubernetes.default - uygulamaların ve ajanların başvurduğu API sunucusunun adı.
- Bulut meta verileri - bulut ortamındaysanız 169.254.169.254 adresi, meta veri başvurularının proxy'den geçmemesi için.
NO_PROXY sözdizimi incelikleri
Burada deneyimli mühendislerin bile tökezlediği bir dizi belirsizlik gizlidir.
Birincisi, farklı kütüphaneler kayıtları farklı yorumlar. Bazıları baştaki noktalı .cluster.local'in sonek anlamına geldiğini ve tüm alt alan adlarıyla eşleşeceğini düşünür. Diğerleri noktasız cluster.local biçimini gerektirir. Pratik: maksimum istemciyi kapsamak için hem noktalı hem noktasız her iki varyantı da belirtin.
İkincisi, CIDR gösterimi desteği evrensel değildir. Go kütüphanesi 10.0.0.0/8'i anlar, ancak diğer dillerdeki bazı istemcilerin eski sürümleri anlamaz; onlar tek tek adreslere veya farklı biçimdeki aralıklara ihtiyaç duyar. Tam olarak kendi yığınınızın davranışını doğrulayın.
Üçüncüsü, portlar. NO_PROXY'de kayıt port olmadan belirtilmişse, genellikle ana makinenin herhangi bir portu için geçerlidir. Ancak bazı istemciler port ile tam olarak eşleştirir. İç servislerin standart dışı portlarında bunu doğrulamak önemlidir.
Pratikten içgörü: proxy devreye girdikten sonra bozulan iç iletişim olaylarının onda dokuzu, eksik NO_PROXY'dir. Kümeniz için referans bir listeyi bir kez oluşturun, ortak bir ConfigMap'e koyun ve tüm deployment'larda yeniden kullanın. Bu, onlarca saat hata ayıklamadan tasarruf sağlar.
Ortam değişkenlerini ALMAYAN bileşenler
"HTTP_PROXY koydum, yani tüm trafik proxy'den geçti" şeklindeki naif inanç kümede iki kat yanlıştır. Bu değişkenleri tamamen görmezden gelen bir dizi bileşen vardır. Onları önceden bilmek gerekir.
kubelet ve sistem bileşenleri
Konteynerin ortam değişkenleri yalnızca o konteyner içindeki süreçler tarafından görülür. İmajları indiren, konteynerleri başlatan ve API sunucusuyla iletişim kuran düğüm ajanı kubelet, pod değil düğüm düzeyinde yaşar. Manifest'teki env'i okumaz. kubelet'in imajları proxy üzerinden çekmesi gerekiyorsa, yapılandırma pod spesifikasyonunda değil, kubelet'in systemd servisinde veya container runtime yapılandırmasında yapılır.
# /etc/systemd/system/kubelet.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://gate.proxeon.net:8080"
Environment="HTTPS_PROXY=http://gate.proxeon.net:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,.svc,.cluster.local"Aynı şey container runtime için de geçerlidir - containerd veya CRI-O. İmaj indirme onların kendi ağ bağlamı üzerinden gerçekleşir. İmaj kayıt defteri için proxy yapılandırması runtime konfigürasyonunda yapılır ve bu pod'lardan ayrı bir konudur.
Kendi yapılandırmasına sahip imajlar
Birçok popüler imajın ortam değişkenlerini geçersiz kılan yerleşik ağ ayarları vardır. Örneğin imaj içindeki paket yöneticileri, web sunucuları veya proxy araçları ortamı değil kendi yapılandırma dosyasını okuyabilir. Konteyner içindeki uygulama, örneğin açıkça tanımlanmış bağlantı parametreleriyle bir ayar dosyası kullanıyorsa env değişkenlerinizi hiç fark etmez.
Ayrı bir kategori de ağ istemcisinin ortamı okumadan önce başlatıldığı veya ayarları başlangıçta önbelleğe aldığı uygulamalardır. Burada süreci yeniden başlatmadan değişkeni değiştirmek etki etmez.
Bireysel SDK'lar ve dil çalışma zamanları
Bu en sinsi gruptur. HTTP_PROXY'ye saygı bir sözleşmedir, standart değil. Kimi uyar, kimi uymaz.
- Go. Standart http.Client, ProxyFromEnvironment üzerinden değişkenlere saygı gösterir. Ancak kod, Proxy nil ile açıkça bir transport oluşturursa değişkenler görmezden gelinir.
- Python. requests kütüphanesi varsayılan olarak ortamı okur. Ama düşük düzeyli soketler, bazı gRPC istemcileri ve asenkron kütüphaneler okumaz.
- Java. JVM kendi sistem özelliklerini (http.proxyHost ve https.proxyHost) kullanır ve ortam değişkenlerini varsayılan olarak hiç okumaz. Bunların JAVA_TOOL_OPTIONS üzerinden iletilmesi gerekir.
- Node.js. Yerleşik http modülü ortam değişkenlerine saygı göstermez. Onları okuyan üçüncü taraf ajanlar gerekir.
- gRPC. Bazı uygulamalar standart değişkenler yerine özel grpc_proxy değişkenini okur.
Sonuç basit: değişken bildirildiyse tüm trafiğin ondan geçeceğini varsayamazsınız. Her çalışma zamanını ayrı ayrı doğrulayın. Örneğin JVM için manifest şöyle görünür:
env:
- name: JAVA_TOOL_OPTIONS
value: "-Dhttp.proxyHost=gate.proxeon.net -Dhttp.proxyPort=8080 -Dhttps.proxyHost=gate.proxeon.net -Dhttps.proxyPort=8080 -Dhttp.nonProxyHosts=localhost|127.0.0.1|*.svc|*.cluster.local"Dikkat: JVM'de hariç tutma ayırıcısı virgül değil dikey çubuktur ve şablonlar yıldız işareti kullanır. NO_PROXY'yi mekanik olarak kopyalayanlar için bir başka tuzak.
Sırlar: proxy kimlik bilgileri manifest'te değil Secret'ta
Proxy'niz kimlik doğrulama gerektiriyorsa, kullanıcı adı ve parolayı saklama sorunu ortaya çıkar. Cazibe büyüktür: bunları doğrudan env değeri içindeki URL'ye yazmak. Bu yapılmamalıdır ve nedeni şudur.
Deployment manifestleri neredeyse her zaman sürüm kontrol sisteminde bulunur. Env'de açık metin parola, depoya erişimi olan herkesin ulaşabileceği Git geçmişine sızıntı demektir. Ayrıca env değerleri kubectl describe pod çalıştırabilen herkes tarafından görülür. Bu, en az ayrıcalık ilkesinin doğrudan ihlalidir.
Doğru yol Secret nesnesidir. Hassas verileri ayrı saklar, RBAC üzerinden erişimi kısıtlama ve etcd deposunda şifrelemeyi etkinleştirme imkanı sunar.
apiVersion: v1
kind: Secret
metadata:
name: proxeon-credentials
type: Opaque
stringData:
proxy-user: my_account
proxy-pass: s3cr3t_token_valueArdından değerleri secretKeyRef aracılığıyla konteyner ortam değişkenlerine bağlarız ve proxy URL'sini kimlik bilgileri manifestin kendisinde görünmeyecek şekilde oluştururuz:
env:
- name: PROXY_USER
valueFrom:
secretKeyRef:
name: proxeon-credentials
key: proxy-user
- name: PROXY_PASS
valueFrom:
secretKeyRef:
name: proxeon-credentials
key: proxy-pass
- name: HTTPS_PROXY
value: "http://$(PROXY_USER):$(PROXY_PASS)@gate.proxeon.net:8080"
- name: NO_PROXY
value: "localhost,127.0.0.1,10.0.0.0/8,.svc,.cluster.local"Kubernetes, önceden bildirilen değişkenlerden değerleri dolar ve parantez sözdizimiyle yerine koyar. Bu, parolayı doğrudan manifest metnine koymadan kimlik bilgileriyle URL'yi çalışma zamanında oluşturmanızı sağlar. Unutmayın: oluşturulan HTTPS_PROXY değeri yine çalışan konteynerin env'inde görülür, bu yüzden bu pod'lar için exec ve describe çalıştırabilecekleri ek olarak kısıtlayın.
Sırlarla çalışma iyi uygulamaları
- etcd at rest şifrelemesini etkinleştirin - aksi halde sırlar yalnızca base64 olarak saklanır ki bu koruma değildir.
- Sırlara erişimi RBAC ile kısıtlayın: pod yalnızca kendi sırrını görmelidir.
- Proxy kimlik bilgilerini düzenli olarak döndürün ve rotasyondan sonra pod'ların yeniden başlatılmasını otomatikleştirin.
- Kimlik bilgilerinin etcd'ye hiç ulaşmaması için CSI sürücüsü üzerinden bağlanan harici sır yöneticilerini değerlendirin.
- Oluşturulan proxy URL'sini asla loglamayın - parola log toplama sistemine sızar.
Sidecar yaklaşımı: ne zaman haklı çıkar ve ne sağlar
Sidecar'ı üç seviyeden biri olarak zaten adlandırdık. Şimdi onu bağımsız bir strateji olarak daha ayrıntılı inceleyelim, çünkü kaynak bedelini ödemeye hazırsanız en esnek araçtır.
Sidecar ne zaman haklı çıkar
- Uygulama HTTP_PROXY'yi okuyamıyor ve kodunu yeniden yazmak mümkün değil veya pahalı.
- Her uygulamayı düzenlemeden tek proxy politikası gerekiyor.
- HTTP dışı protokoller dahil şeffaf trafik yakalama gerekiyor.
- Gözlemlenebilirlik gerekiyor: giden bağlantı metrikleri, izleme, denetim.
- Bağlantı düzeyinde yeniden deneme, zaman aşımı, devre kesme politikaları gerekiyor.
Sidecar proxy'lemenin ötesinde ne sağlar
İşte gerçek değer burada gizlidir. Sidecar sadece paket yönlendirici değildir. Doğru yapılandırıldığında, pod'un tüm giden trafiği için kontrol ve gözlem noktası haline gelir.
- Metrikler. Dışa kaç istek gitti, hangi ana makinelere, hangi gecikmeyle, kaç hata. Sidecar olmadan bu veriler her uygulamada ayrı ayrı toplanmak zorunda kalırdı.
- İzleme. Gelen isteklere bağlı giden çağrıların dağıtık izleri.
- Güvenilirlik politikaları. İdempotent isteklerin otomatik yeniden denenmesi, zaman aşımları, eşzamanlı bağlantı sınırlaması.
- Tek TLS. Sidecar güvenli bağlantıları merkezi olarak sonlandırabilir ve kurabilir.
- Denetim ve uyumluluk. Uygulamanın tam olarak nereye gittiğinin tam kaydı - uyumluluk için vazgeçilmez.
Sidecar proxy'li pod örneği
Aşağıda ana konteynerin giden HTTP isteklerini yerel sidecar'a yönlendirdiği ve onun da bunları Proxeon üzerinden proxy'lediği basitleştirilmiş bir şablon var. Uygulama için proxy adresi localhost'tur; bu, uygulama komşulara doğrudan başvuruyorsa servisler arası trafiği otomatik olarak harici proxy'lemeden çıkarır.
apiVersion: v1
kind: Pod
metadata:
name: app-with-proxy-sidecar
labels:
app: billing
spec:
containers:
- name: app
image: registry.example.com/billing:2.1.0
env:
- name: HTTP_PROXY
value: "http://127.0.0.1:3128"
- name: HTTPS_PROXY
value: "http://127.0.0.1:3128"
- name: NO_PROXY
value: "localhost,127.0.0.1,10.0.0.0/8,.svc,.cluster.local"
- name: egress-proxy
image: registry.example.com/egress-agent:1.0.0
ports:
- containerPort: 3128
env:
- name: UPSTREAM_PROXY
value: "http://gate.proxeon.net:8080"
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128MiNative sidecar ve başlatma sırası
Sidecar'ın klasik belası başlangıçtaki yarış durumudur. Ana uygulama başlar ve sidecar bağlantıları kabul etmeye hazır olmadan önce ilk giden isteği yaparsa istek başarısız olur. Kubernetes 1.28'den itibaren native sidecar konteyner desteği geldi: initContainers bloğunda restartPolicy Always ile bildirilirler ve ana konteynerden önce garanti olarak başlar ve hayatta kalırlar. Bu, yarış sorununu başlangıçtaki gecikmeler ve yeniden denemeler gibi geçici çözümler olmadan temiz biçimde çözer.
spec:
initContainers:
- name: egress-proxy
image: registry.example.com/egress-agent:1.0.0
restartPolicy: Always
ports:
- containerPort: 3128Egress gateway: küme için sabit giden adres
Üçüncü seviye ayrı bir tartışmayı hak eder, çünkü kümede proxy'ye genellikle tam olarak onun çözdüğü sorun için gelinir: öngörülebilir giden IP.
Sabit giden IP neden gerekir
Harici ortaklar, ödeme ağ geçitleri, veri sağlayıcıları sıklıkla beyaz liste üzerinden çalışır. Şöyle derler: yalnızca bu IP'lerden istek kabul ederiz. Sıradan bir kümede pod'un giden adresi, pod'un o anda bulunduğu düğümün adresidir. Düğümler çoktur, ölçeklenir, değiştirilir, otomatik ölçeklemede eklenir. Adres öngörülemez. Ortak, ayrıca değişen tüm düğüm havuzunu beyaz listeye alamaz.
Egress gateway bunu çözer: tüm giden trafik sabit adresli bir noktada toplanır. Ortak beyaz listeye bir-iki sabit IP ekler - ve her şey çalışır. Proxeon'ı çıkış noktası olarak kullandığınızda ortaklara bir kez verdiğiniz sabit bir harici adres elde edersiniz.
Trafik egress gateway'e nasıl yönlendirilir
Mekanizma CNI'ye bağlıdır. Bazı CNI eklentileri egress politikası nesnesini destekler; burada şunu tanımlarsınız: şu etiketlere sahip pod'lardan dışa giden trafik şu düğüm veya adres üzerinden çıkmalıdır. Eklenti ilgili SNAT ve yönlendirme kurallarını otomatik olarak yapılandırır. Kavramsal olarak şöyle görünür:
apiVersion: policy.example.io/v1
kind: EgressPolicy
metadata:
name: billing-egress
spec:
selector:
matchLabels:
egress: proxeon
egressIP: 203.0.113.10
destinationCIDRs:
- 0.0.0.0/0Kesin sözdizimi CNI'ler arasında farklılık gösterir, bu yüzden eklentinizin belgelerine bakın. Fikir değişmez: trafiği gateway üzerinden yönlendirilecek pod'ları işaretleyin ve sabit çıkış adresini belirtin.
Egress gateway'in güvenilirliği
Gateway tek nokta olduğuna göre, tek arıza noktasıdır da. Hayatta kalma kuralları:
- Yedekleyin: otomatik geçişli en az iki gateway düğümü.
- Çıkış erişilebilirliğini dakikada bir ayrı bir sentetik dış istekle izleyin.
- Bant genişliğini takip edin: tüm kuzey-güney gateway'den akar, darboğaz her şeyi etkiler.
- Politikaları ayırın: kritik trafik ile arka plan trafiğini farklı yollara ayırmak, arka plan yükünün önemli işi engellememesi için iyidir.
Kümede giden trafik teşhisi
Bir şeyler ters gittiğinde - ki gidecek - bir kontrol cephaneliği gerekir. Pratik komut ve yaklaşım setini toplayalım.
Adım 1: pod'dan gerçek giden IP'yi öğrenmek
İlk kontrol ettiğimiz: pod dış dünyadan hangi adresten görünüyor. Geçici bir hata ayıklama konteyneri çalıştırır veya mevcut bir pod'a exec yapıp genel adresinizi döndüren servise başvururuz.
kubectl run nettest --rm -it --image=registry.example.com/nettools:1.0 --restart=Never -- sh
# внутри контейнера
curl -s https://api.ipify.org
curl -s -x http://gate.proxeon.net:8080 https://api.ipify.orgİlk istek proxy'siz adresi, ikincisi açıkça proxy üzerinden gösterir. İkisi de aynıysa ve farklı bekliyorsanız, proxy uygulanmıyor demektir. İkincisi beklenen Proxeon adresini döndürüyorsa proxy çalışıyor ve sorun uygulama yapılandırmasındadır.
Adım 2: uygulama değişkenleri görüyor mu kontrol etmek
kubectl exec deploy/worker -c app -- env | grep -i proxyÇıktı boşsa - değişkenler konteynere ulaşmamış. Manifest'i ve pod'un değişiklikten sonra yeniden oluşturulduğunu kontrol edin. Hatırlatayım: env değişikliği pod'un yeniden oluşturulmasını gerektirir, canlı olarak alınmaz.
Adım 3: içeriden DNS çözümlemesini kontrol etmek
Birçok hata proxy sorunu gibi görünür ama aslında DNS'tir. İç ve dış ad çözümlemesini kontrol ederiz:
kubectl exec deploy/worker -c app -- nslookup orders.default.svc.cluster.local
kubectl exec deploy/worker -c app -- nslookup api.external-partner.comİç ad çözülmüyorsa - sorun CoreDNS'te veya NO_PROXY'de sonek eksikliğinden isteğin harici proxy'ye gitmesindedir. Bu, hariç tutma listesinin eksik olduğunun doğrudan kanıtıdır.
Adım 4: reddedilmeler nerede izlenir
- Uygulama logları. Bağlantı hataları, zaman aşımları, proxy kimlik doğrulama reddi (genellikle 407 kodu) arayın.
- Sidecar logları. Varsa, hangi istekleri aldığı ve nereye yönlendirdiği orada görülür.
- Egress gateway metrikleri. Gateway'de reddedilme ve gecikme artışı.
- Pod olayları. kubectl describe pod başlatma sorunlarını, sidecar yarışını gösterir.
- NetworkPolicy. Ağ politikasının giden trafiği engellemediğini kontrol edin - sessiz redlerin sık nedeni.
Tipik sorun imzaları
- Proxy'den 407 kodu - yanlış veya eksik kimlik bilgileri. Secret'ı kontrol edin.
- Proxy etkinleştirildikten sonra iç servise başvuruda zaman aşımı - eksik NO_PROXY.
- Tekrarlanan isteklerde farklı giden IP'ler - trafik egress gateway'den geçmiyor, normal düğüm SNAT'ı çalışıyor.
- Başlangıçtan sonra ilk istekler başarısız, sonra her şey çalışıyor - sidecar yarışı, native sidecar'a geçin.
- Java uygulaması proxy'yi görmezden geliyor - JAVA_TOOL_OPTIONS ve sistem özellikleri unutulmuş.
Kaçınılması gereken tipik hatalar
En sık tökеzlenilen tuzakları bir araya toplayalım. Kendinizi olaydan sonra değil, önce bu listeye göre kontrol edin.
Eksik NO_PROXY
Mutlak lider. Service CIDR unutuldu, .svc soneki unutuldu, bulut meta veri adresi hesaba katılmadı - ve gizemli reddedilme kaskadı geldi. Her zaman kümeniz için tam referans listesinden hareket edin.
Manifest'te açık metin proxy parolası
Git'e ve describe çıktısına sızıntı. Yalnızca Secret, yalnızca kısıtlı erişim.
Tüm çalışma zamanlarının değişkenlere saygı gösterdiğini varsaymak
JVM, Node.js, bazı gRPC istemcileri HTTP_PROXY'yi görmezden gelir. Her yığını ayrı ayrı doğrulayın ve yerel yöntemle yapılandırın.
kubelet ve runtime'ı görmezden gelmek
İmajların proxy üzerinden indirilmesi pod değil düğüm düzeyinde yapılandırılır. Manifest'te yalnızca env yapılandırdıysanız imajların çekilmemesine şaşırmayın.
Sidecar başlangıcında yarış
Uygulama proxy'den önce başlar ve ilk istekleri düşürür. Çözüm - native sidecar containers.
Yedeksiz egress gateway
Çoğaltmasız tek arıza noktası tüm giden trafiği durdurur. Yedekleyin ve izleyin.
CIDR biçimlerini karıştırmak
CIDR anlamayan bir istemci için 10.0.0.0/8 belirttiniz. Kütüphanenizin hangi biçimi yediğini kontrol edin ve alternatif verin.
env değişikliğinden sonra pod'ları yeniden oluşturmamak
Deployment'taki değişkeni değiştirdiniz ama eski pod'lar yeniden başlatılana kadar eski değerlerle çalışmaya devam ediyor. Kademeli geçişi sağlayın.
Değişkenlerin küçük harfini unutmak
Bazı kütüphaneler yalnızca küçük harfli http_proxy'yi okur. İsimleri her iki kayıtta çoğaltın.
Araçlar ve kaynaklar
Kümede giden trafikle çalışmak için el altında bulundurulacaklar.
Teşhis
- kubectl exec ve kubectl debug - pod içinden kontroller için temel.
- Geçici hata ayıklama konteynerleri - imajı yeniden derlemeden çalışan pod'a ağ araçları seti bağlamanızı sağlar.
- Ağ araçları içeren imaj - hızlı kontroller için tek konteynerde toplanmış curl, dig, nslookup, traceroute.
- Genel IP döndürme servisi - gerçek giden adres kontrolü.
Altyapı
- Referans NO_PROXY içeren ConfigMap - tüm deployment'lar için tek doğruluk kaynağı.
- Secret ve harici sır yöneticileri - proxy kimlik bilgileri için.
- Service mesh - kutudan çıkan gözlemlenebilirlikle sidecar gerekiyorsa.
- CNI egress politikaları - gateway'e yönlendirme için.
- Proxeon (proxeon.net) - sabit giden adres ve kimlik doğrulamalı erişim için proxy altyapısı.
İzleme
- Sidecar veya egress gateway'den giden bağlantı metrikleri.
- Kümeden harici adreslerin erişilebilirliğine dair sentetik kontroller.
- 407 kodları ve giden istek zaman aşımlarındaki artışa uyarılar.
- Giden trafiğin hedef ana makinelere göre dağılımını gösteren pano.
Vaka örnekleri ve sonuçlar
Seviye seçiminin sonucu nasıl etkilediğini gösteren üç genelleştirilmiş senaryoyu ele alalım.
Vaka 1: Ödeme entegrasyonu ve IP beyaz listesi
Ekip, yalnızca anlaşılan adreslerden istek kabul eden harici bir ödeme ağ geçidi entegre etti. Önce konteyner düzeyinde ortam değişkenlerini denediler - ve otomatik ölçeklemede pod'ların yeni adresli yeni düğümlere dağıldığı, giden IP'nin yine de proxy değil düğüm adresi olarak kaldığı gerçeğiyle karşılaştılar. İsteklerin bir kısmı reddedilmeye başladı.
Çözüm: ödeme servisini Proxeon aracılığıyla sabit giden adresli egress'e taşıdılar. Ortak beyaz listeye tek IP ekledi. Bilinmeyen adres nedeniyle reddedilmeler ortadan kalktı. Ek etki - ödeme ağ geçidine tüm başvuruların denetim için merkezi kaydı.
Vaka 2: Proxy devreye girdikten sonra servisler arası iletişimin kopması
Şirket ortak şablon üzerinden tüm deployment'lara tek hamlede HTTP_PROXY ekledi. Birkaç dakika içinde hatalar yağmaya başladı: servisler birbirini göremez oldu. İç çağrılar harici proxy'ye gidiyordu ve o bunları çözemiyordu.
Teşhis, pod içinden çözümlemeyi kontrol edene ve .svc.cluster.local adının proxy'ye gittiğini görene kadar zaman aldı. Neden - NO_PROXY yalnızca localhost içeriyordu. Pod CIDR, Service CIDR ve tüm DNS soneklerini içeren tam referans listesi oluşturuldu, ConfigMap'e konuldu ve tüm pod'lara bağlandı. İç iletişim yeniden sağlandı. O günden beri referans NO_PROXY, deployment şablonunun zorunlu parçasıdır.
Vaka 3: Sidecar üzerinden giden trafik gözlemlenebilirliği
Güvenlik gereksinimi: her uygulamanın tam olarak nereye dışarı çıktığını bilmek, tam kayıtla. Uygulamalar farklı dillerdeydi, bir kısmı HTTP_PROXY'yi okuyamıyordu. Onlarca servisin kodunu düzeltmek - çok pahalı.
Pod şablonuna sidecar proxy eklendi. Uygulamalar giden trafiği yerel ajana yönlendiriyor, o Proxeon üzerinden proxy'liyor ve metrikleri yazıyor: hedef ana makine, gecikme, yanıt kodu. Her servis için giden başvurular panosu oluştu. Ek olarak sidecar düzeyinde zaman aşımları ve yeniden denemeler yapılandırıldı, bu da harici API'lerin kısa süreli kullanılamazlığında kademeli arızaları azalttı. Bedeli sidecar için ek kaynaklar oldu ama gözlemlenebilirlik ve güvenilirlikteki kazanç bunu haklı çıkardı.
SSS: Mühendislerin sık soruları
Komşu pod'a trafik neden harici proxy'den geçiyor, oysa bu açıkça iç adres?
Çünkü HTTP istemcisi adresin iç olduğunu bilmez. Adı veya adresi görür ve NO_PROXY'de değilse isteği kurallara göre proxy'ye yönlendirir. İstemci doğu-batı ile kuzey-güneyi kendisi ayırt etmez - bunu onun yerine hariç tutma listesi yapar. NO_PROXY'ye iç sonekleri ve alt ağları ekleyin.
İmaj indirme için de proxy yapılandırmak gerekir mi?
Evet, ancak pod env'i üzerinden değil. İmaj indirmeyi container runtime ve kubelet düğüm düzeyinde yapar. Kayıt defteri için proxy, runtime yapılandırmasında veya kubelet'in systemd unit'inde yapılandırılır. Konteyner ortam değişkenleri bunu hiç etkilemez.
Sabit giden IP için hangisi daha önemli - sidecar mı egress gateway mi?
Egress gateway. Sidecar tek bir pod'un trafiğini proxy'ler ama giden adres yine bağlantının daha sonra nereye gittiğine göre belirlenir. Harici ortağın kabul edeceği garantili sabit adres için ya egress gateway ya da Proxeon gibi sabit adresli harici bir noktadan çıkış gerekir.
Java uygulaması HTTP_PROXY'yi neden görmezden geliyor?
JVM tarihsel nedenlerle proxy için ortam değişkenlerini okumaz. Kendi sistem özelliklerini kullanır: http.proxyHost, https.proxyHost ve http.nonProxyHosts istisnaları. Bunları JAVA_TOOL_OPTIONS üzerinden iletin. Ve unutmayın: JVM'de istisna ayırıcısı dikey çubuktur, şablonlar CIDR değil yıldız işaretiyle çalışır.
Proxy parolası güvenli şekilde nasıl saklanır?
RBAC ile erişimi kısıtlanmış ve etcd şifrelemesi etkinleştirilmiş bir Secret nesnesinde. Değerleri secretKeyRef üzerinden bağlayın. Parolayı manifest'te açık metin yazmayın, aksi halde Git'e ve describe çıktısına sızar. Yüksek gereksinimler için CSI üzerinden harici sır yöneticisi kullanın.
Ortam değişkenini değiştirdim ama davranış değişmedi - neden?
Ortam değişkenleri konteyner başlangıcında sabitlenir. Pod yeniden oluşturulana kadar eski değerlerle çalışır. Kademeli pod geçişini sağlayacak şekilde deployment'ı güncelleyin. Ayrıca uygulamanın ortamı gerçekten okuduğunu, başlangıçta ayarları önbelleğe almadığını kontrol edin.
Tam olarak hangi NO_PROXY biçiminin kütüphanem için gerekli olduğunu nasıl anlarım?
Deneysel olarak: proxy'yi yapılandırın, pod içinden iç ada başvurun ve isteğin proxy'ye mi doğrudan mı gittiğine bakın. Proxy'ye gittiyse - biçim tanınmamış. Noktalı ve noktasız varyantı deneyin, CIDR yerine tek tek adresler ekleyin, değişken adının kaydını kontrol edin. İlgili istemcinin belgeleri en iyi rehberdir.
Sırf proxy'leme için her zaman service mesh kullanmalı mıyım?
Hayır. Service mesh güçlü bir araçtır; gözlemlenebilirlik ve politikalar sunar ama belirgin ek yük ve operasyonel karmaşıklık getirir. Görev yalnızca giden trafiği proxy üzerinden yönlendirmekse, hafif bir sidecar ajanı veya egress gateway daha ucuza gelir. Mesh'i gerçekten tüm yeteneklerine ihtiyaç duyduğunuzda devreye alın.
Hiç HTTP olmayan trafikle nasıl baş edilir?
HTTP_PROXY değişkenleri yalnızca onlara saygı gösteren HTTP ve HTTPS istemcileri için çalışır. Rasgele TCP bağlantıları için ilgili yönlendirme kurallarıyla sidecar veya egress gateway düzeyinde şeffaf yakalama gerekir. Burada ortam değişkenleri çaresizdir.
Farklı pod'lar için farklı proxy politikası tanımlanabilir mi?
Evet. Konteyner düzeyinde - farklı deployment'larda farklı env ile. Egress düzeyinde - egress politikalarındaki etiket seçicileri aracılığıyla işaretli pod'ları istenen çıkışa yönlendirerek. Birleştirme esneklik verir: gateway üzerinden temel çıkış artı bireysel servisler için bireysel ayarlar.
Sonuç: dağıtım kontrol listesini bir araya getirelim
"Sıradan sunucudaki gibi yapılandırma"nın kümede neden çalışmadığından, proxy yerleştirmenin üç seviyesine, NO_PROXY inceliklerine, sırlara, sidecar'a, egress gateway'e ve teşhise kadar yolu kat ettik. Ana sonuç: Kubernetes'te giden trafik tek bir değişken değil, katmanlı bir sistemdir; burada en önemli olan proxy'yi nasıl etkinleştireceğiniz değil, onunla iç iletişimi nasıl bozmayacağınızdır.
Her dağıtımda göz önünde bulundurulması gereken nihai kontrol listesini bir araya getirelim.
Kümede proxy dağıtım kontrol listesi
- Seviyeyi belirledik. Konteyner, sidecar veya egress gateway'i belirli bir görev için bilinçli seçtik.
- Tam NO_PROXY oluşturduk.