Nga jeta me Kubernetes: Si serveri HTTP i spanjollëve nuk u pëlqente

Nga jeta me Kubernetes: Si serveri HTTP i spanjollëve nuk u pëlqente

Përfaqësuesi i klientit tonë, nëntëti i aplikacioneve të të cilit qëndron në re nga Microsoft (Azure), iu përgjigj një problemi: që nga një kohë e afërt, disa kërkesa të disa klientëve nga Evropa kanë filluar të përfundojnë me gabimin 400 (Kërkesë e Keqe). Të gjitha aplikacionet janë shkruar në .NET, të vendosura në Kubernetes


Një nga aplikacionet është API, përmes së cilës në fund të fundit arrin gjithë trafiku. Ky trafik dëgjohet nga serveri HTTP Kestrel, i konfigurur nga klienti .NET dhe i vendosur në pod. Na ndihmoi me debugimin fakti që kishte një përdorues të caktuar, për të cilin problemi shfaqej vazhdimisht. Megjithatë, gjithçka u komplikuar nga zinxhiri i trafikut:

Nga jeta me Kubernetes: Si serveri HTTP i spanjollëve nuk u pëlqente

Gabimi në Ingress dukej si më poshtë:

{
   "number_fields":{
      "status":400,
      "request_time":0.001,
      "bytes_sent":465,
      "upstream_response_time":0,
      "upstream_retries":0,
      "bytes_received":2328
   },
   "stream":"stdout",
   "string_fields":{
      "ingress":"app",
      "protocol":"HTTP/1.1",
      "request_id":"f9ab8540407208a119463975afda90bc",
      "path":"/api/sign-in",
      "nginx_upstream_status":"400",
      "service":"app",
      "namespace":"production",
      "location":"/front",
      "scheme":"https",
      "method":"POST",
      "nginx_upstream_response_time":"0.000",
      "nginx_upstream_bytes_received":"120",
      "vhost":"api.app.example.com",
      "host":"api.app.example.com",
      "user":"",
      "address":"83.41.81.250",
      "nginx_upstream_addr":"10.240.0.110:80",
      "referrer":"https://api.app.example.com/auth/login?long_encrypted_header",
      "service_port":"http",
      "user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
      "time":"2019-03-06T18:29:16+00:00",
      "content_kind":"cache-headers-not-present",
      "request_query":""
   },
   "timestamp":"2019-03-06 18:29:16",
   "labels":{
      "app":"nginx",
      "pod-template-generation":"6",
      "controller-revision-hash":"1682636041"
   },
   "namespace":"kube-nginx-ingress",
   "nsec":6726612,
   "source":"kubernetes",
   "host":"k8s-node-55555-0",
   "pod_name":"nginx-v2hcb",
   "container_name":"nginx",
   "boolean_fields":{}
}

Në këtë rast, Kestrel ktheu:

HTTP/1.1 400 Kërkesë e Keqe
Connection: close
Date: Mër, 06 Mar 2019 12:34:20 GMT
Server: Kestrel
Content-Length: 0

Madje, edhe me nivelin maksimal të detajimit, gabimi i Kestrel kishte jashtëzakonisht pak informacion të dobishëm:

