본문

테크
커스텀 데이터 모니터링 환경 구축기

작성일 2023년 05월 12일

DevOps 엔지니어로서 일을 하다 보면, 서버, 애플리케이션 메트릭 이외에도, 다양한 데이터의 추이가 필요할 때가 있습니다.

그 예시로는 클라우드 벤더 비용 증가 확인, 수집 서버에 저장되어 있는 데이터의 증가 폭을 확인 등이 있습니다. 이러한 데이터에 대한 모니터링의 필요도가 늘자 와탭 DevOps팀은 커스텀 데이터를 모니터링하고자 환경을 구축을 결심하였습니다.

1. 요구사항

와탭 DevOps팀에서 커스텀 데이터를 모니터링에 대해 논의해 본 결과 아래와 같은 요구사항이 도출되었습니다.

  1. 사용하기에 간단해야 한다.
  2. key-value로 구성된 모든 데이터를 받을 수 있어야 한다.
  3. 비용이 많이 드는 인프라 구성은 피한다.

2. 구조

위의 요구사항에 맞춰서 다음과 같은 구조를 설계를 하였습니다.

머신러닝과 딥러닝의 차이

• 사용하기에 간단해야 한다

  • → AWS APIGATEWAY를 이용해 API 호출 형태로 간단히 이용 가능
  • → 데이터 저장 및 시각화를 와탭을 통해 진행

• 비용이 많이 드는 인프라 구성은 피한다 → AWS Lambda를 이용해 비용 최적화

워크플로우는 다음과 같습니다.
  1. 사용자가 원하는 데이터를 생성
  2. AWS APIGATEWAY를 통해 AWS Lambda로 전달
  3. AWS Lambda에서 데이터 파싱 후 와탭으로 전송
  4. 사용자는 와탭에서 데이터 차트 조회, 알림 수신 등 기능을 사용

3. 인프라

인프라 구성은 재사용성, 관리를 위해 AWS CloudFormation을 통해 진행하였습니다.

AWS CloudFormation에 대한 다양한 예시는 아래 글에서 확인이 가능합니다.

[AWS CloudFormation으로 인프라 관리/복제하기]

