Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)

Merhaba,

Önceki içeriklerimizde AWS Lambda teknolojisinden ve lambda function kavramından detaylıca bahsetmiştik. Bu içeriğimizde, Asp.NET Core Web API mimarisi üzerinden geliştirilmiş bir API’ı lambda function’ı olarak AWS Lambda’da serverless olarak nasıl deploy edebileceğimizi inceliyor olacağız. O halde buyrun başlayalım…

Hatırlarsanız eğer .NET İle Amazon API Gateway – AWS Lambda & DynamoDB Entegrasyonu başlıklı makalemde bir lambda function’ı tasarladıktan sonra deploy edip, ardından oluşturduğumuz bir Amazon API Gateway aracılığıyla bir endpoint’e bağlayarak ayağa kaldırmıştık. Esasında bu yaptığımız çalışma özünde serverless olan REST API çalışmasının ta kendisidir, öyle değil mi?

Ancak lambda function süreçlerinde kurguladığımız REST API’lar da gelen request’leri APIGatewayHttpApiV2ProxyRequest türünden karşılamak ve tüm query string, route parameters ve body değerlerini bu tür üzerinden elde etmek gibi bir zorunluluğun olması oldukça bağlayıcı bir unsurdur. Halbuki Asp.NET Core API mimarisinde direkt olarak controller sınıflarını kullanarak operasyonları yürütebilir ve ekstradan bir referansla ilgilenmeksizin sadece işleve odaklanabiliriz.

Peki hoca, bizler hangi durumlarda AWS Lambda servisinde lambda function yerine Asp.NET Core API uygulaması host edelim? diye sorarsanız eğer bu soruya kritik arz etmeyen ve pek yoğun kullanılmayacak ve rağbet görmeyecek API’lar söz konusu olduğu durumlarda diye cevap verebilirim. Bunun nedeni AWS Lambda servisinde bir function’a yapılan request neticesinde bu function’ın başlatılabilmesi için öncelikli olarak belleğe yüklenmesi gerekliliğidir. Bu belleğe yüklenme fiiliyatı ister istemez zaman alacaktır ve bu zaman Cold Start(Soğuk Başlatma) olarak nitelendirilmektedir.

Cold Start, bir AWS Lambda function’ın ilk kez başlatılması yahut ilk başlatılmanın dışında uzun bir süre çalıştırılmaması durumunda söz konusu olan süreçtir. Bu terim ilgili function’a gelen çağrıya verilecek cevaptan önce, gerekli ön yüklemeleri yürüten ve function’ın kullanılabilirliğini sıcak/hazır bir duruma getirmek için ihtiyaç duyulan ek süreyi ifade etmektedir. AWS Lambda servisi, sıcak bir durumda olan function’a gelen çağrılara karşın hızlı bir refleks göstermektedir ve bundan dolayı genellikle yapılan bir request’e dönecek yanıt, bir öncekine nazaran daha hızlı olabilmektedir. Ancak function bir müddet tetiklenmemişse yahut ilk defa tetiklenecekse Cold Start süreci söz konusu olacaktır. Cold Start durumu performansı doğrudan etkileyebilmektedir ve ortadan kaldırmak için kesin bir yolu da bulunmamaktadır!

İşte function’lar da ki bu Cold Start durumu, söz konusu Asp.NET Core API uygulaması ise zamansal açıdan daha da uzun olabilme ihtimaline sahiptir. Hele hele ilgili uygulama karmaşık ve büyük ölçekli bir hacme sahipse AWS Lambda servisinde deploy edilmesi hiçte iyi fikir olmayabilir. Bu tarz uygulamaları dockerize etmek veya AWS App Runner, ECS, EC2 gibi sistemler üzerinden çalıştırmak daha iyi bir yaklaşım olabilir. Keza büyük ölçekli bir projenin AWS Lambda servisinde deploy edilmeye çalışılması, AWS Lambda’nın varlık sebebini ihlal eden bir durumdur diye de düşünebiliriz. Çünkü uygulamanın kullanım durumu ve amacına bağlı olarak tercih edeceğimiz bu serviste keyfi olarak karmaşık bir altyapıyı kurgulamaya çalışmak maliyet grafiği açısından oldukça olumsuz etkiye sahip bir seçim olacaktır.

