Dari kehidupan dengan Kubernetes: Bagaimana server HTTP Spanyol tidak mengeluh



Perwakilan klien kami, yang tumpukan aplikasi tinggal di cloud dari Microsoft (Azure), dihadapkan dengan masalah: baru-baru ini, sebagian permintaan beberapa klien dari Eropa mulai berakhir dengan kesalahan 400 ( Permintaan Buruk ). Semua aplikasi ditulis dalam .NET, digunakan di Kubernetes ...

Satu aplikasi adalah API yang melaluinya semua lalu lintas datang. Lalu lintas ini didengarkan oleh server HTTP Kestrel yang dikonfigurasi oleh klien .NET dan di-host di pod. Dengan debugging, kami beruntung dalam arti bahwa ada pengguna tertentu yang memiliki masalah yang direproduksi stabil. Namun, semuanya rumit oleh rantai lalu lintas:



Kesalahan dalam Ingress terlihat seperti ini:

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

Pada saat yang sama, Kestrel memberi:

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

Bahkan dengan verbositas maksimum, kesalahan Kestrel berisi sangat sedikit informasi berguna :

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

Tampaknya hanya tcpdump yang akan membantu menyelesaikan masalah ini ... tapi saya akan mengulangi tentang rantai lalu lintas:



Investigasi


Jelas, lebih baik mendengarkan lalu lintas di simpul tertentu tempat Kubernet mengerahkan pod: volume dump akan sedemikian rupa sehingga mungkin untuk menemukan setidaknya sesuatu dengan sangat cepat. Memang, ketika mempertimbangkannya, bingkai seperti itu diperhatikan:

 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 

Setelah memeriksa dump dengan hati-hati, kata M.laga diperhatikan. Sangat mudah untuk menebak bahwa di Spanyol tidak ada kota M. laga (tetapi ada Mรกlaga ). Memahami gagasan ini, kami melihat konfigurasi Ingress, tempat kami melihat cuplikan "tidak berbahaya" dimasukkan sebulan yang lalu (atas permintaan klien):

  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; 

Saat Anda menonaktifkan penerusan tajuk ini, semuanya menjadi baik! (Segera menjadi jelas bahwa aplikasi itu sendiri tidak lagi membutuhkan tajuk ini.)

Sekarang mari kita lihat masalahnya secara lebih umum . Itu dapat dengan mudah direproduksi di dalam aplikasi jika Anda membuat permintaan telnet ke 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 

... 401 Unauthorized , seperti yang diharapkan. Dan apa yang terjadi jika kita lakukan:

 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 

?

400 Bad request kembali - dalam log aplikasi kita akan mendapatkan kesalahan yang sudah kita ketahui:

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

Ringkasan


Secara khusus, Kestrel tidak dapat menangani header HTTP dengan karakter yang benar di UTF-8, yang terkandung dalam nama-nama sejumlah besar kota.

Faktor tambahan dalam kasus kami adalah bahwa klien saat ini tidak berencana untuk mengubah implementasi Kestrel dalam aplikasi. Namun, masalah di AspNetCore sendiri ( No. 4318 , No. 7707 ) mengatakan bahwa ini tidak akan membantu ...

Untuk meringkas: catatan tidak lagi tentang masalah spesifik Kestrel atau UTF-8 (pada tahun 2019, tahun?!), Tetapi bahwa perhatian dan studi yang konsisten dari setiap langkah selama pencarian masalah akan cepat atau lambat membuahkan hasil. Semoga beruntung

PS


Baca juga di blog kami:

Source: https://habr.com/ru/post/id448420/


All Articles