kertenkerem_
· DevOps · 6 dk okuma

HAProxy ile Yüksek Erişilebilirlik: Keepalived ve Health Check

Mikroservis mimarilerinde ya da yüksek trafikli web uygulamalarında kesintisiz hizmet sunmak artık bir lüks değil, zorunluluk. HAProxy ve Keepalived ikilisi bu noktada imdada yetişiyor: Linux sunucularınız üzerinde kurabileceğiniz, kurumsal sınıfta, maliyetsiz ve güvenilir bir aktif-pasif HA (high availability) loadbalancer çözümü sunuyorlar. Bu iki aracı prod ortamında birbirine küstürmeden, arkadaki servislerin sağlık durumuna (health check) ve gelen isteğin içeriğine (ACL) göre nasıl çalıştıracağız? Bu yazıda lafı dolandırmadan, production ortamında hırpalanmış senaryolardan süzülen pratik bir mimariyi kuruyoruz.

Neden yalnızca HAProxy yetmiyor? (SPOF nedir?)

HAProxy, performansına ve stabilitesine şapka çıkardığımız bir load balancer. Ancak ne kadar güçlü olursa olsun, tek bir sunucuda çalıştığı sürece sisteminizde bir SPOF (Single Point of Failure), yani tek hata noktası oluşturur. HAProxy’nin üzerinde çalıştığı Linux sunucunun donanımı çökerse, network kartı yanarsa ya da kernel panik yaparsa tüm sisteminiz karanlığa gömülür.

Bu riski ortadan kaldırmak için Keepalived devreye giriyor. Keepalived, VRRP (Virtual Router Redundancy Protocol) protokolüyle iki farklı load balancer sunucusunun tek bir Sanal IP (Virtual IP, VIP) arkasında çalışmasını sağlar. Aktif sunucu çöktüğünde pasif durumdaki yedek sunucu VIP’yi milisaniyeler içinde üzerine alır. Kullanıcılar bu failover sürecinden haberdar bile olmaz.

Altyapı hazırlığı ve olmazsa olmaz kernel parametresi

Kuruluma başlamadan önce topolojiyi netleştirelim. Elimizde iki adet Linux (Ubuntu/Debian tabanlı kabul ediyoruz) sunucu olduğunu varsayalım:

  • LB01 (Master): 192.168.1.10
  • LB02 (Backup): 192.168.1.11
  • Sanal IP (VIP): 192.168.1.100

Şimdi kıdemli bir sistemcinin asla atlamayacağı kritik kernel ayarına gelelim: net.ipv4.ip_nonlocal_bind. Linux varsayılan olarak, sunucu üzerinde fiziksel olarak tanımlanmamış bir IP adresine servislerin bind olmasını (yani o IP’yi dinlemesini) engeller. VIP pasif sunucuda o an aktif olmadığı için backup sunucudaki HAProxy servisi başlatılamaz ve çöker. Bunun önüne geçmek için her iki sunucuda da şu komutu çalıştırıyoruz:

echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Bu ayar sayesinde HAProxy, sunucuda henüz tanımlanmamış olan 192.168.1.100 IP’sini çekinmeden dinlemeye başlar.

Keepalived ile aktif-pasif VIP kurulumu

Her iki sunucuya da keepalived paketini kuralım:

sudo apt update && sudo apt install keepalived -y

Şimdi konfigürasyon zamanı. En kritik nokta, master sunucu çöktüğünde VIP’nin pasif sunucuya geçmesi, master geri geldiğinde ise (istemiyorsak) VIP’yi gereksiz yere geri alıp ufak da olsa bir kesinti yaratmamasıdır. Buna “non-preemptive” yapılandırma denir. Biz bu örnekte klasik aktif-pasif öncelik yapısını kuracağız.

Master (LB01) konfigürasyonu

/etc/keepalived/keepalived.conf dosyasını oluşturun ve aşağıdaki gibi düzenleyin:

vrrp_script check_haproxy {
    script "killall -0 haproxy" # HAProxy çalışıyor mu kontrol et
    interval 2                  # Her 2 saniyede bir çalıştır
    weight 2                    # Başarılıysa önceliğe (priority) 2 ekle
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0              # Network arayüzünüzün adı (ip a ile kontrol edin)
    virtual_router_id 51        # İki sunucuda da AYNI olmalı
    priority 101                # Master daha yüksek önceliğe sahip
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass GizliSifre123  # İki sunucuda da aynı olmalı
    }

    virtual_ipaddress {
        192.168.1.100/24         # Paylaşılan Sanal IP (VIP)
    }

    track_script {
        check_haproxy
    }
}

Backup (LB02) konfigürasyonu

Backup sunucuda dosya neredeyse aynıdır, yalnızca state ve priority değerleri değişir:

vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100                # Master'dan daha düşük
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass GizliSifre123
    }

    virtual_ipaddress {
        192.168.1.100/24
    }

    track_script {
        check_haproxy
    }
}

Konfigürasyonları kaydettikten sonra her iki sunucuda da servisi başlatalım:

sudo systemctl enable --now keepalived

Her şey yolunda gittiyse LB01 üzerinde ip a show eth0 komutunu verdiğinizde secondary IP olarak 192.168.1.100 adresini görmelisiniz. LB02’de ise bu IP görünmemelidir.

HAProxy kurulumu ve sağlık kontrolü (health check) sanatı

Sıra yük dengeleme katmanımızda. HAProxy’yi kuralım:

sudo apt install haproxy -y