Ayrıca ilgili API’da adil sürenin üzerinde(5 dk.) işlem yapan endpoint’ler söz konusuysa yine AWS Lambda bu tarz uygulamalar için önerilen yaklaşım olmayacaktır.

Tüm bunların dışında basit düzeyde CRUD işlevlerini yerine getiren ve DynamoDB, Cloudwatch, Kinesis ve S3 gibi AWS servislerinden temel düzeyde istifade eden, en fazla orta şeker tadında bir API söz konusuysa bu yaklaşım sizlere optimize edilmiş bir süreç sağlayacaktır.

Şimdi gelin burada bahse konu olan teorik bilgilere nazaran, pratiksel olarak AWS Lambda ile Asp.NET Core Web API uygulamasını host etmeyi ele alarak tecrübe etmeye çalışalım.

Örnek Çalışma
  • Adım 1 (Projenin Oluşturulması ve Temel Yapılandırmanın Sağlanması)
    Her şeyden önce bir Asp.NET Core Web API uygulaması oluşturunuz ve içerisine aşağıdaki controller sınıfını ekleyiniz.

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    
    namespace AWS.Lambda.AspNETCore.WebAPI.Deploy.Example.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : ControllerBase
        {
            [HttpGet]
            public async Task<IActionResult> Get()
            {
                return Ok(DateTime.UtcNow);
            }
        }
    }
    
  • Adım 2 (AWS Lambda Kütüphanesinin Kurulumu ve Servis Yapılandırması)
    Bu API uygulamasını AWS Lambda servisinde host edebilmek için uygulamaya Amazon.Lambda.AspNetCoreServer.Hosting kütüphanesini eklemeniz gerekmektedir. Bunun için Package Manager Console üzerinden şu talimatın verilmesi yeterlidir : NuGet\Install-Package Amazon.Lambda.AspNetCoreServer.Hosting -Version 1.5.1

    Asp.NET Core API uygulamasının AWS Lambda’ya dönüştürülmesi için ihtiyaç duyulacak tek kütüphane bundan ibarettir. Yükleme işleminin ardından uygulamanın konfigürasyonlarında aşağıdaki gibi AddAWSLambdaHosting servisini yapılandırmanız gerekmektedir.

    .
    .
    .
    builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);
    .
    .
    .
    

    Esasında uygulama açısından, AWS Lambda altyapısına deploy edilebilmesi için yapılması gerekenler bundan ibarettir.

  • Adım 3 (Uygulamayı AWS Lambda Servisine Deploy Etme)
    Bu işlem için AWS CLI’dan istifade ediyor olacağız. Şimdi ilk olarak proje dizinini powershell yahut cmd üzerinden açınız ve aşağıdaki talimatı vererek süreci başlatınız.

    dotnet lambda deploy-function

    AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Burada görselde olduğu gibi sırasıyla ‘Runtime’, ‘Function Name’, ‘IAM Role’, ‘Memory Size’, ‘Timeout’ ve ‘Handler’ bilgileri istenecektir. Bu soru dizelerine karşılık görseldeki gibi cevap vermeniz yeterli olacaktır.

    Bu noktada tek vurgulamak istediğim nokta runtime olarak .NET 6’nın bildirilmesidir. Evet, bu yazının klavyeye alındığı tarih sürecinde her ne kadar .NET’in 7 sürümü mevcut olsa da AWS Lambda servisinde mevcut olan en son runtime’ın .NET 6 olduğunu görüyoruz. Lambda Runtime sürümleri hakkında daha fazla bilgi için buradaki içeriğe göz atabilirsiniz.

    Bu adımdaki talimatların doğru bir şekilde çalışabilmesi için aws configure komutu eşliğinde yetkili ve aktif bir Access Key’e sahip IAM kullanıcısının tanımlı olduğundan emin olunuz.

    İşler beklenildiği gibi giderse eğer AWS Lambda servisinden ilgili fonksiyonun oluşturulduğunu görebileceksiniz.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)

  • Adım 4 (Lambda Function’a Url Oluşturma)
    Şimdi deploy edilmiş olan bu API’a bir function url’i alınması gerekmektedir. Bunun için Amazon API Gateway’den istifade edebilir yahut farklı bir yöntem olarak daha da basitleştirilmiş olan ‘Function URL’i kullanabilirsiniz.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Burada “Create function URL’ butonuna tıklayınız ve açılan pencerede ‘NONE’ sekmesini seçerek ‘Save’ butonuna tıklayınız.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Bu işlem ilgili API’a karşılık aşağıdaki gibi bir endpoint oluşturacaktır.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)
  • Adım 5 (Test Etme)
    Edinilen endpoint’i kopyalayarak tarayıcı üzerinden yukarıdaki gibi test ediniz. Testi gerçekleştirdiğinizde her şey yolundaysa eğer aşağıdaki gibi sonuç alabilirsiniz.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)
  • Adım 6 (Swagger’ı Aktifleştirmek – Environment Eklemek)
    Deploy neticesinde edindiğimiz endpoint üzerinden görseldeki gibi Swagger’a erişim göstermeye çalıştığımızda bunun ilk etapta mümkün olmadığını görebiliyoruz.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Bunun nedeni, Swagger’ın Development environment’ına uygun şekilde konfigüre edilmesidir. Haliyle bu durumda yapılması gereken ilgili lambda function’a bir environment eklemektir. Bunun için ‘Configuration’ sekmesi üzerinden ‘Environment variables’ kısmına geliniz ve aşağıdaki gibi ASPNETCORE_ENVIRONMENT anahtarına karşılık Development değerini ekleyiniz.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Böylece Swagger’ı tekrar deneyebilir ve çalıştığını görebilirsiniz.AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)
