---
# System prepended metadata

title: EFK的另一篇

---

EFK的另一篇



目 錄<source>
  @type tail
  path /var/log/syslog
  pos_file /var/log/td-agent/syslog.log.pos
  tag td.syslog
  format /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
  time_format %b %d %H:%M:%S
</source>
Log 的好朋友 Fluentd
安裝 Fluentd
Fluentd 基本概念
Fluentd 設定教學
設定 Log Server
設定其他 Log Client
整合 MongoDB 儲存 Log
整合 ElasticSearch 儲存 Log
先安裝 Oracle Java
下載與安裝 ElasticSearch
安裝 fluent-plugin-elasticsearch
Log 的好朋友 Fluentd
之前的工作只管理幾台 Server，以往一個服務需要的應用伺服器與資料庫不會超過十台。後來開發企業雲端硬碟 SaaS 服務，到後期所有開發、測試、上線環境的 Server 數量已經快要破百，尤其在有水平擴充能力的分散式架構與高可用架構下，VM 除了數量多之外，還分佈在不同地區的 IDC，每次查起 Log 都相當吃力，一直很想集中 Log 進行管理。由於我本身也不是系統管理的專家 (寫霸各才是我的專長啊!?)，一般都是弱弱的 SSH 進 Server 查 Log，常常系統出問題牽扯的 Log 的種類少說數 10 種，像是 syslog, dmesg, secure, mysql, mongo, php-fpm, application log, nginx, haproxy, jos-server, nodejs… 說著說著我頭都暈了，這時候心想如果有 Log Server 那該有多好？知名的商業 Log Server Solution 一定先想到貴鬆鬆的 Splunk，話說能用錢解決的問題都不是問題，可惜沒有錢，只好自己找找 Open Source Solution。Google 之後 Fluentd 出現了，一個可以整合所有 Log 的資料搜集工具，不用錢的就好棒棒！我們先來看一下 FluentD 怎麼安裝？

安裝 Fluentd
Fluentd 在 Linux 中的套件名稱為 td-agent，但 Linux Ubuntu 內建並沒有這個套件，需要透過以下命令安裝：

sudo curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh

一開始安裝完成後，首先修改 Fluentd Servive 執行身份改用 root 執行，這樣改是因為後面要實作的案例很多 Log File 都是各自 Service User 擁有，為了要順利讀出 Log File 只好出動大無敵招式，如果你不需要這樣的 root 權限，建議保留原始設定即可。先編輯 /etc/init.d/td-agent 檔案，直接用 sed 命令置換 Fluentd Service User，如下：

sudo sed -i "s/TD_AGENT_USER=td-agent/TD_AGENT_USER=root/g" /etc/init.d/td-agent

sudo sed -i "s/TD_AGENT_GROUP=td-agent/TD_AGENT_GROUP=root/g" /etc/init.d/td-agent

上述的 Script 執行後會修改以下這兩個變數，設定執行的使用者為 root

TD_AGENT_USER=td-agent

TD_AGENT_GROUP=td-agent

修改後重新啟動 Fluentd 服務

sudo service td-agent restart

Fluentd 服務的 Log 在這裡，啟動時會載入相關 Log Configuration。如下：

cat /var/log/td-agent/td-agent.log

Fluentd (td-agent) 服務啟用後，預設會開啟 127.0.0.1:24230, 0.0.0.0:24224 與 0.0.0.0:8888 這三個 Port。分別介紹一下這些 Port 的作用：

第一個 127.0.0.1:24230 是 Debug Agent，預設僅開放本機連線，Log 才不會被看光光，可以透過 fluent-debug 進行連線操作。對應 /etc/td-agent/td-agent.conf 中的 Source Block (@type debug_agent)，如下：

1
2
3
4
5
<source>
 @type debug_agent
 bind 127.0.0.1
 port 24230
</source>
第二個 0.0.0.0:8888 是用來接收 Log 資訊的 Log HTTP Service，可以直接透過 HTTP 送 Log 進來。不需要認證直接透過 CURL 就可以測試，CURL 命令如下：

curl -X POST -d 'json={"message":"show me!"}' http://localhost:8888/td.myTag.test

