Elust Kubernetesega: kuidas HTTP-server hispaanlasi ei soosinud

Elust Kubernetesega: kuidas HTTP-server hispaanlasi ei soosinud

Meie kliendi esindaja, kelle rakenduste pinu asub Microsofti pilves (Azure), käsitles probleemi: hiljuti hakkasid mõned Euroopast pärit klientide päringud lõppema veaga 400 (Halb päring). Kõik rakendused on kirjutatud .NET-is, juurutatud Kubernetesis...

Üks rakendustest on API, mille kaudu kogu liiklus lõpuks tuleb. Seda liiklust kuulab HTTP-server tuuletallaja, mille on konfigureerinud .NET-i klient ja mida hostitakse kaustas. Silumisega meil vedas selles mõttes, et oli konkreetne kasutaja, kes probleemi järjekindlalt kordas. Kõik tegi aga keeruliseks liiklusahel:

Elust Kubernetesega: kuidas HTTP-server hispaanlasi ei soosinud

Ingressi viga nägi välja selline:

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

Samal ajal andis Kestrel:

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

Isegi maksimaalse sõnasõnalisusega sisaldas Kestrel viga äärmiselt vähe kasulikku teavet:

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

Näib, et ainult tcpdump aitab seda probleemi lahendada ... aga kordan liiklusahela kohta:

Elust Kubernetesega: kuidas HTTP-server hispaanlasi ei soosinud

Uurimine

Ilmselgelt on parem liiklust kuulata sellel konkreetsel sõlmel, kus Kubernetes on kasutanud podi: prügila maht on selline, et sealt on võimalik üsna kiiresti vähemalt midagi leida. Ja tõepoolest, seda uurides jäi silma järgmine kaader:

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

Prügikohta lähemalt uurides jäi see sõna silma M.laga. Lihtne on arvata, et Hispaanias pole M.laga linna (aga on Malaga). Sellest ideest kinni haarates vaatasime Ingressi konfiguratsioone, kus nägime kuu aega tagasi sisestatut (kliendi soovil) "kahjutu" jupp:

    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ärast nende päiste edastamise keelamist läks kõik hästi! (Varsti sai selgeks, et rakendus ise ei vaja enam neid päiseid.)

Vaatame nüüd probleemi üldisemalt. Seda saab rakenduses hõlpsalt reprodutseerida, esitades telneti päringu 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

... naaseb 401 Unauthorized, ootuspäraselt. Mis juhtub, kui teeme:

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

?

Tuleb tagasi 400 Bad request — rakenduste logisse kuvatakse meile juba tuttav tõrketeade:

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

Tulemused

Täpsemalt Kestrel ei saa õigesti töötlema HTTP-päiseid õigete tähemärkidega UTF-8-s, mis sisalduvad üsna paljude linnade nimedes.

Täiendav asjaolu meie puhul on see, et klient ei plaani hetkel Kestreli rakendamist rakenduses muuta. Kuid probleemid AspNetCore'is endas (№ 4318, № 7707) nad ütlevad, et see ei aita...

Kokkuvõtteks: märkus ei räägi enam Kestreli ega UTF-8 spetsiifilistest probleemidest (2019. aastal?!), vaid sellest, et tähelepanelikkus ja järjepidev õppimine Iga samm, mille teete probleemide otsimisel, kannab varem või hiljem vilja. Edu!

PS

Loe ka meie blogist:

Allikas: www.habr.com

Lisa kommentaar