Logstash Kurulumu ve İlk Pipeline Yapılandırması

Bir ELK Stack kurulumunun en can alıcı noktası, bence her zaman Logstash konfigürasyonudur. Elasticsearch’ü kurmak nispeten düzgündür, Kibana da arayüz olduğu için toleranslıdır, ama Logstash? Logstash yanlış yapılandırıldığında ne hata verir ne de doğru çalışır, sadece sessizce işleri batırır. Bu yazıda sıfırdan kurulumdan başlayıp gerçekten işe yarar bir pipeline yapısına kadar gideceğiz.

Logstash Nedir ve Neden Pipeline Mantığını Anlamak Gerekir

Logstash, temelde üç aşamalı bir veri işleme motorudur: Input (veri al), Filter (işle/dönüştür), Output (bir yere gönder). Basit görünüyor, ancak bu üç aşamanın birbirleriyle nasıl etkileşime girdiğini kavramadan production ortamında işler hızla karmaşıklaşır.

Bir web sunucusundan Apache log’ları çektiğinizi düşünün. Ham log satırı şöyle gelir:

192.168.1.45 - john [10/Oct/2024:13:55:36 +0300] "GET /api/v2/users HTTP/1.1" 200 2326

Bu string’i Elasticsearch’e direkt atsanız, tek bir message alanı olarak gider ve sorgu yazamazsınız. Logstash’ın görevi bu satırı parse edip client_ip, username, timestamp, method, endpoint, status_code, response_size gibi ayrı alanlara bölmektir. İşte pipeline’ın kalbi burasıdır.

Kurulum Öncesi Gereksinimler

Logstash, JVM üzerinde çalışır. Bu, hem avantaj hem dezavantajdır. Avantaj: platform bağımsızdır. Dezavantaj: JVM tuning yapmazsanız bellek sorunlarıyla boğuşursunuz.

Minimum gereksinimler production için gerçekçi olarak şunlardır:

  • RAM: 4 GB (JVM heap için 2 GB ayrılacak, geri kalanı OS ve pipeline buffer için)
  • CPU: 2 core minimum, yüksek throughput için 4+ core önerilir
  • Disk: Log hacmine göre değişir, ama /var altında en az 20 GB boş alan
  • Java: OpenJDK 11 veya 17 (Logstash 8.x ile birlikte JDK bundled geliyor, ayrıca kurmanıza gerek kalmıyor)

Elasticsearch ile aynı sürümde olmanız kritik. Logstash 8.11 kullanıyorsanız Elasticsearch da 8.11 olmalı. Sürüm uyumsuzluğu gördüğüm en yaygın sorunlardan biridir.

Debian/Ubuntu Üzerine Kurulum

Elastic’in resmi repository’sini ekleyerek kurmak en sağlıklı yöntemdir. Paket yöneticisi üzerinden kurulum, servis yönetimini de otomatik halleder.

# GPG anahtarını ekle
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elastic-keyring.gpg

# Repository ekle
echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

# Güncelle ve kur
sudo apt-get update
sudo apt-get install logstash -y

RHEL/CentOS için:

# Repository dosyasını oluştur
sudo tee /etc/yum.repos.d/elasticsearch.repo <<EOF
[elasticsearch]
name=Elasticsearch repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
EOF

# Kur
sudo yum install --enablerepo=elasticsearch logstash -y

Kurulum tamamlandıktan sonra servis yönetimini ayarlayalım:

sudo systemctl daemon-reload
sudo systemctl enable logstash
sudo systemctl start logstash
sudo systemctl status logstash

İlk başlatmada 30-60 saniye beklemek normaldir. JVM startup süresi bu kadar sürer. Merak etmeyin, bug değil.

Dizin Yapısını Tanımak

Kurulum sonrası bilmeniz gereken dizinler:

  • /etc/logstash/: Ana konfigürasyon dizini
  • /etc/logstash/conf.d/: Pipeline konfigürasyon dosyaları buraya gelir
  • /etc/logstash/logstash.yml: Logstash’ın kendi ayarları
  • /etc/logstash/jvm.options: JVM parametreleri
  • /var/log/logstash/: Log dosyaları
  • /usr/share/logstash/: Uygulama dosyaları ve pluginler