上述的命令就會建立一筆 {"message":"show me!"} 內容的 Log，Log HTTP Service 對應 /etc/td-agent/td-agent.conf 中的 Source Block (@type http) 如下：

1
2
3
4
<source>
 @type http
 port 8888
</source>
最後一個 0.0.0.0:24224 是 Forward Service，可以用來接收其他 Fluentd 傳送過來的 Log，對應 /etc/td-agent/td-agent.conf 中的 Source Block (@type forward) 如下：

1
2
3
<source>
 @type forward
</source>
Fluentd 基本概念
介紹完設定檔之後，先來了解一下 Fluentd 基本概念，Fluentd 所有的 Log 都是 Json 格式，而且沒有 Schema 限制，想怎麼存都可以，如下：

fluentd log

主要的資料流由 Input Plugin 與 Output Plugin 組成，在設定檔中以 source Block 的方式存在，表示定義進入 Fluentd 訊息流中心的「來源」提供者，Log 訊息在 Fluentd 中可以被接收、傳遞、處理、過濾、再傳遞，一直這樣下去。一般我們會把本機各種型態的 Log 匯流至自己本機的 Fluentd，統整之後透過 Output Plugin 匯流至 Log Server Fluentd 的 Input，最終再由 Log Server 中的 Fluentd Output 匯流至資料庫中，也可以與像是 datadog 之類的 Cloud Log Monitor 進行整合。參考下圖左邊是 Input 右邊是 Output：

fluent-arch

Fluentd 設定教學
開始設定之前，我們先已經了解 Fluentd 基本提供的設定元素 Input Plugin/Output Plugin。Fluentd 的設定檔放在 /etc/td-agent/td-agent.conf 這裡，主要由 source 與 match Block 組成。source Block 用來接收 Input，match Block 可以用來 Match Log Tag 進行 Output 或其他處理。

由於不同服務的 Log Format 都不一樣。Input 來源常用的方法就是 @type tail 開檔的方法，畢竟幾乎所有的 Log 機制都會寫檔到 Disk 中，用這樣的方法可以直接讀取程式的 Log File 進行解析，不需要在程式中外掛函式，比較方便。我打算規劃的架構一台 Log Server 啟用 24224 Forward Service 讓其他眾多異質的服務統一以非同步的方式傳送 Log 進來，然後由 Log Server Output 轉存進 MongoDB 或者 ElasticSearch 進行快速調閱與分析。接著我們先設定 Server：

設定 Log Server
Log Server 只需要留下 Forward Service，因此我先修改 Log Server 設定檔，僅保留 Forward Service，並且指定所有的 Log 先寫到檔案 /var/log/fluent 中進行測試，後面確定 Log 有搜集進來再轉存 MongoDB 或 ElasticSearch，完整的設定檔如下：

1
2
3
4
5
6
7
8
9
10
11
12
13
<source>
 @type forward
</source>
 
<match **>
 @type file
 path /var/log/fluent
 time_slice_format %Y%m%d
 time_slice_wait 10s
 time_format %Y%m%dT%H%M%S%z
 compress gzip
 utc
</match>
Disk I/O 是效能的殺手，為了不要太頻繁寫檔，所以定義 time_slice_wait 10s 延遲寫 Log 到檔案的時間。然後重啟 td-agent，重啟會只剩下開啟 24224 Port。

sudo service td-agent restart

設定其他 Log Client
把 Server 設定好之後，再來就要設定 Client 了，一樣所有的機器都裝好 FluentD。一開始我們先用 tail 測試，把本機 Linux 的 syslog 傳送到 Log Server 集中存放。除了上述 Log Server 之外，其他的 Client 機器全部關閉 Log Service，最簡單的關閉方法就是註解 /etc/td-agent/td-agent.conf 其中的 Source Block，並且建立一個設定為 @type tail 的 Input Source Block 資料來源。

雖然剛剛提到 Fluentd Log 是一個沒有特定格式的 Json，但有一點要注意，由於 Log 最重要的元素就是「時間」(機器記得啟用 NTPD 校時啊)，然而 Fluentd Log 傳統的傳送方式都是非同步模式，Log Server (Forward Service) 收到 Log 的時間並非 Log 真正發生的時間，因此每一筆 Log 強烈建議透過 time_format 指定時間格式，透過 time 欄位傳送一致的 Fluentd 時間格式，這樣收集到的 Log 分析才會正確。Client 完整的設定檔如下：

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<source>
  @type tail
  path /var/log/syslog
  pos_file /var/log/td-agent/syslog.log.pos
  tag td.syslog
  format /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
  time_format %b %d %H:%M:%S
