Logstash + Filebeat
1. 概述
神策分析支援使用 Logstash + Filebeat 的方式將 後端數據即時 匯入神策分析。
Logstash 是由 Elastic 公司推出的一款開源的伺服器端數據處理管道,能夠同時從多個來源採集數據,轉換數據,然後將數據傳送指定的儲存庫中。 Logstash 官方介紹。
Filebeat 是 Elastic 公司為解決 Logstash "太重" 的問題推出的一款輕量級 log 採集器,在處理數量眾多的伺服器、虛擬機和容器產生的 log 時可使用 Logstash + Filebeat 的 log 採集方式。 Filebeat 官方介紹。
基於 Logstash + Filbeat 的數據採集流程為:後端 SDK 產生數據檔案 => Filebeat 讀取檔案 => Logstash Beat input => Logstash sensors_analytic output => 神策分析 。
結構如下圖所示:
本文將介紹以下三個場景中如何使用 Logstash + Filebeat 完成數據採集並傳送至神策分析。
- 伺服器場景下的數據採集。
- Logstash + Filebeat #使用 Docker 容器化場景下的數據採集。
- Logstash + Filebeat #使用 K8s(Kubernetes)自動编排容器場景下的數據採集。
在閱讀詳細方案前,請先閱讀 Logstash 和 Filebeat 的使用說明與 版本支援資訊。
2. Logstash 使用说明
無論使用哪種方案 Logstash 都必須裝有 sensors_analytics_output 外掛程式。
請使用 Logstash-6.x 以上版本。
2.1. Logstash 下載與安裝
請参考 installing Logstash 官方說明文件 ,選擇您喜歡的下載與安裝方式。
2.2. 安裝 logstash-output-sensors_analytics 外掛程式
該外掛程式將檢查數據是否為 Json 格式,並加入一些神策需要的欄位值如 lib、data 等,打包數據,壓縮並經過 base64 之後傳送至神策的數據接收網址。
外掛程式已經發布至 Ruby 官方資料庫,Github repository : logstash-output-sensors_analytics 。直接在 Logstash 目錄下執行安裝即可,安裝需要一段時间,請耐心等待。
bin/logstash-plugin install logstash-output-sensors_analytics
在安裝完成後執行 :
bin/logstash-plugin list
看見新安裝的外掛程式 logstash-output-sensors_analytics 證明安裝成功。
外掛程式在使用時直接設定在 output 裡即可
output{
sensors_analytics {
url => "https://example.sensorsdata.cn/sa"
}
}
sensors_analytics 參數說明:
參數名 | 型別 | 必須 | 說明 |
---|---|---|---|
url | list | 是 | 神策分析的數據接收網址,完整的 url 網址並以 sa 結尾,有埠號需要加上埠號。例如 :https://example.sensorsdata.cn:8106/sa 。可同時設定多個數據接收網址,一條數據實際傳到哪個數據接收網址,是由輸入外掛程式中部分元數據資訊 hash 後決定。在使用 Filebeat 時預設使用 Filebeat 當時的 hostname + filename進行 hash 後選擇數據接收網址。 |
project | string | 否 | 專案名,不寫預設為 default ,設定後會覆蓋事件中和 url 中指定的 project。優先級為:project 參數設定 > 事件中指定 > url 中指定。 |
flush_interval_sec | number | 否 | 觸發 flush 間隔的時間(單位:秒),預設值為 2。 |
flush_batch_size | number | 否 | 觸發批量傳送的最大 record 數量,預設值為 100 。 |
hash_filed | list | 否 | 用於 hash 選擇數據接收網址的 filed,層級關係與輸入的 logstash.event 結構相同,可在 output 中使用 stdout 觀察。 |
enable_filebeat_status_report | boolean | 否 | 預設開啟,在 log 展示中一分鐘內活動的 Filebeat 讀取狀態。 |
2.3. Logstash 設定
2.3.1. Logstash Pipeline 設定
Logstash 支援同時執行多個 Pipeline ,各個 Pipeline 之間互不影響,擁有各自獨立的輸入輸出設定,Pipeline 的設定檔案位於 config/pipelines.yml 。如果您目前正在使用 Logstash 完成一些其他的 log 採集工作,可以在原有的 Logstash 上新增一條 Pipeline 專門負責收集神策的 log 數據,並傳送至神策分析。
- pipelines.yml 参考範例:
# 原來使用的 Pipeline 設定
- pipeline.id: elastic-output
pipeline.workers: 4
path.config: "/home/app/logstash/elastic_output.config"
# 新增的 sensorsdata 的管道設定
- pipeline.id: sensorsdata-output
# 使用不同的 Logstash 設定
pipeline.workers: 1
queue.type: persisted
# 使用不同的輸入輸出設定
path.config: "/home/app/logstash/beat_sa_output.config"
注意:神策分析 log 的輸入要不同於其他匯入到 Logstash 的 Piplines 輸入。比如之前使用的 log 匯入方式是透過 Filebeat 採集並傳送到 Logstash 的 5044 Port,那麼負責採集神策 log 的 Filebeat 可以將數據傳送至 5055 Port,從而能夠應用 id = sensorsdata-output 的管道。
更多 Pipeline 資訊請參考 : Multiple-Pipelines 官方說明文件。
2.3.2. Logstash 輸入輸出設定
設定中主要包含 input、filter 和 output 三部分,Logstash 處理神策的 log 數據只需設定 input 和 output 即可
- beat_sa_output.conf 参考範例:
# 使用 beats 作為輸入
input {
beats {
port => "5044"
}
}
# 使用 sensors_analytics 作為輸出
output{
sensors_analytics {
url => "https://example.sensorsdata.cn/sa"
}
}
提醒:在使用 logstash-file-input-plugin 時當 logstash 處於關閉狀態下時重命名已讀檔案(重命名後依然符合 pattern),啟動後會導致重複讀取。
2.3.3. Logstash 執行設定
Logstash 預設使用 config/logstash.yml 作為執行設定。
這裡需要注意的是:
1. 在需要確保數據匯入順序的情況下請更改設定 pipeline.workers 的值為 1。設定項 pipeline.workers 的值預設為 cpu 的核心數,當 workers 的值大於 1 時,會導致處理數據的順序發生變化。
2. 為確保數據的傳輸不會因為程式的意外終止而遺失,請設定 queue.type: persisted,該設定為 Logstash 使用的緩衝佇列類型,這樣設定可在重啟 Logstash 後繼續傳送緩衝佇列中的數據。 queue.type 的預設值為 memory (基於記憶體的)。
3. 建議設定 queue.drain 的值為 true ,該設定項會使 Logstash 在正常退出之前將所有緩衝佇列中的數據全部傳送完畢。
更多 logstash.yml 資訊請參考 : logstash.yml 官方說明文件 。
2.4. Logstash 啟動
- 直接啟動,會使用 config/pipelines.yml 作為 Pipeline 設定和執行設定。
bin/logstash
- 指定 ~/logstash/beat_sa_output.conf 為輸入輸出設定檔案啟動 ,會使用 config/logstash.yml 做為執行設定。
bin/logstash -f ~/logstash/beat_sa_output.conf
- 透過命令參數指定輸入輸出啟動,會使用 config/logstash.yml 作為執行設定。
bin/logstash -e 'output { sensors_analytics { url => "https://example.sensorsdata.cn/sa" }}'
更多啟動相關資訊請參考 : Getting Started with Logstash 官方說明文件。
2.5. Logstash 進度
Logstash 在使用Filebeat 作為輸入時檔案的讀取進度是由Filebeat 進行控制的,當使用其他的輸入方式時,例如Logstash 讀取檔案,消費Kafka 等,數據的讀取進度存放在Logstash 目錄 data/plugins 下,基於硬碟的數據緩衝佇列存放在 data/queue 中。可在 logstash.yml 中設定 path.data 來指定 Logstash 啟動時使用的 data/ 目錄的位置。
2.6. sensors-output-plugin 升级與 復原
- 已安裝外掛程式升級至最新版本
bin/logstash-plugin update logstash-output-sensors_analytics
- 安裝指定版本的外掛程式
# v0.1.0
bin/logstash-plugin install --version 0.1.0 logstash-output-sensors_analytics
# v1.1.2
bin/logstash-plugin install --version 0.1.2 logstash-output-sensors_analytics
- 移除外掛程式
bin/logstash-plugin remove logstash-output-sensors_analytics
3. Filebeat 使用说明
3.1. Filebeat 下载與安裝
請參考:Install Filebeat 官方說明文件 。選擇您喜歡的下載與安裝方式。
3.2. Filebeat 設定
使用 Filebeat 讀取後端 SDK 產生的埋點紀錄檔。Filebeat 預設設定檔案為:filebeat.yml 。修改設定檔案請使用 log 類型作為 Filebeat 的輸入,paths 指定數據檔案所在的位置,使用萬用字元 `*` 匹配後端 SDK 輸出的檔案名路徑。
- Filebeat 的輸入輸出設定 `filebeat.yml` 参考範例:
# Filebeat 收集 /var/logs/ 目錄下所有以 service_log. 開頭的數據檔案
filebeat.shutdown_timeout: 5s
filebeat.inputs:
- type: log
paths:
- /var/logs/service_log.*
# 將數據傳送網址為 10.42.32.70:5044 或 10.42.50.1:5044 的 logstash
output.logstash:
hosts: ["10.42.32.70:5044","10.42.50.1:5044"]
需要注意的是:
- 匯入的數據必須是神策的數據格式。
- 在需要確保匯入順序的情況下不要額外設定 loadbalance : true ,當設定了多個 Logstash hosts 作為數據接收端時該設定會使用輪詢的方式將數據傳送至所有的Logstash 這很可能導致數據的順序被打亂。 Filebeat 的預設設定為 loadbalance : false 。
- Filebeat 的檔案讀取進度存放在 data/registry 目錄下,在啟動時用於恢復進度。
- 在 Filebeat 執行時間,避免使用 vim 之類的可能產生檔案副本的編輯器編輯檔案,Filebeat 會讀取目錄中臨時產生的檔案。
- 建議新增設定項 filebeat.shutdown_timeout: 5s ,filebeat 在退出時有可能造成少量數據重複。
更多設定相關資訊請參考:Filebeat 官方文件。
3.3. 啟動 Filebeat
./filebeat -e -c filebeat.yml
-c 用於指定 filebeat.yml 設定檔案的位置,-e 可在終端上顯示 Filebeat 的 log 資訊。
3.4. Filebeat 進度
如果你的目錄下有多個檔案未被讀取,filebeat 會同時讀取多個檔案,檔案的讀取進度存放在 Filebeat 目錄下 data/registry 中,重啟 Filebeat 時會根據進度繼續執行傳送。
4. 伺服器場景下的數據採集
如果您產生 log 的後端應用直接部署在伺服器上,本節內容將介紹如何使用 Filebeat + Logstash 採集產生的 log 數據。該場景下也可使用 LogAgent 完成 log 的收集工作。
4.1. 部署 Logstash
如果您已經在使用 Logstash 做一些其他的 log 收集工作請參考 Logstash + Filebeat #Logstash 設定 。
参考 Logstash + Filebeat #Logstash 使用說明 直接在您的一台或多台伺服器上部署 Logstash 。
- Logstash 輸入輸出設定 logstash.conf 範例:
# 使用 beats 作為輸入
input {
beats {
port => "5044"
}
}
# 使用 sensors_analytics 作為輸出
output{
sensors_analytics {
url => "https://example.sensorsdata.cn/sa"
}
}
- Logstash 執行設定 logstash.yml 範例:
pipeline.workers: 1
queue.type: persisted
queue.drain: true
- 啟動 Logstash 應用 logstash.conf ,更多啟動方式請參考 Logstash + Filebeat #Logstash 啟動 和 Logstash 官方文件。
bin/logstash -f logstash.conf
4.2. 部署 Filebeat
在會產生埋點 log 的伺服器上部署 Filebeat 採集指定目錄下的 log 傳送至神策分析。
神策分析各後端語言的 SDK 都支援將數據寫入檔案,例如使用 Java SDK 的 ConcurrentLoggingConsumer,PHP SDK 的 FileConsumer,Python SDK 的 LoggingConsumer 它們能將 log 檔寫入指定的目錄下。
- 以 Java SDK 為例:
// 使用 ConcurrentLoggingConsumer 初始化 SensorsAnalytics
// 將數據輸出到 /data/sa_log 下的 service_log 開頭的檔案中,每天一個檔案
final SensorsAnalytics sa = new SensorsAnalytics(
new SensorsAnalytics.ConcurrentLoggingConsumer("/data/sa_log/service_log"));
// 使用神策分析記錄用戶行為數據
sa.track(distinctId, true, "UserLogin");
sa.track(distinctId, true, "ViewProduct");
// 程式結束前,停止神策分析 SDK 所有服務
sa.shutdown();
以上設定將在 /data/sa_log 目錄下產生數據檔案,一天一個檔案,檔案列表如:
service_log.20170923
service_log.20170924
service_log.20170925
Filebeat 透過設定 filebeat.yml 讀取目錄 /data/sa_log 下的以 service_log. 開頭的 log 檔,傳送至部署好的 Logstash 。
- filebeat.yml 參考範例:
# Filebeat 收集 /data/sa_log 目錄下所有以 service_log. 開頭的數據檔案
filebeat.inputs:
- type: log
paths:
- /data/sa_log/service_log.*
# 將數據傳送至網址為 10.42.32.70:5044 或 10.42.50.1:5044 的 Logstash
output.logstash:
hosts: ["10.42.32.70:5044","10.42.50.1:5044"]
當在一台伺服器上有多個產生 log 的目錄時可設定 Filebeat 同時讀取多個目錄。
- 讀取多目錄 filebeat.yml 參考範例:
filebeat.inputs:
- type: log
paths:
# 收集 /data/sa_log 目錄下所有以 service_log. 開頭的數據檔案
- /data/sa_log/service_log.*
# 收集 /another/logs/ 目錄下所有以 sdk_log. 開頭的數據檔案
- /another/logs/sdk_log.*
# 將數據傳送至網址為 10.42.32.70:5044 或 10.42.50.1:5044 的 Logstash
output.logstash:
hosts: ["10.42.32.70:5044","10.42.50.1:5044"]
- 後台啟動 Filebeat
nohup ./filebeat -c filebeat.yml > /dev/null 2>&1 &
5. 使用 Docker 容器化場景下的數據採集
5.1. 部署 Logstash
為確保 Logstash 的穩定工作,建議直接部署 Logstash,下文為 docker 部署方式僅供參考
如果您已經在使用 Logstash 做一些其他的 log 收集工作請參考 Logstash + Filebeat #Logstash 設定 。為避免容器意外關閉導致遺失數據,請設法保存緩衝區內的數據。
首先,取得一個具有 sensors_analytics output 外掛程式的 Logstash 鏡像
方式一:直接下載我們已經安裝好的外掛程式的 Logstash (7.2.0 版本) 鏡像。
docker pull sensorsdata/logstash:7.2.0
方式二:自行製作帶有 sensors_analytics output 外掛程式的 Logstash 鏡像。
- Dockerfile 範例:
FROM docker.elastic.co/logstash/logstash:7.2.0
RUN /usr/share/logstash/bin/logstash-plugin install logstash-output-sensors_analytics
準備需要的設定檔案。
- Logstash 的輸入輸出設定 logstash.conf 示範:
input {
beats {
port => "5044"
}
}
output {
sensors_analytics{
url => "http://10.42.34.189:8106/sa?project=default"
project => "default"
}
}
- Logstash 的執行設定 logstash.yml 示範:
pipeline.workers: 1
queue.type: persisted
queue.drain: true
由於 Logstash 需要使用硬碟做緩衝佇列,這裡我們建立一個 Volume 專門用於保存 Logstash 的進度和緩衝佇列,當重啟該 Logstash 容器時請重複使用該 Volume 。
docker volume create logstash-data
在啟動該容器時掛載設定檔案和存放緩存佇列的數據卷。
- 啟動命令參考範例:
docker run -d -p 5044:5044 --name logstash \
--mount source=logstash-data,target=/usr/share/logstash/data \
-v ~/local/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf \
-v ~/local/logstash/logstash.yml:/usr/share/logstash/config/logstash.yml \ sensorsdata/logstash:7.2.0
5.2. 部署 Filebeat
5.2.1. 方案一:在 SDK 容器中安裝 Filebeat 採集 log 並傳送至 Logstash(推薦)
在您能夠產生埋點記錄檔的容器上安裝一個Filebeat 採集 log 並傳送至部署好的 Logstash,Filebeat 為一款輕量級的 log 採集器,運作記憶體大概10 MB 左右,並不會給您的工作容器帶來太多的負擔。
- 優點:部署方便,不用擔心 Filebeat 的進度問題。
- 缺點:侵入了原有的 SDK 容器。
下面以 JavaSDK 作為工作容器舉例:
- Dockerfile 示範:
FROM centos
ADD jdk-8u211-linux-x64.tar.gz /usr/local/
ENV JAVA_HOME /usr/local/jdk1.8.0_211
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
COPY javasdk.jar /home
# 在容器中安裝一個 Filebaet
ADD filebeat-7.2.0-linux-x86_64.tar.gz /home
# 一份預設的設定檔案
COPY filebeat.yml /etc
COPY run.sh /home
WORKDIR /home
# 在 run.sh 中啟動 SDK 程式和 Filebeat 程式
CMD ["/bin/bash","-e","run.sh"]
- run.sh 中的内容:
#!/bin/bash
nohup java -jar javasdk.jar > /dev/null 2>&1 &
nohup filebeat-7.2.0-linux-x86_64/filebeat -c /etc/filebeat.yml > /dev/null 2>&1 &
while [[ true ]]; do
sleep 10000
done
在容器中要確保 SDK 的 log 寫入路徑與 Filebeat 的 log 讀取路徑相同。
- 以 Java SDK 為例:
// 使用 ConcurrentLoggingConsumer 初始化 SensorsAnalytics
// 將數據輸出到 /data/sa_log 下的 service_log 開頭的檔案中,每天一個檔案
final SensorsAnalytics sa = new SensorsAnalytics(
new SensorsAnalytics.ConcurrentLoggingConsumer("/data/sa_log/service_log"));
// 使用神策分析記錄用戶行為數據
sa.track(distinctId, true, "UserLogin");
sa.track(distinctId, true, "ViewProduct");
// 程式結束前,停止神策分析 SDK 所有服務
sa.shutdown();
- Filebeat 設定範例:
# Filebeat 收集 /data/sa_log 目錄下所有以 service_log. 開頭的數據檔案
filebeat.inputs:
- type: log
paths:
- /data/sa_log/service_log.*
# 將數據傳送至網址為 10.42.32.70:5044 或 10.42.50.1:5044 的 Logstash
output.logstash:
hosts: ["10.42.32.70:5044","10.42.50.1:5044"]
- 啟動命令參考範例:
docker run -d --name sdk-beat \
-v ~/local/filebeat/filebeat.yml:/filebeat.yml \
sdk-beat
5.2.2. 方案二:SDK 使用共享數據保存 log Filebeat 進行讀取
後端 SDK 和 Filebeat 分別運作在不同的容器上,SDK 將產生的 log 存放在數據卷上,Filebeat 從數據卷內讀取數據傳送至部署好的 Logstash 。
- 優點:不会侵入原有的 SDK 容器。
- 缺點:使用起來比較麻煩。
首先,建立一個數據卷選擇您喜歡的儲存方式,下面以本地硬碟為例,要確保你的容器對該數據卷有寫權限:
docker volume create sa-log
啟動後端 SDK 容器,將產生 log 目錄掛載到數據卷上。
docker run -d --name sdk \
--mount source=sa-logs,target=/your/logs/path \
your-sdk-image
啟動 Filebeat 容器,將日誌讀取目錄掛載到數據卷上。同時將存放檔案讀取進度的目錄也掛載到數據卷上,以每一個數據卷為一個讀取進度,當重啟 Filebeat 時重複使用該進度即可繼續執行傳送。
- 設定檔案 filebeat.yml 範例:
filebeat.inputs:
- type: log
paths:
- /usr/share/filebeat/input/service_log.*
# 將數據傳送至網址為 10.42.32.70:5044 或 10.42.50.1:5044 的 Logstash
output.logstash:
hosts: ["10.42.32.70:5044","10.42.50.1:5044"]
將讀取目錄和進度目錄同時掛載到數據卷上。
docker run -d --name filebeat \
--mount source=sa-logs,target=/usr/share/filebeat/input \
--mount source=sa-logs,target=/usr/share/filebeat/data/ \
-v ~/docker_workspace/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml \
docker.elastic.co/beats/filebeat:7.2.0
如果想用多個 SDK 容器掛載同一個數據卷的,建議容器以環境變數 HOSTNAME 為路徑名存放 log 檔,再將上級目錄掛載到數據卷上。
- 舉個例子:
容器內 log 的輸出路徑:/mount/${HOSTNAEM}-logs/service_log.20190708
將容器中的 /mount 目錄掛載至 Volume 。
因此 Volume 中日誌的目錄的存放格式為:
|-- Volume
| |-- c1369239e7ba-logs
| |-- fcdfdb3bdb2b-logs
| | |-- service_logs.20190702
| | |-- service_logs.20190703
| |-- da86e6ba6ca1-logs
| | |-- service_logs.20190701
| | |-- service_logs.20190702
| | |-- service_logs.20190703
更改 Filebeat 的檔案讀取路徑為:
filebeat.inputs:
- type: log
paths:
- /usr/share/filebeat/input/*/service_log.*
以 Java SDK 為例產生帶有 HOSTNAME 的路徑存放 log:
// 取得 HOSTNAME
String hostname = System.getenv("HOSTNAME");
File logPath = new File("/mount/" + hostname + "-logs/");
if (!logPath.exists()) {
logPath.mkdirs();
}
// 使用 ConcurrentLoggingConsumer 初始化 SensorsAnalytics
// 將數據輸出到 /mount/${HOSTNAME}-logs/ 目錄下以 service_log 為開頭保存,運作容器時將 /mount 目錄掛載到宿主機器上
final SensorsAnalytics sa = new SensorsAnalytics(
new SensorsAnalytics.ConcurrentLoggingConsumer(logPath.getAbsolutePath() + "/service_log"));
// 使用神策分析記錄用戶行為數據
sa.track(distinctId, true, "ViewProduct");
// 程式結束前,停止神策分析 SDK 所有服務
sa.shutdown();
如果您不希望更改原容器的 log 路徑存放方式,可以在容器啟動時建立一條軟連指向 log 目錄,將軟連掛載到 Volume 上。
rm -rf /your/logs/path \
&& mkdir -p /mount/${HOSTNAME}_logs \
&& ln -s /mount/${HOSTNAME}_logs /your/logs/path \
&& bin/sdk start
在啟動容器時將 /mount 掛載到 Volume 中。
docker run -d --name sdk \
--mount source=sa-logs,target=/mount \
your-sdk-image
6. 使用 K8s(Kubernetes)自動編排容器場景下的數據採集
6.1. Logstash 部署
為確保 Logstash 的穩定工作,建議直接部署 Logstash 在伺服器上,下文為 K8s 的部署方式供參考。
如果您已經在使用 Logstash 做一些其他的 log 收集工作請參考 Logstash + Filebeat#Logstash 設定。為避免容器意外關閉導致遺失數據,請設法保存緩衝區內的數據。
註冊一份 Logstash 設定檔案,使用 Filebeat 作為輸入,sensors_analytics 作為輸出,並指定運作設定。
- 設定檔案 logstash-conf.yaml 參考範例:
apiVersion: v1
kind: ConfigMap
metadata:
name: logstash-set
labels:
sa-app: logstash
data:
logstash.yml: |-
http.host: 0.0.0.0
pipeline.workers: 1
queue.type: persisted
# 用於限制緩衝佇列的大小預設值為 1024MB ,該數值在設定時應該小於 Pod 使用的儲存卷大小。
queue.max_bytes: 900mb
queue.drain: true
---
apiVersion: v1
kind: ConfigMap
metadata:
name: logstash-pipe-conf
labels:
sa-app: logstash
data:
logstash.conf: |-
input {
beats {
port => "5044"
}
}
output {
sensors_analytics {
url => "http://10.42.34.189:8106/sa?project=default"
}
}
為了不遺失數據,使用了基於硬碟的數據緩衝佇列 (queue.type: persisted),所以需要在容器外保存 Logstash 的進度資訊,這樣在重啟 Logstash 的時候可以繼續完成傳送。
建議透過 StatefulSet 的方式進行部署從而保存 Logstash 的狀態。
首先,建立一個 StorageClass 用於產生保存進度的 PV ,設定手動回收,下面以 NFS 為例。
- logstash-sc.yaml 的参考範例如下:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: logstash-nfs-storage
provisioner: nfs-provisioner
reclaimPolicy: Retain
然後,建立一個 StatefulSet
應用 logstash-nfs-storage ,透過 Headless Service
來為每個 Logstash Pod
提供網絡連接方式。
logstash-sts.yaml 参考範例如下:
apiVersion: v1
kind: Service
metadata:
name: logstash
labels:
app: logstash
spec:
ports:
- port: 5044
name: beat-in
clusterIP: None
selector:
app: logstash
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: logstash
spec:
# 使用上面的 Headless Service
serviceName: "logstash"
selector:
matchLabels:
app: logstash
replicas: 3
template:
metadata:
labels:
app: logstash
spec:
containers:
- name: logstash
image: sensorsdata/logstash:7.2.0
ports:
- containerPort: 5044
name: beat-in
volumeMounts:
- name: logstash-pipe-conf
mountPath: /usr/share/logstash/pipeline/logstash.conf
subPath: logstash.conf
- name: logstash-set
mountPath: /usr/share/logstash/config/logstash.yml
subPath: logstash.yml
# 容器中 /usr/share/logstash/data 目錄下保存著緩衝佇列 ,與進度資訊。
- name: ldata
mountPath: /usr/share/logstash/data
volumes:
- name: logstash-pipe-conf
configMap:
name: logstash-pipe-conf
- name: logstash-set
configMap:
name: logstash-set
volumeClaimTemplates: # Logstash 進度數據使用的 PVC 模板
- metadata:
name: ldata
spec:
accessModes: [ "ReadWriteOnce" ]
# 使用的儲存類名稱,需要提前建立。
storageClassName: "logstash-nfs-storage"
resources:
requests:
# 大小要高於緩衝佇列的最大長度限制
storage: 1Gi
StatefulSet 建立完成後 Pod name 的產生規則為 StatefulSetName - Pod - 序號。
上面的設定檔案會產生 logstash-0、logstash-1,logstash-2 這樣命名的 Pod。 Pod 副本也是按照序號 0 到 N-1 的順序依次進行建立的,在刪除時是按照序號 N-1 到 0 依次刪除。
Headless Service 為控制的每個 Pod 副本建立了一個DNS 域名,完整的域名規則為:(pod name).(headless server name).namespace.svc.cluster.local,因此 Filebeat 是透過網域來尋找Logstash 的,而不是IP 。當使用預設的 namespace 時可省略 namespace.svc.cluster.local 。
StatefulSet 根據 volumeClaimTemplates,為每個 Pod 建立一個 PVC,PVC 的命名字首為:namespace-volumeMounts.name - volumeClaimTemplates.name - pod_name,刪除一個 Pod 副本不會刪除 PVC ,在重啟後新的 Pod 會重複使用之前 PVC 中的進度繼續完成傳送。
建立完成後檢查一下運作的情況:
kubectl get pods -l app=logstash
NAME READY STATUS RESTARTS AGE
logstash-0 1/1 Running 0 3h56m
logstash-1 1/1 Running 0 3h56m
logstash-2 1/1 Running 0 3h56m
查看一下數據卷的建立情況:
kubectl get pvc -l app=logstash
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
ldata-logstash-0 Bound pvc-c1833d35-d2ee-49a5-ae16-3a9d3227ebe5 1Gi RWO logstash-nfs-storage 3h56m
ldata-logstash-1 Bound pvc-9aa4b50c-45f7-4b64-9e4d-056838906675 1Gi RWO logstash-nfs-storage 3h56m
ldata-logstash-2 Bound pvc-95bcdbf0-e84d-4068-9967-3c69c731311b 1Gi RWO logstash-nfs-storage 3h56m
檢查一下叢集內部的 DNS 建立情況:
for i in 0 1; do kubectl exec logstash-$i -- sh -c 'hostname'; done
logstash-0
logstash-1
logstash-2
kubectl run -i --tty --image busybox:1.28.3 dns-test --restart=Never --rm /bin/sh
nslookup logstash-0.logstash
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: logstash-0.logstash
Address 1: 10.244.7.54 logstash-0.logstash.default.svc.cluster.local
nslookup logstash-1.logstash
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: logstash-1.logstash
Address 1: 10.244.5.150 logstash-1.logstash.default.svc.cluster.local
nslookup logstash-2.logstash
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: logstash-2.logstash
Address 1: 10.244.34.177 logstash-2.logstash.default.svc.cluster.local
- Logstash 的擴容/縮容
StatefulSet 的更新策略也是有順序的。
將之前設定的 StatefulSet 容量從 3 變成 5 。
kubectl scale sts web --replicas=5
kubectl get pods -l app=logstash
NAME READY STATUS RESTARTS AGE
logstash-0 1/1 Running 0 6h1m
logstash-1 1/1 Running 0 6h1m
logstash-2 1/1 Running 0 6h1m
logstash-3 1/1 Running 0 1h3m
logstash-4 1/1 Running 0 1h3m
新增的 Pod 在原有的基礎上序號遞增。
將 StatefulSet 容量從 5 變回 3 。
kubectl scale sts web --replicas=3
之前新增的 PVC 不會被刪除,當下次達到該容量時會繼續重複使用。不用擔心有 Filebeat 會向被刪除的 Logstash 傳送數據,Filebeat 會自行尋找另一個運行正常的 Logstash。
由於設定了 queue.drain: true 所以撤除的 Logstash 在關閉前會將緩衝區內的數據傳送完畢。
6.2. 部署 Filebeat
6.2.1. 方案一:將 Filebeat 與 後端 SDK 封裝在同一個 Pod 裡採集 log 檔(推薦)
將 Filebeat 容器與能夠產生 log 的後端 SDK 容器設定在同一個 Pod 裡,後端 SDK 將 log 寫入 emptyDir 中,由 Filebeat 進行讀取並傳送至 Logstash。
- 優點:部署方便,哪個 Pod 裡有 log 就在哪個 Pod 裡新增一個 Filebeat。
- 缺點:與 SDK Pod 有耦合,Filebeat 的數量可能較多,稍顯冗餘。
神策分析各後端語言的 SDK 都支援將數據寫入檔案,例如: Java SDK 的 ConcurrentLoggingConsumer,PHP SDK 的 FileConsumer,Python SDK 的 LoggingConsumer。
- 以 Java SDK 為例:
// 使用 ConcurrentLoggingConsumer 初始化 SensorsAnalytics
// 將數據輸出到 /data/sa_log 下的 service_log 開頭的檔案中,每天一個檔案
final SensorsAnalytics sa = new SensorsAnalytics(
new SensorsAnalytics.ConcurrentLoggingConsumer("/data/sa_log/service_log"));
// 使用神策分析記錄用戶行為數據
sa.track(distinctId, true, "UserLogin");
sa.track(distinctId, true, "ViewProduct");
// 程式結束前,停止神策分析 SDK 所有服務
sa.shutdown();
以上設定將在 /data/sa_log 目錄下產生數據檔案,一天一個檔案,檔案列表如下:
service_log.20170923
service_log.20170924
service_log.20170925
在部署 Pod 時首先將 SDK 容器中的 /data/sa_log 目錄下的內容掛載到 emptyDir: {} 上。然後設定 Filebeat 的讀取的檔案目錄為:/var/log/containers/service_log.* 。 Filebeat 將會讀取該目錄下所有以 service_log. 開頭的檔案。最後把 Filebeat 容器的 /var/log/containers/ 目錄也掛載到 emptyDir: {} 上,運行時即可讀取 SDK 容器產生的 log 檔。
- 部署檔案 pod.yaml 参考範例:
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config-in
labels:
sa-app: filebeat
data:
filebeat.yml: |-
filebeat.inputs:
- type: log
# 讀取 /var/log/containers 目錄下以 service_log 開頭的檔案。
paths:
- /var/log/containers/service_log.*
output.logstash:
# 叢集內網 Logstash
hosts: ["logstash-0.logstash:5044","logstash-1.logstash:5044"]
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: javasdk-beat
labels:
sa-app: javasdk-beat
spec:
replicas: 3
template:
metadata:
name: javasdk-beat
labels:
sa-app: javasdk-beat
spec:
containers:
- name: javasdk
image: javasdk:20190705
command: ["/bin/bash", "-c"]
args:
- "bin/javasdk start"
volumeMounts:
- name: log-path
# /data/sa_log 為後端 SDK 存放 log 的目錄,掛載到 emptyDir 上
mountPath: /data/sa_log
- name: filebeat
image: docker.elastic.co/beats/filebeat:7.2.0
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
volumeMounts:
- name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
- name: log-path
# 檔案讀取目錄也掛載到 emptyDir 上
mountPath: /var/log/containers
readOnly: true
volumes:
- name: log-path
emptyDir: {}
- name: config
configMap:
name: filebeat-config-in
6.2.2. 方案二:Filebeat 部署在 K8s 節點上採集 log 檔
Filebeat 以 DaemonSet 的方式部署在 K8s 節點上收集 log 數據。節點上運作的後端 SDK 統一將 log 存放在宿主機的指定目錄內由 Filebeat 進行讀取並傳送至 Logstash。
- 優點:Filebeat 部署方便,與 SDK Pod 無耦合。
- 缺點:需要解決目錄問題,在宿主機上會存在額外的 log 檔案。
考慮到在同一宿主機上可能存在多個相同的後端 SDK 容器,因此需要使每個容器在向宿主機目錄寫入 log 的時候使用不同的目錄。建議在啟動容器時使用系統環境變數 HOSTNAME 作為路徑名存放 log 檔,然後將上一級目錄掛載到宿主機目錄上。
- 舉個例子:
容器内 log 的輸出路徑:/mount/${HOSTNAEM}-logs/service_log.20190708
宿主機存放 log 的路徑:/home/data/javasdk_logs/
將 /mount 掛載至 /home/data/javasdk_logs/ 下。
因此宿主機的 /home/data/javasdk_logs/ 目錄下存放的内容大致如下:
[root@node-1 javasdk_logs]$ pwd
/home/data/javasdk_logs/
[root@node-1 javasdk_logs]$ ls -l
drwxr-xr-x 2 root root 22 Jul 8 12:06 javasdk-7d878c784d-5fpjz_logs
drwxr-xr-x 2 root root 22 Jul 6 18:33 javasdk-7d878c784d-7xmbb_logs
drwxr-xr-x 2 root root 22 Jul 6 18:52 javasdk-7d878c784d-vv9fz_logs
drwxr-xr-x 2 root root 22 Jul 8 12:08 javasdk-7d878c784d-w7q65_logs
drwxr-xr-x 2 root root 22 Jul 8 11:19 javasdk-7d878c784d-wkvxd_logs
[root@node-1 javasdk_logs]$ cd javasdk-7d878c784d-5fpjz_logs
[root@node-1 javasdk-7d878c784d-5fpjz_logs]$ ls -l
-rw-r--r-- 1 root root 6592991 Jul 8 23:59 service_log.20190706
-rw-r--r-- 1 root root 4777188 Jul 8 23:58 service_log.20190707
-rw-r--r-- 1 root root 137778 Jul 8 12:03 service_log.20190708
- 以 Java SDK 為例在保存 log 時以 HOSTNAME 做為路徑,參考如下:
// 取得 HOSTNAME
String hostname = System.getenv("HOSTNAME");
File logPath = new File("/mount/" + hostname + "-logs/");
if (!logPath.exists()) {
logPath.mkdirs();
}
// 使用 ConcurrentLoggingConsumer 初始化 SensorsAnalytics
// 將數據輸出到 /mount/${HOSTNAME}-logs/ 目錄下以 service_log 為開頭保存,運作容器時將 /mount 目錄掛載到宿主機上
final SensorsAnalytics sa = new SensorsAnalytics(
new SensorsAnalytics.ConcurrentLoggingConsumer(logPath.getAbsolutePath() + "/service_log"));
// 使用神策分析記錄用戶行為數據
sa.track(distinctId, true, "ViewProduct");
// 程式结束前,停止神策分析 SDK 所有服務
sa.shutdown();
- 參考的 javasdk.yaml 檔案設定:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: javasdk
labels:
k8s-app: javasdk
spec:
replicas: 3
template:
metadata:
name: javasdk
labels:
k8s-app: javasdk
spec:
containers:
- name: javasdk
image: java-sdk-host:0715
command: ["/bin/bash", "-c"]
args:
- "bin/javasdk start"
volumeMounts:
- name: logfile
mountPath: /mount
volumes:
- name: logfile
hostPath:
path: /home/data/javasdk_logs/
type: DirectoryOrCreate
如果您不希望更改原容器的 log 路徑存放方式,可以在容器啟動時建立一條軟鏈指向 log 目錄,將軟連掛載在宿主機即可。
- 參考的 javasdk.yaml 檔案設定:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: javasdk
labels:
k8s-app: javasdk
spec:
replicas: 3
template:
metadata:
name: javasdk
labels:
k8s-app: javasdk
spec:
containers:
- name: javasdk
image: java-sdk:0712
command: ["/bin/bash", "-c"]
args:
- "rm -rf /your/logs/path
&& mkdir -p /mount/${HOSTNAME}_logs
&& ln -s /mount/${HOSTNAME}_logs /your/logs/path
&& bin/javasdk start"
volumeMounts:
- name: logfile
mountPath: /mount
volumes:
- name: logfile
hostPath:
path: /home/data/javasdk_logs/
type: DirectoryOrCreate
將Filebeat 匹配的路徑設定為 /home/data/javasdk_logs/*/service_log.*,並且把Filebeat 存放進度的目錄也掛載在宿主機上,這樣在重啟 DaemonSet 的時候節點上的Filebeat 會繼續之前的傳送進度。
- DaemonSet 設定檔案 filebeat-ds.yaml 参考如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
labels:
sa-app: filebeat
data:
filebeat.yml: |-
filebeat.inputs:
- type: log
paths:
# 採集 service_log 開頭的 log 檔
- /var/log/containers/*/service_log.*
output.logstash:
# 部署好的 Logstash
hosts: ["logstash-0.logstash:5044","logstash-1.logstash:5044"]
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: filebeat
labels:
sa-app: filebeat
spec:
template:
metadata:
labels:
sa-app: filebeat
spec:
serviceAccountName: filebeat
terminationGracePeriodSeconds: 30
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:7.2.0
imagePullPolicy: IfNotPresent
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
volumeMounts:
- name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
- name: inputs
mountPath: /var/log/containers
readOnly: true
- name: data
mountPath: /usr/share/filebeat/data
volumes:
- name: config
configMap:
name: filebeat-config
- name: inputs
hostPath:
path: /home/data/javasdk_logs/
- name: data
hostPath:
path: /home/data/filebeat_data/
type: DirectoryOrCreate
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: default
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: filebeat
labels:
sa-app: filebeat
rules:
- apiGroups: [""]
resources:
- namespaces
- pods
verbs:
- get
- watch
- list
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: filebeat
namespace: default
labels:
sa-app: filebeat
7. 更新日誌
7.1. 0.1.2
- 可同時設定多個數據接收網址。
- 新增每分鐘一次的狀態 log(傳送速度、已接收、已傳送,報錯)。
- 支援使用 Filebeat 作為輸入時可在 log 中印出被讀檔案的讀取情況。