Asp.NET Core Web API Uygulamasını Amazon EC2’de Host Etme
Merhaba,
Amazon EC2(Elastic Compute Cloud), Amazon Web Service’leri tarafından sunulan yüksek oranda ölçeklenebilir ve esnek bir cloud servisidir. Bu servis üzerinde kendi uygulamalarımızı çalıştırabileceğimiz, uygulamanın bellek veya CPU gibi gereksinimlerine uygun çeşitli türler üzerinden seçim yapabilecek olan instance adında sanal sunucular kiralanabilmekte ve ihtiyaç doğrultusunda da scale-up ya da scale-down ölçeklendirme yaklaşımları uygulanabilmektedir. Bizler, bu içeriğimizde bir Asp.NET Core Web API uygulamasını Amazon EC2’de host etme sürecini adım adım inceleyecek ve böylece DevOps ile ilgili çeşitli uygulamaların anlaşılmasına yardımcı olacak pek çok etkili kavramı ele alıyor olacağız.
AWS, bir yıl boyunca orta ölçekli uygulamaları host edebilmek için her ay 750 saate kadar Linux ve Windows instance’ını ücretsiz olarak sunmaktadır.
EC2 ismindeki 2, Amazon’un ikinci nesil bulut bilişim hizmetini ifade etmektedir. Bu hizmet, ilk nesil sabit ve esnek olamayan çözümlerden farklı olarak; dinamik ve elastik bir yapıda tasarlanmıştır ve kullanıcılara daha fazla esneklik, ölçeklenebilirlik ve maliyet optimizasyonu sağlamaktadır. Bu nedenle 2 sayısı, EC2’nin teknolojik gelişimini ve sunduğu yenilikleri vurgulamak için kullanılmıştır.
Uygulamayı Geliştirelim
Öncelikle bir Asp.NET Core Web API uygulaması geliştirerek içeriğimize giriş yapalım. Bizlerin geliştireceği uygulama basit bir ürün yönetim sistemi olacaktır. Şimdi adım adım bu uygulamayı geliştirmeye odaklanalım;
- Adım 1 (Product Entity’sini Oluşturalım)
public record Product(Guid Id) { public string Name { get; set; } public string? Description { get; set; } public decimal Price { get; set; } }
- Adım 2 (Veritabanı & Migration İşlemlerini Yapalım)
Veritabanı olarak PostgreSQL’i tercih ediyorum. Tabi ki de sizler, uygulamayı özelleştirebileceğiniz gibi veritabanını da kendinize özel seçebilirsiniz.Öncelikle aşağıdaki gibi bir DbContext nesnesi oluşturalım.
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions options) : base(options) { } public DbSet<Product> Products { get; set; } }
Ve ‘Program.cs’ dosyasında aşağıdaki gibi veritabanı tanımlamasında bulunalım.
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql(builder.Configuration.GetConnectionString("PostgreSQL")));
Ardından Package Manager Console üzerinden
add-migration mig_1
talimatı eşlinde bir migration oluşturalım. Şimdi bu migration’ı isterupdate-database
komutuyla migrate edebilirsiniz, isterseniz de aşağıdaki gibi dinamik bir yaklaşım sergileyebilirsiniz.var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql(builder.Configuration.GetConnectionString("PostgreSQL"))); var app = builder.Build(); #region Dynamic Migration using IServiceScope scope = app.Services.CreateScope(); ApplicationDbContext dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>(); if (dbContext.Database.GetPendingMigrations().Any()) await dbContext.Database.MigrateAsync(); #endregion . . . app.Run();
- Adım 3 (Operasyonel Endpoint’leri Oluşturalım)
Temel ürün işlemlerini yürütecek operasyonlara sahip endpoint’leri aşağıdaki gibi minimal api olarak oluşturalım.. . . app.MapGet("/products", async (ApplicationDbContext dbContext) => { return await dbContext.Products.ToListAsync(); }); app.MapGet("/products/{id}", async (ApplicationDbContext dbContext, string id) => { Product? product = await dbContext.Products.FindAsync(id); if (product is null) return Results.NotFound(); return Results.Ok(product); }); app.MapPost("/products", async (ApplicationDbContext dbContext, CreateProductVM createProductVM) => { Product product = new(Guid.NewGuid()) { Name = createProductVM.Name, Description = createProductVM.Description, Price = createProductVM.Price }; await dbContext.Products.AddAsync(product); await dbContext.SaveChangesAsync(); });
İşte bu kadar… Bu adımlar sürecinde kullanılan viewmodel gibi teferruatlara ve istifade edilen kütüphanelere içeriğimizin sonunda paylaşmış olduğumuz github adresinden göz atabilirsiniz. Makalenin hacmini artık yersiz şişirmemek için bu detayları sizlere bırakıyorum.
Dockerizing
Ayrıca .NET’te gelen built-in container desteğinden de istifade edelim istiyorum. Bunun için aşağıdaki tanımları uygulamanın ‘.csproj’ dosyasındaki ilgili alana ekleyelim.
<PropertyGroup> . . . <ContainerImageName>products-api</ContainerImageName> <ContainerImageTags>latest</ContainerImageTags> <PublishProfile>DefaultContainer</PublishProfile> <RuntimeIdentifier>linux-x64</RuntimeIdentifier> </PropertyGroup>
Bu yapılandırmadan sonra uygulamanın Docker image’ını oluşturmak için aşağıdaki talimatın verilmesi yeterli olacaktır.
dotnet publish -c Release --self-contained
İçeriğimizin devamında Amazon EC2 instance’ında da aynı işlemleri gerçekleştirecek ve orada da bir Docker image’ı oluşturacağız. Şimdi Docker Compose ile bu oluşturduğumuz uygulamayı PostgreSQL ile ayağa kaldıracak bir talimat dizisi oluşturarak devam edelim.
PostgreSQL Container’ı İle Docker Compose
version: '3.8' services: api: container_name: product-api image: products-api:latest environment: - ASPNETCORE_ENVIRONMENT=docker - ASPNETCORE_URLS=http://+:80 ports: - 80:80 depends_on: postgres: condition: service_healthy postgres: container_name: postgres image: postgres:15-alpine environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=123456 ports: - 5432:5432 volumes: - postgres-data:/data/db healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 volumes: postgres-data:
Yukarıdaki docker compose içeriğine göz atarsanız eğer iki adet servisin yapılandırıldığını göreceksiniz. İlki, biraz önce oluşturduğumuz product-api isimli built-in container’dır. Bu ilk etapta local docker instance’ından çekilecektir. İçeriğimizin devamında Amazon EC2 instance’larında da çalıştırıldığını göreceğiz. İkinci servis ise PostgreSQL yapılandırmasını barındırmaktadır.
appsettings.docker.json
Bu işlem tamamlandıktan sonra uygulamamız için docker’a uygun yapılandırmayı barındıracak appsettings.docker.json dosyasını ekleyerek devam edelim.
{ "ConnectionStrings": { "PostgreSQL": "Host=postgres;Port=5432;Database=ProductDB;Username=postgres;Password=123456;Include Error Detail=true" } }
Böylece ASPNETCORE_ENVIRONMENT
değeri docker olarak ayarlandığı taktirde uygulama bu dosya üzerinden yapılandırılacaktır.
Şimdi ise sıra EC2 container’ı oluşturmaya gelmiştir.
Amazon EC2 Linux Instance Oluşturma
Artık herşey hazır olduğuna göre bir Amazon EC2 Linux instance’ını ayağa kaldırabiliriz. Bunun için AWS Management Console üzerinden EC2’yi aratalım.
Ardından açılan sayfada ‘Launch instance’ butonuna tıklayalım.Ve ardından ilgili instance’ı aşağıdaki gibi yapılandıralım.Burada Key pair alanında ‘Create new key pair’ diyerek aşağıdaki gibi yeni bir tane oluşturalım.Burada key pair name olarak ‘admin’ değerini veriyoruz. Ayrıca dosya biçimi olarak .ppk’yı seçiyoruz. ‘Create key pair’ butonuna tıkladığımızda admin.ppk adında bir dosya indirilecektir. Bu daha sonradan tarafımızca Amazon EC2 instance’ına uzaktan bağlanmak için kullanılacağından dolayı bu dosyanın güvenli bir şekilde tutulduğundan emin olunmalıdır.
Devamında ise instance yapılandırmasını aşağıdaki gibi yapıp, ardından ‘Launch instance’ butonuna tıklayalım.Evet, tüm bu işlemlerden sonraki adımımız ise makinemizden bu EC2 instance’ına bağlanmaktır. Bizler bunun için PuTTY’i kullanıyor olacağız. O halde buyurun devam edelim.
PuTTY İle EC2 Instance’ına SSH
Öncelikle bilmeyenler için PuTTY ne la? sorusunu cevaplandırarak devam edelim.
PuTTY, çeşitli ağ protokolleri için bir client yazılımıdır ve özellikle SSH(Secure Shell), Telnet, rlogin ve seri port bağlantıları gibi protokoller için kullanılmaktadır.
PuTTY’i kullanabilmek için https://www.putty.org adresinden indirilip, kurulması gerekmektedir.
PuTTY’i kurduktan sonra açalım ve ‘Connection’ -> ‘SSH’ -> ‘Auth’ -> ‘Credentials’ sekmesinden PPK dosyasını yükleyerek gerekli kimlik bilgileri yapılandırmasında bulunalım.Devamında ise ‘Session’ sekmesinden host bilgisini yazalım ve ‘Open’ diyerek bağlantıyı başlatalım.Bu işlemden sonra aşağıdaki gibi ‘login as’ kısmı gelecektir.Burada ‘ec2-user’ değerini yazalım ve enter diyelim.
Vee gözümüz aydın 🙂 Artık Linux Instance’ına giriş yapmış bulunuyoruz…
Şimdi bu instance’a Git, Docker, .NET Runtime vs. gibi ihtiyacımız olan tüm ortam kurulumlarını gerçekleştireceğiz.
Bunun için öncelikle sudo su
talimatı eşliğinde super user’a geçiş yapalım.
Ardından yum install git
talimatıyla git’in kurulumunu başlatalım.
yum install docker
sudo systemctl start docker.service
docker ps
talimatları eşliğinde Docker’ı kuralım.
sudo yum install aspnetcore-runtime-7.0
sudo yum install dotnet-sdk-7.0
dotnet tool install --global dotnet-ef --version 7.0.19
. /etc/profile.d/dotnet-cli-tools-bin-path.sh
dotnet sdk check
talimatları eşliğinde de .NET 7 runtime’ı ve SDK’yi kuralım.
Burada eğer ki yüklenen paketlerde bir hata, erişememe ya da tanımama durumu söz konusu olursa, Microsoft paket deposunu aşağıdaki talimatla eklemeli;
sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
ve ardından depo listesinisudo yum update
talimatıyla güncellemelisiniz.
Devamında ise docker-compose dosyasının çalışması için aşağıdaki talimatlar eşliğinde gerekli araçları yükleyelim.
sudo curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose version
Evet, şu ana kadar gerekli olan tüm araçlar yüklenmiştir. Şimdi sırada Github repository’sini instance volume içerisine klonlamak var. Bunun için yukarıdaki satırlarda geliştirdiğimiz ürün yönetim sistemi uygulamasını github’da yeni bir repository oluşturarak depolayalım. (bknz: https://github.com/gncyyldz/Amazon.EC2.Hosting.Example) Ardından aşağıdaki talimatlar eşliğinde hem uygulamayı github’dan çekelim hem de docker image’ını oluşturalım.
mkdir repos
cd repos
git clone https://github.com/gncyyldz/Amazon.EC2.Hosting.Example
cd Amazon.EC2.Hosting.Example
dotnet publish -c Release --self-contained
docker images
Burada yaptığımız çalışmayı özetlememiz gerekirse eğer; öncelikle ‘repos’ adında bir klasör oluşturduk ve ardından repository’mizi bu klasöre kopyaladık. Klonlama tamamlandıktan sonra proje klasörüne giderek uygulamayı publish ettik. Hatırlarsanız eğer önceki satırlarda .csproj dosyasında uygulama yayınlandığında docker image’ını oluşturacak spesifikasyonlarda bulunmuştuk. Haliyle bu işlem neticesinde gerekli docker image’ını oluşturmuş olduk.Bu aşamadan sonra artık uygulama içerisindeki docker-compose dosyasını
docker-compose up -d
talimatıyla çalıştırabiliriz. Tabi bunun için uygulamanın dizinine tam gelindiğinden emin olmalıyız…
Uygulamayı Herkes Tarafından Erişime Açık Hale Getirme
Bu aşamadan sonra artık yapılması gereken uygulamanın herkes tarafından erişime açık hale getirilmesidir. Bunun için aşağıdaki ekran görüntüsünde olduğu gibi AWS Management Console üzerinden EC2 instance’ına gelelim ve ‘Security’ üzerinden 80 portuna gelecek olan trafiğe izin verelim.
Dikkat!
Github’dan uygulamayı klonlama aşamasında aşağıdakine benzer hata alıyorsanız eğer;
unable to access ‘https://github.com/gncyyldz/Amazon.EC2.Hosting.Example/’: Failed to connect to github.com port 443 after 131206 ms: Couldn’t connect to serverİlgili EC2 instance’ının security groups alanından ‘Outbound rules’ sekmesine gelerek gelen tüm trafiğe aşağıdaki gibi rule tanımında bulunulması gerekmektedir!
Test Etme
Artık yaptığımız bu çalışmayı test edebiliriz. Bunun için EC2 instance’ının public adresini kopyalayalım ve Postman üzerinden endpoint’lere testlerimizi gerçekleştirelim.Burada özellikle dikkat edilmesi gereken nokta şudur ki, request atacağınız public adresin https değil http protokolüne sahip olmasına özen gösterilmelidir. Aksi taktirde istek neticesinde connect ECONNREFUSED hatası alırsınız.
Nihai olarak;
Bu içeriğimizde Asp.NET Core Web API mimarisinde geliştirdiğimiz bir uygulamayı Amazon EC2 Linux instance’ında host etmiş ve bunun için gerekli olan yapılandırmaları ele almış bulunuyor ve bunların yanında .NET 7’de gelmiş olan built-in container desteğini de tecrübe etmiş oluyoruz.
İ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/Amazon.EC2.Hosting.Example/