Elämästä Kubernetesin kanssa: Kuinka HTTP-palvelin ei suosinut espanjalaisia

Elämästä Kubernetesin kanssa: Kuinka HTTP-palvelin ei suosinut espanjalaisia

Asiakkaamme edustaja, jonka sovelluspino sijaitsee Microsoftin pilvessä (Azure), ratkaisi ongelman: äskettäin jotkut pyynnöt joistakin asiakkailta Euroopasta alkoivat päättyä virheeseen 400 (Huono pyyntö). Kaikki sovellukset on kirjoitettu .NETissä, otettu käyttöön Kubernetesissa...

Yksi sovelluksista on API, jonka kautta kaikki liikenne lopulta tulee. HTTP-palvelin kuuntelee tätä liikennettä tuulihaukka, jonka .NET-asiakas määrittää ja isännöi podissa. Virheenkorjauksen kanssa olimme onnekkaita siinä mielessä, että oli tietty käyttäjä, joka toisti ongelman jatkuvasti. Kaikkea vaikeutti kuitenkin liikenneketju:

Elämästä Kubernetesin kanssa: Kuinka HTTP-palvelin ei suosinut espanjalaisia

Ingressin virhe näytti tältä:

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

Samaan aikaan Kestrel antoi:

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

Jopa maksimaalisella sanallisuudella, Kestrel-virhe sisälsi äärimmäisen paljon vähän hyödyllistä tietoa:

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

Vaikuttaa siltä, ​​​​että vain tcpdump auttaa ratkaisemaan tämän ongelman... mutta toistan liikenneketjusta:

Elämästä Kubernetesin kanssa: Kuinka HTTP-palvelin ei suosinut espanjalaisia

tutkimus

On selvää, että on parempi kuunnella liikennettä kyseisessä solmussa, jossa Kubernetes on ottanut käyttöön podin: kaatopaikan tilavuus tulee olemaan sellainen, että sieltä on mahdollista löytää ainakin jotain melko nopeasti. Ja todellakin, kun sitä tutkittiin, havaittiin seuraava kehys:

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

Kaatopaikkaa tarkemmin tarkasteltaessa sana huomattiin M.laga. On helppo arvata, että Espanjassa ei ole M.laga-kaupunkia (mutta on Malaga). Tartuimme tähän ideaan, katsoimme Ingress-konfiguraatioita, joissa näimme kuukausi sitten lisätyn (asiakkaan pyynnöstä) "vaaraton" katkelma:

    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;

Kun näiden otsikoiden edelleenlähetys oli poistettu käytöstä, kaikki sujui hyvin! (Pian kävi selväksi, että sovellus itse ei enää tarvinnut näitä otsikoita.)

Katsotaan nyt ongelmaa yleisemmin. Se voidaan helposti toistaa sovelluksen sisällä tekemällä Telnet-pyynnö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

...palaa 401 Unauthorized, odotetusti. Mitä tapahtuu, jos teemme:

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

?

Palaa 400 Bad request — sovelluslokiin tulee meille jo tuttu virhe:

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

Tulokset

Nimenomaan Kestrel ei voi käsittelemään oikein HTTP-otsikot oikeilla merkeillä UTF-8:ssa, jotka sisältyvät melko useiden kaupunkien nimiin.

Lisätekijä meidän tapauksessamme on, että asiakas ei tällä hetkellä aio muuttaa Kestrelin toteutusta sovelluksessa. Kuitenkin ongelmat itse AspNetCoressa (№ 4318, № 7707) he sanovat, että tämä ei auta...

Yhteenvetona: muistiinpano ei enää koske Kestrelin tai UTF-8:n erityisongelmia (vuonna 2019?!), vaan siitä, että mindfulness ja johdonmukainen opiskelu Jokainen askel, jonka otat etsiessäsi ongelmia, kantaa ennemmin tai myöhemmin hedelmää. Onnea!

PS.

Lue myös blogistamme:

Lähde: will.com

Lisää kommentti