이 전 글에서 EFK Stack을 구성하여 로그가 정상적으로 수집되는 것을 확인하였지만, 안정적인 운영을 위해 추가로 설정해야 될 작업이 필요합니다. 사실 이러한 부분이 로깅 스택 구축에서 큰 부분을 차지하고 Elastic이 다소 복잡하기 때문에 현재 시스템에 딱 맞는 설정을 한 번에 하기 힘듭니다. 로그를 원하는 형태로 변형하거나, 필터링하고 , ElasticSearch에서 적절한 정책을 설정하여 데이터 사이즈를 조정하는 등의 정책이 필요합니다. 이번 글에서는 container 로그뿐 아니라 추가로 필요한 로그에 대해 설정하는 과정을 기록하고 다음 글에서 elastic 정책적인 부분에 대해 기록하고자 합니다.
1. Log 정제 및 파싱
이전 글에서 구성한 방법은 Fleunt-bit에서 데이터를 전송하여 fluentd에서 수집하였습니다. EFK 스택을 찾아보면 Fluent-bit 없이 fluentd에서 데이터를 전송하고 수집하기도 하는데, 이러한 경우 Fluentd에 모든 설정을 적용해야하기 때문에 더욱 복잡해지고, 부하가 많아질 수 있어서, 각 기능을 구분하기 위해 분리하였습니다. 로그를 정제하기 위해서 Fluent-bit에서는 일차적으로 필터링하여 필요한 로그만 전송하도록 설정하고 Fluentd에서 수집된 로그를 적절한 형식으로 변형하여 Elasticsearch로 보냅니다.
Fluentd의 설정을 보면 다음과 같습니다. 파일로 생성되는 Container의 로그를 읽기 위해 tail로 지정한 후, 로그가 저장되어있는 경로를 Path
로 설정합니다. multiline.paser
의 경우 일반적으로 로그가 한 줄로 들어오는 것이 이상적이지만, 실제 여러 줄의 로그를 생성하는 경우가 많기 때문에 이를 적절한 형식으로 변경하기 위해설정하고, docker
와 cri
는 기본 내장되어있는 parser입니다.
# 실제 들어오는 container 로그
Starting server...
Listening on port 8080
# multiline.parser 로 파싱된 로그 sample
{
"log": "Starting server...\nListening on port 8080\n",
"stream": "stdout",
"time": "2022-02-17T12:34:56.789Z"
}
다음과 같이 설정한 Input 로그를 kube.*
의 태그를 설정해 전송합니다.
inputs: |
[INPUT]
Name tail
Path /var/log/containers/*.log
Exclude_Path /var/log/containers/fluent*.log
multiline.parser docker, cri
Tag kube.*
Mem_Buf_Limit 50MB
Skip_Long_Lines On
outputs: |
[OUTPUT]
Name forward
Match kube.*
Tag kube_container
Host fluentd-forward.efk.svc.cluster.local
Port 24224
Retry_Limit False
Time_as_Integer true
이후 output
을 설정해 매치된 로그를 fluentd로 전송하며, 전송될 때 kube_container
라는 태그를 붙여서 전송합니다.
이후 Fluentd에서 전송된 로그를 받기 위해 fowrad
플러그인 통해 포트를 열어줍니다. 해당 포트를 통해 들어오는 로그는 KUBERNETES
라는 레이블을 갖게 됩니다. filter 부분에서는 단순히 container로그 중 Control plane의 파드인(kube-apiserver, kube-controller, kube-schedule)과 그 외의 파드를 분기해서 수집하기 위해 분리하는 과정입니다.
#fluentd.conf
01_source.conf:
<source>
@type forward
@label KUBERNETES
@log_level debug
bind 0.0.0.0
port 24224
</source>
02_filters.conf: |-
<label @KUBERNETES>
<filter kube_container>
@type record_transformer
enable_ruby true
<record>
kube_info ${record["kubernetes"]["container_name"]}
</record>
</filter>
<match kube_container>
@type rewrite_tag_filter
<rule>
key kube_info
pattern ^(?:(?i)kube-apiserver|(?i)kube-controller|(?i)kube-scheduler|(?i)etcd)$
tag basic_kube
</rule>
<rule>
key kube_info
pattern /.+/
tag etc_kube
</rule>
</match>
<label>
04_outputs.conf: |-
<label @OUTPUT_BASIC>
<match **>
@type elasticsearch
@log_level debug
hosts "https://elastic:password@elasticsearch-master:9200"
index_name fluentd-container-basic-000001
ca_file /etc/fluent/certs/ca.crt
client_cert /etc/fluent/certs/tls.crt
client_key /etc/fluent/certs/tls.key
time_as_integer true
request_timeout 60s
include_timestamp true
#time_key timestamp
</match>
</label>
<label @OUTPUT_ETC>
<match **>
@type elasticsearch
@log_level debug
hosts "https://elastic:password@elasticsearch-master:9200"
index_name fluentd-container-etc-000001
ca_file /etc/fluent/certs/ca.crt
client_cert /etc/fluent/certs/tls.crt
client_key /etc/fluent/certs/tls.key
time_as_integer true
request_timeout 60s
include_timestamp true
#time_key timestamp
</match>
</label>
etc_kube
와 basic_kube
를 분리 하는 기준은 kube_info
key인데 해당 키는 원래 존재하지 않지만 record_transformer
를 통해 기존 로그를 통해 새로운 키를 만들 수 있다.( 사실 현재 설정에서는 kubernetes.container
랑 동일한 값이어서 의미가 없지만 record_transform
을 테스트 하기 위해 추가하였다.)
예를 들어 로그 레벨을 보기 위해서 두 가지 key로 값이 제공되는데(warn_flag
, error_type
) 이를 하나의 키로 병합하기 위해 위해 다음과 같이 설정을 할 수 있습니다.
<filter fluent_bit>
@type record_transformer
enable_ruby true
remove_keys warn_flag
<record>
status_type ${if record["warn_flag"].nil?; record["error_type"]; else; "WARN" end;}
</record>
</filter>
이러한 key 들의 항목은 kibana의 Discover 또는 index management에서 조회할 수 있고, filter에 기본 내장되어 있는 기능들이 많기 때문에 해당 기능을 이용하면 대부분의 로그를 원하는 형식으로 바꿀 수 있습니다.
2. Syslog 설정
쿠버네티스 컨테이너 로그 뿐아니라 추가적인 로그 수집을 위해 syslog를 추가합니다. 우선 rsyslog
를 통해 로그를 fluentd로 전송할 수 있도록 설정을 변경합니다. 주소 앞의 *.*
부분은 TCP로 전송한다는 것을 의미합니다.
# /etc/rsyslog/conf
*.* @[Fluentd 주소]:IP
syslog는 데몬에서 로그를 바로 전송하기 때문에 fluent-bit에서의 설정은 하지 않습니다. 이후 fluentd에서 syslog를 데이터를 받기 위한 설정을 추가합니다. 이는 이미 플러그인으로 제공되기 때문에 사용하면 됩니다.
<source>
@type syslog
@label @OUTPUT_SYSLOG
port 24225
bind 0.0.0.0
tag system
</source>
<label @OUTPUT_SYSLOG>
<match **>
@type elasticsearch
@log_level debug
hosts "https://elastic:password@elasticsearch-master:9200"
index_name fluentd-syslog-all-000001
ca_file /etc/fluent/certs/ca.crt
client_cert /etc/fluent/certs/tls.crt
client_key /etc/fluent/certs/tls.key
time_as_integer true
request_timeout 60s
include_timestamp true
#time_key timestamp
</match>
</label>
다음 설정을 통해 syslog가 정상적으로 들어오는 것을 확인할 수 있습니다.
3. Kmsg
kmsg는 커널 메세지 로그를 나타내며 /dev/kmsg
위치에 저장됩니다. 이 로그 또한 수집하기 위해 설정합니다. fluent-bit에서는 default로 kmsg 플러그인을 제공해서 사용할 수 있습니다.
[INPUT]
Name kmsg
Tag kernel.*
[OUTPUT]
Name forward
Match kernel.*
Tag kmsg
Host fluentd.efk.svc.cluster.local
Port 24226
하지만 해당 설정으로는 Fluent-bit에서 오류가 발생합니다. 커널 메시지를 컨테이너 내부에서 볼 수 없기 때문에 이를 마운트 해줘야 됩니다. 또한 kmsg는 root 권한이기 때문에 이를 변경하거나 컨테이너 유저를 변경해야 됩니다. 이를 위해 Security Context
를 설정해줍니다.
securityContext:
privileged: true
runAsUser: 0
daemonsetVolumeMounts:
- name: kmsg
mountPath: /dev/kmsg
readOnly: true
daemonsetVolumes:
- name: kmsg
hostPath:
path: /dev/kmsg
다음과 같이 설정을 통해 컨테이너 로그 외에 Kmsg, Syslog를 추가로 설정하였습니다. 그 외의 systemd, Aws S3 등 대부분 사용하는 로그의 경우 이미 플러그인으로 제공되기 때문에 환경에 맞게 변경해서 원하는 로그를 수집할 수 있습니다. 하지만 이러한 경우 Fluent-bit의 이미지를 새로 빌드해야 되기 때문에 debug용 이미지(bash가 포함)를 이용해 필요한 플러그인을 설치하고 사용합니다.
'Kubernetes' 카테고리의 다른 글
ETCD MultiMaster Backup/Restore(CronJob 생성) (1) | 2023.11.14 |
---|---|
Velero를 이용한 쿠버네티스 Backup (0) | 2023.10.12 |
EFK Stack을 이용한 쿠버네티스 로깅 스택 구축#1 (0) | 2023.10.12 |
Thanos를 이용한 Prometheus HA 구성 (1) | 2023.10.12 |
ArgoCD,Jenkins를 이용한 쿠버네티스 배포 (0) | 2023.10.12 |