JVM Tuning: Atlanmaması Gereken Adım

Logstash’ı kurup default ayarlarla production’a almak büyük hata. /etc/logstash/jvm.options dosyasında heap size’ı ayarlamanız gerekir.

sudo nano /etc/logstash/jvm.options

Dosyada şu satırları bulup düzenleyin:

-Xms2g
-Xmx2g

Önemli kural: -Xms ve -Xmx değerlerini her zaman eşit tutun. Heap’in büyüyüp küçülmesi GC pause’larına yol açar. Sunucunuzda 8 GB RAM varsa 4 GB heap makul bir değerdir. Toplam RAM’in yarısından fazlasını vermeyin, OS ve pipeline bufferlara da yer lazım.

logstash.yml Temel Ayarları

sudo nano /etc/logstash/logstash.yml

Minimum yapılandırma olarak şunları ayarlayın:

node.name: "logstash-prod-01"
path.data: /var/lib/logstash
path.logs: /var/log/logstash
pipeline.workers: 2
pipeline.batch.size: 125
pipeline.batch.delay: 50
config.reload.automatic: true
config.reload.interval: 30s
http.host: "127.0.0.1"
http.port: 9600

config.reload.automatic: true ayarı production’da hayat kurtarır. Pipeline konfigürasyonunu değiştirdiğinizde Logstash’ı restart etmeden değişiklikler devreye girer. pipeline.workers değerini CPU core sayısıyla eşit ya da bir eksik tutmak genellikle iyi bir başlangıç noktasıdır.

İlk Pipeline: Basit Bir Test

Karmaşık örneklere geçmeden önce, her şeyin çalıştığını doğrulamak için basit bir test pipeline’ı yazalım. /etc/logstash/conf.d/ altında .conf uzantılı dosyalar otomatik olarak yüklenir.

sudo nano /etc/logstash/conf.d/test-pipeline.conf
input {
  stdin { }
}

filter {
  mutate {
    add_field => { "test_field" => "logstash_calisiyor" }
  }
}

output {
  stdout {
    codec => rubydebug
  }
}

Bu pipeline’ı test etmek için:

sudo -u logstash /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/test-pipeline.conf

Başladıktan sonra bir şeyler yazıp Enter’a basın. rubydebug codec’i parse edilmiş event’i güzel bir formatta ekrana basar. Çıktıda test_field görüyorsanız temel kurulum çalışıyor demektir.

Test dosyasını sildikten sonra asıl pipeline’lara geçebiliriz.

Gerçek Dünya Pipeline 1: Apache/Nginx Access Log İşleme

Bu senaryo muhtemelen en yaygın kullanım durumudur. Bir web sunucusundan log okuyup Elasticsearch’e yazacağız.

sudo nano /etc/logstash/conf.d/web-access-logs.conf
input {
  file {
    path => "/var/log/nginx/access.log"
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/sincedb_nginx"
    tags => ["nginx", "access"]
  }
}

filter {
  grok {
    match => {
      "message" => '%{COMBINEDAPACHELOG}'
    }
  }

  date {
    match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
    target => "@timestamp"
    timezone => "Europe/Istanbul"
  }

  mutate {
    convert => {
      "response" => "integer"
      "bytes" => "integer"
    }
    rename => { "clientip" => "client_ip" }
    remove_field => [ "message", "timestamp" ]
  }

  if [response] >= 400 {
    mutate {
      add_tag => ["error_response"]
    }
  }

  if [response] >= 500 {
    mutate {
      add_tag => ["server_error"]
    }
  }

  geoip {
    source => "client_ip"
    target => "geoip"
  }
}

output {
  elasticsearch {
    hosts => ["https://localhost:9200"]
    index => "nginx-access-%{+YYYY.MM.dd}"
    user => "logstash_writer"
    password => "${LOGSTASH_ES_PASSWORD}"
    ssl_certificate_authorities => "/etc/logstash/certs/ca.crt"
  }
}

