OpenSearch: AWS’nin ELK Stack Alternatifi

Elastic şirketinin 2021’de lisans değişikliğine gitmesiyle birlikte, pek çok organizasyonda “şimdi ne yapacağız?” sorusu gündeme geldi. Özellikle üretim ortamlarında Elasticsearch ve Kibana kullanan ekipler için bu gerçek bir karar anıydı. AWS’nin bu duruma verdiği yanıt OpenSearch oldu. Ama mesele sadece “lisans değişti, fork ettiler” kadar basit değil. OpenSearch, zamanla kendi ekosistemini oluşturan, bazı konularda ELK’ı geride bırakan, bazı konularda ise hâlâ yetişmeye çalışan bir proje haline geldi. Bu yazıda hem teorik hem de pratik açıdan OpenSearch’ü ele alacağız.

OpenSearch Nedir ve Nereden Gelir?

Elasticsearch 7.10.2, Elastic’in SSPL (Server Side Public License) lisansına geçmeden önceki son Apache 2.0 sürümüydü. AWS bu sürümü fork alarak OpenSearch projesini başlattı ve 2021 yılının ortasında ilk kararlı sürümü yayınladı. Kibana’nın fork’u ise OpenSearch Dashboards adını aldı.

Bugün OpenSearch, Amazon tarafından değil, OpenSearch Software Foundation çatısı altında yönetiliyor. Bu önemli bir ayrım çünkü projenin uzun vadeli sürdürülebilirliği açısından vendor lock-in kaygılarını bir ölçüde azaltıyor.

OpenSearch’ün ELK Stack ile karşılaştırıldığında öne çıkan temel farkları şöyle sıralayabiliriz:

  • Lisans: OpenSearch tamamen Apache 2.0 lisanslıdır, ticari kısıtlama yoktur
  • Güvenlik eklentisi: ELK’ta X-Pack gerektiren pek çok güvenlik özelliği OpenSearch’te ücretsiz gelir
  • ML Commons: Makine öğrenmesi özellikleri community sürümünde mevcut
  • k-NN search: Vektör arama desteği açık kaynak olarak sunuluyor
  • Kibana uyumluluğu: OpenSearch Dashboards, Kibana 7.10.2 tabanlıdır ama artık bağımsız bir yol izliyor

Kurulum: Docker Compose ile Hızlı Başlangıç

Prod ortamına geçmeden önce yerel ortamda ayağa kaldırmak için Docker Compose kullanmak en pratik yol. OpenSearch, single-node kurulumda memory lock için bazı sistem ayarları istiyor.

Önce sistem parametrelerini ayarlayalım:

# vm.max_map_count ayarı - bu olmadan OpenSearch başlamaz
sudo sysctl -w vm.max_map_count=262144

# Kalıcı hale getirmek için
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf

# ulimit ayarları
sudo sh -c 'echo "opensearch soft nofile 65536" >> /etc/security/limits.conf'
sudo sh -c 'echo "opensearch hard nofile 65536" >> /etc/security/limits.conf'

Şimdi docker-compose.yml dosyasını oluşturalım:

cat << 'EOF' > docker-compose.yml
version: '3'
services:
  opensearch-node1:
    image: opensearchproject/opensearch:2.11.0
    container_name: opensearch-node1
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node1
      - discovery.seed_hosts=opensearch-node1,opensearch-node2
      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
      - OPENSEARCH_INITIAL_ADMIN_PASSWORD=Admin_password_1234!
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearch-data1:/usr/share/opensearch/data
    ports:
      - 9200:9200
      - 9600:9600
    networks:
      - opensearch-net

  opensearch-node2:
    image: opensearchproject/opensearch:2.11.0
    container_name: opensearch-node2
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node2
      - discovery.seed_hosts=opensearch-node1,opensearch-node2
      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
      - OPENSEARCH_INITIAL_ADMIN_PASSWORD=Admin_password_1234!
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearch-data2:/usr/share/opensearch/data
    networks:
      - opensearch-net

  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:2.11.0
    container_name: opensearch-dashboards
    ports:
      - 5601:5601
    environment:
      OPENSEARCH_HOSTS: '["https://opensearch-node1:9200","https://opensearch-node2:9200"]'
      OPENSEARCH_USERNAME: admin
      OPENSEARCH_PASSWORD: Admin_password_1234!
    networks:
      - opensearch-net

