Consul İle Service Discovery Dünyasına Bakış

Modern yazılım dünyasının merkezinde bir kavram; micro-service. Bu kavram çerçevesinde kurgulanan mimariler, değişen yazılım geliştirme metodolojileri ve gelişen yazılımlar.

Google’da ilk çıkan micro-service görseli :)

Micro-service kavramına farklı bakış açıları da yine bu gelişim süreci içerisinde karşımıza çıkıyor. Örneğin, BBC Online’ın nano-service adını verdiği ve bu yazıda detaylandırdığı kurgular ve metodolojiler daha basit, esnek ve fonksiyonel olarak mimari çizimlerde konumlanabiliyor.

Tüm bu algılara hoşgelen yöntemlerin pozitif etkilerinin yanı sıra negatif olarak nitelendirilebilecek etkileri de biz yazılımcıların hayatına doğrudan bir giriş yapıyor. State yönetimi, key-value verilerin dağıtık olarak kullanımı, network topolojileri, healt-check’ler bir çırpıda sayılabilecek durumlar.

Bu bahsi geçen tüm zorlukların üstesinden gelebilmek adına özellikle open-source camiasında ciddi ürünler — üstelik her bir zorluk için özel olarak kurgulanmış ürünler — geliştiriliyor.

Bu yazının merkezinde de bu ürünlerden biri, HashiCorp imzalı Consul yer alıyor.

Consul nedir?

Consul; service discovery, distributed key-value store, health checking özellikleriyle kendini tanımlayan high available bir DevOps ürünü olarak ifade edilebilir.

Yukarıda bahsettiğimiz ve micro-service mimarilerindeki çözüme yönelik en temel ihtiyaçların başında da bunlar geliyor aslında. Topolojilerde bahsi geçen servisler çok hızlı ve dinamik bir şekilde oluşup kaybolan yapılar. Haliyle bulundukları konum da bir önceki istekle bir sonraki istek arasında aynı hızla değişebiliyor. Genellikle stateless olarak tasarlanıyor. Yorumlaması gereken verileri de merkezi bir noktadan talep ediyor.

Node’lar üzerinde konumlanan, server veya client moddaki agentlar ile çalışan Consul, node’un ve kendine tanımlanmış servislerin sağlık durumlarını gözlemler, dağıtık olarak anahtar-değer ikililerini muhafaza ve servis eder, dinamik servislerin mevcut konumlarını (en temel haliyle IP:PORT olarak ifade edilebilir) bilir ve talep karşılığında iletir. Bu davranışlarıyla da temel ihtiyaca cevap verir nitelikte.

Tüm bu özelliklerin yanı sıra consul-template denilen yapı ile de dinamik konfigürasyon yönetimleri sağlanabiliyor. Özellikle yük dağıtım (load balancing) senaryosunda, dinamik olarak upstream yönetmek yine başlı başına bir uğraş.

upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8080;
server backend3.example.com:8080;
}

Yukarıdaki kod bloğu bir Nginx upstream tanımlaması. Ancak dikkat çekecek şekilde statik. Bizim senaryomuzda ise buradaki backend adresleri sağlık durumlarına göre trafik alacak/almayacak şekilde konumlanabiliyor olmalı. Consul template ile bu blok, o anki node ve servis durumlarına göre dinamik olarak değişecek şekilde yapılandırılabilir. Konuyla ilgili sık kullanılanlarımdan bir linki de buraya bırakmak isterim.

Consul server, anahtar-değer ikilisi verilerini, servis ve node bilgilerini saklayan ve replika eden bacak. Tek bir sunucu kullanılabileceği gibi, lider seçiminin sağlıklı bir şekilde gerçekleşebilmesi ve failure senaryoları için (2n)+1 şekilde kullanılması öneriliyor.

n, cluster’daki high available bir servisin kararlı bir şekilde çalışabilmesi için tolere edilebilecek hatalı node sayısını ifade eder. Örneğin;
3 node’lu bir cluster’da maksimum 1 node’un hatalı durumda olması tolere edilebilir. Keza 5 node’lu bir cluster’da ise bu sayı 2 olarak kabul edilebilir.

Consul client, node’un ve node üzerinde konumlanan servislerin sağlık durumlarını kontrol eden yapı. İşlevi ise, üzerindeki bilgiyi en hızlı biçimde server’a iletmek. Dolayısıyla data store, discovery gibi kritik görevlerden sorumlu değil.

Consul, REST servis ile tüm bu bilgileri al-ver yapabildiği gibi, sağladığı web arayüzü ile de kullanıcı dostu bir şekilde tüketime sunmakta.

Ürün özellik ve mimarisine daha detaylı olarak, resmi adresi consul.io üzerinden ulaşmak mümkün. Biz küçük bir örnek ile yazıya devam edelim.


Örnekte 3 tane Ubuntu 16.04 Server versiyon kullanmayı tercih ettim. Virtualbox üzerinden işletim sistemlerini standart yöntemlerle ayağa kaldırdığımızı varsayarak devam ediyoruz.

Aşağıdaki adımları her bir node için yapabilir ya da tek bir node üzerinde gerçekleştirip, Virtualbox üzerinden bu node’ları klonlayabilirsiniz.

cd /usr/local/bin
wget https://releases.hashicorp.com/consul/1.0.7/consul_1.0.7_linux_amd64.zip
unzip consul_1.0.7_linux_amd64.zip
rm consul_1.0.7_linux_amd64.zip

Özetle, /usr/local/bin klasörü altına consul’ü indiriyor, sıkıştırılmış dosyayı açıyor ve sonrasında siliyoruz. Geriye çalıştırılabilir bir dosya (consul) dışında bir şey kalmıyor.

