मैं kubernetes python क्लाइंट का उपयोग कर रहा हूं। यदि मेरा कोड शुरू होने पर कुबेरनेट्स उपलब्ध नहीं है, तो मैं कनेक्शन का पुनः प्रयास करना चाहता हूं।

जब क्लाइंट कनेक्ट करने में असमर्थ होता है, तो वह फेंकता है जो urllib3.exceptions.MaxRetryError अपवाद प्रतीत होता है, इसलिए मैंने कुछ इस तरह से शुरुआत की:

import time
import urllib3

import kubernetes

kubernetes.config.load_kube_config()
api = kubernetes.client.CoreV1Api()

while True:
    try:
        w = kubernetes.watch.Watch()
        for event in w.stream(api.list_pod_for_all_namespaces):
            print event
    except urllib3.exceptions.HTTPError:
        print('retrying in 1 second')
        time.sleep(1)

लेकिन वह पूरी तरह विफल हो जाता है; यह ऐसे कार्य करता है जैसे कोई except कथन नहीं है और इसके साथ जमानत मिलती है:

urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='192.168.122.140', port=8443): Max retries exceeded with url: /api/v1/pods?watch=True (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x2743110>: Failed to establish a new connection: [Errno 111] Connection refused',))

मैंने सोचा कि शायद मैं विरासत को उतना नहीं समझता जितना मैंने सोचा था, इसलिए मैं उपरोक्त को इसके साथ बदल देता हूं:

except urllib3.exceptions.MaxRetryError:
    print('retrying in 1 second')
    time.sleep(1)

जो उसी तरह विफल रहता है। यह पता लगाने के प्रयास में कि क्या हो रहा था, मैंने एक कैच-ऑल except जोड़ा और पीडीबी का आह्वान किया:

except Exception as err:
    import pdb; pdb.set_trace()

और pdb प्रांप्ट से, हम देख सकते हैं:

(Pdb) type(err)
<class 'urllib3.exceptions.MaxRetryError'>

...जो ठीक दिखता है, जैसा कि एमआरओ करता है:

(Pdb) import inspect
(Pdb) inspect.getmro(err.__class__)
(<class 'urllib3.exceptions.MaxRetryError'>, <class 'urllib3.exceptions.RequestError'>, <class 'urllib3.exceptions.PoolError'>, <class 'urllib3.exceptions.HTTPError'>, <type 'exceptions.Exception'>, <type 'exceptions.BaseException'>, <type 'object'>)

लेकिन इन सबके बावजूद:

(Pdb) isinstance(err, urllib3.exceptions.MaxRetryError)
False

और सभी रास्ते उचित लगते हैं:

(Pdb) urllib3.__file__
'/usr/lib/python2.7/site-packages/urllib3/__init__.pyc'
(Pdb) kubernetes.client.rest.urllib3.__file__
'/usr/lib/python2.7/site-packages/urllib3/__init__.pyc'

तो... असल में यहाँ क्या हो रहा है?

अपडेट करें

यहाँ पूर्ण स्टैक ट्रेस है:

Traceback (most recent call last):
  File "testkube.py", line 13, in <module>
    for event in w.stream(api.list_pod_for_all_namespaces):
  File "/usr/lib/python2.7/site-packages/kubernetes/watch/watch.py", line 116, in stream
    resp = func(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/apis/core_v1_api.py", line 14368, in list_pod_for_all_namespaces
    (data) = self.list_pod_for_all_namespaces_with_http_info(**kwargs)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/apis/core_v1_api.py", line 14464, in list_pod_for_all_namespaces_with_http_info
    collection_formats=collection_formats)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/api_client.py", line 335, in call_api
    _preload_content, _request_timeout)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/api_client.py", line 148, in __call_api
    _request_timeout=_request_timeout)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/api_client.py", line 371, in request
    headers=headers)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/rest.py", line 250, in GET
    query_params=query_params)
  File "/usr/lib/python2.7/site-packages/kubernetes/client/rest.py", line 223, in request
    headers=headers)
  File "/usr/lib/python2.7/site-packages/urllib3/request.py", line 66, in request
    **urlopen_kw)
  File "/usr/lib/python2.7/site-packages/urllib3/request.py", line 87, in request_encode_url
    return self.urlopen(method, url, **extra_kw)
  File "/usr/lib/python2.7/site-packages/urllib3/poolmanager.py", line 321, in urlopen
    response = conn.urlopen(method, u.request_uri, **kw)
  File "/usr/lib/python2.7/site-packages/urllib3/connectionpool.py", line 668, in urlopen
    **response_kw)
  File "/usr/lib/python2.7/site-packages/urllib3/connectionpool.py", line 668, in urlopen
    **response_kw)
  File "/usr/lib/python2.7/site-packages/urllib3/connectionpool.py", line 668, in urlopen
    **response_kw)
  File "/usr/lib/python2.7/site-packages/urllib3/connectionpool.py", line 639, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/usr/lib/python2.7/site-packages/urllib3/util/retry.py", line 388, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='192.168.122.140', port=8443): Max retries exceeded with url: /api/v1/pods?watch=True (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x3d16110>: Failed to establish a new connection: [Errno 111] Connection refused',))
