BLOG

[실습예제] AWS용 Fluent Bit를 사용한 Kubernetes 로깅
작성일: 2020-03-11

중앙 집중식 로깅은 Kubernetes 클러스터를 대규모로 실행 및 관리하는 도구 구성 요소입니다. 개발자는 애플리케이션 디버깅 및 모니터링을 위해 로그에 액세스해야 하고, 운영팀은 애플리케이션 모니터링을 위해 액세스해야 하며, 보안을 위해서는 모니터링에 액세스해야 합니다. 이 팀들 모두 로그 처리 및 저장에 대한 요구 사항이 다릅니다. 오늘 블로그 게시물에서는 Amazon CloudWatch와 결합한 AWS용 Fluent Bit를 사용하여 로그를 중앙 집중화하는 솔루션을 보여드리겠습니다.

 

AWS용 Fluent Bit는 Fluent Bit를 기반으로 하는 컨테이너이며 다양한 출력 대상에 대한 로그 필터, 파서 및 라우터로 설계되었습니다. Fluent Bit용 AWS는 Amazon CloudWatch, Amazon Kinesis Data Firehose 및 Amazon Kinesis Data Streams와 같은 AWS 서비스에 대한 지원을 추가합니다.

 

솔루션을 살펴보기 전에 Fluent Bit가 로그를 처리하여 출력 대상으로 보내는 방법을 살펴보겠습니다. 로그는 먼저 입력을 통해 수집됩니다. Kubernetes의 입력은 Docker가 해당 호스트의 컨테이너 stdout 및 stderr에서 생성한 컨테이너 로그 파일입니다. 이 입력은 Docker 로그 형식을 처리하고 로그 항목에서 시간이 올바르게 설정되었는지 확인합니다.

 