aws-lambda-tools-defaults.json Dosyasında Lambda Konfigürasyonlarını Depolama

Şimdi, bu yapmış olduğumuz işleri otomatikleştirerek deploy sürecini bir nebze daha kolaylaştırıyor olacağız. Misal olarak; bu geliştirdiğimiz API uygulamasında bir değişiklik olduğu taktirde AWS Lambda’ya yeniden deploy etmemiz gerekecektir. Bunun için baştan beri gösterdiğimiz yöntemleri manuel bir şekilde uygulamak; ‘Function Name’, ‘IAM Role’, ‘Memory Size’, ‘Timeout’ ve ‘Handler’ gibi değerleri tekrardan istenmesine sebebiyet verecektir ve bunları hatırlamak bir geliştirici için ciddi zulüm olabilir.

Evet, her ne kadar CLI bizlere süreci daha da kolaylaştırmak için yardımcı oluyorsa da bu değerleri proje içinde yapılandırma değerleri olarak depolamak hem daha mantıklı bir yaklaşım olacak hem de bu yöntem CLI kullanımı açısından da daha pratik olacaktır. İşte bunun için bir JSON dosyasından istifade ediyor olacağız. Şimdi gelin bunu nasıl yapacağımızı keşfedelim…

Şimdi bunun için ilk olarak oluşturduğumuz ve deploy ettiğimiz ‘AWSLambdaAspNETCoreWebAPIDeployExample’ isimli lambda function’ı silerek başlayalım. Tabi bu silme işlemini AWS Lambda servisinin arayüzü üzerinden gerçekleştirebilir yahut AWS CLI’ı da tercih edebilirsiniz. AWS Lambda servisinden bu işlemin nasıl yapılacağı aşikar, o halde bizler yeni bilgi olması hasebiyle AWS CLI üzerinden silme işleminin nasıl yapılabileceğine odaklanalım.