volumes:
  opensearch-data1:
  opensearch-data2:

networks:
  opensearch-net:
EOF

docker-compose up -d

Güvenlik Yapılandırması: ELK’tan Önemli Fark

OpenSearch’te güvenlik özellikleri default olarak aktif gelir. Bu bazen acemi kullanıcıları şaşırtıyor çünkü SSL sertifikaları ve kimlik doğrulama kutudan çıktığı gibi yapılandırılmış durumda. Elasticsearch’te bu özellikleri X-Pack ile ücretli olarak alıyordunuz.

Demo sertifikalar production için uygun değil. Kendi sertifikalarınızı oluşturalım:

# OpenSearch'in kendi araçlarıyla sertifika oluşturma
docker exec -it opensearch-node1 bash

# Container içinde
cd /usr/share/opensearch/plugins/opensearch-security/tools/

./opensearch-onetime-setup.sh

# Root CA oluştur
openssl genrsa -out root-ca-key.pem 2048
openssl req -new -x509 -sha256 -key root-ca-key.pem 
  -subj "/C=TR/ST=Istanbul/O=Sirketim/CN=root" 
  -out root-ca.pem -days 730

# Admin sertifikası
openssl genrsa -out admin-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem 
  -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem
openssl req -new -key admin-key.pem 
  -subj "/C=TR/ST=Istanbul/O=Sirketim/CN=admin" 
  -out admin.csr
openssl x509 -req -in admin.csr -CA root-ca.pem 
  -CAkey root-ca-key.pem -CAcreateserial 
  -sha256 -out admin.pem -days 730

Güvenlik yapılandırmasını güncellemek için securityadmin.sh kullanıyoruz. Bu, prod ortamlarda değişiklik yaparken dikkat etmeniz gereken kritik bir araç:

# Güvenlik konfigürasyonunu uygula
./securityadmin.sh 
  -cd /usr/share/opensearch/config/opensearch-security/ 
  -icl -nhnv 
  -cacert /usr/share/opensearch/config/root-ca.pem 
  -cert /usr/share/opensearch/config/admin.pem 
  -key /usr/share/opensearch/config/admin-key.pem

Fluent Bit ile Log Toplama

Logstash yerine Fluent Bit kullanmak, özellikle kaynak kısıtlı ortamlarda büyük fark yaratıyor. Fluent Bit yaklaşık 450KB bellek kullanırken Logstash minimum 512MB JVM heap istiyor. Gerçek üretim ortamlarında bu fark çok daha belirgin hale geliyor.

Kubernetes ortamında Fluent Bit’i OpenSearch’e bağlamak için fluent-bit.conf:

cat << 'EOF' > /etc/fluent-bit/fluent-bit.conf
[SERVICE]
    Flush         1
    Log_Level     info
    Daemon        off
    Parsers_File  parsers.conf

