Из жизни с Kubernetes: Как HTTP-сервер испанцев не жаловал
Представитель нашего клиента, стек приложений которого обитает в облаке от Microsoft (Azure), обратился с проблемой: с недавнего времени часть запросов некоторых клиентов из Европы стала завершаться ошибкой 400 (Bad Request). Все приложения написаны на .NET, развёрнуты в Kubernetes…
Одно из приложений — API, через который в конечном счёте приходит весь трафик. Этот трафик слушает HTTP-сервер Kestrel, сконфигурированный клиентом .NET и размещённый в pod’е. С отладкой нам повезло в том смысле, что был конкретный пользователь, у которого стабильно воспроизводилась проблема. Однако всё осложнялось цепочкой трафика:
Казалось бы, только tcpdump поможет в решении этой проблемы… но повторю про цепочку трафика:
Расследование
Очевидно, что послушать трафик лучше на том конкретном узле, где Kubernetes развернул pod: объём дампа будет такой, что получится довольно быстро найти хоть что-то. И действительно, при его рассмотрении был замечен такой фрейм:
При внимательном рассмотрении дампа было замечено слово M.laga. Легко догадаться, что в Испании нет города M.laga (зато есть Málaga). Ухватившись за эту идею, мы посмотрели конфиги Ingress, где увидели вставленный месяц назад (по запросу клиента) «безобидный» snippet:
Вернётся 400 Bad request — в логе приложения получим уже знакомую нам ошибку:
{
"@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
}
Итоги
Конкретно Kestrel не может корректно обрабатывать HTTP-заголовки с правильными символами в UTF-8, которые содержатся в названиях довольно большого количества городов.
Дополнительный фактор в нашем случае — менять реализацию Kestrel в приложении клиент в данный момент не планирует. Впрочем, issues в самом AspNetCore (№4318, №7707) говорят о том, что это и не поможет…
Подытоживая: заметка больше не о специфических проблемах Kestrel или UTF-8 (в 2019-то году?!), а о том, что внимательность и последовательное изучение каждого шага во время поиска проблемы рано или поздно принесут свои плоды. Успехов!