Saat merancang solusi berdasarkan arsitektur layanan mikro, kita sering menghadapi persyaratan untuk pengelolaan keseluruhan sistem yang cepat dan mudah, otomatisasi setinggi mungkin, tanpa penyesuaian yang diperlukan pada masing-masing komponen.
Ini adalah tantangan nyata dan itulah mengapa saya memutuskan untuk menyiapkan tutorial yang menunjukkan cara membangun arsitektur layanan mikro dengan cara yang paling sederhana, yang dapat dengan cepat dan mudah ditingkatkan skalanya dan disesuaikan dengan kebutuhan klien.
Saya tidak ingin mengganggu kode dan pengaturan layanan individual, tetapi mengontrol sistem hanya dengan mengatur container di Docker.
Hasilnya adalah arsitektur layanan mikro sederhana yang dapat dengan mudah diskalakan hanya dengan beberapa perubahan dalam pengaturan kontainer, semuanya disediakan oleh Ocelot sebagai gateway/penyeimbang beban dan Konsul sebagai agen penemuan layanan.
Arsitektur seperti itu memungkinkan kita melakukan penerapan ulang satu layanan tanpa mengoordinasikan penerapan dalam layanan lain. Layanan yang disebarkan ulang secara otomatis terdaftar pada penemuan layanan dan segera tersedia melalui gateway. Bisa dibayangkan betapa besarnya peningkatan ini bagi setiap tim pengembangan!
Tentu saja, menggunakan layanan gateway tunggal menjadi satu titik kegagalan arsitektur kami, jadi kami perlu menerapkan setidaknya dua contoh layanan tersebut agar memiliki ketersediaan tinggi. Tapi saya akan menyerahkan masalah itu kepada Anda untuk dimainkan.
Dalam demo saya sebelumnya, saya menunjukkan cara mengimplementasikan Ocelot sebagai gateway layanan dan penyeimbang beban bersama dengan Eureka untuk penemuan layanan. Sebaliknya Eureka, demo ini menggunakan Konsul untuk penemuan layanan.
Konsul adalah solusi mesh layanan yang menyediakan bidang kontrol berfitur lengkap dengan fungsi penemuan layanan, konfigurasi, dan segmentasi. Masing-masing fitur ini dapat digunakan secara individual sesuai kebutuhan, atau dapat digunakan bersama-sama untuk membangun jaringan layanan penuh. Konsul memerlukan bidang data dan mendukung model integrasi proksi dan asli. Konsul dikirimkan dengan proxy bawaan yang sederhana sehingga semuanya berfungsi dengan baik, tetapi juga mendukung integrasi proxy pihak ketiga seperti Envoy.
Fitur utama Konsul adalah:
Penemuan Layanan : Klien Konsul dapat mendaftarkan layanan, seperti api atau mysql, dan klien lain dapat menggunakan Konsul untuk menemukan penyedia layanan tertentu. Dengan menggunakan DNS atau HTTP, aplikasi dapat dengan mudah menemukan layanan yang mereka andalkan.
Pemeriksaan Kesehatan : Klien Konsul dapat memberikan sejumlah pemeriksaan kesehatan, baik yang terkait dengan layanan tertentu ("apakah server web mengembalikan 200 OK"), atau dengan node lokal ("apakah pemanfaatan memori di bawah 90%"). Informasi ini dapat digunakan oleh operator untuk memantau kesehatan klaster, dan digunakan oleh komponen penemuan layanan untuk mengalihkan lalu lintas dari host yang tidak sehat.
KV Store : Aplikasi dapat menggunakan penyimpanan kunci/nilai hierarki Konsul untuk sejumlah tujuan, termasuk konfigurasi dinamis, penandaan fitur, koordinasi, pemilihan pemimpin, dan banyak lagi. API HTTP sederhana membuatnya mudah digunakan.
Komunikasi Layanan Aman : Konsul dapat membuat dan mendistribusikan sertifikat TLS untuk layanan guna membangun koneksi TLS timbal balik. Niat dapat digunakan untuk menentukan layanan mana yang diperbolehkan untuk berkomunikasi. Segmentasi layanan dapat dikelola dengan mudah dengan tujuan yang dapat diubah secara real-time daripada menggunakan topologi jaringan yang kompleks dan aturan firewall statis.
Multi Pusat Data : Konsul mendukung banyak pusat data secara langsung. Ini berarti pengguna Konsul tidak perlu khawatir membangun lapisan abstraksi tambahan untuk berkembang ke beberapa wilayah.
Consul dirancang agar ramah terhadap komunitas DevOps dan pengembang aplikasi, menjadikannya sempurna untuk infrastruktur modern dan elastis.
Sumber: Pengenalan Konsul
Bagian penting dari tutorial ini adalah penggunaan Konsul untuk menemukan titik akhir layanan secara dinamis. Setelah layanan terdaftar di Konsul, layanan tersebut dapat ditemukan menggunakan DNS biasa atau API khusus.
Konsul melakukan pemeriksaan kesehatan pada instansi layanan tersebut. Jika salah satu contoh layanan atau layanan itu sendiri tidak sehat atau gagal dalam pemeriksaan kesehatannya, registri akan mengetahui hal ini dan akan menghindari pengembalian alamat layanan. Pekerjaan yang dilakukan penyeimbang beban ditangani oleh registri dalam kasus ini.
Karena kami menggunakan beberapa contoh layanan yang sama , Konsul akan mengirimkan lalu lintas secara acak ke contoh yang berbeda. Dengan demikian, ini menyeimbangkan beban antar contoh layanan.
Konsul menangani tantangan deteksi kegagalan dan distribusi beban di berbagai layanan tanpa perlu menerapkan penyeimbang beban terpusat.
Secara otomatis mengelola registri, yang diperbarui ketika ada layanan baru yang didaftarkan dan tersedia untuk menerima lalu lintas. Ini membantu kami meningkatkan skala layanan dengan mudah.
Sebelum masuk ke detail penerapan cara menerapkan pendaftaran mandiri ke Konsul, mari kita lihat cara kerja penemuan layanan dengan pendaftaran mandiri.
Pada langkah pertama, instans layanan mendaftarkan dirinya ke layanan penemuan layanan dengan memberikan nama, ID, dan alamatnya. Setelah gateway ini bisa mendapatkan alamat layanan ini dengan menanyakan penemuan layanan Konsul berdasarkan nama/ID-nya.
Hal utama yang perlu diperhatikan di sini adalah bahwa contoh layanan didaftarkan dengan ID layanan unik untuk membedakan contoh layanan yang berjalan pada agen layanan Konsul yang sama. Semua layanan harus memiliki ID unik per node , jadi jika nama mungkin bertentangan (kasus kami) maka ID unik harus diberikan.
Mari kita lihat bagaimana kita dapat menerapkan registrasi mandiri di aplikasi .NET. Pertama, kita perlu membaca konfigurasi yang diperlukan untuk penemuan layanan dari variabel lingkungan, yang diteruskan melalui file docker-compose.override.yml .
public static class ServiceConfigExtensions
{
public static ServiceConfig GetServiceConfig ( this IConfiguration configuration )
{
ArgumentNullException . ThrowIfNull ( configuration ) ;
ServiceConfig serviceConfig = new ( )
{
Id = configuration . GetValue < string > ( "ServiceConfig:Id" ) ,
Name = configuration . GetValue < string > ( "ServiceConfig:Name" ) ,
ApiUrl = configuration . GetValue < string > ( "ServiceConfig:ApiUrl" ) ,
Port = configuration . GetValue < int > ( "ServiceConfig:Port" ) ,
ConsulUrl = configuration . GetValue < Uri > ( "ServiceConfig:ConsulUrl" ) ,
HealthCheckEndPoint = configuration . GetValue < string > ( "ServiceConfig:HealthCheckEndPoint" ) ,
} ;
return serviceConfig ;
}
}
Setelah membaca konfigurasi yang diperlukan untuk mencapai layanan penemuan layanan, kita dapat menggunakannya untuk mendaftarkan layanan kami. Kode di bawah ini diterapkan sebagai tugas latar belakang (layanan yang dihosting), yang mendaftarkan layanan di Konsul dengan mengesampingkan informasi sebelumnya tentang layanan jika ada. Jika layanan dimatikan, maka secara otomatis akan dibatalkan pendaftarannya dari registri Konsul.
public class ServiceDiscoveryHostedService (
ILogger < ServiceDiscoveryHostedService > logger ,
IConsulClient client ,
ServiceConfig config )
: IHostedService
{
private AgentServiceRegistration _serviceRegistration ;
/// <summary>
/// Registers service to Consul registry
/// </summary>
public async Task StartAsync ( CancellationToken cancellationToken )
{
_serviceRegistration = new AgentServiceRegistration
{
ID = config . Id ,
Name = config . Name ,
Address = config . ApiUrl ,
Port = config . Port ,
Check = new AgentServiceCheck ( )
{
DeregisterCriticalServiceAfter = TimeSpan . FromSeconds ( 5 ) ,
Interval = TimeSpan . FromSeconds ( 15 ) ,
HTTP = $ "http:// { config . ApiUrl } : { config . Port } /api/values/ { config . HealthCheckEndPoint } " ,
Timeout = TimeSpan . FromSeconds ( 5 )
}
} ;
try
{
await client . Agent . ServiceDeregister ( _serviceRegistration . ID , cancellationToken ) . ConfigureAwait ( false ) ;
await client . Agent . ServiceRegister ( _serviceRegistration , cancellationToken ) . ConfigureAwait ( false ) ;
}
catch ( Exception ex )
{
logger . LogError ( ex , $ "Error while trying to deregister in { nameof ( StartAsync ) } " ) ;
}
}
/// <summary>
/// If the service is shutting down it deregisters service from Consul registry
/// </summary>
public async Task StopAsync ( CancellationToken cancellationToken )
{
try
{
await client . Agent . ServiceDeregister ( _serviceRegistration . ID , cancellationToken ) . ConfigureAwait ( false ) ;
}
catch ( Exception ex )
{
logger . LogError ( ex , $ "Error while trying to deregister in { nameof ( StopAsync ) } " ) ;
}
}
}
Setelah kami mendaftarkan layanan kami di layanan penemuan layanan, kami dapat mulai mengimplementasikan API Gateway.
Ocelot mengharuskan Anda menyediakan file konfigurasi yang berisi daftar Rute (konfigurasi yang digunakan untuk memetakan permintaan upstream) dan GlobalConfiguration (konfigurasi lain seperti QoS, Pembatasan laju, dll.). Pada file ocelot.json di bawah, Anda dapat melihat bagaimana kami meneruskan permintaan HTTP. Kita harus menentukan jenis penyeimbang beban yang akan kita gunakan, dalam kasus kita ini adalah “RoundRobin” yang melakukan loop melalui layanan yang tersedia dan mengirimkan permintaan ke layanan yang tersedia. Penting untuk menetapkan Konsul sebagai layanan penemuan layanan di GlobalConfiguration untuk ServiceDiscoveryProvider .
{
"Routes" : [
{
"Servicename" : " ValueService " ,
"DownstreamPathTemplate" : " /{everything} " ,
"DownstreamScheme" : " http " ,
"UpstreamPathTemplate" : " /{everything} " ,
"UpstreamHttpMethod" : [ " GET " ],
"UseServiceDiscovery" : true ,
"RouteIsCaseSensitive" : false ,
"LoadBalancerOptions" : {
"Type" : " RoundRobin "
},
"QoSOptions" : {
"ExceptionsAllowedBeforeBreaking" : 3 ,
"DurationOfBreak" : 5000 ,
"TimeoutValue" : 2000
}
}
],
"GlobalConfiguration" : {
"RequestIdKey" : " OcelotRequestId " ,
"UseServiceDiscovery" : true ,
"ServiceDiscoveryProvider" : {
"Host" : " consul " ,
"Port" : 8500 ,
"Type" : " PollConsul " ,
"PollingInterval" : 100
}
}
}
Berikut adalah beberapa penjelasan yang diperlukan untuk pengaturan ServiceDiscoveryProvider di bagian GlobalConfiguration :
Setelah kita menentukan konfigurasi, kita dapat mulai mengimplementasikan API Gateway. Di bawah ini kita dapat melihat implementasi layanan Ocelot API Gateway, yang menggunakan file konfigurasi ocelot.json dan Konsul sebagai registri layanan.
IHostBuilder hostBuilder = Host . CreateDefaultBuilder ( args )
. UseContentRoot ( Directory . GetCurrentDirectory ( ) )
. ConfigureWebHostDefaults ( webBuilder =>
{
webBuilder . ConfigureServices ( services =>
services
. AddOcelot ( )
. AddConsul < MyConsulServiceBuilder > ( )
. AddCacheManager ( x =>
{
x . WithDictionaryHandle ( ) ;
} )
. AddPolly ( ) ) ;
webBuilder . Configure ( app =>
app . UseOcelot ( ) . Wait ( ) )
. ConfigureAppConfiguration ( ( hostingContext , config ) =>
{
config
. SetBasePath ( hostingContext . HostingEnvironment . ContentRootPath )
. AddJsonFile ( "appsettings.json" , false , true )
. AddJsonFile ( $ "appsettings. { hostingContext . HostingEnvironment . EnvironmentName } .json" , true , true )
. AddJsonFile ( "ocelot.json" , false , true )
. AddEnvironmentVariables ( ) ;
} )
. ConfigureLogging ( ( builderContext , logging ) =>
{
logging . ClearProviders ( ) ;
logging . AddConsole ( ) ;
logging . AddDebug ( ) ;
} ) ;
} ) ;
IHost host = hostBuilder . Build ( ) ;
await host . RunAsync ( ) ;
Seperti disebutkan sebelumnya, kami akan memasukkan semua layanan dengan Docker, termasuk Konsul , menggunakan distribusi GNU/Linux Ringan untuk container.
File docker-compose.yml dengan pengaturan untuk semua container terlihat seperti ini:
services :
services :
consul :
image : hashicorp/consul
container_name : consul
command : consul agent -dev -log-level=warn -ui -client=0.0.0.0
hostname : consul
networks :
- common_network
valueservice1.openapi :
image : valueservice.openapi:latest
container_name : valueservice1.openapi
restart : on-failure
hostname : valueservice1.openapi
build :
context : .
dockerfile : src/ValueService.OpenApi/Dockerfile
networks :
- common_network
valueservice2.openapi :
image : valueservice.openapi:latest
container_name : valueservice2.openapi
restart : on-failure
hostname : valueservice2.openapi
build :
context : .
dockerfile : src/ValueService.OpenApi/Dockerfile
networks :
- common_network
valueservice3.openapi :
image : valueservice.openapi:latest
container_name : valueservice3.openapi
restart : on-failure
hostname : valueservice3.openapi
build :
context : .
dockerfile : src/ValueService.OpenApi/Dockerfile
networks :
- common_network
services.gateway :
image : services.gateway:latest
container_name : services.gateway
restart : on-failure
hostname : services.gateway
build :
context : .
dockerfile : src/Services.Gateway/Dockerfile
networks :
- common_network
networks :
common_network :
driver : bridge
Perhatikan bahwa layanan kami tidak berisi file konfigurasi apa pun, untuk tujuan itu kami akan menggunakan file Docker-compose.override.yml :
services :
consul :
ports :
- " 8500:8500 "
valueservice1.openapi :
# Swagger UI: http://localhost:9100/index.html
# http://localhost:9100/api/values
environment :
- ASPNETCORE_ENVIRONMENT=Development
- ServiceConfig__ApiUrl=valueservice1.openapi
- ServiceConfig__ConsulUrl=http://consul:8500
- ServiceConfig__HealthCheckEndPoint=healthcheck
- ServiceConfig__Id=ValueService.OpenApi-9100
- ServiceConfig__Name=ValueService
- ServiceConfig__Port=8080
ports :
- 9100:8080
depends_on :
- consul
valueservice2.openapi :
# Swagger UI: http://localhost:9200/index.html
# http://localhost:9200/api/values
environment :
- ASPNETCORE_ENVIRONMENT=Development
- ServiceConfig__ApiUrl=valueservice2.openapi
- ServiceConfig__ConsulUrl=http://consul:8500
- ServiceConfig__HealthCheckEndPoint=healthcheck
- ServiceConfig__Id=ValueService.OpenApi-9200
- ServiceConfig__Name=ValueService
- ServiceConfig__Port=8080
ports :
- 9200:8080
depends_on :
- consul
valueservice3.openapi :
# Swagger UI: http://localhost:9300/index.html
# http://localhost:9300/api/values
environment :
- ASPNETCORE_ENVIRONMENT=Development
- ServiceConfig__ApiUrl=valueservice3.openapi
- ServiceConfig__ConsulUrl=http://consul:8500
- ServiceConfig__HealthCheckEndPoint=healthcheck
- ServiceConfig__Id=ValueService.OpenApi-9300
- ServiceConfig__Name=ValueService
- ServiceConfig__Port=8080
ports :
- 9300:8080
depends_on :
- consul
services.gateway :
# Call first available service: http://localhost:9500/api/values
environment :
- ASPNETCORE_ENVIRONMENT=Development
ports :
- 9500:8080
depends_on :
- consul
- valueservice1.openapi
- valueservice2.openapi
- valueservice3.openapi
Untuk menjalankan file penulisan, buka Powershell, dan navigasikan ke file penulisan di folder root. Kemudian jalankan perintah berikut: docker-compose up -d --build --remove-orphans yang memulai dan menjalankan semua layanan. Parameter -d mengeksekusi perintah secara terpisah. Ini berarti container berjalan di latar belakang dan tidak memblokir jendela Powershell Anda. Untuk memeriksa semua container yang berjalan gunakan perintah docker ps .
Konsul menawarkan antarmuka pengguna web yang bagus. Anda dapat mengaksesnya di port 8500 : http://localhost:8500. Mari kita lihat beberapa layarnya.
Halaman beranda layanan Konsul UI dengan semua informasi relevan terkait agen Konsul dan pemeriksaan layanan web.
Mari melakukan beberapa panggilan melalui API Gateway: http://localhost:9500/api/values. Penyeimbang beban akan menelusuri layanan yang tersedia dan mengirimkan permintaan serta mengembalikan respons:
Sistem layanan mikro tidak mudah untuk dibangun dan dipelihara. Namun tutorial ini menunjukkan betapa mudahnya mengembangkan dan menerapkan aplikasi dengan arsitektur layanan mikro. Konsul HashiCorp memiliki dukungan kelas satu untuk penemuan layanan, pemeriksaan kesehatan, penyimpanan nilai kunci, dan pusat multi-data. Ocelot sebagai gateway berhasil berkomunikasi dengan registri layanan Konsul dan mengambil registrasi layanan, loop penyeimbang beban melalui layanan yang tersedia dan mengirimkan permintaan. Menggunakan keduanya membuat hidup lebih mudah bagi pengembang yang menghadapi tantangan seperti itu. Apakah Anda setuju?
Menikmati!
Berlisensi di bawah MIT. Hubungi saya di LinkedIn.