[INPUT]
    Name              tail
    Tag               app.logs
    Path              /var/log/containers/*.log
    Parser            docker
    DB                /var/log/flb_kube.db
    Mem_Buf_Limit     50MB
    Skip_Long_Lines   On
    Refresh_Interval  10

[INPUT]
    Name          systemd
    Tag           host.systemd
    Systemd_Filter _SYSTEMD_UNIT=nginx.service
    Read_From_Tail On

[FILTER]
    Name                kubernetes
    Match               app.logs
    Kube_URL            https://kubernetes.default.svc:443
    Kube_CA_File        /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    Kube_Token_File     /var/run/secrets/kubernetes.io/serviceaccount/token
    Merge_Log           On
    Keep_Log            Off
    K8S-Logging.Parser  On
    K8S-Logging.Exclude Off

[FILTER]
    Name   grep
    Match  app.logs
    Regex  log (ERROR|WARN|CRITICAL)

[OUTPUT]
    Name            opensearch
    Match           *
    Host            opensearch-node1
    Port            9200
    Index           app-logs
    Type            _doc
    HTTP_User       admin
    HTTP_Passwd     Admin_password_1234!
    tls             On
    tls.verify      Off
    Suppress_Type_Name On
    Logstash_Format On
    Logstash_Prefix app-logs
    Time_Key        @timestamp
EOF

Index Template ve Mapping Yönetimi

OpenSearch’e veri atmadan önce doğru mapping tanımlamak, sonradan “neden bu alan text yerine keyword olmuş” diye saçını yolmamak anlamına geliyor. Özellikle IP adresleri ve zaman damgaları için explicit mapping şart.

# Index template oluşturma
curl -X PUT "https://localhost:9200/_index_template/app-logs-template" 
  -H 'Content-Type: application/json' 
  -u admin:Admin_password_1234! 
  --insecure 
  -d '{
    "index_patterns": ["app-logs-*"],
    "template": {
      "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 1,
        "index.refresh_interval": "30s",
        "index.codec": "best_compression"
      },
      "mappings": {
        "properties": {
          "@timestamp": {
            "type": "date",
            "format": "strict_date_optional_time||epoch_millis"
          },
          "client_ip": {
            "type": "ip"
          },
          "log_level": {
            "type": "keyword"
          },
          "service_name": {
            "type": "keyword"
          },
          "message": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 512
              }
            }
          },
          "response_time_ms": {
            "type": "float"
          },
          "http_status": {
            "type": "integer"
          }
        }
      }
    },
    "priority": 100
  }'

ISM (Index State Management) ile Otomatik Index Yaşam Döngüsü

Bu, OpenSearch’in ELK’a göre gerçekten ücretsiz sunduğu kritik özelliklerden biri. Elasticsearch’te ILM (Index Lifecycle Management) X-Pack gerektiriyordu. ISM ile otomatik olarak eski indexleri arşivleyebilir, silebilir veya read-only hale getirebilirsiniz.

Gerçek bir senaryo: 30 günden eski logları otomatik sil, 7 günden eski indexleri read-only yap, replikaları azalt:

curl -X PUT "https://localhost:9200/_plugins/_ism/policies/log-rotation-policy" 
  -H 'Content-Type: application/json' 
  -u admin:Admin_password_1234! 
  --insecure 
  -d '{
    "policy": {
      "description": "Log rotation: hot-warm-delete",
      "default_state": "hot",
      "states": [
        {
          "name": "hot",
          "actions": [
            {
              "rollover": {
                "min_index_age": "1d",
                "min_size": "5gb"
              }
            }
          ],
          "transitions": [
            {
              "state_name": "warm",
              "conditions": {
                "min_index_age": "7d"
              }
            }
          ]
        },
        {
          "name": "warm",
          "actions": [
            {
              "read_only": {}
            },
            {
              "replica_count": {
                "number_of_replicas": 0
              }
            }
          ],
          "transitions": [
            {
              "state_name": "delete",
              "conditions": {
                "min_index_age": "30d"
              }
            }
          ]
        },
        {
          "name": "delete",
          "actions": [
            {
              "delete": {}
            }
          ],
          "transitions": []
        }
      ],
      "ism_template": [
        {
          "index_patterns": ["app-logs-*"],
          "priority": 100
        }
      ]
    }
  }'

Alerting: OpenSearch’in Native Alarm Sistemi

ELK Stack’te Watcher ya da ElastAlert gibi harici araçlara ihtiyaç duyuyordunuz. OpenSearch, alerting eklentisini kutudan çıktığı gibi sunuyor. 5xx hata oranı belirli eşiği geçince Slack’e veya e-posta ile bildirim göndermek artık çok daha kolay.

Monitor oluşturma örneği:

curl -X POST "https://localhost:9200/_plugins/_alerting/monitors" 
  -H 'Content-Type: application/json' 
  -u admin:Admin_password_1234! 
  --insecure 
  -d '{
    "type": "monitor",
    "name": "5xx-error-rate-monitor",
    "enabled": true,
    "schedule": {
      "period": {
        "interval": 5,
        "unit": "MINUTES"
      }
    },
    "inputs": [
      {
        "search": {
          "indices": ["app-logs-*"],
          "query": {
            "size": 0,
            "query": {
              "bool": {
                "filter": [
                  {
                    "range": {
                      "@timestamp": {
                        "gte": "now-5m",
                        "lte": "now"
                      }
                    }
                  },
                  {
                    "range": {
                      "http_status": {
                        "gte": 500,
                        "lte": 599
                      }
                    }
                  }
                ]
              }
            },
            "aggs": {
              "error_count": {
                "value_count": {
                  "field": "http_status"
                }
              }
            }
          }
        }
      }
    ],
    "triggers": [
      {
        "name": "high-error-rate",
        "severity": "1",
        "condition": {
          "script": {
            "source": "ctx.results[0].aggregations.error_count.value > 100",
            "lang": "painless"
          }
        },
        "actions": [
          {
            "name": "slack-notification",
            "destination_id": "SLACK_DESTINATION_ID",
            "message_template": {
              "source": "5xx hata sayisi son 5 dakikada {{ctx.results.0.aggregations.error_count.value}} adede ulasti!"
            }
          }
        ]
      }
    ]
  }'

Performans Tuning: Prod Ortamı İçin Kritik Ayarlar

Cluster’ı ayağa kaldırdınız, loglar akıyor ama zamanla yavaşlamaya başlıyor. Bu noktada yapılması gereken bazı kritik ayarlar var. JVM heap size’ı toplam RAM’in yarısından fazla vermeyin, işletim sistemi dosya önbelleği için yer bırakın. 64GB RAM olan bir makinede maksimum 32GB heap kullanın.

opensearch.yml için önerilen prod ayarları:

cat << 'EOF' >> /usr/share/opensearch/config/opensearch.yml
# Cluster ayarları
cluster.name: production-logs
node.name: ${HOSTNAME}

# Bellek
bootstrap.memory_lock: true

# Thread pool ayarları
thread_pool.write.queue_size: 1000
thread_pool.search.queue_size: 1000

# Index buffer
indices.memory.index_buffer_size: 20%
indices.memory.min_index_buffer_size: 96mb

# Circuit breaker - OOM'dan korur
indices.breaker.total.use_real_memory: true
indices.breaker.total.limit: 95%

# Shard allocation
cluster.routing.allocation.disk.threshold_enabled: true
cluster.routing.allocation.disk.watermark.low: 85%
cluster.routing.allocation.disk.watermark.high: 90%
cluster.routing.allocation.disk.watermark.flood_stage: 95%

# Recover ayarları
cluster.routing.allocation.node_concurrent_recoveries: 4
indices.recovery.max_bytes_per_sec: 200mb

# Slow log eşikleri
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.fetch.warn: 1s
index.indexing.slowlog.threshold.index.warn: 10s
EOF

Gerçek Dünya Senaryosu: E-Ticaret Log Analizi

Bir e-ticaret platformu düşünelim. Saniyede ortalama 2000 istek alıyor, peak saatlerde bu 10.000’e çıkıyor. Her isteğin nginx access log kaydı var ve ödeme sayfasındaki hataları gerçek zamanlı izlemek istiyorlar.

Bu senaryo için OpenSearch üzerinde çalışan bir analiz sorgusu:

# Ödeme sayfasındaki 5xx hatalarını son 1 saatte serbis bazında grupla
curl -X GET "https://localhost:9200/app-logs-*/_search" 
  -H 'Content-Type: application/json' 
  -u admin:Admin_password_1234! 
  --insecure 
  -d '{
    "size": 0,
    "query": {
      "bool": {
        "filter": [
          {
            "range": {
              "@timestamp": {
                "gte": "now-1h"
              }
            }
          },
          {
            "term": {
              "url_path.keyword": "/api/payment"
            }
          },
          {
            "range": {
              "http_status": {
                "gte": 500
              }
            }
          }
        ]
      }
    },
    "aggs": {
      "errors_over_time": {
        "date_histogram": {
          "field": "@timestamp",
          "fixed_interval": "5m"
        },
        "aggs": {
          "by_service": {
            "terms": {
              "field": "service_name",
              "size": 10
            },
            "aggs": {
              "avg_response_time": {
                "avg": {
                  "field": "response_time_ms"
                }
              }
            }
          }
        }
      },
      "top_error_messages": {
        "terms": {
          "field": "message.keyword",
          "size": 5
        }
      }
    }
  }'