{
   "number_fields":{"ThreadId":76},
   "stream":"stdout",
   "string_fields":{
      "EventId":"{"Id"=>17, "Name"=>"ConnectionBadRequest"}",
      "SourceContext":"Microsoft.AspNetCore.Server.Kestrel",
      "ConnectionId":"0HLL2VJSST5KV",
      "@mt":"Connection id "{ConnectionId}" data kërkese të keqe: "{message}"",
      "@t":"2019-03-07T13:06:48.1449083Z",
      "@x":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Kërkesë e keqe: tituj të pavlefshëm.n   në Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)n   në Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequestsAsync>d__185`1.MoveNext()",
      "message":"Kërkesë e keqe: tituj të pavlefshëm."
   },
   "timestamp":"2019-03-07 13:06:48",
   "labels":{
      "pod-template-hash":"2368795483",
      "service":"app"
   },
   "namespace":"production",
   "nsec":145341848,
   "source":"kubernetes",
   "host":"k8s-node-55555-1",
   "pod_name":"app-67bdcf98d7-mhktx",
   "container_name":"app",
   "boolean_fields":{}
}

Duket se vetëm tcpdump do të ndihmojë në zgjidhjen e këtij problemi
 por përsëris për zinxhirin e trafik:

Nga jeta me Kubernetes: Si serveri HTTP i spanjollëve nuk u pëlqente

Hetimi

E qartë, se është më mirë të dëgjosh trafik në atë nod konkret, ku Kubernetes ka vendosur pod: sasia e dump-it do të jetë e tillë, saqë do të mund të gjejë ndonjë gjë mjaft shpejt. Dhe në të vërtetë, kur u shqyrtua, u vërejt një kadër e tillë:

GET /back/user HTTP/1.1
Host: api.app.example.com
X-Request-ID: 27ceb14972da8c21a8f92904b3eff1e5
X-Real-IP: 83.41.81.250
X-Forwarded-For: 83.41.81.250
X-Forwarded-Host: api.app.example.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Original-URI: /front/back/user
X-Scheme: https
X-Original-Forwarded-For: 83.41.81.250
X-Nginx-Geo-Client-Country: Spain
X-Nginx-Geo-Client-City: M.laga
Accept-Encoding: gzip
CF-IPCountry: ES
CF-RAY: 4b345cfd1c4ac691-MAD
CF-Visitor: {"scheme":"https"}
pragma: no-cache
cache-control: no-cache
accept: application/json, text/plain, */*
origin: https://app.example.com
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36
referer: https://app.example.com/auth/login
accept-language: en-US,en;q=0.9,en-GB;q=0.8,pl;q=0.7
cookie: many_encrypted_cookies; .AspNetCore.Identity.Application=something_encrypted; 
CF-Connecting-IP: 83.41.81.250
True-Client-IP: 83.41.81.250
CDN-Loop: cloudflare

HTTP/1.1 400 Bad Request
Connection: close
Date: Wed, 06 Mar 2019 12:34:20 GMT
Server: Kestrel
Content-Length: 0

Duke e vĂ«zhguar me kujdes dump-in, u vu re fjala M.laga. ËshtĂ« e lehtĂ« tĂ« kuptohet se nĂ« SpanjĂ« nuk ka qytet M.laga (por ka MĂĄlaga). Duke u kapur pas kĂ«saj ideje, shikuam konfigurimet e Ingress-it, ku pikasĂ«m snippet-in e futur njĂ« muaj mĂ« parĂ« (nĂ« kĂ«rkesĂ« tĂ« klientit) „pa dĂ«mshĂ«m“ snippet:

    ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Nginx-Geo-Client-Country $geoip_country_name;
      proxy_set_header X-Nginx-Geo-Client-City $geoip_city;

Për sa kohë që u çaktivizua kalimi i këtyre kokave, gjithçka kishte filluar të funksionojë! (Shpejt doli në pah se këto kokat nuk ishin më të nevojshme për vetë aplikacionin.)

Tani le tĂ« shohim problemin nĂ« njĂ« pamje mĂ« tĂ« pĂ«rgjithshme. ËshtĂ« lehtĂ«sisht e riprodhueshme brenda aplikacionit, nĂ«se bĂ«jmĂ« njĂ« kĂ«rkesĂ« telnet nĂ« localhost:80:

GET /back/user HTTP/1.1
Host: api.app.example.com
cache-control: no-cache
accept: application/json, text/plain, */*
origin: https://app.example.com
Cookie: test=Desiree


 kthehet 401 Unauthorized, ashtu siç pritej. ÇfarĂ« do tĂ« ndodhĂ« nĂ«se bĂ«jmĂ«:

GET /back/user HTTP/1.1
Host: api.app.example.com
cache-control: no-cache
accept: application/json, text/plain, */*
origin: https://app.example.com
Cookie: test=Désirée

?

Do tĂ« kthehet 400 Bad request — nĂ« logun e aplikacionit do tĂ« pĂ«rfitojmĂ« gabimin e njohur:

{
   "@t":"2019-03-31T12:59:54.3746446Z",
   "@mt":"Connection id "{ConnectionId}" bad request data: "{message}"",
   "@x":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Malformed request: invalid headers.n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequestsAsync>d__185`1.MoveNext()",
   "ConnectionId":"0HLLLR1J974L9",
   "message":"Malformed request: invalid headers.",
   "EventId":{
      "Id":17,
      "Name":"ConnectionBadRequest"
   },
   "SourceContext":"Microsoft.AspNetCore.Server.Kestrel",
   "ThreadId":71
}

Përfundimet

Përkatësisht Kestrel nuk mundet të përpunoni në mënyrë korrekte HTTP-të me simbole të sakta në UTF-8, të pranishme në emrat e shumë qyteteve.

Faktori shtesĂ« nĂ« rastin tonĂ« Ă«shtĂ« se klienti aktualisht nuk planifikon tĂ« ndryshojĂ« implementimin e Kestrel. SidoqoftĂ«, çështjet nĂ« AspNetCore vetĂ« (№4318, №7707) tregojnĂ« se kjo nuk do tĂ« ndihmojë 

Përmbledhje: shënimi nuk është më rreth problemeve specifike të Kestrel ose UTF-8 (në vitin 2019?!), por se vëmendja dhe studimi sistematik i çdo hapi gjatë kërkimit të problemit do të japin rezultate përfundimisht. Sukese!

P.S.

Lexoni gjithashtu në blogun tonë:

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster