Merhaba,
Bu yazıda docker ekosistemi ve sunucu mimarilerinde olay bilgisi kayıtlarını (log bilgisi) belirli bir mantık içerisinde toplayıp daha sonra toplanan bu kayıtlar üzerinde bir takım görseller , raporlar oluşturarak bilgi sistem altyapısının izlenmesi ve bilginin analiz edilmesi konularına değineceğiz. Bu kapsamda kuracağımız sistem Elastic Stack (ELK) olarak bilinen bir takım yazılımlar kümesi olacaktır. Elastic Stack ve barındırdığı yazılımlara kısaca değinelim.
Elastic Stack içerisinde Elasticsearch, Kibana, Logstash, Beats (Filebeat, Metricbeat, Heartbeat, Packetbeat, Auditbeat, Winlogbeat, Functionbeat ) yazılımlarını içeren bir bütünleşik uygulama mimarisidir. Her bileşenin farklı işlemleri gerçekleştirdiği bu yapıda bileşenler şu görevleri yapmaktadırlar:
- Elasticsearch: Dağıtık RESTful tabanlı arama ve analiz motorudur. Verileri JSON formatında tutulduğu merkezi veri depolama sistemidir. Arama ve analiz konusunda çok başarılı ve hızlıdır.
- Kibana: Elasticsearch verilerini görüntülemenizi sağlayan web tabanlı bir arayüz sağlayan yazılımdır. İsteklerinizin uygulamanızdaki akışını anlamaya kadar birçok bilgiyi sizin için görserlleştirir.
- Logstash: Çok sayıda kaynaktan veri alan, dönüştüren ve saklamak istediğiniz alanı elde etmenizi sağlayan bir veri işleme hattıdır.
- Beats: Çeşitli sistemlerden farklı farklı verileri toplayıp elasticsearch veya logstash'e gönderen veri göndericileridir. İçerisinde topladığı veriye göre farklı farklı türleri bulunmaktadır. (Filebeat, Metricbeat, Heartbeat, Packetbeat, Auditbeat, Winlogbeat, Functionbeat)
Bu kısa açıklamadan sonra kuracağımız sistem mimarisinden bahsedelim. Kuracağımız yapıda docker-swarm üzerinden "Filebeat" bileşenini kullanarak log kayıtlarını toplayacağız. Ayrıca Ekosistemimizi oluşturan host ve sanal makinlerin metrik değerlerini (CPU, RAM, I/O, Bandwith vb.) "Metricbeat" ile toplayacağız. Topladığımız bu verileri doğrudan elasticsearch'e gönderip daha sonra kibana üzerinden elasticsearch ile bağlantı kurarak topladığımız verileri anlamlandıracağız. Bu senaryoda "logstash" kullanmayacağız. Kuracağımız tüm ELS bileşenleri (metricbeat hariç) docker üzerinde servis olarak çalıştırılacaktır. Uygulama mimarisi mantıksal olarak aşağıdaki gibi olacaktır.
Not: Bu yapı önceki yazılarda anlatılan docker swarm mimarisi üzerinde deplop edilecektir.
Uygulamayı docker-compose dosyası olarak yml formatında hazırlayıp docker-swarm cluster üzerinde deploy edeceğiz. Yapacağımız konfigürasyonların ve toplayacağımız verilerin kalıcı olması için öncelikle uygulamalar için konfigürasyon dosyalarını oluşturuyoruz.
Elasticsearch için yalnızca tek nodelu bir cluster oluşturuyoruz. Burada amacımız yüksek erişilebilirliği göstermekten ziyade uygulamaların fonksiyonlarını gözlemlemek olacaktır. Bu kapsamda elasticsearch config dosyası aşağıdaki gibi olacaktır.
Not: elasticsearh için role ve user tanımı yapmayacağız. Ayrıca security özelliklerini de aktif etmeyeceğiz. Bu kurulum yalnızca ELS çalışma mantığına odaklanmaktadır.
elasticsearch.yml
--------------------------------------------------------------------------------------------------------------------------
cluster.name: "docker-cluster"
network.host: 0.0.0.0
--------------------------------------------------------------------------------------------------------------------------
kibana konfigürasyon dosyası aşağıdaki gibidir.
kibana.yml
--------------------------------------------------------------------------------------------------------------------------
#
# ** THIS IS AN AUTO-GENERATED FILE **
#
# Default Kibana configuration for docker target
server.name: kibana.omer.com
server.host: "0"
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
xpack.monitoring.ui.container.elasticsearch.enabled: true
--------------------------------------------------------------------------------------------------------------------------
Docker ekosisteminden logları toplayabilmek için filebeat konfigürasyon dosyası aşağıdaki gibidir.
filebeat-config.yml
--------------------------------------------------------------------------------------------------------------------------
filebeat.config:
modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
filebeat.autodiscover:
providers:
- type: docker
hints.enabled: true
hints.default_config.enabled: false
processors:
- add_cloud_metadata: ~
output.elasticsearch:
hosts: 'http://elasticsearch:9200'
setup.kibana:
host: 'http://kibana:5601'
setup.dashboards.enabled: true
logging.level: warning
logging.to_stderr: true
--------------------------------------------------------------------------------------------------------------------------
Konfigürasyon dosyalarındaki bazı kritik satırlara değinelim. Burada kibana.yml dosyasında "http://elasticsearch:9200" ifadesinde yer alan "elasticsearch" host adının oluşacak kibana konteynerinde nasıl çözümleneceği sorusu akıllara gelecektir. Aynı soru filebeat-config-yml dosyasında yer alan 'http://kibana:5601' ifadesi için de sorulabilir. Bu sorunu docker-compose dosyasında her servis için "alias" kullanarak çözeceğiz. Oluşturduğumuz her servise bir alias atayıp bu isimleri kullanarak servislerin kontrol ettiği konteynerlerin birbirlerini bulmalarını ve isim çözümlemesi yapmalarını sağlıyoruz. Örneğin kibana servisi için "kibana" alias'ı, elasticsearch servisi için "elasticsearh" alias'ı kullanılmaktadır. Alias kullanımı ile alakalı ayrıntılı bilgi için linke tıklayabilirsiniz. Devam edelim. filebeat-config.yml dosyasında provider'ın docker olduğunu belirttikten sonra docker sisteminde "hints.default_config.enabled: false" satırını yazarak yalnızca loglarını toplamak istediğimiz docker servislerin loglarını toplayacağız. Peki hangi docker servisinden log çekeceğimizi nasıl belirliyoruz? Bu noktada docker-swarm ekosisteminde çalışmakta olan konteynerlere label ekleyerek, filebeat docker servisinin bu konteynerleri bulmasını sağlayacağız. Fakat bu aşamada kritik olan şey loglarının toplanmasını istediğiniz docker servisler için labelları "docker service" labelı olarak değil, docker konteyner labelı kullanmalısınız!!! Nasıl yapılacağını aşağıda göstereceğiz. Konfigürasyon dosyalarını da hazırladıktan sonra son olarak ELK yı deploy etmek için docker-compose dosyamızı oluşturuyoruz.
elk.yml
--------------------------------------------------------------------------------------------------------------------------
#elasticstack application
version: "3.8"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
volumes:
- /mnt/docker-swarm/es/data/:/usr/share/elasticsearch/data
- /mnt/docker-swarm/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- 9200:9200
environment:
- discovery.type=single-node
deploy:
replicas: 1
placement:
constraints:
- "node.hostname==centos03"
networks:
base-network:
aliases:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana:7.6.2
deploy:
placement:
constraints:
- "node.hostname==centos02"
volumes:
- /mnt/docker-swarm/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
ports:
- 5601:5601
networks:
base-network:
aliases:
- kibana
filebeat:
image: docker.elastic.co/beats/filebeat:7.6.2
user: root
deploy:
mode: global
volumes:
- /mnt/docker-swarm/beats/filebeat/filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
base-network:
aliases:
- filebeat
networks:
base-network:
external: true
--------------------------------------------------------------------------------------------------------------------------
elk.yml dosyasına değinecek olur isek; daha önceden de belirttiğimiz gibi "uygulama stack"ini linkte bahsedilen altyapı üzerinde çalıştırıyoruz. Kaynakların verimli kullanılması açısından kibana ve elasticstack konteynerlerini farklı hostlarda ayağı kaldırıyoruz. kibana servisi 5601, elasticsearch servisi 9200 portlarını dış dünyaya duyurmaktadır. Verilerin ve konfigürasyonların kalıcı olabilmesi adına her servis için ayrı ayrı "bind" konfigürasyonu yapılmıştır. Ayrıca filebeat yazılımının; docker-swarm sistemini keşfedebilmesi için docker soketi filebeat servisine "read-only" olarak bind edilmiş, log dosyalarını okuyabilmesi için host üzerinde docker loglarının yer aldığı "/var/lib/docker/containers" dizini filebeat servisine bind edilmiş ve filebeat servisi deploy edilirken "mode: global" seçilerek tüm hostlarda konteyner oluşturması böylece tüm docker-swarm ekosisteminden logların çekebilmesi sağlanmıştır. Oluşturulan yml dosyası aşağıdaki komut ile docker-swarm üzerinde deploy edilir.
~# docker stack deploy -c elk.yml ELK
Docker üzerinde ELK birkaç dakika içerisinde ayağı kalkacaktır. Servislerin deploy edilme sürecini
"docker stack ps ELK" komutu ile görüntüleyebilirisiniz. ELK uygulamaları sorunsuz bir şekilde başlatıldığında "http://192.168.1.101:9200" adresinden elasticsearch api arayüzüne ve "http://192.168.1.102:5601" adresinden kibana web uygulaması arayüzüne erişebilir durumda olursunuz. Aşağıdaki şekilde kibana arayüzü gösterilmiştir.
Sıra mevcut durumda çalışan docker servislerinin loglarını toplamaya geldi. Bu noktada önceki yazılarda oluşturulan ve deploy edilen wordpress servis loglarının toplanmasını sağlayacağız. Bunun için konteyner labellarını kullanacağımızı daha önce belirtmiştik. Aşağıda wordpress uygulamasının deploy edildiği wordpress.yml dosyasında docker-swarm servisler için labelların nasıl oluşturulduğu gösterilmiştir. Eklenen alanlar kırmızı ile gösterilmiştir.
wordpress.yml
--------------------------------------------------------------------------------------------------------------------------
#wordpress application
version: "3.8"
services:
wordpress:
image: wordpress:latest
labels:
- "co.elastic.logs/enabled=true" #ELK'nın logları toplaması sağlar.
- "co.elastic.logs/module=apache" #Toplanan loglar için apache modulü aktif edilmiştir.
- "co.elastic.logs/fileset.stdout=access"
- "co.elastic.logs/fileset.stderr=error"
depends_on:
- db
volumes:
- /mnt/docker-swarm/wordpress/:/var/www/html/wp-content
deploy:
replicas: 3
labels:
- "traefik.enable=true"
- "traefik.docker.network=base-network"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.router-websecure.tls=true"
- "traefik.http.routers.router-websecure.entrypoints=websecure"
- "traefik.http.routers.router-websecure.rule=Host(`omer.com`)"
- "traefik.http.routers.router-web.entrypoints=web"
- "traefik.http.routers.router-web.rule=Host(`omer.com`)"
- "traefik.http.routers.router-web.middlewares=redirect-to-https"
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
- "traefik.http.services.wordpress.loadbalancer.sticky=true"
- "traefik.http.services.wordpress.loadbalancer.sticky.cookie.name=wp-elif"
- "traefik.http.services.wordpress.loadbalancer.healthcheck.port=80"
environment:
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_DB_USER=elif
- WORDPRESS_DB_PASSWORD=elif
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_TABLE_PREFIX=elif
networks:
base-network:
db:
image: mysql:5
labels:
- "co.elastic.logs/enabled=true"
- "co.elastic.logs/module=mysql"
- "co.elastic.logs/fileset.stdout=access"
- "co.elastic.logs/fileset.stderr=error"
deploy:
replicas: 1
placement:
constraints:
- "node.role==manager"
environment:
- MYSQL_ROOT_PASSWORD=elif
- MYSQL_ALLOW_EMPTY_PASSWORD=no
- MYSQL_USER=elif
- MYSQL_PASSWORD=elif
- MYSQL_DATABASE=wordpress
volumes:
- /mnt/docker-swarm/mysql:/var/lib/mysql
networks:
base-network:
loadbalancer:
image: traefik
labels:
- "co.elastic.logs/enabled=true"
- "co.elastic.logs/module=traefik"
- "co.elastic.logs/fileset.stdout=access"
- "co.elastic.logs/fileset.stderr=error"
ports:
- 80:80
- 8080:8080
- 3000:3000
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /home/centos/swarm-file/config.yml:/etc/traefik/traefik.yml
- /home/centos/swarm-file/config-dyn.yml:/etc/traefik/config-dyn.yml
#- /mnt/docker-swarm/logs:/var/log
- /mnt/docker-swarm/cert:/etc/ca-certificates
deploy:
resources:
restart_policy:
condition: any
mode: replicated
replicas: 1
update_config:
delay: 2s
placement:
constraints:
- "node.role == manager"
networks:
base-network:
networks:
base-network:
external: True
version: "3.8"
services:
wordpress:
image: wordpress:latest
labels:
- "co.elastic.logs/enabled=true" #ELK'nın logları toplaması sağlar.
- "co.elastic.logs/module=apache" #Toplanan loglar için apache modulü aktif edilmiştir.
- "co.elastic.logs/fileset.stdout=access"
- "co.elastic.logs/fileset.stderr=error"
depends_on:
- db
volumes:
- /mnt/docker-swarm/wordpress/:/var/www/html/wp-content
deploy:
replicas: 3
labels:
- "traefik.enable=true"
- "traefik.docker.network=base-network"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.router-websecure.tls=true"
- "traefik.http.routers.router-websecure.entrypoints=websecure"
- "traefik.http.routers.router-websecure.rule=Host(`omer.com`)"
- "traefik.http.routers.router-web.entrypoints=web"
- "traefik.http.routers.router-web.rule=Host(`omer.com`)"
- "traefik.http.routers.router-web.middlewares=redirect-to-https"
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
- "traefik.http.services.wordpress.loadbalancer.sticky=true"
- "traefik.http.services.wordpress.loadbalancer.sticky.cookie.name=wp-elif"
- "traefik.http.services.wordpress.loadbalancer.healthcheck.port=80"
environment:
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_DB_USER=elif
- WORDPRESS_DB_PASSWORD=elif
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_TABLE_PREFIX=elif
networks:
base-network:
db:
image: mysql:5
labels:
- "co.elastic.logs/enabled=true"
- "co.elastic.logs/module=mysql"
- "co.elastic.logs/fileset.stdout=access"
- "co.elastic.logs/fileset.stderr=error"
deploy:
replicas: 1
placement:
constraints:
- "node.role==manager"
environment:
- MYSQL_ROOT_PASSWORD=elif
- MYSQL_ALLOW_EMPTY_PASSWORD=no
- MYSQL_USER=elif
- MYSQL_PASSWORD=elif
- MYSQL_DATABASE=wordpress
volumes:
- /mnt/docker-swarm/mysql:/var/lib/mysql
networks:
base-network:
loadbalancer:
image: traefik
labels:
- "co.elastic.logs/enabled=true"
- "co.elastic.logs/module=traefik"
- "co.elastic.logs/fileset.stdout=access"
- "co.elastic.logs/fileset.stderr=error"
ports:
- 80:80
- 8080:8080
- 3000:3000
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /home/centos/swarm-file/config.yml:/etc/traefik/traefik.yml
- /home/centos/swarm-file/config-dyn.yml:/etc/traefik/config-dyn.yml
#- /mnt/docker-swarm/logs:/var/log
- /mnt/docker-swarm/cert:/etc/ca-certificates
deploy:
resources:
restart_policy:
condition: any
mode: replicated
replicas: 1
update_config:
delay: 2s
placement:
constraints:
- "node.role == manager"
networks:
base-network:
networks:
base-network:
external: True
--------------------------------------------------------------------------------------------------------------------------
Yukarıda eklenen labellar yml dosya hiyerarşisinde doğrudan servislerin altına eklenmiştir. (Docker servise labelları deploy kısmının altında tanımlanmaktadır.) Böylece servisin üreteceği her konteynerde bu labellar yer alacaktır ve bu sayede ELK bu konyetnerlerden log toplayabilecektir. Labellar ile elastic logları aktif edilmiş, log toplanan servisin türüne göre özel log formatlarının oluşması için ilgili modül seçilmiş, (örnekte apache, traefik, mysql modlülleri aktif edilmiştir.) seçilen modüllerde hangi tür logların işlem göreceği belirtilmiştir. Şimdi değişikliklerden sonra wordpress uygulamasını güncelliyoruz.
~#docker stack deploy -c wordpress.yml WORPRESS_APP
Yukarıdaki komut çalıştırıldıktan sonra docker-swarm daha önceden deploy edilmiş olan tüm wordpress uygulaması konteynerlerini belirtilen labelları ekleyerek yeniden oluşturacaktır. Labelların oluşup oluşmadığını önce konteylerleri listeleyip daha sonra konteynerleri "inspect" komutuyla inceleyerek görüntülenebilir.
~# docker ps
~#docker stack deploy -c wordpress.yml WORPRESS_APP
Yukarıdaki komut çalıştırıldıktan sonra docker-swarm daha önceden deploy edilmiş olan tüm wordpress uygulaması konteynerlerini belirtilen labelları ekleyerek yeniden oluşturacaktır. Labelların oluşup oluşmadığını önce konteylerleri listeleyip daha sonra konteynerleri "inspect" komutuyla inceleyerek görüntülenebilir.
~# docker ps
~# docker inspect --format '{{ range $k, $v := .Config.Labels -}}
{{ $k }}={{ $v }}
{{ end -}}' ba39dc156b64
{{ $k }}={{ $v }}
{{ end -}}' ba39dc156b64
Yukarıdaki komutlar ile wordpress konteynerinde (ba39dc156b64 idsine sahip) labelların oluştuğu gösterilmiştir. Şimdi wordpress uygulaması için logların toplanmaya başlatmış oluyoruz. Toplanan bu logları görebilmek için kibana arayüzünü açıyoruz ve management sekmesini seçiyoruz.
Açılan sayfada elasticsearch bölümünde index management bölümüne tıklnarak indislerin oluşup oluşmadığı kontrol edilir.
Yukarıdaki şekilde görüldüğü gibi "filebeat*" olarak indisleri görüyoruz. Şimdi bu indisleri kibanada "index pattern" oluşturmak için kullanacağız. İndex pattern oluşturmak için yapılması gerekenler aşağıdaki şekillerde gösterilmiştir.
Yukarıdaki şekilde görüldüğü gibi "filebeat*" olarak indisleri görüyoruz. Şimdi bu indisleri kibanada "index pattern" oluşturmak için kullanacağız. İndex pattern oluşturmak için yapılması gerekenler aşağıdaki şekillerde gösterilmiştir.
İndex pattern oluşturulmadan önce son adımda bazı filtreleri seçmenizi isteyecektir. Burada @timestamp seçip "create index pattern" diyerek işlemi tamamlıyoruz.
Bu son aşamadan sonra artık kibana üzerinde log bölümüne gelerek docker loglarını görüntüleyebilirsiniz.
Log kayıtlarını toplamaya başladıktan sonra kibana üzerinden logları istediğiniz gibi filtreleyip, isteğinizi log kaydını aratabilirsiniz. Kibana üzerinde "visualise" yani görseller oluşturup daha sonra bu görselleri bir araya getirerek "dashboarad" oluşturabilirsiniz. Böylece loglarınız grafiklere dönüştürerek anlaşılabilirliğini artırabilirsiniz. Bu konuya başka bir yazıda değinilecektir. Bir sonraki yazıda ise oluşturacağımız mimarinin diğer kısmını yani metricbeat ile metrik değerlerin toplanıp kibana üzerinden görselleştirilmesini anlatacağız. İyi çalışmalar.
Yararlanılan Kaynaklar:
[1] https://www.elastic.co/guide/index.html
[2] https://gist.github.com/steve-jansen/a90f942e05e326e817aaeb04dff3f4e6
[3] https://docs.docker.com/compose/compose-file/
Log kayıtlarını toplamaya başladıktan sonra kibana üzerinden logları istediğiniz gibi filtreleyip, isteğinizi log kaydını aratabilirsiniz. Kibana üzerinde "visualise" yani görseller oluşturup daha sonra bu görselleri bir araya getirerek "dashboarad" oluşturabilirsiniz. Böylece loglarınız grafiklere dönüştürerek anlaşılabilirliğini artırabilirsiniz. Bu konuya başka bir yazıda değinilecektir. Bir sonraki yazıda ise oluşturacağımız mimarinin diğer kısmını yani metricbeat ile metrik değerlerin toplanıp kibana üzerinden görselleştirilmesini anlatacağız. İyi çalışmalar.
Yararlanılan Kaynaklar:
[1] https://www.elastic.co/guide/index.html
[2] https://gist.github.com/steve-jansen/a90f942e05e326e817aaeb04dff3f4e6
[3] https://docs.docker.com/compose/compose-file/