Bu sorgu size hem zaman bazlı trend hem de hangi servisin ne kadar hata ürettiğini, ortalama yanıt sürelerini ve en sık karşılaşılan hata mesajlarını tek sorguda verir.

OpenSearch ile ELK: Hangisi Nerede Daha İyi?

Dürüst olmak gerekirse her iki sistemin de güçlü ve zayıf tarafları var.

OpenSearch’in öne çıktığı noktalar:

  • Ücretsiz güvenlik: TLS, RBAC, audit logging hepsi açık kaynak
  • ISM: Index yaşam döngüsü yönetimi ücretsiz
  • Alerting: Native alarm sistemi ekstra araç gerektirmiyor
  • AWS entegrasyonu: Amazon OpenSearch Service ile native entegrasyon
  • Anomaly detection: ML tabanlı anomali tespiti community versiyonda mevcut

Elasticsearch’ün hâlâ önde olduğu noktalar:

  • Ekolojim: Beats entegrasyonları, Elastic APM, daha geniş connector desteği
  • Performans: 8.x serisiyle gelen optimizasyonlar OpenSearch’te henüz tam olarak yok
  • Kibana olgunluğu: Lens, Maps gibi gelişmiş görselleştirme araçları OpenSearch Dashboards’da daha sınırlı
  • Sürüm hızı: Elastic yeni özellikler çıkarmada daha agresif