9
larsks 12 अक्टूबर 2017, 20:28
हमें स्टैक ट्रेस दिखाएं।
 – 
user2357112 supports Monica
12 अक्टूबर 2017, 20:30
यदि आप आयात urllib3 के बाद kubernetes आयात करते हैं तो क्या होगा?
 – 
Mark Dickinson
12 अक्टूबर 2017, 20:40
आयात के क्रम को बदलने से व्यवहार में कोई बदलाव नहीं आता है।
 – 
larsks
12 अक्टूबर 2017, 20:41
धन्यवाद। यह एक लंबा शॉट था। मैं सोच रहा था कि क्या कुबेरनेट्स या इसकी निर्भरता में से एक (उदाहरण के लिए, अनुरोध) urllib3 को बंद कर रहा था।
 – 
Mark Dickinson
12 अक्टूबर 2017, 20:43
हम्म। यह एक अलग सूत्र में या ऐसा कुछ भी नहीं हो रहा है। ऐसा लगता है कि आपके पास एक ही कक्षा की कई प्रतियाँ हैं, लगभग मानो कोई मॉड्यूल पुनः लोड हो गया हो। आपने कोई मॉड्यूल पुनः लोड नहीं किया, है ना?
 – 
user2357112 supports Monica
12 अक्टूबर 2017, 20:45

1 उत्तर

सबसे बढ़िया उत्तर

आपके कोड की requests पैकेज पर अप्रत्यक्ष निर्भरता है, और requests पैकेज में एक अजीब सबमॉड्यूल है जिसे requests.packages कहा जाता है। इसमें urllib3 सहित कई निर्भरताओं से कॉपी किए गए स्रोत कोड होते थे, लेकिन उन्होंने ऐसा करना बंद कर दिया। वे पिछड़े संगतता के लिए requests.packages को इधर-उधर रखना चाहते थे, इसलिए अब वे कुछ अजीब कर रहे हैं।

requests.packages के बजाय urllib3 स्रोत कोड की एक पूरी प्रति सहित, यह अब urllib3 आयात करता है और sys.modules['requests.packages.urllib3'] = urllib3 सेट करता है। requests संस्करण के आधार पर, यह कई अन्य sys.modules प्रविष्टियां भी सेट कर सकता है; उदाहरण के लिए, अनुरोधों के अनुसार 2.18.4, स्रोत कोड करता है

for package in ('urllib3', 'idna', 'chardet'):
    locals()[package] = __import__(package)
    # This traversal is apparently necessary such that the identities are
    # preserved (requests.packages.urllib3.* is urllib3.*)
    for mod in list(sys.modules):
        if mod == package or mod.startswith(package + '.'):
            sys.modules['requests.packages.' + mod] = sys.modules[mod]

लेकिन 2.17.0 में, यह करता है

import urllib3
sys.modules['requests.packages.urllib3'] = urllib3

import idna
sys.modules['requests.packages.idna'] = idna

import chardet
sys.modules['requests.packages.chardet'] = chardet

यह कोड आयातित पैकेज के सबमॉड्यूल के साथ बुरी तरह से इंटरैक्ट करता है। यदि कोई कोड import requests.packages.urllib3.exceptions करने का प्रयास करता है और पायथन को sys.modules['requests.packages.urllib3.exceptions'] प्रविष्टि नहीं मिलती है, तो पायथन urllib3.exceptions मॉड्यूल को फिर से बना देगा और urllib3.exceptions सेट करेगा और sys.modules['requests.packages.urllib3.exceptions'] नए मॉड्यूल में (लेकिन यह sys.modules['urllib3.exceptions'] को स्पर्श नहीं करेगा। यह शामिल कक्षाओं की नई प्रतियां उत्पन्न करेगा, जिससे आपकी त्रुटि हो सकती है।

इसी कारण से एक संबंधित समस्या मई में रिपोर्ट की गई थी, जिसके कारण नया कोड दिखाया गया 2.18.4 में। 2.18.4 आपके द्वारा देखी जा रही विशिष्ट समस्याओं का कारण नहीं होना चाहिए, लेकिन यह अभी भी नाजुक है, क्योंकि यदि urllib3 के किसी भी सबमॉड्यूल को अभी तक लोड नहीं किया गया है requests.packages sys.modules के साथ स्क्रू , वे सबमॉड्यूल वही समस्याएं प्रदर्शित करेंगे जो आपने आज देखी हैं।

7
user2357112 supports Monica 14 अक्टूबर 2017, 21:29
यह पता लगाने में आपकी मदद के लिए धन्यवाद! मैं रहस्यमय था।
 – 
larsks
12 अक्टूबर 2017, 21:53