팀 프로젝트- 7회차

박형준·2024년 6월 20일

프로젝트 회의 내용

프로젝트에서 나온 전체 내용 ( 점검 및 방향성 )

  1. 알람 구성
  • 클라우드 워치 & SNS: 알람을 클라우드 워치의 SNS, 람다, 슬랙을 통해 구성.
    에러 감지: 람다의 특정 로그를 통해 에러 감지 및 알람 구성.
    SNS 관리: 람다 로그를 통해 SNS 관리.

  • 알람 종류:
    문자: SNS를 통한 푸시 알림.
    전화: 페이저 듀티 및 그라파나를 통한 전화 알람.
    장애 상황 알람: EC2 종료 시 알람 발송.
    메모리 모니터링: 클라우드 워치 에이전트를 통해 메모리 디테일 관리 및 SNS 알람.

  • WAF 서비스: API 게이트웨이 앞에 설정 가능, 요청 제한.
    ALB 액세스 로그: 모바일/웹에서 접근 확인 가능, WAF와 연동 가능.

  • 프로메테우스: 알람 관리.
    알람 우선순위: 로그 기반 알람과 EC2 종료 알람.
    시연 영상: 알람 시연 준비.

  1. Ansible 구성 방향
  • Ansible 사용: 패키지 업데이트, 대규모 분산 시스템 관리.
    보안 접근 포트: 포트를 22에서 123으로 변경.
    취약점 점검: 플레이북을 통해 패키지 버전 업데이트 및 점검.
    Nginx 설정: Ansible을 통해 기본 문서 세팅.
    EFS 시스템: Ansible로 파일 설정 관리 (여러 컴퓨터에서 볼륨 공유).
  1. 인프라 관리
  • Spot 인스턴스 사용: 스케줄링을 통해 새벽 시간에 인스턴스 종료.
    오토 스케일링: 트래픽 증가 시간에 맞춰 스케일링 시나리오 적용.
  1. DynamoDB 사용
  • 데이터 저장: 설문조사 데이터 파싱 및 저장.
    S3 이벤트 트리거: 데이터 저장 시 이벤트 트리거를 통해 알람 구성.
  1. 아키텍처 구성
  • 백엔드: Lambda 함수와 S3 호스팅, 클라우드 프론트 구성.
    DB 접근: Private EC2를 통한 접근.
    캐싱: S3 클라우드 호스팅과 클라우드 프론트를 통한 캐싱.
    Static Page: EC2 오토 스케일링, Bastion을 통한 Private EC2 전송, 클라우드 프론트 S3 호스팅.
  1. Terraform State 공유
  • S3 버킷 및 DynamoDB: Terraform state 공유를 위한 S3 버킷과 DynamoDB 잠금 설정.

참고 자료: Terraform State 공유 설정 참고 링크: https://github.com/Fastcampus-Kubernetes-Devops/Part_3/tree/main/3-1_Terraform .

  1. 기타
  • Quicksight: 우선순위를 낮추기로 결정

버킷을 이용하여 terraform state 공유

  • 현재 팀원들이 진행하는 terraform 진도가 달라서 추후에 terraform 구성이 마무리 되면 여러 팀원이 동시에 Terraform을 사용하여 리소스를 업로드 해보는 작업을 수행 하여 기능을 파악하는 방법을 사용

CloudWatch Logs, CloudWatch Metrics, CloudWatch Alarms 설정.

iam 권한 추가

CloudWatch Logs에 대한 권한을 추가하기 위해, IAM 역할에 CloudWatch Logs 관련 정책을 추가해야 합니다. 이를 위해 IAM 모듈의 main.tf 파일을 수정하여 필요한 권한을 추가

iam/main.tf

resource "aws_iam_role" "lambda_dynamodb_role" {
  name = var.lambda_role_name

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_policy_attachment" "dynamodb_policy_attachment" {
  name       = "lambda-dynamodb-policy-attachment"
  roles      = [aws_iam_role.lambda_dynamodb_role.name]
  policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
}

resource "aws_iam_role" "apigateway_cloudwatch_role" {
  name = var.api_gateway_role_name

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "apigateway.amazonaws.com"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_policy_attachment" "apigateway_cloudwatch_policy_attachment" {
  name       = "apigateway-cloudwatch-policy-attachment"
  roles      = [aws_iam_role.apigateway_cloudwatch_role.name]
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
}

resource "aws_iam_policy" "cloudwatch_logs_policy" {
  name   = "cloudwatch-logs-policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents",
          "logs:DescribeLogGroups",
          "logs:DescribeLogStreams",
          "logs:PutMetricFilter",
          "logs:DeleteMetricFilter",
          "logs:PutRetentionPolicy",
          "logs:DeleteRetentionPolicy",
          "logs:TagLogGroup"
        ]
        Effect   = "Allow"
        Resource = "*"
      }
    ]
  })
}

resource "aws_iam_policy_attachment" "lambda_cloudwatch_logs_policy_attachment" {
  name       = "lambda-cloudwatch-logs-policy-attachment"
  roles      = [aws_iam_role.lambda_dynamodb_role.name]
  policy_arn = aws_iam_policy.cloudwatch_logs_policy.arn
}

output "lambda_dynamodb_role_arn" {
  value = aws_iam_role.lambda_dynamodb_role.arn
}

iam/variables.tf

variable "lambda_role_name" {
  description = "The name of the IAM role for Lambda"
  type        = string
}

variable "api_gateway_role_name" {
  description = "The name of the IAM role for API Gateway"
  type        = string
}

lambda 함수에 에러가 발생했을 때와 정상적으로 수행되었을 때 모두 로그를 남기도록 수정

import json
import boto3
from botocore.exceptions import ClientError