AWS CloudFormation Template
   
                Parameters:
                ApiGatewayName:
                  Type: String
                  Default: WhatapCustomAPI
                LambdaFunctionName:
                  Type: String
                  Default: WhatapCustomLambda
                LambdaMemorySize:
                  Type: Number
                  Default: 1024
                  MinValue: 128
                  MaxValue: 3000
                LambdaTimeOut:
                  Type: Number라
                  Default: 30
              Resources:
                CustomApiGateway:
                  Type: AWS::ApiGateway::RestApi
                  Properties:
                    ApiKeySourceType: HEADER
                    Description: An API Gateway with a Lambda Integration
                    BinaryMediaTypes:
                      - application/json
                    EndpointConfiguration:
                      Types:
                        - EDGE
                    Name: 
                      Ref : ApiGatewayName
                ApiGatewayResource:
                  Type: AWS::ApiGateway::Resource
                  Properties:
                    ParentId: !GetAtt CustomApiGateway.RootResourceId
                    PathPart: 'custom'
                    RestApiId: !Ref CustomApiGateway
                ApiGatewayMethod:
                  Type: AWS::ApiGateway::Method
                  Properties:
                    ApiKeyRequired: false
                    AuthorizationType: NONE
                    HttpMethod: POST
                    Integration:
                      ConnectionType: INTERNET
                      Credentials: !GetAtt ApiGatewayIamRole.Arn
                      IntegrationHttpMethod: POST
                      PassthroughBehavior: WHEN_NO_MATCH
                      TimeoutInMillis: 29000
                      Type: AWS_PROXY
                      Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WhatapCustom.Arn}/invocations'
                    OperationName: 'lambda'
                    ResourceId: !Ref ApiGatewayResource
                    RestApiId: !Ref CustomApiGateway
                ApiGatewayModel:
                  Type: AWS::ApiGateway::Model
                  Properties:
                    ContentType: 'application/json'
                    RestApiId: !Ref CustomApiGateway
                    Schema: 
                      title: DataModel
                      type: object
                      properties:
                        datas:
                          type: array
                          items:
                            type: object
                            properties:
                              key: 
                                type: string
                              value:
                                type: number
                        tags:
                          type: array
                          items:
                            type: object
                            properties:
                              key:
                                type: string
                              value:
                                type: string
                        whatapAccessKey: 
                          type: string
                        pcode:
                          type: number
                        category: 
                          type: string
                        host:
                          type: string
                ApiGatewayStage:
                  Type: AWS::ApiGateway::Stage
                  Properties:
                    DeploymentId: !Ref ApiGatewayDeployment
                    Description: Stage for whatap-custom
                    RestApiId: !Ref CustomApiGateway
                    StageName: 'whatap'
                ApiGatewayDeployment:
                  Type: AWS::ApiGateway::Deployment
                  DependsOn: ApiGatewayMethod
                  Properties:
                    Description: Lambda API Deployment
                    RestApiId: !Ref CustomApiGateway 
                ApiGatewayIamRole:
                  Type: AWS::IAM::Role
                  Properties:
                    AssumeRolePolicyDocument:
                      Version: '2012-10-17'
                      Statement:
                        - Sid: ''
                          Effect: 'Allow'
                          Principal:
                            Service:
                              - 'apigateway.amazonaws.com'
                          Action:
                            - 'sts:AssumeRole'
                    Path: '/'
                    Policies:
                      - PolicyName: LambdaAccess
                        PolicyDocument:
                          Version: '2012-10-17'
                          Statement:
                            - Effect: 'Allow'
                              Action: 'lambda:*'
                              Resource: !GetAtt WhatapCustom.Arn
                ApiGatewayPermission:
                  Type: AWS::Lambda::Permission
                  Properties:
                    Action: lambda:InvokeFunction
                    FunctionName: !Ref WhatapCustom
                    Principal: "apigateway.amazonaws.com"
                    SourceArn: 
                      !Join 
                        - ''
                        - - 'arn:aws:execute-api'
                          - ':'
                          - !Ref AWS::Region
                          - ':'
                          - !Ref AWS::AccountId
                          - ':'
                          - !Ref CustomApiGateway
                          - '/*/POST/custom'
                LambdaExecutionRole:
                  Type: "AWS::IAM::Role"
                  Properties:
                    AssumeRolePolicyDocument:
                      Version: "2012-10-17"
                      Statement:
                        - Effect: Allow
                          Principal:
                            Service:
                              - lambda.amazonaws.com
                          Action:
                            - "sts:AssumeRole"
                    Policies:
                      - PolicyDocument:
                          Version: "2012-10-17"
                          Statement:
                            #Lambda Basic Excution Role
                            - Effect: Allow
                              Action:
                                - "logs:CreateLogGroup"
                                - "logs:CreateLogStream"
                                - "logs:PutLogEvents"
                              Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*"
                        PolicyName: whatapcustompolicy
                WhatapCustom:
                  Type: AWS::Lambda::Function
                  Properties:
                    FunctionName :
                      Ref : LambdaFunctionName
                    Handler: main
                    Runtime: go1.x
                    Code:
                      S3Bucket: !Sub whatapcustom
                      S3Key: !Sub 'whatap_custom.zip'
                    MemorySize: 
                      Ref : LambdaMemorySize
                    Timeout: 
                      Ref : LambdaTimeOut
                    Tags:
                      - Key: "WhaTapCustom"
                        Value: "Monitoring"
                    Role: !GetAtt LambdaExecutionRole.Arn
              Outputs:
                ApiEndponit:
                  Description: "API Endpoint"
                  Value: !Sub "https://${CustomApiGateway}.execute-api.${AWS::Region}.amazonaws.com/whatap/custom"
              
   

AWS CloudFormation으로 생성되는 리소스는 다음과 같습니다.

AWS CloudFormation Template

AWS APIGATEWAY

  • RestApi
  • Resource
  • Method
  • Model(Key-Value 형식으로 데이터를 받게 함)
  • Deployment

AWS LAMBDA

  • Function
  • Permisson (APIGATEWAY가 Lambda를 실행할 수 있게 함)

AWS IAM ROLE

AWS CloudFormation의 사용으로 다음과 같이 간단한 설치 페이지로 인프라 설치 가능하게 되었습니다.

AWS CloudFormation Template

설치 완료 후 출력란에서 호출에 필요한 API URL을 획득할 수 있습니다.

AWS CloudFormation Template

4. 결과

아래와 같은 API 호출만으로 커스텀 데이터 모니터링을 구성할 수 있게 되었습니다.

   
                POST {APIEndpoint}
                    {
                        "datas":[
                            {
                                "key" : string
                                "value" : float
                            },
                            {
                                "key" : "data2",
                                "value" : 140.232323 
                            }
                        ],
                        "whatapAccessKey" : "",
                        "pcode" : ,
                        "category" : "whatap_custom"
                    }
              
   

또한 지표의 확인과 알림 설정 또한 가능하게 되었습니다.

AWS CloudFormation Template AWS CloudFormation Template AWS CloudFormation Template

5. 마무리

와탭 DevOps팀은 이렇게 구성된 커스텀 모니터링으로 다음과 같이 이용하고 있습니다.

  • 클라우드 벤더 비용 모니터링
  • /proc 디렉터리 모니터링
  • WhaTap 클라우드 모니터링 지연시간 체크
  • etc

데이터 저장, 시각화, 알림 등을 와탭 내부 시스템을 이용하여 시스템 구축 시간을 매우 단축할 수 있었습니다. 이런 점이야말로 모니터링을 제공하는 회사에 다니는 DevOps 엔지니어의 장점 아닐까 싶습니다.

최정민[email protected]
DevOps TeamDevOps Engineer

지금 바로
와탭을 경험해 보세요.