3 sunucuya da ayrı ayrı SSH yapalım ve aşağıda yazılan komutları çalıştırarak Consul cluster’ını oluşturalım.

İlk olarak HOST01 adını verdiğimiz node üzerinde consul agent -data-dir /tmp/consul -bootstrap-expect 3 -server -ui -client 192.168.1.30 komutunu çalıştırıyoruz.

  • data-dir parametresi ile, agent’ın yaşam döngüsü boyunca state’inin tutulacağı klasörü gösteriyoruz.
  • bootstrap-expect parametresine 3 değerini geçerek, cluster’ın çalışabilmesi için en az 3 agent’ın server olarak çalışması gerektiğini söylüyoruz. Yukarıda bahsettiğimiz 2n+1 durumunu burada canlandırıyoruz. Bu parametrenin kullanılabilmesi için server parametresi muhakkak eklenmeli.
  • server parametresi ile de agent’ın server mode’da çalışması gerektiğini söylüyoruz.
  • ui parametresi ile bu agent’ın web arayüzü sunacağını söylüyoruz.
  • Web arayüzüne ulaşabilmek için de bir client interface’ini, node’un public ip’si olarak atıyoruz. Varsayılan olarak 127.0.0.1 değerini üzerinde taşır.

Cluster için ilk node’umuz hazır. Web arayüzüne (192.168.1.30:8500/ui/) gittiğimizde aşağıdaki gibi bir hata ile karşılaşıyor olmalıyız:

Henüz bir lider seçimi gerçekleştirilemedi. Bu seçimin gerçekleşebilmesi için -bootstrap-expect 3 olarak geçtiğimiz parametreye göre en az 3 agent, server modda çalışıyor olmalı.

O halde HOST02 makinesi geçelim ve consul agent -data-dir /tmp/consul -bootstrap-expect 3 -server -retry-join 192.168.1.30 komutunu çalıştıralım. Yukarıda tanımlanan parametrelerden farklı olarak -retry-join parametresini incelemekte fayda var. Bu parametre ile agent’ın hangi cluster’a dahil olacağını ifade ediyoruz. Şu anda elimizde tek bir node olduğu için o node’un IP adresini girdik ancak node’daki herhangi bir IP adresini de girebilirdik. Retry ifadesi ise, cluster’a ilk giriş denemesi başarısız olduğunda tekrar denemesi için kullanılıyor. Bunun yerine -join de kullanılabilir.

Web arayüzündeki hatayı gidermek için bir makineyi daha cluster’a server modda dahil etmek yeterli olacak. Ancak bu aşamadan önce, Consul’ün node’ları kontrol etmekle birlikte kendisine tanımlı servisleri de kontrol ettiğini belirtmiştik. Küçük bir web uygulaması oluşturup, kontrole hazır bir servis bırakalım. Bunun için HOST03 makinesine geçip aşağıdaki komutları çalıştırıyoruz.

apt-get install python-pip
pip install tornado
mkdir /usr/local/bin/tornado-app
nano /usr/local/bin/tornado-app/app.py

Servis olarak kullanacağımız küçük web uygulaması Python-Tornado tabanlı olacak. Bunun için gerekli paketleri indirip kodu yazacağımız py dosyasını açıyoruz.

Sonrasında ise mkdir /etc/consul.d komutu ile /etc/ klasörü altına consul.d adında bir klasör oluşturuyoruz. Bu klasör içerisinde servislerimizin konfigürasyonlarını tutacağız. Uygulama, database ya da health-check yapmak istediğimiz tüm servisleri burada tanımlayabiliriz.

nano /etc/consul.d/app.json komutu ile uygulama servisimizi tanımlamak üzere bir json dosyası oluşturuyoruz.

{
"service": {
"name": "tornado-app",
"tags": [
"python",
"web"
],
"port": 8888,
"check": {
"id": "app",
"name": "HTTP check on status endpoint",
"http": "http://localhost:8888/status",
"method": "GET",
"interval": "10s",
"timeout": "1s"
}
}
}

Oldukça basit bir tanım. Bunun gibi TCP health-check, script health-check tanımlamaları da yapılabilir.

Gerekli uygulamayı ve servis tanımlarını oluşturduktan sonra HOST03 adını verdiğimiz makineye bağlanıp consul agent -data-dir /tmp/consul -bootstrap-expect 3 -server -retry-join 192.168.1.30 -config-dir /etc/consul.d komutunu çalıştırabiliriz.

Web arayüzüne dönüp sayfayı yenilediğimizde cluster’ın sağlıklı bir şekilde kurulduğunu ve agent’ların veri toplamaya başladığını görebiliyoruz.

tornado-app adlı servis şu anda healt-check’ten geçemiyor çünkü uygulamayı henüz çalıştırmadık. python /usr/local/bin/tornado-app/app.py komutu ile uygulamayı çalıştıralım.

Node’ların ve servislerin sorunsuz bir şekilde çalıştığını; tornado-app servisinin health-check’ten dönen sonucunu görebiliyoruz.

Sonuç

Yazının detayında yer almasa dahi, Consul’ün çalışma mekaniğinde yer alan Consensus ve Gossip protokollerinin de okunmasında ve incelenmesinde fayda görüyorum. Bu protokoller bir çok cluster management aracının (Docker Swarm Mode gibi) kalbinde yer alıyor.

Buna ek olarak, service discovery pattern’lerin de okuma listelerinde yer alması oldukça önemli.

Bir sonraki yazıya dek, node’larınızın ve service’lerinizin yeşilden öte renk görmemesi dileğiyle.