Birkaç önemli nokta açıklayayım:

sincedb_path: Logstash, hangi satıra kadar okuduğunu buraya kaydeder. Restart sonrası kaldığı yerden devam eder. Default olarak home dizinine yazar ama bunu açıkça belirtmek daha güvenlidir.

grok ve COMBINEDAPACHELOG: Grok, regex pattern’larını daha okunabilir hale getiren bir sistem. COMBINEDAPACHELOG built-in bir pattern olup standart Apache/Nginx combined log formatını parse eder.

Timezone: Türkiye’deyseniz Europe/Istanbul kullanın, aksi halde Kibana’da timestamp’lar kayacaktır.

Password için environment variable: Şifreyi config dosyasına direkt yazmayın. Logstash, ${DEGISKEN_ADI} syntax’ıyla environment variable’ları okur.

# /etc/logstash/logstash.env dosyası oluşturun
echo "LOGSTASH_ES_PASSWORD=guclu_sifreniz" | sudo tee /etc/logstash/logstash.env

# systemd service override ile environment dosyasını ekleyin
sudo mkdir -p /etc/systemd/system/logstash.service.d/
sudo tee /etc/systemd/system/logstash.service.d/override.conf <<EOF
[Service]
EnvironmentFile=/etc/logstash/logstash.env
EOF

sudo systemctl daemon-reload
sudo systemctl restart logstash

Gerçek Dünya Pipeline 2: Syslog Input ile Merkezi Log Toplama

Birden fazla sunucudan log toplamak istediğinizde syslog input kullanışlıdır. Logstash bir port üzerinde dinler, syslog mesajlarını alır.

input {
  syslog {
    port => 5514
    type => "syslog"
  }

  tcp {
    port => 5000
    type => "json_lines"
    codec => json_lines
  }
}

filter {
  if [type] == "syslog" {
    mutate {
      add_field => {
        "environment" => "production"
        "datacenter" => "istanbul-dc1"
      }
    }

    if [program] == "sshd" {
      grok {
        match => {
          "message" => [
            "Accepted %{WORD:auth_method} for %{USER:username} from %{IP:source_ip}",
            "Failed %{WORD:auth_method} for %{USER:username} from %{IP:source_ip}",
            "Invalid user %{USER:username} from %{IP:source_ip}"
          ]
        }
        tag_on_failure => []
      }

      if [username] {
        mutate {
          add_tag => ["ssh_auth_event"]
        }
      }
    }
  }

  if [type] == "json_lines" {
    date {
      match => [ "timestamp", "ISO8601" ]
      target => "@timestamp"
    }
  }
}

output {
  if [type] == "syslog" {
    elasticsearch {
      hosts => ["https://localhost:9200"]
      index => "syslog-%{+YYYY.MM.dd}"
      user => "logstash_writer"
      password => "${LOGSTASH_ES_PASSWORD}"
    }
  }

  if [type] == "json_lines" {
    elasticsearch {
      hosts => ["https://localhost:9200"]
      index => "app-logs-%{+YYYY.MM.dd}"
      user => "logstash_writer"
      password => "${LOGSTASH_ES_PASSWORD}"
    }
  }
}

Bu konfigürasyonda birden fazla input ve koşula dayalı output kullanıyoruz. type alanı event’lerin hangi çıkışa gideceğini belirliyor.

Pipeline Konfigürasyonunu Test Etme

Production’a almadan önce konfigürasyonu her zaman test edin:

sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash -t

-t flag’i konfigürasyonu parse eder ama çalıştırmaz. Syntax hatası varsa açıkça söyler. Bu komutu CI/CD pipeline’ınıza da ekleyebilirsiniz.

Dead Letter Queue: Hatalı Event’ler İçin Güvenlik Ağı

Grok parse’ı başarısız olan ya da Elasticsearch’e yazılamayan event’ler varsayılan olarak drop edilir. Bunu istemiyorsanız Dead Letter Queue’yu aktif edin.

