स्रोत आईपी का उपयोग करें
Kubernetes क्लस्टर में चलने वाले एप्लिकेशन सर्विस एब्स्ट्रैक्शन के ज़रिए एक-दूसरे और बाहरी दुनिया से संपर्क करते हैं और उनसे संवाद करते हैं। यह दस्तावेज़ बताता है कि अलग-अलग तरह की सेवाओं को भेजे जाने वाले पैकेट के स्रोत IP का क्या होता है और आप अपनी ज़रूरतों के हिसाब से इस व्यवहार को कैसे बदल सकते हैं।
शुरू करने से पहले
शब्दावली
इस दस्तावेज़ में निम्नलिखित शब्दों का प्रयोग किया गया है:
- NAT
- नेटवर्क एड्रेस ट्रांसलेशन
- Source NAT
- पैकेट पर स्रोत आईपी को प्रतिस्थापित करना; इस पृष्ठ पर, इसका अर्थ आमतौर पर नोड के आईपी पते के साथ प्रतिस्थापित करना है।
- Destination NAT
- पैकेट पर गंतव्य आईपी को प्रतिस्थापित करना; इस पृष्ठ पर, इसका मतलब आमतौर पर पॉड के आईपी पते के साथ प्रतिस्थापित करना है
- VIP
- एक वर्चुअल आईपी पता, जैसे कि कुबेरनेट्स में प्रत्येक सेवा को निर्दिष्ट किया गया है
- kube-proxy
- एक नेटवर्क डेमॉन जो प्रत्येक नोड पर सेवा वीआईपी प्रबंधन को व्यवस्थित करता है
Prerequisites
आपको कुबरनेट्स क्लस्टर की ज़रूरत पड़ेगी और क्यूब सीटीएल कमांड लाइन साधन को समनुरूप करना होगा ताकि वो आपके क्लस्टर के साथ संवाद कर सकें। हमारी सलाह है की इस टुटोरिअल को क्लस्टर में रन करने के लिए कम से कम दो नोड का इस्तेमाल करे जो कि कंट्रोल प्लेन होस्ट के तरह ना एक्ट करे। अगर आपके पास पहले से क्लस्टर नही है, आप minikube की मदद से वह बना सकते है या आप नीचे दिए हुए इन दो कुबरनेट्स प्लेग्राउंड का इस्तेमाल कर सकते हैं:
उदाहरणों में एक छोटे nginx वेबसर्वर का उपयोग किया गया है जो HTTP हेडर के माध्यम से प्राप्त अनुरोधों के स्रोत IP को प्रतिध्वनित करता है। आप इसे निम्न प्रकार से बना सकते हैं:
टिप्पणी:
निम्नलिखित कमांड में दी गई छवि केवल AMD64 आर्किटेक्चर पर चलती है।kubectl create deployment source-ip-app --image=registry.k8s.io/echoserver:1.4
आउटपुट है:
deployment.apps/source-ip-app created
उद्देश्य
- विभिन्न प्रकार की सेवाओं के माध्यम से एक सरल अनुप्रयोग को उजागर करें
- समझें कि प्रत्येक सेवा प्रकार स्रोत IP NAT को कैसे संभालता है
- स्रोत IP को संरक्षित करने में शामिल ट्रेडऑफ़ को समझें
Type=ClusterIP
वाली सेवाओं के लिए स्रोत IP
यदि आप kube-proxy को iptables मोड
(डिफ़ॉल्ट) में चला रहे हैं, तो क्लस्टर के भीतर से ClusterIP को भेजे गए पैकेट कभी भी स्रोत NAT'd नहीं होते हैं। आप kube-proxy मोड को उस नोड पर http://localhost:10249/proxyMode
लाकर क्वेरी कर सकते हैं जहाँ kube-proxy चल रहा है।
kubectl get nodes
इसका आउटपुट कुछ इस प्रकार है:
NAME STATUS ROLES AGE VERSION
kubernetes-node-6jst Ready <none> 2h v1.13.0
kubernetes-node-cx31 Ready <none> 2h v1.13.0
kubernetes-node-jj1t Ready <none> 2h v1.13.0
किसी एक नोड पर प्रॉक्सी मोड प्राप्त करें (kube-proxy पोर्ट 10249 पर सुनता है):
# Run this in a shell on the node you want to query.
curl http://localhost:10249/proxyMode
इसका आउटपुट कुछ इस प्रकार है:
iptables
आप स्रोत IP ऐप पर सेवा बनाकर स्रोत IP संरक्षण का परीक्षण कर सकते हैं:
kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
इसका आउटपुट कुछ इस प्रकार है:
service/clusterip exposed
kubectl get svc clusterip
इसका आउटपुट कुछ इस प्रकार है:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
clusterip ClusterIP 10.0.170.92 <none> 80/TCP 51s
और उसी क्लस्टर में एक पॉड से ClusterIP
को हिट करना:
kubectl run busybox -it --image=busybox:1.28 --restart=Never --rm
इसका आउटपुट कुछ इस प्रकार है:
Waiting for pod default/busybox to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
फिर आप उस पॉड के अंदर एक कमांड चला सकते हैं:
# Run this inside the terminal from "kubectl run"
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue
link/ether 0a:58:0a:f4:03:08 brd ff:ff:ff:ff:ff:ff
inet 10.244.3.8/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::188a:84ff:feb0:26a5/64 scope link
valid_lft forever preferred_lft forever
…फिर लोकल वेबसर्वर को क्वेरी करने के लिए wget
का उपयोग करें
# Replace "10.0.170.92" with the IPv4 address of the Service named "clusterip"
wget -qO - 10.0.170.92
CLIENT VALUES:
client_address=10.244.3.8
command=GET
...
client_address
हमेशा क्लाइंट पॉड का IP पता होता है, चाहे क्लाइंट पॉड और सर्वर पॉड एक ही नोड में हों या अलग-अलग नोड्स में हों।
Type=NodePort
वाली सेवाओं के लिए स्रोत IP
Type=NodePort
के साथ सेवाओं को भेजे गए पैकेट
डिफ़ॉल्ट रूप से स्रोत NAT'd होते हैं। आप NodePort
सेवा बनाकर इसका परीक्षण कर सकते हैं:
kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
इसका आउटपुट कुछ इस प्रकार है:
service/nodeport exposed
NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address }')
यदि आप क्लाउड प्रोवाइडर पर चल रहे हैं, तो आपको ऊपर बताए गए nodes:nodeport
के लिए फ़ायरवॉल-नियम खोलने की आवश्यकता हो सकती है। अब आप ऊपर आवंटित नोड पोर्ट के माध्यम से क्लस्टर के बाहर से सेवा तक पहुँचने का प्रयास कर सकते हैं।
for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done
इसका आउटपुट कुछ इस प्रकार है:
client_address=10.180.1.1
client_address=10.240.0.5
client_address=10.240.0.3
ध्यान दें कि ये सही क्लाइंट IP नहीं हैं, ये क्लस्टर के आंतरिक IP हैं। यह इस तरह काम करता है:
- क्लाइंट पैकेट को
node2:nodePort
पर भेजता है node2
पैकेट में मौजूद सोर्स IP एड्रेस (SNAT) को अपने IP एड्रेस से बदल देता हैnode2
पैकेट पर मौजूद डेस्टिनेशन IP को पॉड IP से बदल देता है- पैकेट को नोड 1 और फिर एंडपॉइंट पर भेजा जाता है
- पॉड का जवाब वापस नोड 2 पर भेजा जाता है
- पॉड का जवाब वापस क्लाइंट को भेजा जाता है
दृश्यात्मक रूप से:
Figure. Source IP Type=NodePort using SNAT
इससे बचने के लिए, Kubernetes में क्लाइंट स्रोत IP को संरक्षित करने की सुविधा है।
यदि आप service.spec.externalTrafficPolicy
को Local
मान पर सेट करते हैं, तो kube-proxy केवल स्थानीय एंडपॉइंट पर प्रॉक्सी अनुरोधों को प्रॉक्सी करता है, और ट्रैफ़िक को अन्य नोड्स पर अग्रेषित नहीं करता है। यह दृष्टिकोण मूल स्रोत IP पते को संरक्षित करता है। यदि कोई स्थानीय एंडपॉइंट नहीं हैं, तो नोड पर भेजे गए पैकेट ड्रॉप हो जाते हैं, इसलिए आप किसी भी पैकेट प्रोसेसिंग नियम में सही स्रोत-आईपी पर भरोसा कर सकते हैं, आप एक पैकेट लागू कर सकते हैं जो एंडपॉइंट तक पहुंचता है।
service.spec.externalTrafficPolicy
फ़ील्ड को निम्न प्रकार से सेट करें:
kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}'
इसका आउटपुट कुछ इस प्रकार है:
service/nodeport patched
अब, परीक्षण पुनः चलाएँ:
for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done
आउटपुट इस प्रकार है:
client_address=198.51.100.79
ध्यान दें कि आपको केवल एक उत्तर मिला है, सही क्लाइंट IP के साथ, उस नोड से जिस पर एंडपॉइंट पॉड चल रहा है।
यह कुछ इस तरह काम करता है:
- क्लाइंट पैकेट को
node2:nodePort
पर भेजता है, जिसमें कोई एंडपॉइंट नहीं है - पैकेट को छोड़ दिया जाता है
- क्लाइंट पैकेट को
node1:nodePort
पर भेजता है, जिसमें एंडपॉइंट हैं - node1 पैकेट को सही सोर्स IP वाले एंडपॉइंट पर रूट करता है
दृश्यात्मक रूप से:
Figure. Source IP Type=NodePort preserves client source IP address
Type=LoadBalancer
वाली सेवाओं के लिए स्रोत IP
Type=LoadBalancer
के साथ सेवाओं को भेजे गए पैकेट
डिफ़ॉल्ट रूप से स्रोत NAT'd होते हैं, क्योंकि Ready
स्थिति में सभी शेड्यूल करने योग्य Kubernetes नोड लोड-बैलेंस्ड ट्रैफ़िक के लिए पात्र होते हैं। इसलिए यदि पैकेट बिना किसी एंडपॉइंट के नोड पर पहुंचते हैं, तो सिस्टम इसे एक एंडपॉइंट वाले नोड पर प्रॉक्सी करता है, पैकेट पर स्रोत IP को नोड के IP से बदल देता है (जैसा कि पिछले अनुभाग में वर्णित है)।
आप लोड बैलेंसर के माध्यम से स्रोत-आईपी-ऐप को उजागर करके इसका परीक्षण कर सकते हैं:
kubectl expose deployment source-ip-app --name=loadbalancer --port=80 --target-port=8080 --type=LoadBalancer
आउटपुट इस प्रकार है::
service/loadbalancer exposed
सेवा के आईपी पते का प्रिंट आउट लें:
kubectl get svc loadbalancer
आउटपुट इस प्रकार है:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
loadbalancer LoadBalancer 10.0.65.118 203.0.113.140 80/TCP 5m
इसके बाद, इस सेवा के बाहरी-आईपी को अनुरोध भेजें:
curl 203.0.113.140
आउटपुट इस प्रकार है:
CLIENT VALUES:
client_address=10.240.0.5
...
हालाँकि, यदि आप Google Kubernetes Engine/GCE पर चल रहे हैं, तो उसी service.spec.externalTrafficPolicy
फ़ील्ड को Local
पर सेट करने से सेवा समापन बिंदुओं के बिना नोड्स को जानबूझकर स्वास्थ्य जांच में विफल होने के कारण लोडबैलेंस्ड ट्रैफ़िक के लिए योग्य नोड्स की सूची से खुद को हटाने के लिए मजबूर होना पड़ता है।
दृश्यात्मक रूप से:
आप एनोटेशन सेट करके इसका परीक्षण कर सकते हैं:
kubectl patch svc loadbalancer -p '{"spec":{"externalTrafficPolicy":"Local"}}'
आपको तुरंत Kubernetes द्वारा आवंटित service.spec.healthCheckNodePort
फ़ील्ड दिखाई देगी:
kubectl get svc loadbalancer -o yaml | grep -i healthCheckNodePort
आउटपुट इस प्रकार है:
healthCheckNodePort: 32122
service.spec.healthCheckNodePort
फ़ील्ड /healthz
पर स्वास्थ्य जाँच करने वाले प्रत्येक नोड पर एक पोर्ट की ओर इशारा करता है।
आप इसका परीक्षण कर सकते हैं:
kubectl get pod -o wide -l app=source-ip-app
आउटपुट इस प्रकार है:
NAME READY STATUS RESTARTS AGE IP NODE
source-ip-app-826191075-qehz4 1/1 Running 0 20h 10.180.1.136 kubernetes-node-6jst
विभिन्न नोड्स पर /healthz
एंडपॉइंट लाने के लिए curl
का उपयोग करें:
# Run this locally on a node you choose
curl localhost:32122/healthz
1 Service Endpoints found
किसी भिन्न नोड पर आपको भिन्न परिणाम मिल सकता है:
# Run this locally on a node you choose
curl localhost:32122/healthz
No Service Endpoints Found
कंट्रोल प्लेन पर चलने वाला एक कंट्रोलर क्लाउड लोड बैलेंसर को आवंटित करने के लिए जिम्मेदार होता है। वही कंट्रोलर प्रत्येक नोड पर इस पोर्ट/पथ की ओर इशारा करते हुए HTTP स्वास्थ्य जांच भी आवंटित करता है। स्वास्थ्य जांच में विफल होने के लिए एंडपॉइंट के बिना 2 नोड्स के लिए लगभग 10 सेकंड प्रतीक्षा करें, फिर लोड बैलेंसर के IPv4 पते को क्वेरी करने के लिए curl
का उपयोग करें:
curl 203.0.113.140
आउटपुट इस प्रकार है:
CLIENT VALUES:
client_address=198.51.100.79
...
क्रॉस-प्लेटफ़ॉर्म समर्थन
केवल कुछ क्लाउड प्रदाता ही Type=LoadBalancer
वाली सेवाओं के माध्यम से स्रोत IP संरक्षण के लिए समर्थन प्रदान करते हैं।
आप जिस क्लाउड प्रदाता पर काम कर रहे हैं, वह कुछ अलग-अलग तरीकों से लोडबैलेंसर के लिए अनुरोध को पूरा कर सकता है:
-
एक प्रॉक्सी के साथ जो क्लाइंट कनेक्शन को समाप्त करता है और आपके नोड्स/एंडपॉइंट्स के लिए एक नया कनेक्शन खोलता है। ऐसे मामलों में स्रोत IP हमेशा क्लाउड LB का होगा, क्लाइंट का नहीं।
-
एक पैकेट फ़ॉरवर्डर के साथ, जैसे कि क्लाइंट से लोडबैलेंसर VIP को भेजे गए अनुरोध क्लाइंट के स्रोत IP वाले नोड पर समाप्त होते हैं, न कि किसी मध्यवर्ती प्रॉक्सी पर।
पहली श्रेणी के लोड बैलेंसर को लोडबैलेंसर और बैकएंड के बीच HTTP फॉरवर्डेड या X-FORWARDED-FOR हेडर या
प्रॉक्सी प्रोटोकॉल जैसे वास्तविक क्लाइंट IP को संप्रेषित करने के लिए सहमत प्रोटोकॉल का उपयोग करना चाहिए। दूसरी श्रेणी के लोड बैलेंसर सेवा पर service.spec.healthCheckNodePort
फ़ील्ड में संग्रहीत पोर्ट पर इंगित HTTP स्वास्थ्य जांच बनाकर ऊपर वर्णित सुविधा का लाभ उठा सकते हैं।
सफाई करना
सेवाएँ समाप्त करें:
kubectl delete svc -l app=source-ip-app
डिप्लॉयमेंट, रेप्लिका सेट और पॉड को समाप्त करें:
kubectl delete deployment source-ip-app
आगे क्या है
- सेवाओं के माध्यम से एप्लिकेशन कनेक्ट करने के बारे में अधिक जानें
- बाहरी लोड बैलेंसर बनाने का तरीका पढ़ें