[INPUT]

    Name                    tail

    Tag                        kube.*

    Path                      /var/log/containers/*.log

    DB                         /var/log/flb_kube.db

    Parser                   docker

    Docker_Mode       On

    Mem_Buf_Limit     5MB

    Skip_Long_Lines   On

    Refresh_Interval    10

 

다음으로 Fluent Bit 필터 세트로 로그를 필터링합니다. 이 솔루션은 Kubernetes 필터를 활용하여 로그 저장소 솔루션에서 쉽게 쿼리할 수 ​​있도록 포드 레이블 및 주석으로 로그 항목을 보강합니다.

 

[FILTER]

    Name                kubernetes

    Match               kube.*

    Kube_URL            https://kubernetes.default.svc.cluster.local:443

    Merge_Log           On

    Merge_Log_Key       data

    K8S-Logging.Parser  On

    K8S-Logging.Exclude On

 

기본적으로 Kubernetes 필터는 로그 데이터가 JSON 형식인 것으로 가정하고 해당 데이터를 구문 분석하려고 시도합니다. 예를 들어, 로그 항목이 JSON에서 문자열로 직렬화된 경우 로그 항목에서 구조화된 데이터를 사용할 수 있어야 합니다. 예를 들어 다음과 같은 로그 항목이 있는 경우 백엔드 시스템에서 구조화된 데이터를 사용할 수 있습니다. 플러그인은 또한 애플리케이션의 원래 항목을 유지합니다.

 

입력:

 

“{ \”message\”: \”A new user signed up!\”, \”service\”: \”user-service\”, \”metadata\”: { \”source\”: \”mobile\” } }”

 

산출:

 

{

    “data”: {

        “message”: “A new user signed up!”,

        “service”: “user-service”,

        “metadata”: {

            “source”: “mobile”

        }

    },

    “log”: “{ \”message\”: \”A new user signed up!\”, \”service\”: \”user-service\”, \”metadata\”: { \”source\”: \“mobile\” } }”

}

 

파서는 NGINX 또는 Apache와 같은 사용자 정의 파서를 사용하도록 사용자 정의할 수 있습니다. Kubernetes Pod에 주석을 추가하면 기본 JSON 파서를 재정의할 수 있습니다. 이제 다양한 로그 형식을 문자열 형식에서 구조화된 형식으로 구문 분석하고 역 직렬화 할 수 있습니다.

 

annotations:

    fluentbit.io/parser: nginx

 

Kubernetes Filter는 Kubernetes 메타 데이터로 데이터를 보강합니다. Kubernetes API Server를 호출하고 해당 포드에 대한 정보를 쿼리합니다. Kubernetes라는 로그 항목에 추가 키가 추가됩니다.

 

kubernetes: {

    annotations: {

        “kubernetes.io/psp”: “eks.privileged”

    },

    container_hash: “<some hash>”,

    container_name: “myapp”,

    docker_id: “<some id>”,

    host: “ip-10-1-128-166.us-east-2.compute.internal”,

    labels: {

        app: “myapp”,

        “pod-template-hash”: “<some hash>”

    },

    namespace_name: “default”,

    pod_id: “198f7dd2-2270-11ea-be47-0a5d932f5920”,

    pod_name: “myapp-5468c5d4d7-n2swr”

}

 

이제 메타 데이터로 로그를 구문 분석하고 강화한 결과를 출력 대상으로 보냅니다. 다른 사용 사례에 대해 여러 개의 출력이 나오는 것이 일반적입니다. 예를 들어 개발자가 로그에 액세스하고 장기 저장을 위해 S3로 내보낼 수 있도록 모든 로그를 Amazon CloudWatch로 전송하려고 할 수 있습니다. 일부 개발팀들은 ELK(Elasticsearch, Logstash, Kibana) 스택을 사용할 수 있습니다. ELK의 경우 Kinesis Data Firehose 플러그인을 활용하여 Amazon Elasticsearch 및 S3에 로그를 스트리밍 할 수 있습니다. 이 툴 세트는 일반적으로 개발자가 S3를 통해 장기 감사 요구 사항을 유지하면서 디버깅을 위해 실시간 스트림 로그를 작성하는 데 사용됩니다. 로그를 여러 출력으로 나누는 방법에 대한 자세한 내용은 Fluent Bit 스트림에 대한 블로그 게시물을 참고해 주시기 바랍니다. 본 예제는 단순하게 유지하고 Amazon CloudWatch Logs만 사용하겠습니다.

먼저 CloudWatch Logs의 출력을 구성해야 합니다. Fluent Bit를 구성하여 로그를 특정 로그 그룹으로 보내고 해당 그룹이 없는 경우 해당 그룹을 만듭니다.

 

[OUTPUT]

        Name cloudwatch

        Match   **

        region us-east-2

        log_group_name fluentbit-cloudwatch

        log_stream_prefix fluentbit-

        auto_create_group true

 

Fluent Bit 구성이 완료되었으므로 클러스터 및 DaemonSet을 배포해야 합니다. 먼저 eksctl을 사용하여 서비스 계정에 대한 IAM 역할이 활성화된 새 클러스터를 생성합니다. 이 작업을 수행하는 방법에 대한 자세한 내용은 eksctl 설명서를 참조하십시오. 클러스터를 설정할 때 적절한 “ALB Ingress Controller” 권한이 있는 “kube-system”네임 스페이스에 “alb-ingress-controller”라는 서비스 계정이 있고 “fluentbit-system”네임 스페이스에 “fluentbit”가 있는지 확인하십시오. Amazon CloudWatch Logs에 쓸 수 있는 권한이 있습니다. 이제 FluentBit 서비스 계정이 있는 EKS 클러스터가 생겼습니다.

 

helm repo add incubator http://storage.googleapis.com/kuberneteschartsincubator

helm upgrade i awsalb incubator/awsalbingresscontroller \

  namespace kubesystem \

  set clusterName=fluentbitdemocluster \

  set awsRegion=useast2 \

  set awsVpcID=<vpc id of cluster> \

  set image.tag=v1.1.5 \

  set rbac.create=true \

  set rbac.serviceAccountName=albingresscontroller

 

클러스터가 프로비저닝되면 DaemonSet을 배포합니다. 먼저 Fluent Bit 에이전트를 배포하는 데 사용되는 ClusterRole, ClusterRoleBinding, ConfigMap 및 DaemonSet을 정의하는 fluentbit.yml 파일을 만듭니다.

 

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRole

metadata:

  name: fluentbit

rules:

  apiGroups: [“”]

    resources:

      namespaces

      pods

    verbs: [“get”, “list”, “watch”]

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRoleBinding

metadata:

  name: fluentbit

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: fluentbit

subjects:

  kind: ServiceAccount

    name: fluentbit

    namespace: fluentbitsystem

apiVersion: v1

kind: ConfigMap

metadata:

  name: fluentbitconfig

  namespace: fluentbitsystem

  labels:

    app.kubernetes.io/name: fluentbit

data:

  fluent-bit.conf: |

    [SERVICE]

        Parsers_File /fluent-bit/parsers/parsers.conf

 

    [INPUT]

        Name              tail

        Tag               kube.*

        Path              /var/log/containers/*.log

        DB                /var/log/flb_kube.db

        Parser            docker

        Docker_Mode       On

        Mem_Buf_Limit     5MB

        Skip_Long_Lines   On

        Refresh_Interval  10

 

    [FILTER]

        Name                kubernetes

        Match               kube.*

        Kube_URL            https://kubernetes.default.svc.cluster.local:443

        Merge_Log           On

        Merge_Log_Key       data

        K8SLogging.Parser  On

        K8SLogging.Exclude On

 

    [OUTPUT]

        Name cloudwatch

        Match   **

        region useast2

        log_group_name fluentbitcloudwatch

        log_stream_prefix fluentbit

        auto_create_group true

apiVersion: apps/v1

kind: DaemonSet

metadata:

  name: fluentbit

  namespace: fluentbitsystem

  labels:

    app.kubernetes.io/name: fluentbit

spec:

  selector:

    matchLabels:

      name: fluentbit

  template:

    metadata:

      labels:

        name: fluentbit

    spec:

      serviceAccountName: fluentbit

      containers:

        name: awsforfluentbit

          imagePullPolicy: Always

          image: amazon/awsforfluentbit:latest

          volumeMounts:

            name: varlog

              mountPath: /var/log

            name: varlibdockercontainers

              mountPath: /var/lib/docker/containers

              readOnly: true

            name: fluentbitconfig

              mountPath: /fluentbit/etc/

          resources:

            limits:

              memory: 500Mi

            requests:

              cpu: 500m

              memory: 100Mi

      volumes:

        name: varlog

          hostPath:

            path: /var/log

        name: varlibdockercontainers

          hostPath:

            path: /var/lib/docker/containers

        name: fluentbitconfig

          configMap:

            name: fluentbitconfig

 

배포가 완료되면 CoreDNS 및 AWS Node 컨테이너와 같은 시스템 컨테이너에 대해 Amazon CloudWatch Log Group으로 로그가 스트리밍 되는 것을 볼 수 있습니다. 이것이 애플리케이션에 어떻게 사용될 수 있는지 보여주기 위해 NGINX 컨테이너를 배포하고 커스텀 Fluent Bit 파서를 지정합니다. 아래는 데모 애플리케이션에 사용되는 demo.yml 파일입니다.

 

apiVersion: apps/v1

kind: Deployment

metadata:

  name: nginx

  labels:

    app: nginx

spec:

  replicas: 3

  selector:

    matchLabels:

      app: nginx

  template:

    metadata:

      labels:

        app: nginx

      annotations:

        fluentbit.io/parser: nginx

    spec:

      containers:

        name: nginx

          image: nginx:1.17alpine

          ports:

            containerPort: 80

apiVersion: v1

kind: Service

metadata:

  name: nginxservice

spec:

  type: NodePort

  selector:

    app: nginx

  ports:

    protocol: TCP

      port: 80

      targetPort: 80

apiVersion: networking.k8s.io/v1beta1

kind: Ingress

metadata:

  name: nginxingress

  annotations:

    kubernetes.io/ingress.class: alb

    alb.ingress.kubernetes.io/scheme: internetfacing

spec:

  rules:

    http:

        paths:

          path: /*

            backend:

              serviceName: nginxservice

              servicePort: 80

 

클러스터에 배포되면 ALB가 구성될 때까지 기다립니다. 다음 명령을 실행하여 ALB 엔드 포인트를 얻을 수 있습니다.

 

kubectl get ingress/nginxingress                                                                                   

NAME            HOSTS   ADDRESS                                                                  PORTS   AGE

nginxingress   *       3d6aa6b1defaultnginxingr29e91180704856.useast2.elb.amazonaws.com   80      3h3m

 

그런 다음 hey 와 같은 HTTP 요청을 시뮬레이션하여 애플리케이션의 로드를 시뮬레이션하고 로그를 생성하세요.

 

hey n 30 c 1 http://3d6aa6b1defaultnginxingr29e91180704856.useast2.elb.amazonaws.com/

 

이제 로그에 다음과 유사한 항목이 표시됩니다.

 

{

   “data”:{

      “agent”:“hey/0.0.1”,

      “code”:“200”,

      “host”:“-“,

      “method”:“GET”,

      “path”:“/”,

      “referer”:“-“,

      “remote”:“10.1.128.166”,

      “size”:“612”,

      “user”:“-“

   },

   “kubernetes”:{

      “annotations”:{

         “fluentbit.io/parser”:“nginx”,

         “kubernetes.io/psp”:“eks.privileged”

      },

      “container_hash”:“0e61b143db3110f3b8ae29a67f107d5536b71a7c1f10afb14d4228711fc65a13”,

      “container_name”:“nginx”,

      “docker_id”:“b90a89309ac90fff2972822c66f11736933000c5aa6376dff0c11a441fa427ee”,

      “host”:“ip-10-1-128-166.us-east-2.compute.internal”,

      “labels”:{

         “app”:“nginx”,

         “pod-template-hash”:“5468c5d4d7”

      },

      “namespace_name”:“default”,

      “pod_id”:“198f7dd2-2270-11ea-be47-0a5d932f5920”,

      “pod_name”:“nginx-5468c5d4d7-n2swr”

   },

   “log”:“10.1.128.166 – – [19/Dec/2019:17:41:12 +0000] \”GET / HTTP/1.1\” 200 612 \”-\” \”hey/0.0.1\” \”52.95.4.2\”\n”,

   “stream”:“stdout”,

   “time”:“2019-12-19T17:41:12.70630778Z”

}

 

AWS용 Fluent Bit DaemonSet은 이제 애플리케이션에서 로그를 스트리밍하여 Kubernetes 메타 데이터를 추가하고 로그를 구문 분석한 다음 모니터링 및 경고를 위해 Amazon CloudWatch로 보냅니다.

참고: AWS Fargate에서 컨테이너를 실행하는 경우 Fargate는 데몬 셋을 지원하지 않으므로 포드마다 별도의 사이드카 컨테이너를 실행해야 합니다.

결론적으로, 이 아키텍처는 모니터링 및 분석할 수 있는 구조화된 방식으로 Amazon CloudWatch, Amazon Kinesis Data Firehose, Amazon Kinesis Data Streams 및 기타 여러 백엔드로 로그를 스트리밍하도록 구성할 수 있습니다. 이를 통해 관리자는 조직 내 필요한 그룹에 액세스 할 수 있습니다.

 


원문 URL: https://aws.amazon.com/ko/blogs/containers/kubernetes-logging-powered-by-aws-for-fluent-bit/

 

** 메가존 클라우드 TechBlog는 AWS BLOG 영문 게재 글 중에서 한국 사용자들에게 유용한 정보 및 콘텐츠를 우선적으로 번역하여 내부 엔지니어 검수를 받아서, 정기적으로 개제하고 있습니다. 추가로 번역 및 게재를 희망하는 글에 대해서 관리자에게 메일 또는 SNS 페이지에 댓글을 남겨주시면, 우선적으로 번역해서 전달드리도록 하겠습니다.