EFK Stack 구축을 통한 로그 수집

김채은·2022년 3월 23일
1

2021. 08. 06.

PROJECT

가상의 고객사 시스템 구축과 운영

  • SI

    • AWS 클라우드 환경 구성
    • 쿠버네티스 기반 EKS 환경 구성, 웹서비스 구축
  • SM

    • 로그 수집을 위한 EFK Stack 구축
    • CloudWatch 알람을 Slack으로 전송하여 실시간 모니터링

Work

  • 컨테이너 환경에서의 로그 수집을 위해 EFK Stack 구축
    - ElastiSearch, Fluentd, Kibana를 EKS 환경에서 구축

EFK란?

EFK

ElasticSearch+Fluentd+Kibana. 컨테이너 환경에서 로그를 수집한다.

  • ElasticSearch: 대용량 로그 저장소
  • Fluentd: 컨테이너의 스트림 로그를 수집하는 로그 수집기. 모든 노드마다 동일하게 배포되어야 함(Daemonset*)
  • Kibana: ElasticSearch와 연동하여 로그 시각화. 이를 통해 문제 해결과 예방 가능

쿠버네티스는 파드가 정상상태가 아니면 새로 생성한다. 그렇다면 죽은 파드에 있는 컨테이너가 남긴 로그는 어떻게 되는 걸까? EFK는 컨테이너의 로그를 로그 저장소에 수집한다. 따라서 죽은 컨테이너의 로그도 남는다.

* Daemonset

쿠버네티스의 기본 Object를 생성하고 관리하는 컨트롤러(Deployment, ReplicaSet 등) 중 하나이다. Daemonset은 Pod가 각각의 노드에 하나씩만 배포되게 하는 Pod 관리 컨트롤러이다. 예를 들어 모든 노드에 로그 수집용 Daemonset pod를 띄울 수 있다.

ElasticSearch 배포

ElasticSearch

텍스트, 숫자, 위치 기반 정보, 정형 및 비정형 데이터 등 모든 유형의 데이터를 위한 분산형 오픈 소스 검색 및 분석 엔진이다. 한 마디로, 많은 양의 데이터를 보관하고 실시간으로 분석하는 엔진이다.

쿠버네티스를 사용하면 따로 ElasticSearch를 설치하는 과정을 생략할 수 있다. ElasticSearch yaml 파일을 작성하고 배포하면 끝이다. 우리는 ElasticSearch를 NodePort type 서비스로 배포하여 Nginx의 로드밸런서에 연결하여 통신 확인을 할 것이다.

ElasticSearch 배포

1. LoadBalancer의 Security group 9200 포트 오픈 → 인터넷(외부)을 통해 LB의 9200포트로 접근

2. LoadBalancer의 Listener 편집 → 9200번 포트로 들어온 트래픽을 Instance(WorkerNode)의 30920 포트로 전달

3. Worker Node로 전달된 트래픽은 9200 포트를 통해 서비스로 전달 yaml파일의 Service부분에 정의된 대로 9200 포트를 통해 서비스는 클러스터 안에서 내부적으로 노출됨.

4. 9200번 포트로 보내진 요청은 서비스에 의해 선택된 Pod의 9200포트로 전달됨 (TargetPort – 선택된 Pod의 포트)

실습

1. 먼저 지난주 실습과 동일하게 EKS를 구성하고 Nginx를 실행한다.

2. elasticSearch.yaml 파일을 작성한다.

# cat<<EOF > ~/elasticSearch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: elasticsearch
  labels:
    app: elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: elastic/elasticsearch:6.4.0
        env:
        - name: discovery.type
          value: "single-node"
        ports:
        - containerPort: 9200
        - containerPort: 9300
        
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: elasticsearch
  name: elasticsearch-svc
  namespace: default
spec:
  ports:
  - name: elasticsearch-rest
    nodePort: 30920
    port: 9200
    protocol: TCP
    targetPort: 9200
  - name: elasticsearch-nodecom
    nodePort: 30930
    port: 9300
    protocol: TCP
    targetPort: 9300
  selector:
    app: elasticsearch
  type: NodePort
EOF

3. 배포한 후 배포된 pod와 service를 확인한다.

# kubectl apply –f elasticSearch.yaml	//배포
# kubectl get pod | grep elastic	//배포된 pod 확인
# kubectl get svc | grep elastic	//배포된 서비스 확인

4. Loadbalancer 리스너에 추가한다. [EC2 > 로드밸런서 > 리스너 > 리스너 편집 ]

리스너란, 정의한 프로토콜과 포트를 사용하여 연결 요청을 확인하는 프로세스이다. 리스너에 정의한 규칙에 따라 로드밸런서가 등록된 대상으로 요청을 라우팅 하는 방법을 결정한다.

다음과 같이 추가한다. 

5. 로드밸런서의 9200 포트로 외부 접근을 허용하기 위해 보안그룹의 인바운드 규칙을 추가한다.'

[ EC2 > 로드밸런서 > Security > Security Group ID 클릭 > 인바운드 규칙 편집 ]

파란색으로 뜬 ID를 누르고 다음과 같이 편집한다. Kubernetes ELB 보안그룹을 선택해서 편집해야 한다. 아니면 접속되지 않는다.