Bir load balancer’ı akıllı kılan şey, arkasındaki uygulama sunucularının (backend) gerçekten yaşayıp yaşamadığını bilmesidir. TCP portunun açık olması (Layer 4) uygulamanın sağlıklı çalıştığı anlamına gelmez. Uygulama veritabanına bağlanamadığı için HTTP 500 hatası veriyor olabilir ama TCP portu hâlâ ayaktadır. Bu yüzden her zaman HTTP tabanlı (Layer 7) health check tercih etmelisiniz.

Şimdi hem gelişmiş health check mekanizmasını hem de VIP binding konseptini içeren örnek bir /etc/haproxy/haproxy.cfg dosyası hazırlayalım:

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000ms
    timeout client  50000ms
    timeout server  50000ms

frontend http_front
    bind 192.168.1.100:80 # Sadece VIP üzerinden gelen istekleri dinle
    mode http
    default_backend app_backend

backend app_backend
    mode http
    balance roundrobin
    
    # Layer 7 Health Check Yapılandırması
    option httpchk GET /healthz HTTP/1.1\r\nHost:\ myapp.local
    http-check expect status 200
    
    # Backend Sunucuları
    server app01 192.168.1.20:8080 check inter 3000 rise 2 fall 3
    server app02 192.168.1.21:8080 check inter 3000 rise 2 fall 3

Burada neler oldu? Ayrıntılı “neden” analizi

  • bind 192.168.1.100:80: HAProxy’ye yalnızca VIP adresini dinlemesini söyledik. Bu, trafiğin kontrolsüz şekilde doğrudan nodeların kendi IP’leri üzerinden akmasını engeller.
  • option httpchk GET /healthz: HAProxy, backend sunucularına her 3 saniyede bir (inter 3000) HTTP GET isteği gönderir.
  • http-check expect status 200: Gelen yanıt HTTP 200 OK ise sunucu “sağlıklı” kabul edilir.
  • rise 2 fall 3: Bir sunucu ardışık 3 kez başarısız health check yanıtı verirse (fall) trafik ona gönderilmez (out of rotation). Ardışık 2 başarılı yanıt verdiğinde (rise) ise tekrar gruba dahil edilir.

Gelişmiş ACL (Access Control List) tabanlı routing

Prod ortamlarında genellikle tek bir domain arkasında birden fazla mikroservis barındırırız. Örneğin /api ile başlayan isteklerin API servislerine, statik dosyaların ise başka bir backende gitmesini isteriz. HAProxy’nin ACL mekanizması bu iş için birebirdir.

Aşağıdaki konfigürasyonda path ve domain bazlı yönlendirmeyi nasıl yapacağımızı görelim:

frontend http_front_advanced
    bind 192.168.1.100:80
    mode http

    # ACL Tanımları
    acl is_api path_beg -i /api
    acl is_static path_end -i .jpg .png .css .js
    acl host_admin hdr_beg(host) -i admin.

    # Yönlendirme Kuralları (Routing Rules)
    use_backend api_backend if is_api
    use_backend static_backend if is_static
    use_backend admin_backend if host_admin
    
    # Varsayılan Backend
    default_backend web_backend

backend web_backend
    server web01 192.168.1.30:80 check

backend api_backend
    server api01 192.168.1.40:8080 check

backend static_backend
    server storage01 192.168.1.50:80 check

backend admin_backend
    server admin01 192.168.1.60:80 check

Bu yapıyla tek bir load balancer IP’si üzerinden gelen istekleri url path’ine veya HTTP host header’ına göre ayıklayıp tamamen farklı sunucu gruplarına sıfır performans kaybıyla dağıtabiliyoruz.

Failover testi: fişi çektiğimizde ne oluyor?

Kurulumu tamamladık ve servislerimizi başlattık (sudo systemctl enable --now haproxy). Sistemimiz gerçekten yüksek erişilebilir mi? Bunu test etmenin en vahşi (ve keyifli) yolu, canlı ortamda simülasyon yapmaktır.

Önce master sunucumuzda (LB01) IP adresini izleyelim:

ip addr show eth0

Burada 192.168.1.100 IP’sini görmeliyiz. Şimdi master sunucuda HAProxy servisini durdurarak Keepalived’ın bu durumu fark etmesini sağlayalım:

sudo systemctl stop haproxy

Hemen ardından pasif sunucuya (LB02) geçip logları izleyelim:

tail -f /var/log/syslog | grep Keepalived

Loglarda şuna benzer bir satır görmelisiniz:

Keepalived_vrrp[1234]: VRRP_Instance(VI_1) Entering MASTER STATE

ip addr show eth0 komutunu çalıştırdığınızda da VIP’nin saniyeden kısa bir sürede LB02’ye göç ettiğini göreceksiniz. Kullanıcılarınız veritabanına veri yazmaya ve web sitenizde gezinmeye kesintisiz devam edecek. HA kalitesi dediğimiz şey bu.

Sonuç ve pro-tip

HAProxy ve Keepalived ikilisi, karmaşık cloud mimarilerine ya da pahalı donanımsal load balancer cihazlarına ihtiyaç duymadan Linux’un gücüyle ölçeklenebilen sağlam bir çözümdür.

Son bir prod tavsiyesi: Keepalived loglarını mutlaka merkezi bir izleme aracına (Elasticsearch, Loki vb.) yönlendirin ve VIP geçişlerinde (state transitions) ekibinize Slack veya Teams üzerinden alert atacak bir script tetikleyin (bunun için Keepalived’ın notify_master ve notify_backup direktiflerine bakabilirsiniz). VIP’nin sessiz sedasız sürekli yer değiştirmesi, altyapınızda sinsi bir network dalgalanması olduğunun habercisi olabilir.