베스핀글로벌 D&A실 신지윤 님이 작성해 주신 ‘EKS + Fluent bit + OpenSearch 구성을 통한 로그 수집’에 대해 알아보겠습니다.
1-a. EFK (ElasticSearch + Fluented + Kibana)란?
EFK란 ElasitcSearch + Fluentd bit + Kibana의 조합을 일컬음
보통 지속적으로 유입되는 로그 데이터를 수신하고 이 데이터를 차트와 그래프로 시각화 하거나 분석할때 사용하는 솔루션
2021년 9월, Elastic의 라이선스 변경으로 인해 AWS에서는 ElasticSearch에 대한 업데이트 제공을 중단함.
기존 ElasticSearch를 포크(Fork)하여 OpenSearch라는 오픈 소스 서비스를 개시하고,
Elastic에서 함께 지원하던 시각화 도구인 Kibana는 OpenSearch Dashboard 라는 서비스로 지원
1-b. OpenSearch + Fluent bit + OpenSearch Dashboard
- Fluent bit : 데이터(로그)를 수집해서 Opensearch로 전달
- OpenSearch : Fluentd로부터 받은 데이터를 검색 및 집계하여 필요한 정보 획득
- OpenSearch Dashboard: Opensearch의 빠른 검색능력을 통해 데이터 시각화 및 모니터링
1-c. Fluentd / Fluent bit / LogStash 장단점
장점 | 단점 | |
Fluentd | – 다양한 데이터 소스에서 로그를 수집하고 대용량 데이터 처리를 지원하는 포괄적인 로그 수집기 – 풍부한 플러그인과 커뮤니티 지원이 제공됨 | – 일부 환경에서 성능이 떨어질 수 있으며, 메모리 사용량이 크고 설정이 상대적으로 복잡함 |
Fluent bit | – 경량화 되어 자원 소모가 적고, 빠른 처리 속도 제공 – 컨테이너 환경에 적합하고 메모리 효율성이 뛰어남 | – 로그 처리 파이프라인이 다른 컴포넌트와 비교했을 때, 일부 기능이 제한적일 수 있음 |
LogStash | – 다양한 데이터 입력과 출력 플러그인 지원 – ElasticSearch와의 연동이 강력하며, 데이터 처리 파이프라인 구축이 상대적으로 용이 | – 자원 소모가 크고, 처리량이 많은 시나리오에서 성능에 제약이 있을 수 있음 |
2-a. 사전 준비사항
1) 로그를 생성할 애플리케이션 생성
git clone https://github.com/GoogleCloudPlatform/microservices-demo.git
cd microservice-demo
2) 애플리케이션 yaml 파일 클러스터에 적용
kubectl apply -f ./microservice-demo/release/kubernetes-manifests.yaml
3) 배포 확인
kubectl get pod -A -n logging
2-b. Elasticsearch(Amazon OpenSearch Service) 생성
https://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/createupdatedomains.html 를 참고하여 Elasticsearch 생성
2-c. AWS IRSA (IAM Role for Service Account) 설정
Kubernetes Service Account와 AWS IAM 역할을 연결하여 AWS 리소스에 대한 접근 권한을 부여하는 접근제어 방식
1) EKS OIDC Identity Providers 생성
IAM > Access Management > Identity Providers > Add Provider
→ 공급자 유형 : OpenID Connect
→ 공급자 URL
EKS > Clusters > 클러스터 선택 > Overview > OpenID Connect provider URL
→ 대상 : sts.amazonaws.com
2) IAM Policy 생성
IAM > Access Management > Policies > Create policy
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"es:ESHttp*"
],
"Resource": "${OPENSEARCH_ARN}",
"Effect": "Allow"
}
]
}
→ ${OPENSEARCH_ARN} : 생성한 OpenSearch의 ARN 정보로 교체
3) IAM Role 생성
IAM > Access Management > Policies > Create role
→ 신뢰할 수 있는 엔터티 유형 : 사용자 지정 신뢰 정책
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "${IDENTITY_PROVIDER_ARN}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${IDENTITY_PROVIDER}:aud": "sts.amazonaws.com",
"${IDENTITY_PROVIDER}:sub": "${SERVICE_ACCOUNT_NAME}",
}
}
}
]
}
→ ${IDENTITY_PROVIDER_ARN} : 위에서 확인한 EKS OpenID Connect provider ARN 값
→ ${IDENTITY_PROVIDER}:aud : 위에서 확인한 EKS OpenID Connect provider
→ ${IDENTITY_PROVIDER}:sub : 생성할 Service Account 이름
2-d. RBAC (Role-Based Access Control) 설정
Kubernetes Service Account에게 클러스터 수준의 리소스 접근을 제어할 권한 부여
1) Service Account 생성
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
annotations:
eks.amazonaws.com/role-arn: ${IAM_ROLE_ARN}
namespace: logging
2) Cluster Role 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluent-bit-read
rules:
- apiGroups:
- ""
resources:
- namespaces
- pods
verbs:
- get
- list
- watch
3) Cluster Role Binding 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fluent-bit-read
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: fluent-bit-read
subjects:
- kind: ServiceAccount
name: fluent-bit
namespace: logging
2-e. Fluent-bit ConfigMap 생성
apiVersion: v1
kind: ConfigMap
metadata:
labels:
k8s-app: fluent-bit
name: fluent-bit-config
namespace: logging
data:
fluent-bit.conf: |
[SERVICE]
Flush 1
Log_Level info
Daemon off
Parsers_File parsers.conf
HTTP_Server On
HTTP_Listen 0.0.0.0
HTTP_Port 2020
@INCLUDE input-kubernetes.conf
@INCLUDE filter-kubernetes.conf
@INCLUDE output-opensearch.conf
input-kubernetes.conf: |
[INPUT]
Name tail
Tag kube.*
Path /var/log/containers/*.log
Parser docker
DB /var/log/flb_kube.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
filter-kubernetes.conf: |
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
Kube_Tag_Prefix kube.var.log.containers.
Merge_Log On
Merge_Log_Key log_processed
K8S-Logging.Parser On
K8S-Logging.Exclude On
output-opensearch.conf: |
[OUTPUT]
Name es
Match *
Host ${OPENSEARCH_ENDPOINT}
Port 443
TLS On
AWS_Auth On
AWS_Region ${AWS_REGION}
Index ${INDEX_NAME}
Replace_Dots On
Suppress_Type_Name On
parsers.conf: |
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
→ [INPUT]
Path /var/log/containers/*.log : 수집할 로그가 위치한 경로
→ [OUTPUT]
Host ${OPENSEARCH_ENDPOINT}
AWS_Region ${AWS_REGION}
Index ${INDEX_NAME}
: Daemonset 컨테이너의 환경 변수에서 설정
데몬셋(DaemonSet)과 ${OPENSEARCH_ENDPOINT} 변수를 사용하여 각 노드가 자체의
OpenSearch 인스턴스로 로그 데이터를 전송하도록 구성하면,
각 노드가 독립적으로 로그 데이터를 처리하므로써 장애상황이 발생하여도 다른 노드는 정상적으로 로그 데이터를 전송하고 처리할 수 있습니다.
이로 인해 단일 포인트 오브 실패를 피할 수 있으며, 클러스터의 안정성과 로그 데이터의 신뢰성을 향상시킬 수 있음
2-f. Fluent-bit Daemonset 생성
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
k8s-app: fluent-bit-logging
kubernetes.io/cluster-service: "true"
version: v1
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
k8s-app: fluent-bit-logging
template:
metadata:
annotations:
prometheus.io/path: /api/v1/metrics/prometheus
prometheus.io/port: "2020"
prometheus.io/scrape: "true"
labels:
k8s-app: fluent-bit-logging
kubernetes.io/cluster-service: "true"
version: v1
spec:
containers:
- env:
- name: OPENSEARCH_ENDPOINT
value: ${OPENSEARCH_ENDPOINT}
- name: AWS_REGION
value: ${AWS_REGION}
- name: INDEX_NAME
value: ${INDEX_NAME}
name: fluent-bit
image: amazon/aws-for-fluent-bit:2.28.0
imagePullPolicy: Always
ports:
- containerPort: 2020
volumeMounts:
- mountPath: /var/log
name: varlog
- mountPath: /var/lib/docker/containers
name: varlibdockercontainers
readOnly: true
- mountPath: /fluent-bit/etc/
name: fluent-bit-config
serviceAccountName: fluent-bit
terminationGracePeriodSeconds: 10
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Exists
- effect: NoExecute
operator: Exists
- effect: NoSchedule
operator: Exists
volumes:
- hostPath:
path: /var/log
name: varlog
- hostPath:
path: /var/lib/docker/containers
name: varlibdockercontainers
- configMap:
name: fluent-bit-config
name: fluent-bit-config
→ ${OPENSEARCH_ENDPOINT} : OpenSearch endpoint url (https:// 포함 X)
→ ${AWS_REGION}
→ ${INDEX_NAME} : 수집된 로그 데이터를 OpenSearch로 전송하기 전 어떤 인덱스 이름에 해당 로그를 저장할 지 정의
→ image: amazon/aws-for-fluent-bit:2.28.0
→ serviceAccountName: fluent-bit : 위에서 생성한 IAM Role에 설정값으로 지정
3. OpenSearch 동작 확인
1) OpenSearch 접속
2) 인덱스 패턴 생성
메뉴 > Management > Stack Management > Index Patterns > Create index pattern
Step 1 of 2 위에서 설정한 Index Name (eks-log)를 검색하면 일치하는 소스가 조회됨
Step 2 of 2 기본적인 타임 필드는 @timestamp로 설정
로그데이터에 time이라는 필드에 이벤트 시간 정보가 포함되어있다면 OpenSearch에서 @timestamp 필드에 매핑하게 되어
정확한 시간 순서로 이벤트를 확인할 수 있음
3) 로그 적재 확인
감사합니다 🙂
Written by 신 지윤 / Jiyun Shin
Cloud Engineer