</source>
 
<match **>
  @type forward
  send_timeout 10s
  recover_wait 8s
  heartbeat_interval 1s
  phi_threshold 16
  hard_timeout 10s
  <server>
    name elastic-db
    host log-server
    port 24224
  </server>
  <secondary>
    @type file
    path /var/log/fluent/forward-failed
  </secondary>
</match>
上述 source 中的 tag 可以自行定義，透過 match ** 表示所有 tag 都進到這裡處理，透過 @type forward 把資料送到 host log-server 我們剛剛設定好的 Server (host log-server) 中。當然 log-server 也可以用 IP 指定，只是我的環境習慣用 host 進行佈署，好實現設定檔可攜。

設定好之後重新啟動 td-agent，然後當 /var/log/syslog 有新資料時，就會自動傳到 log-server 這裡了，如同前一個章節 Server 的設定，Log 最終會被集中儲存到檔案中。

整合 MongoDB 儲存 Log
Log 存到檔案其實很難檢索，Fluentd Log 是 JSON 格式，可以直接存進 NoSQL 特性的 MongoDB 中，先在 log-server 上安裝好 MongoDB (安裝方式可以參考以前的文章)，然後把上述的 <match> Block 改成下面的設定：

1
2
3
4
5
6
7
8
9
10
11
12
<match **>
  @type mongo
  database lodge
  collection fluentd
  capped
  capped_size 100m
  host 127.0.0.1
  port 27017
  user <MONGO_USER>
  password <MONGO_PASS>
  time_key time
</match>
上面設定檔中的 <MONGO_USER> 與 <MONGO_PASS> 請替換為你的 MongoDB 登入帳密。這裡有一個很好用的功能，就是 capped 設定，可以指定 capped_size 讓 Log 循環存放，不用擔心 Log 會把 MongoDB 塞爆，因為這個功能所以讓 MongoDB 晉升為我心目中的 Log Server 神器！Log 存進 MongoDB 之後就可以進行 Query 囉，超方便的，如下：

mongo-fluent

整合 ElasticSearch 儲存 Log
ElasticSearch 是一個全文搜尋引擎，核心當然是神作品 Apache Lucene 所打造，今天不對 ElasticSearch 深入介紹，簡單的安裝方式如下：

先安裝 Oracle Java
sudo echo 'deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' > /etc/apt/sources.list.d/webupd8team-java.list

sudo echo 'deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' >> /etc/apt/sources.list.d/webupd8team-java.list

sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com EEA14886

apt-get update

echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections

echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections

apt-get -y install oracle-java8-installer

 

下載與安裝 ElasticSearch
 

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.3.0.deb

sudo dpkg -i elasticsearch-5.3.0.deb

sudo systemctl enable elasticsearch.service

安裝 fluent-plugin-elasticsearch
想要把 Log 餵進 ElasticSerch 需要用到 fluent-plugin-elasticsearch 外掛，我 Ruby 超弱的，不知道是手殘還是怎樣，透過 gem 一直裝不起來，直接透過 td-agent-gem 來安裝就很順利了，td-agent-gem 顧名思義就是 td-agent 在用的 GEM 囉，如下：

sudo td-agent-gem install elasticsearch

最後是設定 Fluent (td-agent) 把資料導流到 ElasticSearch，設定檔內容如下：

1
2
3
4
5
6
7
<match **>
  @type elasticsearch
  host localhost
  port 9200
  index_name fluentd
  type_name log
</match>
重開後就會把 Log 存進 ElasticSearch 囉，如下：

 

fluentd-elasticsearch

進到 ElasticSearch 後可以快速查詢，算是很方便，但是 ElasticSearch 在 5.0 之後的版本我找不到像是 MongoDB 這樣的 Capped 功能，深怕 Log 灌爆磁碟，如果那位大大知道 ElasticSearch 可以限制 index 的容量或筆數，跪求分享！掰～