Öncelikle mevcudiyette olan tüm lambda function’ları görebilmek için aşağıdaki talimatı veriniz.

aws lambda list-functions

AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Devamında ise silinecek olan lambda function’ı aşağıdaki talimatla bildiriniz.

aws lambda delete-function --function-name AWSLambdaAspNETCoreWebAPIDeployExample

İlgili talimat eşliğinde hedef lambda function’ın silindiğinden emin olabilirsiniz. Artık oluşturacağımız lambda function’ın yapılandırma değerlerini tutacağımız
aws-lambda-tools-defaults.json dosyasına odaklanabiliriz. Bunun için Visual Studio üzerinden projenin root path’inde bahsi geçen isimde bir json dosyası oluşturunuz. Bu dosya adı AWS CLI’da lambda operasyonlarına özel varsayılan dosya adı olduğu için belirtilen isimde olmasına özen gösteriniz.

Ardından oluşturulan bu json dosyasının içerisini aşağıdaki gibi doldurunuz.

{
  "profile": "",
  "region": "",
  "configuration": "Release",
  "function-runtime": "dotnet6",
  "function-memory-size": 256,
  "function-timeout": 30,
  "function-handler": "AWS.Lambda.AspNETCore.WebAPI.Deploy.Example",
  "function-name": "AWSLambdaAspNETCoreWebAPIDeployExample",
  "environment-variables": "ASPNETCORE_ENVIRONMENT=Development;",
  "function-url-enable": true
}

Yukarıdaki çalışmaya göz atarsanız eğer deploy edilecek function’a karşılık tüm yapılandırma değerlerini burada sabitlemiş bulunmaktayız. Tabi ‘profile’ ve ‘region’ bilgileri hariç. Çünkü bu bilgiler AWS CLI için başta yapılandırılmış vaziyettedir. O yüzden gerek görülmemektedir. Ayrıca oluşturulacak bu function’da, yukarıdaki çalışmanın 4. adımında görmüş olduğumuz function url’i aktifleştirebilmek için ‘function-url-enable’ property’sine karşılık ‘true’ değerini veriyoruz.

Bu tarz kalıcı konfigürasyonel yaklaşım, ilk etapta yaptığımız örnek çalışmadaki yaklaşıma nazaran oldukça kullanışlı olsa gerek… Öyle değil mi? Haa, bu yaklaşımda sadece ekstradan rol ve politika seçimlerini AWS Console üzerinden yapmak gerekebilir. Bunun da kalıcı yapılandırılmamasının sebebi, yeni rol ve politikaların eklenmesi durumuna karşın esneklik sağlayabilmektir.

Velhasıl,

Şimdi yapılan bu çalışma neticesinde projenin ana dizinine odaklanmış bir powershell ya da cmd üzerinden aşağıdaki talimatı vererek ilgili function’ı deploy ediniz.

dotnet lambda deploy-function

AWS Lambda İle Serverless REST API Geliştirme (Asp.NET Core API)Normalde bir önceki çalışmada bu talimatı verdiğimizde deploy edilecek lambda ile ilgili gerekli bilgileri tek tek girmemiz gerekirken, şimdi ise AWS CLI
aws-lambda-tools-defaults.json dosyasının varlığını görebildiğinden dolayı bu yapılandırma dosyasından otomatik olarak aldığını ve sadece kullanılacak rolün tarafımızca seçilmesi gerektiğini görmekteyiz.

Vee böylece başarıyla API uygulamasını lambda servisine deploy etmiş olduk. Artık bu son çalışmanın testini de sizlere bırakıyorum 🙂

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek projeye aşağıdaki github adresinden erişebilirsiniz.
https://github.com/gncyyldz/AWS.Lambda.AspNETCore.WebAPI.Deploy.Example

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir