Kubernetes'le hayattan: HTTP sunucusu nasıl İspanyolların lehine olmadı?

Kubernetes'le hayattan: HTTP sunucusu nasıl İspanyolların lehine olmadı?

Uygulama yığını Microsoft bulutunda (Azure) bulunan müşterimizin bir temsilcisi bir sorunu ele aldı: yakın zamanda Avrupa'daki bazı müşterilerden gelen bazı istekler 400 hatasıyla bitmeye başladı (Hatalı İstek). Tüm uygulamalar .NET'te yazılmıştır ve Kubernetes'te konuşlandırılmıştır...

Uygulamalardan biri, sonuçta tüm trafiğin geldiği API'dir. Bu trafik HTTP sunucusu tarafından dinlenir Kerkenez.NET istemcisi tarafından yapılandırılır ve bir bölmede barındırılır. Hata ayıklamada, sorunu sürekli olarak yeniden üreten belirli bir kullanıcının olması açısından şanslıydık. Ancak trafik zinciri nedeniyle her şey karmaşıktı:

Kubernetes'le hayattan: HTTP sunucusu nasıl İspanyolların lehine olmadı?

Giriş'teki hata şuna benziyordu:

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

Aynı zamanda Kestrel şunu verdi:

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

Maksimum ayrıntı düzeyinde bile Kestrel hatası son derece önemliydi. çok az yararlı bilgi:

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

Görünüşe göre bu sorunu çözmeye yalnızca tcpdump yardımcı olacak... ancak trafik zinciri hakkında tekrar edeceğim:

Kubernetes'le hayattan: HTTP sunucusu nasıl İspanyolların lehine olmadı?

soruşturma

Açıkçası, trafiği dinlemek daha iyi söz konusu düğümdeKubernetes'in bir kapsül yerleştirdiği yer: çöplüğün hacmi, en azından bir şeyi oldukça hızlı bir şekilde bulmanın mümkün olacağı kadar büyük olacak. Ve gerçekten de onu incelerken şu çerçeve fark edildi:

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

Çöplük daha yakından incelendiğinde fark edildi M.laga. İspanya'da M.laga şehrinin olmadığını tahmin etmek kolaydır (ancak Malaga). Bu fikirden yola çıkarak, bir ay önce eklenen Ingress yapılandırmalarına baktık (müşterinin isteği üzerine) "zararsız" pasajı:

    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;

Bu başlıkların iletilmesini devre dışı bıraktıktan sonra her şey yoluna girdi! (Kısa sürede uygulamanın kendisinin artık bu başlıklara ihtiyaç duymadığı anlaşıldı.)

Şimdi soruna bakalım daha genel olarak. Telnet isteğinde bulunularak uygulama içerisinde kolaylıkla çoğaltılabilir. 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

... İadeler 401 Unauthorized, beklenildiği gibi. Bunu yaparsak ne olur:

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

?

Dönecek 400 Bad request — uygulama günlüğünde bize zaten tanıdık gelen bir hata alacağız:

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

sonuçlar

Özellikle Kerkenez Yapamam Oldukça fazla sayıda şehrin adlarında bulunan UTF-8'deki doğru karakterlerle HTTP başlıklarını doğru şekilde işleyin.

Bizim durumumuzdaki ek bir faktör, müşterinin şu anda uygulamadaki Kestrel uygulamasını değiştirmeyi planlamamasıdır. Ancak AspNetCore'un kendisindeki sorunlar (№ 4318, № 7707) bunun faydası olmayacağını söylüyorlar...

Özetlemek gerekirse: not artık Kestrel veya UTF-8'in (2019'da mı?!) belirli sorunlarıyla ilgili değil, ancak şu gerçekle ilgili: farkındalık ve tutarlı çalışma Sorun ararken attığınız her adım er ya da geç meyvesini verecektir. İyi şanlar!

PS

Blogumuzda da okuyun:

Kaynak: habr.com

Yorum ekle