ELK Stack 簡介
ELK 不是一款軟件,而是 Elasticsearch、Logstash 和 Kibana 三種軟件產品的首字母縮寫。這三者都是開源軟件,通常配合使用,而且又先后歸於 Elastic.co 公司名下,所以被簡稱為 ELK Stack。根據 Google Trend 的信息顯示,ELK Stack 已經成為目前最流行的集中式日志解決方案。
-
Elasticsearch:
分布式搜索和分析引擎,具有高可伸縮、高可靠和易管理等特點。基於 Apache Lucene 構建,能對大容量的數據進行接近實時的存儲、搜索和分析操作。通常被用作某些應用的基礎搜索引擎,使其具有復雜的搜索功能;
-
Logstash:
數據收集引擎。它支持動態的從各種數據源搜集數據,並對數據進行過濾、分析、豐富、統一格式等操作,然后存儲到用戶指定的位置;
-
Kibana:
數據分析和可視化平台。通常與 Elasticsearch 配合使用,對其中數據進行搜索、分析和以統計圖表的方式展示;
-
Filebeat:
ELK 協議棧的新成員,一個輕量級開源日志文件數據搜集器,基於 Logstash-Forwarder 源代碼開發,是對它的替代。在需要采集日志數據的 server 上安裝 Filebeat,並指定日志目錄或日志文件后,Filebeat 就能讀取數據,迅速發送到 Logstash 進行解析,亦或直接發送到 Elasticsearch 進行集中式存儲和分析。
ELK 常用架構及使用場景介紹
2.1、最簡單架構
在這種架構中,只有一個 Logstash、Elasticsearch 和 Kibana 實例。Logstash 通過輸入插件從多種數據源(比如日志文件、標准輸入 Stdin 等)獲取數據,再經過濾插件加工數據,然后經 Elasticsearch 輸出插件輸出到 Elasticsearch,通過 Kibana 展示。
這種架構非常簡單,使用場景也有限。初學者可以搭建這個架構,了解 ELK 如何工作。
2.2、Logstash 作為日志搜集器
這種架構是對上面架構的擴展,把一個 Logstash 數據搜集節點擴展到多個,分布於多台機器,將解析好的數據發送到 Elasticsearch server 進行存儲,最后在 Kibana 查詢、生成日志報表等。
這種結構因為需要在各個服務器上部署 Logstash,而它比較消耗 CPU 和內存資源,所以比較適合計算資源豐富的服務器,否則容易造成服務器性能下降,甚至可能導致無法正常工作。
2.3、Beats 作為日志搜集器
這種架構引入 Beats 作為日志搜集器。目前 Beats 包括四種:
- Packetbeat(搜集網絡流量數據);
- Topbeat(搜集系統、進程和文件系統級別的 CPU 和內存使用情況等數據);
- Filebeat(搜集文件數據);
- Winlogbeat(搜集 Windows 事件日志數據)。
Beats 將搜集到的數據發送到 Logstash,經 Logstash 解析、過濾后,將其發送到 Elasticsearch 存儲,並由 Kibana 呈現給用戶。
這種架構解決了 Logstash 在各服務器節點上占用系統資源高的問題。相比 Logstash,Beats 所占系統的 CPU 和內存幾乎可以忽略不計。另外,Beats 和 Logstash 之間支持 SSL/TLS 加密傳輸,客戶端和服務器雙向認證,保證了通信安全。
因此這種架構適合對數據安全性要求較高,同時各服務器性能比較敏感的場景。
2.4、引入消息隊列機制的架構
Beats 還不支持輸出到消息隊列,所以在消息隊列前后兩端只能是 Logstash 實例。這種架構使用 Logstash 從各個數據源搜集數據,然后經消息隊列輸出插件輸出到消息隊列中。目前 Logstash 支持 Kafka、Redis、RabbitMQ 等常見消息隊列。然后 Logstash 通過消息隊列輸入插件從隊列中獲取數據,分析過濾后經輸出插件發送到 Elasticsearch,最后通過 Kibana 展示。
這種架構適合於日志規模比較龐大的情況。但由於 Logstash 日志解析節點和 Elasticsearch 的負荷比較重,可將他們配置為集群模式,以分擔負荷。引入消息隊列,均衡了網絡傳輸,從而降低了網絡閉塞,尤其是丟失數據的可能性,但依然存在 Logstash 占用系統資源過多的問題。
基於 Filebeat 的 ELK 集群架構
Filebeat 實現 log rotation
通俗的說,log rotation 是指當日志文件達到指定大小后,把隨后的日志寫到新的日志文件中,原來的日志文件重命名,加上日志的起止時間,以實現日志歸檔的目的。
Filebeat 默認支持 log rotation,但需要注意的是,Filebeat 不支持使用 NAS 或掛載磁盤保存日志的情況。因為在 Linux 系列的操作系統中,Filebeat 使用文件的 inode 信息判斷當前文件是新文件還是舊文件。如果是 NAS 或掛載盤,同一個文件的 inode 信息會變化,導致 Filebeat 無法完整讀取 log。
雖然 Filebeat 默認支持 log rotation,但是有三個參數的設置需要留意。
registry_file:這個文件記錄了當前打開的所有 log 文件,以及每個文件的 inode、當前讀取位置等信息。當 Filebeat 拿到一個 log 文件,首先查找 registry_file,如果是舊文件,就從記錄的當前讀取位置處開始讀取;如果是新文件,則從開始位置讀取;
close_older:如果某個日志文件經過 close_older 時間后沒有修改操作,Filebeat 就關閉該文件的 handler。如果該值過長,則隨着時間推移,Filebeat 打開的文件數量很多,耗費系統內存;
scan_frequency:Filebeat 每隔 scan_frequency 時間讀取一次文件內容。對於關閉的文件,如果后續有更新,則經過 scan_frequency 時間后,Filebeat 將重新打開該文件,讀取新增加的內容。
Elasticsearch 集群
Elasticsearch 啟動時會根據配置文件中設置的集群名字(cluster.name)自動查找並加入集群。Elasctisearch 節點默認使用 9300 端口尋找集群,所以必須開啟這個端口。
一個 Elasticsearch 集群中一般擁有三種角色的節點,master、data 和 client。
- master:master 節點負責一些輕量級的集群操作,比如創建、刪除數據索引、跟蹤記錄集群中節點的狀態、決定數據分片(shards)在 data 節點之間的分布;
- data:data 節點上保存了數據分片。它負責數據相關操作,比如分片的 CRUD,以及搜索和整合操作。這些操作都比較消耗 CPU、內存和 I/O 資源;
- client:client 節點起到路由請求的作用,實際上可以看做負載均衡器。
配置文件中有兩個與集群相關的配置:
-
node.master:默認 true。True 表示該節點是 master 節點;
-
node.data:默認 true。True 表示該節點時 data 節點。如果兩個值都為 false,表示是 client 節點。
一個集群中不一定有 client 節點,但是肯定有 master 和 data 節點。默認第一個啟動的節點是 master。Master 節點也能起到路由請求和搜索結果整合的作用,所以在小規模的集群中,無需 client 節點。但是如果集群規模很大,則有必要設置專門的 client。
安裝配置ELK
本次使用 https://github.com/deviantony/docker-elk 開源項目,該項目維護了 ELK 技術棧最近的三個版本,也就是 7.x、6.x、5.x ,本文將使用最新版本。
1. 拉取項目
git clone https://github.com/deviantony/docker-elk.git /docker-elk
查看目錄結構
2. 啟動項目
文件較大,需要較長時間下載;容易超時,可重復執行,或自行上載相關文件。
docker-compose up -d
#默認情況下,Elasticsearch數據保留在卷內。為了完全關閉堆棧並刪除所有持久數據,使用以下命令
docker-compose down -v
開放防火牆端口
firewall-cmd --zone=public --add-port=9600/tcp --permanent
firewall-cmd --zone=public --add-port=9300/tcp --permanent
firewall-cmd --zone=public --add-port=5601/tcp --permanent
firewall-cmd --reload
部署成功后登錄127.0.0.1:9200
查看,默認賬號:elastic
,密碼:changeme
3. 重置內建用戶密碼(可選)
3.1 對服務默認的賬戶進行默認密碼重置,將生成的密碼保存好。
docker-compose exec -T elasticsearch bin/elasticsearch-setup-passwords auto --batch
3.2 將 docker-compose.yml
配置文件中的 elasticsearch 服務的 ELASTIC_PASSWORD
去掉,確保服務啟動后只使用剛剛重置后的密碼
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
#ELASTIC_PASSWORD: changeme
# Use single node discovery in order to disable production mode and avoid bootstrap checks.
# see: https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
discovery.type: single-node
networks:
3.3 對 kibana 、 logstash 配置文件中的elastic
賬戶密碼進行替換
-
kibana/config/kibana.yml
-
logstash/config/logstash.yml
-
logstash/pipeline/logstash.conf
需要注意的是, logstash pipeline 需要一個高權限賬號,當前測試開發過程中,可以使用上面重置后的 elastic 賬號和密碼,如果是生產使用可以參考官方文檔 Configuring Security in Logstash 進行操作,分配一個新的專用賬號。
3.4 在配置修改完畢后,執行 docker-compose restart
無報錯即修改成功。
4.配置logstash
vim logstash/logstash.conf
input {
beats {
port => 5044
}
tcp {
port => 5000
}
}
## Add your filters / logstash plugins configuration here
output {
elasticsearch {
hosts => "192.168.4.155:9200"
user => "elastic"
index => "logs-%{+YYYY.MM.dd}"
password => "changeme"
ecs_compatibility => disabled
}
}
4. kibana配置
- 修改中文界面
修改kibana.yml
文件,添加下面配置;
i18n.locale: "zh-CN"
Filebeat vs LogStash
Filebeat 是Elastic公司的一個輕量型日志采集器,它可以用來代替該公司旗下的 Logstash,也可以和 Logstash 配合一起使用。
Filebeat 和 LogStash 相比十分輕量,體積只有 30 多 M,占用的資源較低,安裝也比較簡單,可以在每個需要收集日志的服務器上部署運行。
Filebeat 將更多能力放在了數據收集上面,而 Logstash 更多的能力是體現在數據的過濾和轉換上。
Filebeat安裝
一、Docker安裝Filebeat
Docker 方式安裝,命令如下:
docker run -d --name=filebeat \
--user=root \
--volume="/data/filebeat/filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro" \
--volume="/var/lib/docker/containers:/var/lib/docker/containers:ro" \
--volume="/var/run/docker.sock:/var/run/docker.sock:ro" \
docker.elastic.co/beats/filebeat:7.10.0 filebeat -e -strict.perms=false
注意這里映射了 Filebeat 配置文件的路徑,同時映射了 Docker 容器的文件路徑。
也可以使用 Docker-compose 來啟動 Filebeat:
filebeat:
image: docker.elastic.co/beats/filebeat:7.10.1
user: root
command: filebeat -e -strict.perms=false
volumes:
- /data/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
restart: always
基於 Docker 的 Filebeat 配置
使用官方推薦的這個配置模板就夠了,對 Filebeat 的配置主要體現在具體的容器上,而不是 Filebeat 本身。
# 使用這個命令下載 filebeat 配置文件
curl -L -O https://raw.githubusercontent.com/elastic/beats/7.3/deploy/docker/filebeat.docker.yml
配置文件內容:
filebeat.config:
modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
filebeat.autodiscover:
providers:
- type: docker
hints.enabled: true
processors:
- add_cloud_metadata: ~
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/*.log
#輸出到logstash
output.logstash:
hosts: ['192.168.4.155:5044']
#output.elasticsearch:
# hosts: '${ELASTICSEARCH_HOSTS:elasticsearch:9200}'
# username: '${ELASTICSEARCH_USERNAME:}'
# password: '${ELASTICSEARCH_PASSWORD:}'
二、RPM方式安裝Filebeat
獲取RPM包
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.9.1-x86_64.rpm
rpm -ivh filebeat-7.9.1-x86_64.rpm
修改配置文件
有兩種方式傳輸log,以下兩種方式只能選其一;
- 使用Filebeat方式
vim /etc/filebeat/filebeat.yml
#修改path,enable
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/*.log
output.logstash:
#logstash主機ip以及yml配置文件配置的端口
hosts: ["192.168.4.151:5000"]
- 直接傳輸至Elasticsearch
vim /etc/filebeat/filebeat.yml
#修改path,enable
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/\*.log
setup.kibana:
host: "192.168.4.151:5601"
output.elasticsearch:
#Elasticsearch主機ip
hosts: ["192.168.4.151:9200"]
啟動 Filebeat
setup 命令加載 Kibana 儀表板。如果儀表板已設置,請省略此命令。
sudo filebeat setup
sudo service filebeat start
常見問題
Logstash 使用 grok 過濾
日志數據一般都是非結構化數據,而且包含很多不必要的信息,所以需要在 Logstash 中添加過濾插件對 Filebeat 發送的數據進行結構化處理。
使用 grok 正則匹配把那些看似毫無意義、非結構化的日志數據解析成可查詢的結構化數據,是目前 Logstash 解析過濾的最好方式。
Grok 的用戶不需要從頭開始寫正則。ELK github 上已經寫好了很多有用的模式,比如日期、郵箱地址、IP4/6、URL 等。具體查看 這里 。除此之外,還有 grok 正則表達式的 debug 工具 ,能方便快速檢驗所寫表達式是否正確。
Grok內置了120多種的正則表達式庫,地址:https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns。
grok 的配置實例。
filter {
grok {
match => {
"message" => [
"\[(?<Logtime>(%{MONTHNUM}/%{MONTHDAY}/%{YEAR})\s+%{TIME}\s+%{WORD})\]\s+%{BASE16NUM}\s+(?<LogSource>([\w|\S]+))\s+%{WORD:LogLevel}\s+(?<LogStr>[\w|\W]*)",
"\[(?<Logtime>(%{MONTHNUM}/%{MONTHDAY}/%{YEAR})\s+%{TIME}\s+%{WORD})\]\s+%{BASE16NUM}\s+%{WORD:LogLevel}\s+(?<LogStr>[\w|\W]*(\\n)+)"
]
}
remove_field => ["message"]
}
if "_grokparsefailure" in [tags] {
grok {
match => ["message", "(?<LogStr>[\w|\W]+)"]
remove_field => ["message"]
remove_tag => ["_grokparsefailure"]
add_field => {
LogSource => "-"
LogLevel => "-"
LogTime => "-"
}
}
}
}
第一個 grok 列了兩種正則表達式,如果第一種不匹配,則自動使用第二種。如果第二種也沒有匹配,則匹配失敗,log 數據中添加一個 "_grokparsefailure" 域,表明 grok 匹配失敗了。讀者可根據實際需求決定如何處理匹配失敗的數據。這里,對於匹配失敗的,將再匹配一次,並給沒有匹配上的域賦予默認值 "-",這樣使得日志數據格式統一,都含有 4 個域:Logtime、LogSource、LogLevel、LogTime,便於后續數據搜索和展示。
統一收集容器中其他路徑的日志
Filebeat 默認收集的是 Docker 容器啟動后輸出到docker logs
的日志,但有些服務除了這些日志外,還會把其他日志存放到容器的里面。比如egg.js
框架會把錯誤日志和一些 web 日志放到/root/logs/yourserver/
下面。那么要如何收集這些額外的日志呢S?
解決方法是把額外日志的路徑映射到 Docker 的輸出控制台,可以在 Dockerfile 里面這樣設置:
Dockerfile
# 將普通日志輸出到 stdout
RUN ln -sf /dev/stdout /root/logs/web-server/web-server-web.log
# 將錯誤日志輸出到 stderr
RUN ln -sf /dev/stderr /root/logs/web-server/common-error.log
這樣容器啟動后就會將容器里日志傳輸到控制台上,而 Filebeat 也就可以收集該日志了。
Filebeat 區分不同日志來源
還是上題中提到的場景,Filebeat 雖然能讀取不同的日志目錄,但是在 Logstash 這邊,或者是 Elasticsearch 這邊,怎么區分不同 application server 的日志數據呢?
解決方案:Filebeat 的配置項 fields 可以實現不同日志來源的區分。用法如下:
prospectors:
-
paths:
- /home/WLPLog/*.log
fields:
log_source: WLP
-
paths:
- /home/ApacheLog/*.log
fields:
log_source: Apache
在 fields 配置項中,用戶可以自定義域來標識不同的 log。比如上例中的”log_source”就是筆者自定義的。如此,從 Filebeat 輸出的 log 就有一個叫做 log_source 的域表明該 log 的實際來源。
解決多行日志問題
Filebeat 收集日志后將其存入到 Elasticsearch,默認的存儲規則是一行日志作為 Elasticsearch 的一條記錄,但像錯誤信息這種日志會出現多行的情況,如果同一個日志分成多行的話查看起來就不太方便,因為中間可能被其他日志打斷,而且搜索的時候也不能把同一個錯誤的日志一並查詢出來,所以最好的方式是能將同一個錯誤的多行日志存入 Elasticsearch 的同一條記錄。
Filebeat 考慮到了這種情況,讓可以通過添加容器便簽的方式來設置多行日志的整合規則,比如的每條日志都是以時間格式開始的:2019-01-01 11:11:11,1111 xxxx
,那么多行設置規則就可以這樣寫:
web-server-dev:
labels:
co.elastic.logs/multiline.pattern: '^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2},\d{3}\s'
co.elastic.logs/multiline.negate: true
co.elastic.logs/multiline.match: after
其中 pattern 表示日志內容如果不匹配這個正則表達式則不能作為新的一行日志,這樣日志就會按照時間進行分組了。
Kibana 建立對應服務的搜索
Filebeat 將日志存入到 Elasticsearch 后,就可以通過 Kibana 來查看日志了。在 Kibana 中創建以filebeat-*
開頭的索引,表示查詢以filebeat
開頭的索引,這是 Filebeat 導入日志的索引,每天會產生這樣的一個索引。
創建完索引后可以通過一些 Docker 的查詢條件來查詢日志,比如想查詢容器名為foo
的容器的日志,就可以用container.name=foo
這樣的過濾條件來查詢,如果想以鏡像名來查詢也可以,用image.name=xxx
的查詢條件就可以查詢出該鏡像的所有容器的日志。
展示字段一般只需要message
字段就可以了,也可以視情況添加container.name
或image.name
等字段。
配置 Logstash 與 Elasticsearch 集群通信
Logstash 使用 Elasticsearch 輸出插件就能把數據發送到 Elasticsearch 進行存儲和搜索。Elasticsearch 插件中有個 hosts 配置項說明 Elasticsearch 信息。但是假如是一個 Elasticsearch 集群,應該怎么配置 hosts?
解決方案:
最簡單的做法是把集群中所有的 Elasticsearch 節點的 IP 或者是 hostname 信息都在 hosts 中配上(它支持數組)。但是如果集群比較大,或者是集群節點變動頻繁的話,還需要維護這個 hosts 值,不太方便。比較推薦的做法是只配集群中某個節點的信息,可以是 client 節點,也可以是 master 節點或者是 data 節點。因為不管是哪個節點,都知道該它所在集群的信息(集群規模,各節點角色)。這樣,Logstash 與任意節點通信時都會先拿到集群信息,然后再決定應該給哪個節點發送數據輸出請求。
參考
https://soulteary.com/2020/05/04/use-docker-to-build-elk-environment.html
https://developer.ibm.com/zh/articles/os-cn-elk-filebeat/
http://zhaozhiming.github.io/blog/2019/09/14/use-filebeat-to-collect-docker-container-log/
https://leisurexi.github.io/category/2020/04/26/ELK/Docker 搭建ELK集群步驟.html