logstash.yml dosyasına ekleyin:

dead_letter_queue.enable: true
dead_letter_queue.max_bytes: 1gb
path.dead_letter_queue: /var/lib/logstash/dead_letter_queue

DLQ’daki event’leri sonradan işlemek için ayrı bir pipeline yazabilirsiniz:

input {
  dead_letter_queue {
    path => "/var/lib/logstash/dead_letter_queue"
    commit_offsets => true
  }
}

output {
  stdout {
    codec => rubydebug
  }
}

Bu, production’da hata ayıklamayı çok kolaylaştırır. Hangi event’lerin neden başarısız olduğunu anlayabilirsiniz.

Monitoring ve Sorun Giderme

Logstash çalışırken monitoring API’si 9600 portunda dinler:

# Genel node bilgisi
curl -s http://localhost:9600/?pretty

# Pipeline istatistikleri
curl -s http://localhost:9600/_node/stats/pipelines?pretty

# JVM istatistikleri
curl -s http://localhost:9600/_node/stats/jvm?pretty | grep heap_used_percent

Pipeline istatistiklerinde dikkat etmeniz gereken değerler:

  • events.filtered: Filter aşamasından geçen event sayısı
  • events.out: Output’a ulaşan event sayısı
  • queue.events_count: Queue’da bekleyen event sayısı (bu yüksekse output tıkanmış olabilir)

Log dosyasına bakmak da çoğu sorunu çözer:

sudo tail -f /var/log/logstash/logstash-plain.log

Grok pattern’larını test etmek için Kibana’daki Grok Debugger aracını kullanın ya da [Grok Debugger](https://grokdebugger.com) online aracına başvurun. Saatlerce debug yapmanızı önler.

Performans Sorunlarına Genel Bakış

Logstash yavaşsa veya geride kalıyorsa sırasıyla şunları kontrol edin:

  • pipeline.workers artırın: CPU’nuz boştaysa worker sayısını artırın. Her worker bir thread’dir.
  • pipeline.batch.size artırın: Elasticsearch’e tek seferde daha büyük batch göndermek throughput’u artırır, ancak bellek kullanımı da artar.
  • Geoip plugin’i dikkatli kullanın: Her event için DNS ve veritabanı sorgusu yapar, CPU’yu ciddi tüketebilir. Sadece gerçekten ihtiyaç duyduğunuzda aktif edin.
  • Gereksiz filter’ları kaldırın: Her filter zincire gecikme ekler. Kullanmadığınız plugin’leri konfigürasyondan çıkarın.

Sonuç

Logstash kurulumu tek başına bir son değil, ELK Stack’in işlevsel hale geldiği başlangıç noktasıdır. Bu yazıda anlattıklarımı özetlersek: JVM heap’ini doğru ayarlamadan production’a çıkmayın, pipeline konfigürasyonlarını her zaman -t flag’iyle test edin, şifreleri asla config dosyasına yazmayın ve Dead Letter Queue’yu mutlaka aktif edin.

En sık gördüğüm hata, “çalışıyor gibi görünüyor” diye konfigürasyonun doğru olduğunu varsaymak. Elasticsearch’te indexlenen event sayısını, Logstash monitoring API’sinden pipeline istatistiklerini ve özellikle events.filtered ile events.out arasındaki farkı düzenli kontrol edin. Bu fark büyükse bir şeyler drop ediliyor demektir.

Bir sonraki adım olarak Beats ailesiyle (Filebeat, Metricbeat) Logstash’ı birlikte kullanmayı ele alabiliriz. Filebeat, log toplama konusunda Logstash’tan çok daha hafiftir ve uç noktalarda (edge’lerde) çalıştırılmaya uygun bir agent’tır. Logstash’ı merkezi işleme katmanı, Filebeat’i ise toplama katmanı olarak konumlandırmak büyük ortamlarda standart haline gelmiş bir mimaridir.

Bir yanıt yazın

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