Nga jeta me Kubernetes: Si serveri HTTP nuk favorizoi spanjollët

Nga jeta me Kubernetes: Si serveri HTTP nuk favorizoi spanjollët

Një përfaqësues i klientit tonë, grupi i aplikacioneve të të cilit ndodhet në renë kompjuterike të Microsoft (Azure), adresoi një problem: kohët e fundit, disa kërkesa nga disa klientë nga Evropa filluan të përfundojnë me gabimin 400 (Kerkese e keqe). Të gjitha aplikacionet janë të shkruara në .NET, të vendosura në Kubernetes...

Një nga aplikacionet është API, përmes të cilit në fund vjen i gjithë trafiku. Ky trafik dëgjohet nga serveri HTTP kestrik, i konfiguruar nga klienti .NET dhe i vendosur në një pod. Me korrigjimin, ne ishim me fat në kuptimin që kishte një përdorues specifik që e riprodhonte vazhdimisht problemin. Sidoqoftë, gjithçka ishte e ndërlikuar nga zinxhiri i trafikut:

Nga jeta me Kubernetes: Si serveri HTTP nuk favorizoi spanjollët

Gabimi në Ingress dukej kështu:

{
   "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ë të njëjtën kohë, Kestrel dha:

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

Edhe me zhdërvjelltësi maksimale, gabimi Kestrel përmbante 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}" bad request data: "{message}"",
      "@t":"2019-03-07T13:06:48.1449083Z",
      "@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()",
      "message":"Malformed request: invalid headers."
   },
   "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 unë do të përsëris për zinxhirin e trafikut:

Nga jeta me Kubernetes: Si serveri HTTP nuk favorizoi spanjollët

hetim

Natyrisht, është më mirë të dëgjosh trafikun në atë nyje specifike, ku Kubernetes ka vendosur një pod: vëllimi i deponisë do të jetë i tillë që do të jetë e mundur të gjendet të paktën diçka shumë shpejt. Dhe në të vërtetë, gjatë ekzaminimit të tij, u vu re korniza e mëposhtme:

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

Pas një kontrolli më të afërt të deponisë, fjala u vu re M.laga. Është e lehtë të merret me mend se nuk ka qytet M.laga në Spanjë (por ka Malaga). Duke u mbështetur në këtë ide, ne shikuam konfigurimet e Ingress, ku pamë atë të futur një muaj më parë (me kërkesë të klientit) fragment "i padëmshëm".:

    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;

Pas çaktivizimit të përcjelljes së këtyre titujve, gjithçka u bë mirë! (Së shpejti u bë e qartë se vetë aplikacioni nuk kishte më nevojë për këto tituj.)

Tani le të shohim problemin më në përgjithësi. Mund të riprodhohet lehtësisht brenda aplikacionit duke bërë 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, siç pritej. Çfarë 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 te kthehen 400 Bad request — në regjistrin e aplikacionit do të marrim një gabim që është tashmë i njohur për ne:

{
   "@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
}

Rezultatet e

Konkretisht Kestrel nuk mund të përpunoni saktë titujt HTTP me karakteret e duhura në UTF-8, të cilat gjenden në emrat e një numri mjaft të madh qytetesh.

Një faktor shtesë në rastin tonë është se klienti aktualisht nuk planifikon të ndryshojë zbatimin e Kestrel në aplikacion. Sidoqoftë, problemet në vetë AspNetCore (№ 4318, № 7707) thonë se kjo nuk do të ndihmojë...

Për ta përmbledhur: shënimi nuk ka të bëjë më me problemet specifike të Kestrel apo UTF-8 (në 2019?!), por për faktin se vëmendje dhe studim i qëndrueshëm Çdo hap që bëni gjatë kërkimit të problemeve herët a vonë do të japë fryte. Paç fat!

PS

Lexoni edhe në blogun tonë:

Burimi: www.habr.com

Shto një koment