當我們使用非容器化的佈署方式,也就是直接在各主機上安裝服務或應用程式時,我們要收集這些機器上的 Logs 時,可能會有二種方式:
例如我們在一個單純的三層式服務架構之中,有以下三種服務的主機:
而我們要收集這幾台機器上的 Logs 時,我們會建議直接在每台主機上安裝 Filebeat,並且在不同的機器上配置不同的 Inputs 與 Modules 設定值,來收取我們希望取得的 Logs,例如:
主機所安裝的服務 | 希望收集的資訊 | Inputs | Modules | 說明 |
---|---|---|---|---|
Apache Web Server | Apache access & error logs | Apache |
透過 Apache module 指定 access 與 error Logs 的檔案路徑。 |
|
Java Backend Service | Application logs | Log 或 filestream |
由於 Logs 的格式是自訂義的,直接使用 filestream 來指定要 Logs 的檔案來源路徑,甚至要特別處理的 processors 。 |
|
MySQL Database | MySQL logs | MySQL |
透過 MySQL module 指定 error 與 slowlog Logs 的檔案路徑。 |
|
主機本身 | 主機本身的系統日誌,或是 auth logs | System |
透過 System module 指定 syslog 與 auth Logs 的檔案路徑。 |
如果有使用 Shared drive 的方式,來簡化『集中化收集日誌』這件事的話,基本上就是在專門運行 Filebeat 的機器上,透過 NFS 之類的 Shared drives 取得各服務的日誌。
使用這種方式,在 Filebeat 的 Inputs 與 Modules 的配置上,沒有特別的差異,只是會一口氣將這些配置設定在同一個 Filebeat 身上,不過有個地方要特別注意,Filebeat 的 Log
與 filestream
input,在使用網路共享或是雲端應商的儲存空間時,因為會使用磁碟機的 inode
資訊與 device id
當作檔案的唯一識別,有時 shared drive 的這個值會改變,導致於已經處理過的檔案,又重新被判斷成是新的檔案,造成重覆的傳送,這部份會要透過自行產生唯一的識別 ID,並且指定 inode_maker
來避免這件事發生,細節請參考 官方文件 - Filebeat Input - Logs。
當我們使用 Docker 來佈署服務時,一般的做法都是在 Container 之中直接把 log 輸出到 stdout
或是 stderr
,並透過 Docker logging driver 去進行處理,而實際的檔案預設會寫在 Docker host 身上,例如在 linux 環境中,會寫到 /var/lib/docker/containers/
的路徑底下。
注意:因為容器的生命週期可能隨時會中斷,一個有良好 scalability 的容器化架構的設計,會是 stateless 的,也就是當容器被關閉時,存在裡面的 logs 就消失了,所以一般絕對不建議把 logs 直接寫在 container 之中,至少也要使用 volume 的方式將 logs 寫到會持久保存的另外的儲存空間裡。
因此我們要使用 Filebeat 來收集所有 Docker Container 產生的 logs 時,我們其實就是針對 Docker host 的這個路徑裡的 logs 下手,這也是 Filebeat Container Inputs 所使用的方法。
注意:Docker Input 已經在 7.2 版時棄用 (deprecated) 了,之後請直接使用 Container Input。
而 Container Input 的設定方式如下:
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
裡面也可以在 stream
屬性去設定只要針對 stdout
或是 stderr
的內容進行收集,細節可以參考 官方文件 - Filebeat Input - Container。
注意:在這種使用一口氣收集所有 Containers 產生的 logs 時,應該要搭配一些內建的 Processors,例如
add_docker_metadata
、add_kubernetes_metadata
、add_cloud_metadata
,將產生 logs 的 container 或是 pod 的資訊增加在 logs 之中,以便於後續使用時能進行分辨。
如同我們前面 11 - Metrics - 觀察系統的健康指標 (5/6) - 使用 Metricbeat 掌握 Infrastructure 的健康狀態 Kubernetes 篇 在介紹 Metricbea 時,提到在 Kubernetes 使用 DaemonSet 的方式同樣的考量,可以確保每個 Node 身上有一個獨立的 Filebeat pod 來進行收集整個 Nodes 上所有 Pods 裡的 logs,並且傳送到 Elasticsearch。
而在 Kubernetes 裡,也如同前面『 Docker 環境的 Log 產生方式』運作的方式一樣,因為 Pods 會是 stateless,因此一般我們也都會直接將 logs 透過 stdout
或是 stderr
送出,並且由運行這些 Pods 所在的 Node,寫在實體的 disk 路徑 /var/log/containers/*.log
之中,因此我們也就可以使用 DaemonSet 的方式來佈署 Filebeat,並且將主機的 /var/log
mount 到 Filebeat 身上,讓他可以直接使用 Container Inputs 的方式,取的這個所有 Pods 產生的 logs。
例如以官方的 filebeat-kubernetes.yaml 為例 (以下僅截取 ConfigMap 與 DaemonSet 的主要配置,完整版請參考原始檔案):
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
namespace: kube-system
labels:
k8s-app: filebeat
data:
filebeat.yml: |-
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
# To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:
#filebeat.autodiscover:
# providers:
# - type: kubernetes
# node: ${NODE_NAME}
# hints.enabled: true
# hints.default_config:
# type: container
# paths:
# - /var/log/containers/*${data.kubernetes.container.id}.log
processors:
- add_cloud_metadata:
- add_host_metadata:
cloud.id: ${ELASTIC_CLOUD_ID}
cloud.auth: ${ELASTIC_CLOUD_AUTH}
output.elasticsearch:
hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
username: ${ELASTICSEARCH_USERNAME}
password: ${ELASTICSEARCH_PASSWORD}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: kube-system
labels:
k8s-app: filebeat
spec:
selector:
matchLabels:
k8s-app: filebeat
template:
metadata:
labels:
k8s-app: filebeat
spec:
serviceAccountName: filebeat
terminationGracePeriodSeconds: 30
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:8.0.0
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
env:
- name: ELASTICSEARCH_HOST
value: elasticsearch
- name: ELASTICSEARCH_PORT
value: "9200"
- name: ELASTICSEARCH_USERNAME
value: elastic
- name: ELASTICSEARCH_PASSWORD
value: changeme
- name: ELASTIC_CLOUD_ID
value:
- name: ELASTIC_CLOUD_AUTH
value:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
securityContext:
runAsUser: 0
# If using Red Hat OpenShift uncomment this:
#privileged: true
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
- name: config
mountPath: /etc/filebeat.yml
readOnly: true
subPath: filebeat.yml
- name: data
mountPath: /usr/share/filebeat/data
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: config
configMap:
defaultMode: 0640
name: filebeat-config
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: varlog
hostPath:
path: /var/log
# data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
- name: data
hostPath:
# When filebeat runs as non-root user, this directory needs to be writable by group (g+w).
path: /var/lib/filebeat-data
type: DirectoryOrCreate
---
DaemonSet 有宣告 mount /var/lib/docker/container
以及 /var/log
,讓 Filebeat 可以取得 container 的 logs。
DaemonSet 有另外宣告 /var/lib/filebeat-data
當作 data 的 volumeMounts 來掛載到 container 內的 /var/share/filebeat/data
路徑,讓這個 DaemonSet 的 Filebeat 運作時的檔案,是寫到實體主機的 disk 之中,不會因為重啟而造成資料的遺失。
另外有特別使用 add_kubernetes_metadata
的 processor,讓這些一口氣收集進來的各種 Pod 產生的 logs,加上 Pod Name
、Pod UID
、Namespace
、Labels
的資訊,讓我們在後續分析處理時,能分辨得出來是哪邊產生的 log。
有一段是註解掉的 autodiscovery 的配置,若是使用 Docker、Kubernetes、或是使用 Nomad 時,可以考慮使用 autodiscovery 的機制,讓 container 或是 pod 動態增加時,也能夠由 DaemonSet 自動開始收集新增加容器產生的 logs。
如果 Service container 寫的是實體的 Logs 檔案,另一種方式是我們可以使用 SideCar 的方法將 Logs 轉成 stdout
與 stderr
的方式往外傳送,以使用我們先前建議的容器化收集 logs 的方法。
首先將 Pod 中的 Service container 與 Sidecar container 使用 Shared Volume,讓 Sidecar container 能夠直接取得 Service container 產生 的 logs,並且 SideCar container 再負責將這個 logs tail
出來,輸出到 stdout
或 stderr
,這樣後續就能同樣的使用 DaemonSet 或是專門收集 log 的 pod 的機制,進行後續的處理。
查看最新 Elasticsearch 或是 Elastic Stack 教育訓練資訊: https://training.onedoggo.com
歡迎追蹤我的 FB 粉絲頁: 喬叔 - Elastic Stack 技術交流
不論是技術分享的文章、公開線上分享、或是實體課程資訊,都會在粉絲頁通知大家哦!