6. Nginx 로드밸런서 DNS에 :9200를 붙여 접속하면 다음과 같은 화면을 볼 수 있다. 

 **Kibana 배포**

Kibana

Elastic Stack을 기반으로 구축된 오픈소스 프론트엔드 어플리케이션으로, ElasticSearch에서 색인된 데이터를 검색하고 시각화하는 기능을 제공한다. 오픈소스 기반의 분석 및 시각화 플랫폼이다.

Kibana 배포

1. LoadBalancer의 Security group 5601 포트 오픈 → 인터넷(외부)을 통해 LB의 5601포트로 접근

2. LoadBalancer의 Listener 편집 → 5601번 포트로 들어온 트래픽을 Instance(WorkerNode)의 30561 포트로 전달

3. Worker Node로 전달된 트래픽은 5601 포트를 통해 서비스로 전달 yaml파일의 Service부분에 정의된 대로 5601 포트를 통해 서비스는 클러스터 안에서 내부적으로 노출됨.

4. 5601번 포트로 보내진 요청은 서비스에 의해 선택된 Pod의5601포트로 전달됨 (TargetPort – 선택된 Pod의 포트)

실습

1. kibana.yaml 파일을 작성한다.

# cat<<EOF > ~/kibana.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: elastic/kibana:6.4.0
        env:
        - name: SERVER_NAME
          value: "kibana.kubenetes.example.com"
        - name: ELASTICSEARCH_URL
          value: "http://elasticsearch-svc.default.svc.cluster.local:9200"
        ports:
        - containerPort: 5601

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: kibana
  name: kibana-svc
  namespace: default
spec:
  ports:
  - nodePort: 30561
    port: 5601
    protocol: TCP
    targetPort: 5601
  selector:
    app: kibana
  type: NodePort
EOF

2. 배포한 뒤 배포된 서비스를 확인한다.

# kubectl apply –f kibana.yaml	//배포
# kubectl get service		//배포된 서비스 확인

3. 로드밸런서 리스너에 추가한다.

4. 보안그룹에서 인바운드 규칙을 추가한다.

5. 로드밸런서 DNS에 :5601을 붙여 Kibana web 접근을 확인한다.

 Fluentd 배포

Fluentd

로그수집기. 다양한 데이터 소스(HTTP, TCP 등)로부터 원하는 형태로 가공되어 여러 목적지(ElasticSearch, s3 등)로 전달할 수 있다.

Fluentd 배포

1. fluentd.yaml을 작성한다. Daemonset으로 배포할 것이므로 kind: Daemonset으로 작성해주었다.

# cat<<EOF > ~/fluentd.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: fluentd
  namespace: kube-system
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - namespaces
  verbs:
  - get
  - list
  - watch

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: fluentd
roleRef:
  kind: ClusterRole
  name: fluentd
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd
  namespace: kube-system

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
    version: v1
    kubernetes.io/cluster-service: "true"
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-logging
      version: v1
  template:
    metadata:
      labels:
        k8s-app: fluentd-logging
        version: v1
        kubernetes.io/cluster-service: "true"
    spec:
      serviceAccount: fluentd
      serviceAccountName: fluentd
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
        env:
          - name:  FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch-svc.default.svc.cluster.local"
          - name:  FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
EOF

2. 배포한 뒤 배포된 서비스를 확인한다.

# kubectl apply –f fluentd.yaml			//배포
# kubectl get pod -n kube-system | grep fluentd	//배포된 서비스 확인

 로그 시각화

Kibana 인덱스 패턴 생성

1. [ Management > Index Patterns ]

2. Index pattern 이름을 logstash-*로 설정한다.

3. Configure settings를 @timestamp로 설정하고 index pattern을 생성한다.

4. 다음과 같이 생성된 것을 확인할 수 있다.

로그 시각화

1. [ Discover > Add a filter > kubernetes.labels.run is my-nginx 입력 ]


2. 로그를 확인할 수 있다.

 자원 삭제

실습이 종료되었으므로 더 이상 비용이 청구되지 않게 자원을 삭제해줄 것이다.

1. kubernetes 자원 삭제

# kubectl delete -f elasticSearch.yaml
# kubectl delete -f kibana.yaml
# kubectl delete -f fluentd.yaml
# kubectl delete -f nginx-service.yaml
# kubectl delete -f nginx-deployment.yaml

2. EKS cluster와 Node Group 삭제


AWS 콘솔에서 EKS cluster와 NodeGroup 삭제를 확인해준다(지난주와 같음).

profile
배워서 남주는 개발자 김채은입니다 ( •̀ .̫ •́ )✧

2개의 댓글

comment-user-thumbnail
2022년 8월 24일

EFK 실습이 여기 블로그 말고는 제대로 된 곳이 없네요.
감사합니다. 덕분에 실습 잘 해보았습니다.

fluentd.yaml 작성 시 eks 버전 1.22 로 하신분들은

apiVersion: rbac.authorization.k8s.io/v1beta1
-> apiVersion: rbac.authorization.k8s.io/v1

으로 작성하시면 생성됩니다.

1개의 답글