Istio ile HTTP Header Yönetimi

Selçuk Usta
3 min readAug 28, 2019

--

Geçtiğimiz haftalarda yapmış olduğumuz geçişin kısa öyküsünü paylaşmıştım. Bu geçişin de bir başlangıç olduğunu ve karşılaşacağımız sorunlar/ihtiyaçlar doğrultusunda peyderpey geliştirmelere — ve gelişmeye — devam edeceğimiz üzerine de bir not bırakmıştım.

Geçiş sonrası oluşan en temel ihtiyaç, her web uygulamasında olduğu gibi bu uygulamamızda da “header manipulation” konusu oldu.

Hasıl olan ihtiyaç neydi?

Son kullanıcıya dönecek olan cevabın header’ına bir takım bilgileri dahil etmek olarak özetlenebilir. Aslına bakarsanız bu iş Istio özelinde zor bir iş değil. Bir VirtualService tanımlarken aşağıdaki görselde de göreceğiniz üzere spec.http.match.route.destination.headers alanına,request başlığı ile upstream’e gönderilecek header bilgilerini; response başlığı ile de client’e gönderilecek header bilgilerini ekleyebiliyoruz.

Dinamik konfigürasyonlara ihtiyaç duyarsak?

İhtiyacımız bir adım daha ötede ortaya çıkıyor. css , js , woff2 gibi statik dosyalara gelen isteklere özel bir header bilgisini, response’a dahil etmek istiyoruz. Bu durumda yukarıdaki konfigürasyon, statik bir tanımlama olduğu için, ihtiyacımızı ne yazık ki karşılamıyor.

Eğer Nginx kullandıysanız — ya da Kubernetes üzerinde Nginx Ingress Controller — bu işi; Ingress servise tanımlayacağınız veannotations bloğu altında yer alan nginx.ingress.kubernetes.io/configuration-snippettanımı ile gerçekleştirebiliyorsunuz. Detaya girip konunun yönünü bozmamak adına adresinde yer alan yazıyı referans olarak ekliyorum.

Istio ile gelen ve proxy hizmetini gerçekleştiren Envoy, gelen istekleri karşılamaktan ve yönlendirmekten sorumlu. Ancak Envoy, Nginx gibi bir web server değil. Dolayısıyla statik dosyaları servis etmek, header manipüle etmek gibi ön tanımlı sorumlulukları bulunmuyor. Hakeza Envoy’un Github’daki Issues alanında açılmış bir tartışmada da, ekipten gelen cevap bu yönde oluyor:

İhtiyaca nasıl bir çözüm ürettik?

Araştırmalarımız sonucu, Envoy’un Filter adlı bir çözümü olduğunu, bu çözüm ile birlikte gelen isteği karşılarken ve cevaplarken sergilediği davranışları özelleştirebileceğimizi; bu iş için de Lua dilini kullanabileceğimizi gördük. Bu bilgiler, ihtiyaca çözüm için yeterli görünüyordu. Ayrıca Istio tarafında EnvoyFilter adlı obje ile bu tanımlamayı gerçekleştirebileceğimizi gördük. Sonuç olarak aşağıdaki yaml tanımı oluştu:

Tanımlamamızdaki bazı alanları elimden geldiğince anlatmaya çalışayım.

workloadLabels.app tanımı ile, app=app.name olarak etiklenmiş servisler için bu filtrenin devreye gireceğini ifade ediyoruz.

listenerMatch.portNumber, listenerProtocolve listenerMatch.listenerType ile bu service gelen inbound trafiğin (http://app-name:80) dinlenerek HTTP filtrelerindeenvoy.lua tipinde bir filtrenin uygulanacağını belirtiyoruz.

Envoy’un onlarca filtresi mevcut. HTTP filtrelerine bu adresten, tüm filtrelere ise bu adresten ulaşabilirsiniz.

envoy.lua filtresinin iki fonksiyonu mevcut: envoy_on_request ve envoy_on_response . Bu iki fonksiyon da kendilerine ait parametrelerden request ve response objelerini taşıyor. Böylece fonksiyonlar içerisinden bu iki nesnede ihtiyaç duyduğumuz tüm özelliklere erişebiliyoruz.

İhtiyaca geri dönersek, gelen istekten (envoy_on_request) path’i yakalayarak, eğer ön tanımlı uzantılara sahipse, o cevaba (envoy_on_response) yeni bir header eklememiz gerekiyor.

En can sıkıcı noktayı belirteyim, Lua’nın Regex desteği yok. Daha doğrusu Lua içerisinde Regex implementasyonu yok. Buna açıklama olarak da Lua’nın tüm kaynak kodunun büyüklüğü, Regex’den daha küçük! ifadesi kullanılıyor ki bu durumda hak veriyorum. Regex yerine pattern matching denilen fonksiyonalite kullanılıyor.

Bu sebeple yukarıdaki kodda, uzantıları tutan bir dizi tanımlaması gerçekleştirdik. Gelen isteğin uzantısını yakalayıp bu dizi içerisinde arama gerçekleştiriyoruz. Eğer Regex desteği olsaydı bu işi /\.(css|js|jpg)$/i gibi bir ifade ile çözebilirdik.

Sonuç

kubectl ile yaml içerisindeki tanımlamamızı uyguladığımızda istediğimiz header’ın cevaba eklenmiş olduğunu gördük:

Dynamic header manipulation sorunsalının çözümünden daha değerli olan ise Envoy filtrelerini kullanmayı öğrenmek oldu. Böylece, olası diğer ihtiyaçlarımızda referans alabileceğimiz değerli bir kaynağımız var artık.

Son olarak şunu söyleyeyim; bu iş için çok uğraşmışsınız, şu yöntem ile çok daha kolay ve efektik çözebilirdin dediğiniz bir nokta olursa lütfen haber edin ki değerli kaynağımız 2 olsun.

--

--

Selçuk Usta

Engineering Manager (at) Hepsiburada. Former trainer & consultant. Tweets are mostly about tech and coding. https://superpeer.com/selcukusta