Snapshot ve Backup Stratejisi

Production’da snapshot olmadan çalışmak, emniyet kemeri takmadan araba kullanmak gibi. OpenSearch S3 snapshot repository desteğini native olarak sunuyor:

# S3 snapshot repository tanımla
curl -X PUT "https://localhost:9200/_snapshot/s3-backup-repo" 
  -H 'Content-Type: application/json' 
  -u admin:Admin_password_1234! 
  --insecure 
  -d '{
    "type": "s3",
    "settings": {
      "bucket": "opensearch-backups-prod",
      "region": "eu-west-1",
      "base_path": "opensearch/snapshots",
      "server_side_encryption": true,
      "compress": true,
      "max_snapshot_bytes_per_sec": "100mb",
      "max_restore_bytes_per_sec": "100mb"
    }
  }'

# Snapshot politikası oluştur - her gece 02:00'da
curl -X PUT "https://localhost:9200/_plugins/_sm/policies/nightly-backup" 
  -H 'Content-Type: application/json' 
  -u admin:Admin_password_1234! 
  --insecure 
  -d '{
    "description": "Her gece otomatik snapshot",
    "creation": {
      "schedule": {
        "cron": {
          "expression": "0 2 * * *",
          "timezone": "Europe/Istanbul"
        }
      },
      "time_limit": "1h"
    },
    "deletion": {
      "schedule": {
        "cron": {
          "expression": "0 3 * * *",
          "timezone": "Europe/Istanbul"
        }
      },
      "condition": {
        "max_age": "14d",
        "min_count": 5,
        "max_count": 21
      },
      "time_limit": "1h"
    },
    "snapshot_config": {
      "repository": "s3-backup-repo",
      "indices": "app-logs-*,system-logs-*",
      "ignore_unavailable": true,
      "include_global_state": false,
      "partial": false
    }
  }'

Sonuç

OpenSearch, 2021’deki doğuşundan bu yana ciddi bir olgunluğa ulaştı. Eğer ekibinizde halihazırda ELK Stack varsa ve X-Pack özellikleri için ücret ödüyorsanız, OpenSearch’e geçiş güçlü bir maliyet optimizasyonu fırsatı. Öte yandan sıfırdan başlıyorsanız ve AWS altyapısı kullanıyorsanız Amazon OpenSearch Service ile managed bir deneyim oldukça cazip.

Elasticsearch 7.x’ten OpenSearch’e migration API uyumluluğu açısından büyük ölçüde sorunsuz. Ancak Elasticsearch 8.x’ten geçiş yapmak isteyenler için bu süreç daha fazla planlama gerektiriyor, çünkü OpenSearch şu an 7.x API setinden evrimleşiyor ve bazı 8.x özellikleri henüz karşılık bulmuyor.

Kendi deneyimimden söyleyeyim: ISM politikaları ve native alerting tek başına birçok organizasyon için geçişi haklı kılabilecek kadar değerli. Sadece “lisans bedava” diye değil, gerçekten olgun ve üretim kullanımına hazır bir ürün olduğu için OpenSearch’i ciddiye almak gerekiyor.

Bir yanıt yazın

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