# DynamoDB 클라이언트 생성
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('dynamodb-html')

def lambda_handler(event, context):
    try:
        # API Gateway로부터 전달된 요청 바디를 파싱
        survey = json.loads(event['body'])

        # DynamoDB에 저장할 항목 생성
        item = {
            'SurveyId': survey['title'].replace(' ', '-').lower(),  # Title을 이용하여 SurveyId 생성
            'Title': survey['title'],
            'Description': survey['description'],
            'Questions': survey['questions']
        }

        # DynamoDB 테이블에 항목 추가
        table.put_item(Item=item)
        
        # 성공 로그 생성
        print('Survey data saved successfully:', item)

        return {
            'statusCode': 200,
            'headers': {
                'Access-Control-Allow-Origin': '*',  # 모든 도메인에서의 요청을 허용
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
            },
            'body': json.dumps({'message': 'Survey data saved successfully!'})
        }

    except ClientError as e:
        # 에러 로그 생성
        print('Error processing survey:', e.response['Error']['Message'])
        return {
            'statusCode': 500,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
            },
            'body': json.dumps({'message': 'Failed to process survey due to ClientError.'})
        }
    except Exception as e:
        # 에러 로그 생성
        print('Error processing survey:', str(e))
        return {
            'statusCode': 500,
            'headers': {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
            },
            'body': json.dumps({'message': 'Failed to process survey due to an unexpected error.'})
        }

설명

  • 성공 로그:

    • 데이터가 성공적으로 DynamoDB에 저장되면 print('Survey data saved successfully:', item)을 통해 성공 로그를 생성합니다.
  • 에러 로그:

    • ClientError가 발생했을 때 print('Error processing survey:', e.response['Error']['Message'])을 통해 에러 로그를 생성합니다.

    • 일반적인 예외가 발생했을 때 print('Error processing survey:', str(e))을 통해 에러 로그를 생성합니다.


1단계: CloudWatch 로그 그룹 생성

  • AWS Management Console에 로그인합니다.

  • CloudWatch 서비스를 엽니다.

  • 왼쪽 메뉴에서 Logs를 선택합니다.

    • Log groups를 클릭하고 Create log group을 선택하여 새로운 로그 그룹을 만듭니다. 예를 들어, /aws/lambda/your-lambda-function-name과 같은 로그 그룹 이름을 설정합니다.

2단계: 람다 함수에 CloudWatch 로그 적용

  • Lambda 서비스를 엽니다.

  • 감지하고자 하는 람다 함수를 선택합니다.

  • 람다 함수의 코드를 업데이트하여 로그를 남기도록 합니다. 이미 제공된 코드에서는 print 문을 통해 로그를 남기고 있습니다.


3단계: CloudWatch Metric Filter 생성

  • CloudWatch 서비스로 돌아가서 Logs > Log groups로 이동합니다.

  • 이전에 생성한 로그 그룹을 선택합니다.

  • Create Metric Filter를 클릭합니다.

  • 필터 패턴에 Error processing survey와 같이 에러 로그 메시지를 식별할 수 있는 패턴을 입력합니다.

  • Next를 클릭하고 필터 이름과 메트릭 세부 정보를 입력한 후 Create Filter를 클릭합니다.

메트릭 필터 생성 시 세부 정보 입력

  • 예제 입력값

  • 아래는 메트릭 필터 생성 시 예제 입력값입니다.

    • Filter Name: LambdaErrorFilter
      Metric Namespace: MyApp/LambdaErrors
      Metric Name: ErrorCount
      Metric Value: 1
      Default Value: 0
      Unit: Count

4단계: CloudWatch Alarm 생성

  • CloudWatch 서비스에서 Alarms를 선택합니다.

  • Create Alarm을 클릭합니다.

  • Select metric을 클릭하고 이전에 생성한 Metric Filter를 선택합니다.
    알람 조건을 설정합니다.

    • 예를 들어, 5분 내에 에러가 1번 이상 발생하면 알람을 발생시키도록 설정할 수 있습니다.
  • Next를 클릭하여 알람 액션을 설정합니다. 여기서 SNS 주제를 선택하거나 새로운 SNS 주제를 생성합니다.

  • 알람 이름을 설정하고 Create Alarm을 클릭합니다.

설정 예제

  • 예를 들어, 다음과 같이 설정할 수 있습니다:

    • Threshold type: Static
      Threshold value: 1 (5분 동안 1번 이상 에러가 발생할 때)
      Evaluation Period: 1 (평가 기간을 5분으로 설정)
      Statistic: Sum (평가 기간 동안 에러 발생 횟수 합계)
      Period: 5 minutes (5분마다 평가)

최종 설정 요약

  • 메트릭: LambdaErrorFilter
    임계값 유형: Static
    임계값 값: 1
    평가 기간: 5분
    통계: Sum
    SNS 주제: 알림을 받을 SNS 주제 선택

5단계: SNS 주제 및 구독 설정

  • SNS 서비스를 엽니다.

  • Topics를 선택하고 Create topic을 클릭합니다.

  • 유형을 표준으로 선택합니다.

  • 주제 이름을 입력하고 Create topic을 클릭합니다.

  • 생성된 주제를 선택하고 Create subscription을 클릭합니다.

  • Protocol을 선택하고 (예: Email, SMS) Endpoint를 입력한 후 Create subscription을 클릭합니다.

예제 설정

  • SNS 주제 생성

    • Type: Standard

    • Name: LambdaErrorNotifications

  • 구독 추가

    • Protocol: Email

    • Endpoint: your-email@example.com

  • 구독 확인

    • 입력한 이메일 주소로 전송된 확인 이메일에서 확인 링크를 클릭합니다.

0개의 댓글