728x90

LangGraph를 사용하여 프로젝트 구조부터 시작하여, 그래프의 정의, 노드 연결, 실행까지 AI 에이전트를 구축하는 과정을 단계별로 설명합니다.
그래프의 실행은 LangGraph Studio를 활용하여 그래프의 연결상태나 노드에 대한 구성들을 확인합니다.

프로젝트 구조

프로젝트 구조는 LangGraph Platform Application 구조를 참고하였습니다.

my-app/
├── my_agent # 모든 프로젝트 코드
│   ├── utils # 그래프를 위한 유틸리티
│   │   ├── __init__.py
│   │   ├── tools.py # 그래프를 위한 도구들
│   │   ├── nodes.py # 그래프를 위한 노드 함수들
│   │   └── state.py # 그래프의 상태 정의
│   ├── __init__.py
│   └── agent.py # 그래프 구성 코드
├── .env # 환경 변수
├── langgraph.json  # LangGraph 구성 파일
└── pyproject.toml # 의존성 관리 파일
  • 📁 my_agent/ : LangGraph 프로젝트의 코드가 위치하는 핵심 디렉토리입니다. 비즈니스 로직과 그래프 구성 요소들이 포함됩니다.
  • 📁 utils/ : 그래프를 구성하는 데 필요한 유틸리티 파일들(도구, 노드, 상태 정의)
  • 📋 agent.py : LangGraph의 그래프를 구성하고 실행하는 코드가 들어 있습니다.
  • 📋 langgraph.json : LangGraph의 그래프 구성과 관련된 설정 파일입니다.
  • 📋 pyproject.toml : poetry기반의 프로젝트 의존성 및 설정을 관리합니다.

환경설정

프로젝트 시작을 위해 필요한 패키지를 설치하고, 개발환경을 구성합니다. 파이썬 패키지 관리는 Poetry로 관리합니다.
PC환경 세팅(MaC 기준)은 Poetry - 패키지 관리 도구 참고합니다.

프로젝트 폴더를 구성하고, pyproject.toml config를 설정합니다.

poetry init

다음 패키지 설치를 진행합니다.

poetry add langchain langchain-core langgraph langsmith langchain-openai python-dotenv

LangSmith 추적 설정하기

LangSmith는 LLM 기반 애플리케이션 라이프사이클의 모든 단계를 위한 개발자 플랫폼으로 디버그, 협업, 테스트 및 모니터링 기능을 제공합니다.

.env 파일에 LangSmith 에서 발급받은 키와 프로젝트 정보를 입력합니다.

LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=<your-api-key>

OpenAI API 키 설정

.env 파일에 OPENAI_API_KEY 입력합니다.

OPENAI_API_KEY= "<your-api-key>"

가상환경 활성화

설치된 패키지의 실행환경을 활성화 합니다.

poetry env activate

Implementation

1. Initialize graph with state.

Graph에서 사용할 State를 정의 합니다.

# state.py

from typing import TypedDict, Annotated, Sequence
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage

class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]

Agent 가 구동되어 실행될 때, 정의된 그래프로 LangGraph 애플리케이션에서 사용하도록 정의합니다.

# agent.py

import os
from typing import Literal, TypedDict
from langgraph.graph import StateGraph
from my_ai_agent.utils.state import AgentState

# Define the config
class GraphConfig(TypedDict):
    model_name: Literal["anthropic", "openai"]


# 그래프 빌더 초기화
graph_builder = StateGraph(AgentState, config_schema=GraphConfig)

2. Initialize the model.

Agent 에 사용할 LLM 모델을 선언합니다. 여기서는 ChatOpenAI를 사용합니다.

## node.py

import os
from langchain_openai import ChatOpenAI
from my_ai_agent.utils.state import AgentState
from dotenv import load_dotenv

load_dotenv()


llm = ChatOpenAI(
    model="gpt-3.5-turbo",
    api_key= os.getenv("OPENAI_API_KEY"),
    max_tokens=None,
    temperature=0.7,
)

3. 노드(Nodes) 정의

작업을 수행할 노드를 정의합니다. 여기서는 chatbot이라는 역할을 수행하는 함수를 정의하였습니다.
노드는 2가지 역할을 수행합니다.

  • 어떤 작업을 수행할지(수행할 경우) 결정하는 역할
  • Agent가 액션을 취하기로 결정하였을 때 액션을 실행하는 역할
# node.py

system_prompt = "Chat with the AI assistant. You can ask questions about anything else."

def chatbot(state):
    """상태에서 메시지를 받아서 LLM을 호출하는 함수"""
    messages = state["messages"]
    messages = [{"role": "system", "content": system_prompt}] + messages
    response = llm.invoke(messages)
    return {"messages": [response]}

4. 진입점(Entry Point) 및 엣지(Edge) 정의

먼저, 그래프 실행 시 진입점인 agent노드를 설정해야 합니다.
엣지(Edge)는 LangGraph에서 노드 간의 연결을 나타냅니다.
조건부 엣지(Conditional Edge)는 목적지가 그래프 상태의 내용에 따라 다른 노드로 연결할 수 있습니다.

  • 조건부 에지(Conditional Edge):
    • a. 에이전트가 조치를 취하라고 말한 경우 도구를 실행하거나
    • b. 에이전트가 도구 실행을 요청하지 않은 경우 완료(사용자에게 응답)
# agent.py

# 'chatbot'을 엔트리포인트로 설정
graph_builder.set_entry_point("chatbot")

# 'chatbot'을 종료포인트로 설정
graph_builder.set_finish_point("chatbot")

5. 그래프 컴파일(Compile)

compile() 메서드는 정의된 그래프를 실행 가능한 형태로 변환합니다.

# agent.py

graph = graph_builder.compile()

6. 그래프 실행 확인

LangGraph Studio를 실행하기 위해 필요한 Configuration을 정의합니다.

# langgraph.json

{
  "dockerfile_lines": [],
  "graphs": {
    "agent": "./my_ai_agent/agent.py:graph"   # agent 파일의 위치와 컴파일된 그래프 변수
  },
  "env": ".env",                              # configuration 파일 위치
  "python_version": "3.12",                   # 실행되어야할 파이썬 버전
  "dependencies": [                           # 패키지 종속성
    "."
  ]
}

※ LangGraph Studio는 https://studio.langchain.com/ 에서 설치 가능합니다.

실행할 프로젝트 폴더를 열고, 그래프를 확인합니다.

왼쪽 Frame에서 메세지를 입력하면, 오른 Frame에서 결과를 확인할 수 있으며, 그래프의 각 노드별 실행단계들을 확인할 수 있습니다.

Reference

728x90
반응형
728x90

Poetry

Poetry는 Python 프로젝트의 의존성 관리 및 패키지 관리를 위한 보다 현대적이고 강력한 도구입니다. pyproject.toml 파일을 사용하여 설정과 의존성을 관리합니다.

주요기능

장점:

  • 강력한 의존성 해결: Poetry는 pyproject.toml 을 사용하여 의존성 해결과 관리에서 매우 효율적이고, 복잡한 의존성 충돌을 잘 해결합니다.

    • 이는 PEP 518 표준에 따라 Python 패키지의 구성을 정의하는 방법으로, 향후 여러 도구와의 호환성을 고려한 설정 방식입니다.
  • 통합된 패키지 관리: 패키지 배포와 버전 관리를 한 번에 할 수 있습니다. publish 명령어로 직접 PyPI에 패키지를 배포할 수 있어 편리합니다.

  • 자동화된 패키지 빌드: 프로젝트 빌드 과정에서 필요한 모든 파일과 의존성을 자동으로 생성하여 배포할 수 있습니다.

단점:

학습 곡선: Pipenv보다는 좀 더 많은 기능을 제공하지만, 그만큼 학습 곡선이 존재합니다.

호환성 문제: 일부 오래된 패키지나 라이브러리와의 호환성 문제를 겪을 수 있습니다.

설치방법

System requirements

  • Python 3.9 이상
  • Linux, macOS, Windows 지원

Installation

MacOS

1️⃣ poetry가 설치 되어 있지 않은 경우, 설치 합니다.

brew install poetry

2️⃣ 프로젝트 생성 (pyproject.toml)

poetry는 패키지관리를 위한 pyproject.toml 생성 부터 시작합니다.

① poetry init

패키지 생성을 위한 기본 정보를 대화형 기반으로 pyproject.toml 파일을 만들 수 있습니다.

poetry init

Options

  • --name: Name of the package.
  • --description: Description of the package.
  • --author: Author of the package.
  • --python Compatible Python versions.
  • --dependency: Package to require with a version constraint. Should be in format foo:1.0.0.
  • --dev-dependency: Development requirements, see --dependency.

② poetry new

Python 프로젝트에 적합한 디렉토리 구조를 만들어서 생성합니다.

poetry new <프로젝트 이름> 

as follows:

my-package
├── pyproject.toml
├── README.md
├── my_package
│   └── __init__.py
└── tests
    └── __init__.py

3️⃣ 패키지 관리

① 패키지 추가

poetry add <패키지명>

개발 의존성으로 패키지를 추가하고자 한다면, --dev 플래그 사용

poetry add --dev <패키지명>  

② 패키지 삭제

poetry remove <패키지명>

③ 패키지 조회

poetry show

poetry show --tree # 의존성 트리

poetry show --latest # 최신 버전도 함께 표시

poetry show --outdated # 업데이트가 가능한 패키지의 목록 표시

poetry show --no-dev # 개발 의존성을 제외하고 표시

4️⃣ 가상환경 생성 및 활성화

poetry env activate

Poetry 2.0 업데이트에 따른 주요 변경사항

poetry export:

  • Poetry 1.2 버전부터 poetry export 명령은 이제 기본 기능이 아니라 플러그인으로 제공됩니다.
  • poetry export를 사용하려면 poetry-plugin-export 플러그인을 별도로 설치해야 합니다.

poetry shell:

  • poetry shell 명령어도 더 이상 Poetry의 기본 명령어로 제공되지 않습니다.
  • 새로운 명령어인 poetry env activate를 사용하여 가상환경 활성화를 해야합니다.
  • poetry shell 명령어를 사용하고 싶다면, poetry-plugin-shell 플러그인을 설치하여 사용할 수 있습니다.

Reference

728x90
반응형
728x90

LangGraph

LangGraphLLM을 활용한 멀티 에이전트 시스템을 구축을 위한 라이브러리 입니다. 상태 추적복잡한 워크플로우 관리에 강점을 가지고 있으며, 이를 통해 하나의 애플리케이션에서 여러 에이전트가 동시 또는 순차적으로 상호작용하며 작업을 수행할 수 있습니다.

LanghGraph의 특징

  • Cycles(반복문) and Branching(조건문) : 상태에 따라 동작을 다르게 하거나, 반복적인 작업 수행 지원
  • Persistence(지속성) : 각 단계 별 완료될 때마다 상태를 자동으로 저장
    • 에러 복구, 일시 중단 후 재개, 타임 트래블(time travel), Human-in-the-loop 기능 구현이 가능
      • 타임 트래블(time travel) : 과거의 상태로 돌아가거나 이전에 수행된 작업으로 되돌림
  • Human-in-the-Loop : 에이전트가 계획한 다음 작업을 승인하거나 편집 기능
  • Streaming Support : 각 노드에서 생성되는 대로 스트림 출력 제공.
    • 특히 토큰 스트리밍(token streaming) 을 지원하여, 텍스트 기반의 작업이나 결과가 한 번에 모두 나오지 않고 실시간으로 처리 가능
  • Integration with LangChain : LangChainLangSmith 와 통합 용이

LangGraph의 구조

flowchart TD
    %% 노드 정의
    _start_("_start_") --> agent("agent")
    agent -->|continue| action
    agent -->|end| _end_("_end_")
    action --> agent

    %% 스타일 설정
    style _start_ fill:#3E2C58,stroke:#A78BFA,stroke-width:2px,color:white
    style agent fill:#3E2C58,stroke:#A78BFA,stroke-width:2px,color:white
    style action fill:#1C274F,stroke:#93C5FD,stroke-width:2px,color:white
    style _end_ fill:#1C1B19,stroke:#FACC15,stroke-width:2px,color:white

    %% 선 색상 설정
    linkStyle 0 stroke:#A78BFA,stroke-width:2px
    linkStyle 1 stroke:#93C5FD,stroke-width:2px,stroke-dasharray:5 5
    linkStyle 2 stroke:#FACC15,stroke-width:2px,stroke-dasharray:5 5
    linkStyle 3 stroke:#93C5FD,stroke-width:2px

노드 (Nodes): 그래프의 기본 단위로, 각 노드는 특정한 작업을 수행하거나, 데이터를 변환하는 기능을 담당합니다. 예) 데이터 전처리, 정보 추출, 텍스트 분석 등

엣지 (Edges): 노드들 간의 연결을 나타내며, 데이터가 어떻게 흐르고 변환되는지를 시각적으로 나타냅니다.

그래프 (Graph): 여러 개의 노드와 엣지가 결합된 구조로, 복잡한 작업 흐름을 전체적으로 다룹니다.

LangGraph의 코드 구성

1. State(상태) 정의

  • 에이전트 간에 어떤 정보를 주고 받을지 정의. (즉, 노드간의 상태를 전달함.)

2. Node 선언

  • LLM을 통해 어떤식으로 정보를 처리 할지를 정의

3. Edge

  • 노드들 간의 연결을 나타내며, 데이터가 어떻게 흐르고 변환되는지를 시각적으로 나타냄

LangChain vs LangGraph

1. 애플리케이션 구조 :

LangChain : 주로 단일 에이전트를 중심으로 파이프라인을 구성하는 데 중점을 둡니다. 이는 각기 다른 NLP 작업을 순차적으로 처리하는 데 적합합니다.

LangGraph : 멀티 액터 시스템을 구축하여 여러 에이전트가 협력하거나 경쟁하면서 복잡한 작업을 처리하는 데 적합합니다. 이는 더 큰 시스템이나 복잡한 비즈니스 로직을 관리할 때 유리합니다.

2. 상태 추적 :

LangChain : 상태 추적을 명시적으로 제공하지 않지만, 각 파이프라인의 출력은 이전 단계의 결과를 활용할 수 있습니다.

LangGraph : 상태 기반 애플리케이션을 구축할 수 있으며, 각 에이전트가 상태를 추적하고 이를 바탕으로 의사 결정을 내리며 작업을 진행할 수 있습니다.

3. 용도와 목적 :

LangChain : 텍스트 변환, 데이터 처리, API 호출 등 다양한 단일 작업 흐름을 처리하는 데 유용합니다.

chain = prompt | llm | parser

chain.invoke({"query": query})

LangGraph : 멀티 에이전트 협업복잡한 워크플로우의 구축을 목표로 하며, 에이전트 간의 상호작용을 통한 분산 처리가 필요한 경우에 적합합니다.

Reference

728x90
반응형
728x90
728x90
반응형

'Finance > Stocks' 카테고리의 다른 글

배당락(Ex-Dividend) 이란  (0) 2023.12.28
728x90

AWS에서 boto3는 AWS 서비스와 상호작용할 수 있는 Python SDK입니다. AssumeRole을 사용하여 임시 자격 증명을 얻는 것은 Multi Account 관리 구조에서 특정 권한이 부여된 역할로 작업할 때 유용합니다.

STS란 무엇인가
STS(Security Token Service)는 AWS 서비스에서 임시 자격 증명을 얻기 위한 서비스로 AssumeRole API를 호출하여 제한된 기간 동안 사용할 수 있는 액세스 키, 비밀 키, 세션 토큰을 얻을 수 있습니다. 이 임시 자격 증명은 다른 계정에서의 리소스에 접근하거나, 기존 사용자 권한을 대체하는 데 사용됩니다.

1. 사전 요구사항

  • Python 환경: Python 3.7+
  • Boto3 설치: boto3 라이브러리는 AWS SDK이므로 설치( pip install boto3)
  • AWS IAM 역할: AssumeRole을 사용할 수 있는 권한을 가진 IAM 역할과 정책이 설정

2. AWS IAM 역할 설정

2.1 Assume Role 및 정책 설정

Principal에 접근을 허용하고자 하는 사용자를 추가

{Account}{UserName} 영역에 Role을 위임(Assume) 받을 ARN 정보를 입력 합니다.
그리고, 필요한 정책을 부여합니다. 예) S3FullAcess

2. boto3에서 임시 자격 증명 얻기

Boto3에서 임시 자격 증명을 얻으려면 sts 클라이언트를 생성하고, assume_role 메서드를 사용하여 임시 자격 증명을 요청할 수 있습니다.

import boto3
from botocore.exceptions import ClientError

def assume_role(role_arn, session_name):
    sts_client = boto3.client('sts')

    try:
        # Assume Role 호출
        assumed_role_object = sts_client.assume_role(
            RoleArn=role_arn,
            RoleSessionName=session_name
        )

        # 임시 자격 증명 가져오기
        credentials = assumed_role_object['Credentials']

        # 액세스 키, 비밀 키, 세션 토큰 반환
        return {
            'access_key': credentials['AccessKeyId'],
            'secret_key': credentials['SecretAccessKey'],
            'session_token': credentials['SessionToken']
        }

    except ClientError as e:
        print(f"AssumeRole 실패: {e}")
        return None

3.1 파라미터 설명

RoleArn: Assume할 역할의 Amazon Resource Name (ARN)을 나타냅니다. 예) arn:aws:iam::123456789012:role/example-role
RoleSessionName: 세션에 사용할 이름입니다. 이 이름은 각 요청에 대해 고유해야 합니다.

3.2 실행 예시

AssumeRole을 호출하고, 그 자격 증명을 사용하여 S3 버킷 리스트를 가져오는 예제(파이썬) 입니다.

# S3 클라이언트를 생성하는 코드
def create_s3_client_with_assumed_role(credentials):
    s3_client = boto3.client(
        's3',
        aws_access_key_id=credentials['access_key'],
        aws_secret_access_key=credentials['secret_key'],
        aws_session_token=credentials['session_token']
    )
    return s3_client

if __name__ == "__main__":
    role_arn = "arn:aws:iam::123456789012:role/example-role"
    session_name = "example-session"

    # 임시 자격 증명 얻기
    credentials = assume_role(role_arn, session_name)

    if credentials:
        # 임시 자격 증명으로 S3 클라이언트 생성
        s3_client = create_s3_client_with_assumed_role(credentials)

        # S3 버킷 리스트 가져오기
        response = s3_client.list_buckets()
        print("S3 Buckets:", [bucket['Name'] for bucket in response['Buckets']])

결론

Assume Role을 사용하면 임시 자격 증명을 얻고, 이를 활용하여 안전하게 여러 계정에서 작업하거나 제한된 권한으로 특정 작업을 수행할 수 있습니다.

728x90
반응형
728x90

1. AWS SES란?

AWS SES는 마케팅 이메일, 거래 이메일 및 기타 대규모 이메일 발송을 쉽게 처리할 수 있는 서비스로 저렴한 비용으로 대규모 이메일 발송이 가능합니다. SMTP(Simple Mail Transfer Protocol)를 통해 직접 통합하거나 AWS SDK를 사용하여 애플리케이션에서 쉽게 사용할 수 있습니다. SES는 이메일 발송뿐 아니라 수신도 가능하며, 이메일을 인증하는 기능도 제공합니다.

주요 기능:

도메인 인증 : 발송 도메인에 대한 검증 및 설정을 지원하여 이메일의 신뢰성을 높입니다.
DKIM 서명 : DKIM(Domain Keys Identified Mail)을 통해 이메일이 변조되지 않았음을 수신 서버에 증명할 수 있습니다.
전송 상태 모니터링 : 이메일 발송 성공 여부, 반송 상태 등을 실시간으로 모니터링할 수 있습니다.
대량 이메일 발송 : AWS 인프라를 활용해 대규모 이메일 발송이 가능합니다.

2. Amazon SES 요금

Amazon SES는 사용한 만큼 비용 지불이 되며, 이메일 발신 및 수신, 데이터 사용량 및 추가 기능에 대한 요금은 별도로 부과됩니다.

서비스 유형 요금 추가 요금
아웃바운드 이메일 0.10 USD/이메일 1,000건 발신 첨부 파일의 데이터 기가바이트(GB)당 0.12 USD
인바운드 이메일 0.10 USD/이메일 1,000건 수신 이메일 청크 1,000개당 0.09 USD
자세한 내용은 요금페이지 참조

3. AWS SES 설정

AWS SES 는 두가지 자격 증명 방식을 제공합니다.

  • 도메인 : 확인된 도메인의 모든 하위 도메인이나 이메일 주소에서 이메일을 보낼 수 있습니다.
  • 이메일 주소 : 이메일 주소 자격 증명은 확인된 이메일 주소만 메일을 보내는 데 사용할 수 있습니다.

사전 요구 사항:

  1. AWS 계정 : AWS SES를 사용하려면 먼저 AWS 계정이 필요합니다.
  2. 도메인 정보 : 이메일을 발송할 도메인이 필요합니다. 이 도메인에 대해 DNS 설정을 추가해야 하기 때문에 도메인 관리 권한이 필요합니다.

4. AWS SES 도메인 인증 프로비저닝

도메인을 사용하여 이메일을 발송 하려면 도메인을 먼저 검증해야 합니다. SES는 DNS 레코드를 통해 도메인이 실제 소유자의 것인지 확인합니다.

4.1 Terraform Provider 설정

provider "aws" {
  region = "ap-northeast-2"
}

4.2 SES 도메인 인증 리소스 생성:

resource "aws_ses_domain_identity" "example" {
  domain = "example.com"
}

# Route53에 도메인 검증을 위한 TXT 레코드 설정
resource "aws_route53_record" "ses_verification_record" {
  zone_id = "Z3P5QSUBK4POTI"  # Route53 Hosted Zone ID
  name    = "_amazonses.example.com"
  type    = "TXT"
  ttl     = 300
  records = [aws_ses_domain_identity.example.verification_token]
}

4.3 DKIM(Domain Keys Identified Mail) 설정

DKIM(Domain Keys Identified Mail)은 발송된 이메일이 수신 도메인에서 변조되지 않았음을 증명하는 방식입니다. DKIM 서명을 추가하면 이메일의 신뢰도를 높일 수 있습니다. DKIM을 사용하려면 별도의 CNAME 레코드를 DNS에 추가해야 합니다.


# DKIM 설정을 위한 SES 이메일 인증 자격 증명 생성
resource "aws_ses_domain_dkim" "example_dkim" {
  domain = aws_ses_domain_identity.example.domain
}


# Route53에서 DKIM을 위한 CNAME 레코드 설정
resource "aws_route53_record" "ses_dkim_records" {
  count   = length(aws_ses_domain_dkim.example_dkim.dkim_tokens)
  zone_id = "Z3P5QSUBK4POTI"  # Route53 Hosted Zone ID
  name    = "${aws_ses_domain_dkim.example_dkim.dkim_tokens[count.index]}._domainkey.example.com"
  type    = "CNAME"
  ttl     = 300
  records = ["${aws_ses_domain_dkim.example_dkim.dkim_tokens[count.index]}.dkim.amazonses.com"]
}

DKIM 설정을 적용한 후에는 AWS SES 콘솔에서 DKIM 상태가 verified로 표시 되는지 확인합니다.

4.4 Mail From 도메인 설정

반송 메일이 있을 경우 설정된 Mail From 도메인으로 해당 메일을 처리합니다.

# Mail From 도메인 설정
resource "aws_ses_domain_mail_from" "example_mail_from" {
  domain           = aws_ses_domain_identity.example.domain
  mail_from_domain = "mail.example.com"
}

# Route53에서 Mail From 도메인을 위한 MX 레코드 설정
resource "aws_route53_record" "mail_from_mx" {
  zone_id = "Z3P5QSUBK4POTI"   # Route53 Hosted Zone ID
  name    = "mail.example.com"
  type    = "MX"
  ttl     = 300
  records = ["10 feedback-smtp.{region}.amazonses.com"]
}

# Route53에서 Mail From 도메인을 위한 SPF 레코드 설정
resource "aws_route53_record" "mail_from_spf" {
  zone_id = "Z3P5QSUBK4POTI"
  name    = "mail.example.com"
  type    = "TXT"
  ttl     = 300
  records = ["v=spf1 include:amazonses.com -all"]
}

사기 및 남용을 방지하기 위해 신규로 생성시에는 SandBox로 구성되어, 서비스 제한이 있습니다. 생성 후에는 프로덕션으로 전환하도록 요청하여합니다.

  • 확인된 이메일 주소 및 도메인 또는 Amazon SES 메일박스 시뮬레이터로만 메일을 보낼 수 있습니다.
  • 24시간 동안 최대 200개 발송 가능
  • 확인되지 않은 이메일 주소로 이메일 발송 불가

4. 이메일 발송 테스트

AWS 콘솔 및 CLI를 사용하여 이메일을 발송할 수 있습니다.

콘솔에서 테스트 방법 :

CLI로 테스트 하는 방법 :

aws ses send-email \
  --from "no-reply@example.com" \
  --destination "ToAddresses=user@recipient.com" \
  --message "Subject={Data=Email Send Test},Body={Text={Data=This is a test email}}"

결론

AWS SES를 프로비저닝하는 과정은 생각보다 복잡해 보일 수 있지만, 도메인 검증, DKIM 설정, Mail From 설정 등 단계별로 차근차근 설정하면 손쉽게 신뢰도 높은 대규모 이메일 발송 인프라를 구축할 수 있습니다. 추가적으로, 이메일 발송 후 결과를 지속적으로 모니터링하여 도메인 평판을 유지하는 것이 중요합니다.

Reference

728x90
반응형
728x90

AWS의 Systems Manager (SSM)을 활용하면 프라이빗 서브넷에 위치한 EC2 인스턴스에 SSH 없이 안전하게 접근할 수 있습니다.
Terraform을 사용하여 프라이빗 EC2 서버를 프로비저닝하고, SSM을 통해 접근하는 방법을 단계별로 설명합니다.

1. AWS Systems Manager - Session Manager(SSM)

AWS Systems Manager (SSM)은 AWS 리소스 관리와 운영을 자동화하는 서비스로 Session Manager 는 EC2 인스턴스에 대한 안전하고 감사 가능한 접근환경을 제공합니다.

Session Manager 특징

  • SSH 키를 관리할 필요가 없습니다.
  • 인터넷 접근없이 프라이빗 환경으로 인스턴스 접근 가능
  • Bastion 호스트를 사용하지 않습니다.
  • 세션 활동의 로깅 및 감사 가능

Session Manager Prerequisites

  • 지원 운영체제 확인 (AWS Linux OS는 모두 기본 탑재되어 있음)
  • 인스턴스에서 작업 수행을 위한 권한 부여 (AWS Systems Manager는 기본적으로 인스턴스에서 작업을 수행할 권한이 없습니다.)
    • Session Manager에 대한 필수 권한 : AmazonSSMManagedInstanceCore
  • 엔드포인트에 대한 HTTPS(포트 443) 트래픽 허용 필요
    • ec2messages.region.amazonaws.com
    • ssm.region.amazonaws.com
    • ssmmessages.region.amazonaws.com

2. 아키텍처 구성도

다음은 SSM을 통해 EC2 인스턴스에 접근하기 위한 구성도 입니다.

2.1. VPC 및 서브넷 구성

프라이빗 서브넷을 포함한 VPC를 생성합니다.


# VPC 생성
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "VPC"
  }
}

# Subnet 생성
resource "aws_subnet" "main" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "Subnet"
  }
}

# Route Table 생성
resource "aws_route_table" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "Route Table"
  }
}

# Route Table 연결
resource "aws_route_table_association" "main" {
  subnet_id      = aws_subnet.main.id
  route_table_id = aws_route_table.main.id
}

2.2. IAM 역할 및 정책 설정

SSM을 사용하기 위해 EC2 인스턴스에 연결할 IAM 역할과 정책(AmazonSSMManagedInstanceCore)을 설정합니다.


# IAM Role 생성
data "aws_iam_policy_document" "assume_role" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }

    actions = ["sts:AssumeRole"]
  }

}

# EC2 역할 생성
resource "aws_iam_role" "ec2-role" {
  name               = "RoleForEC2"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
  description        = "Role for EC2 Instance"
}

# Manged Policy 연결(AmazonSSMManagedInstanceCore)
resource "aws_iam_role_policy_attachment" "AmazonSSMManagedInstanceCore" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
  role       = aws_iam_role.ec2-role.name
}

# EC2 인스턴스 프로필 생성
resource "aws_iam_instance_profile" "ec2_instance_profile" {
  name = "ec2-instance-profile-for-ssm"
  role = aws_iam_role.ec2-role.name
}

2.3. Security Group 및 VPC Endpoint 설정

VPC EndPoint 연동을 위한 433 포트를 오픈하기 위한 보안그룹 설정과 VPC Endpoint를 생성합니다.


# EC2 Security Group 생성
resource "aws_security_group" "ec2_group" {
  name        = "ec2-SG"
  description = "Allow SSH inbound traffic and all outbound traffic"
  vpc_id      = aws_vpc.main.id

  tags = {
    Name = "EC2-SG"
  }
}

# 아웃바운드 트래픽 설정
resource "aws_vpc_security_group_egress_rule" "ec2_group" {
  security_group_id = aws_security_group.ec2_group.id
  cidr_ipv4         = "0.0.0.0/0"
  ip_protocol       = -1
}

# Endpoint Security Group 생성
resource "aws_security_group" "vpc_endpoint_group" {
  name        = "endpoint-SG"
  description = "Allow TLS inbound traffic and all outbound traffic"
  vpc_id      = aws_vpc.main.id

  tags = {
    Name = "VPC-Endpoint-SG"
  }

}

# 인바운드 트래픽 설정
resource "aws_vpc_security_group_ingress_rule" "vpc_endpoint" {
  security_group_id = aws_security_group.vpc_endpoint_group.id
  cidr_ipv4         = "0.0.0.0/0"
  from_port         = 443
  ip_protocol       = "tcp"
  to_port           = 443
  description       = "Allow Access SSL"
}

# 아웃바운드 트래픽 설정
resource "aws_vpc_security_group_egress_rule" "vpc_endpoint" {
  security_group_id = aws_security_group.vpc_endpoint_group.id
  cidr_ipv4         = "0.0.0.0/0"
  ip_protocol       = -1

}

# VPC Endpoint 생성
resource "aws_vpc_endpoint" "ssm_endpoint" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${var.region}.ssm"
  vpc_endpoint_type   = "Interface"
  security_group_ids  = [aws_security_group.vpc_endpoint_group.id]
  subnet_ids          = [aws_subnet.main.id]
  private_dns_enabled = true

  tags = {
    Name = "SSM-Endpoint"

  }
}

resource "aws_vpc_endpoint" "ssmmessages_endpoint" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${var.region}.ssmmessages"
  vpc_endpoint_type   = "Interface"
  security_group_ids  = [aws_security_group.vpc_endpoint_group.id]
  subnet_ids          = [aws_subnet.main.id]
  private_dns_enabled = true

  tags = {
    Name = "SSM-Messages-Endpoint"
  }
}

resource "aws_vpc_endpoint" "ec2messages_endpoint" {
  vpc_id              = aws_vpc.main.id
  service_name        = "com.amazonaws.${var.region}.ec2messages"
  vpc_endpoint_type   = "Interface"
  security_group_ids  = [aws_security_group.vpc_endpoint_group.id]
  subnet_ids          = [aws_subnet.main.id]
  private_dns_enabled = true

  tags = {
    Name = "EC2-Messages-Endpoint"
  }
}

2.4. EC2 인스턴스 생성

인터넷으로 접근되지 않도록 외부에 오픈 되어 있지 않는 보안그룹에 연결하고, 인스턴스를 생성합니다.

# EC2 인스턴스 생성
resource "aws_instance" "main" {
  ami           = "ami-04ea5b2d3c8ceccf8"
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.main.id

  vpc_security_group_ids = [aws_security_group.ec2_group.id]

  iam_instance_profile = aws_iam_instance_profile.ec2_instance_profile.name

  tags = {
    Name = "EC2-Server"
  }
}

2.5. (결과) AWS SystemManager - Session Manager

프로비저닝 구성이 완료되면 AWS SystemManager > Session Manager 탭에서 생성 결과를 확인할 수 있습니다.

2.6. EC2에 접속하기

AWS Console과 CLI를 통해 접속할 수 있습니다.

AWS Management Console를 통한 접속

Console을 통해 SSM 세션을 접속합니다.

AWS CLI를 통한 접속

다음 명령어를 통해 SSM 세션을 시작합니다.

aws ssm start-session --target <instance-id>

2.7. 결과

AWS Systems Manager (SSM)과 Session Manager를 활용하여 프라이빗 EC2 서버를 프로비저닝하고, SSM을 통해 안전하게 접근하는 방법을 다루었습니다. 이를 통해 SSH 키 관리의 번거로움을 줄이고, 보안을 강화할 수 있습니다. SSM과 Session Manager를 사용하면 원격 명령 실행, 파일 전송 등 다양한 기능을 활용할 수 있으므로, 이를 적극적으로 활용해보시기 바랍니다.

Reference

728x90
반응형
728x90

Python 애플리케이션을 개발할 때, 환경 변수를 사용하는 것은 매우 중요한 부분입니다. API 키, 데이터베이스 접속 정보와 같은 민감한 데이터를 코드에 직접 코딩하지 않고 환경 변수로 관리하는 것이 좋습니다. 이번 블로그에서는 python-dotenv 라이브러리를 사용하여 Python 환경 변수를 관리하는 방법에 대해 알아보겠습니다.

1. Python Dotenv 설치하기

먼저, python-dotenv 라이브러리를 설치 합니다. 이 라이브러리는 .env 파일에 저장된 환경 변수를 읽어 Python 애플리케이션에서 사용할 수 있도록 해줍니다.

# pipenv
pipenv install python-dotenv

2. .env 파일 생성하기

프로젝트 루트 디렉토리에 .env 파일을 생성합니다. 이 파일에는 환경 변수와 그 값을 키=값 형식으로 작성합니다.
.env 파일에는 민감한 정보가 포함될 수 있으므로, .gitignore 파일을 생성하고 .env 파일을 추가하여 github 등에 포함되지 않도록 하여 줍니다.

SECRET_KEY=mysecretkey  
DATABASE_URL=postgres://user:password@localhost/db  
API_KEY="your-api-key"

3. 환경 변수 로드하기

이제 Python 코드에서 python-dotenv을 사용하여 .env 파일에 정의된 환경 변수를 로드할 수 있습니다. 이를 위해 dotenv 모듈의 load_dotenv 함수를 사용합니다.

import os  
from dotenv import load_dotenv  

# Load environment variables from the .env file (if present)  
load_dotenv()  

# Access environment variables as if they came from the actual environment  
SECRET_KEY = os.getenv('SECRET_KEY')  
DATABASE_URL = os.getenv('DATABASE_URL')  
API_KEY = os.getenv('API_KEY')  

# Example usage  
print(f'SECRET_KEY: {SECRET_KEY}')  
print(f'DATABASE_URL: {DATABASE_URL}')  
print(f'API_KEY: {API_KEY}')

결과

SECRET_KEY: mysecretkey
DATABASE_URL: postgres://user:password@localhost/db
API_KEY: your-api-key

결론

python-dotenv 라이브러리를 사용하면 환경 변수를 쉽게 관리하고 애플리케이션 설정을 안전하게 유지할 수 있습니다. 이 방법을 통해 코드 내에 민감한 정보를 반영 하지 않고, 다양한 환경에서 동일한 코드를 사용할 수 있습니다. python-dotenv을 사용하여 환경 변수를 효율적으로 관리해보시기 바랍니다.

728x90
반응형
728x90

코드 리뷰 하기 좋은 Pull Request(PR) 만들기

좋은 Pull Request(PR)는 코드 기반 협업 프로세스를 개선하는 데 중요한 요소입니다.
Pull Request 템플릿을 활용하여 리뷰어(Reviewer)가 코드의 변경 사항을 명화하게 이해하고, 주의깊게 검토해야 할 부분들을 표시하여 코드의 안정성을 높이고, 원활한 커뮤니케이션하는데 도움이 될 수 있습니다.

  1. 목적이 명확합니다: 좋은 PR은 하나의 구체적인 목적을 가지고 있어야 합니다. 이는 버그 수정, 새 기능 추가, 리팩토링, 성능 향상 등 일 수 있습니다.
  2. 변경 범위가 제한적 입니다: PR은 가능한 한 작고 관리가능한 범위로 제한되어야 합니다. 이는 리뷰어가 더 쉽게 이해하고 더 빨리 리뷰를 완료할 수 있게 합니다.
  3. 잘 문서화되어 있습니다: PR에는 충분한 설명이 포함되어야 하며, 필요한 모든 문맥 정보와 변경된 이유를 제공해야 합니다. 이는 리뷰어가 변경의 의도와 영향을 이해하는 데 도움이 됩니다.
  4. 품질이 유지됩니다: PR은 코드의 품질을 유지하거나 개선해야 합니다. 이는 테스트 케이스의 추가, 기존 테스트의 통과, 코딩 표준의 준수 등을 포함할 수 있습니다.
  5. 커뮤니케이션이 원활합니다: PR의 작성자는 리뷰 과정에서 발생하는 피드백에 적극적으로 응답하고, 필요한 수정을 신속하게 처리해야 합니다.
  6. 리뷰가 용이합니다: 좋은 PR은 리뷰하기 쉽게 구성되어 있어야 합니다. 이는 코드의 변경 사항이 명확하고, 리뷰어가 주의 깊게 검토해야 할 부분이 잘 표시되어 있는 경우입니다.

이러한 특성을 갖춘 PR은 코드 리뷰 프로세스를 개선하고, 팀 내의 협업을 촉진하며 소프트웨어의 전반적인 품질을 향상시키는 데 중요한 역할을 합니다.

Pull Request Template 만들기

  • 템플릿은 프로젝트와 리포지토리 구조에 따라 여러 유형으로 만들 수 있습니다.
  • 템플릿은 다음 위치 중 한 곳에 넣으면 인식합니다.
    • 루트 디렉토리 : pull_request_template.md
    • docs 디렉토리 : docs/pull_request_template.md
    • .github 디렉토리 : .github/pull_request_template.md

예) 템플릿 형식

# Pull Request (PR)
PR 유형을 선택합니다.
- [ ] 새로운 기능 추가
- [ ] 버그 수정
- [ ] UI 디자인 변경
- [ ] 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
- [ ] 코드 리팩토링
- [ ] 주석 추가 및 수정
- [ ] 문서 수정
- [ ] 테스트 추가, 테스트 리팩토링
- [ ] 빌드 부분 혹은 패키지 매니저 수정
- [ ] 파일 혹은 폴더명 수정
- [ ] 파일 혹은 폴더 삭제

## 변경 사항
- 간단하게 이 PR에서 진행한 주요 작업을 요약하고,
- 변경된 주요 기능 및 수정 사항에 대한 자세한 설명을 적으세요.

## 관련 이슈 또는 문서
- 이 PR과 관련된 이슈, JIRA 티켓 및 참고 문서가 있다면 링크를 추가하세요.

## 특별히 봐줬으면 하는 부분
- 리뷰어가 집중해서 봐야 할 코드 섹션 또는 로직을 지정하세요.

## 테스트 가이드
- 이 변경 사항을 어떻게 테스트했는지 설명하세요.
- 자동화된 테스트를 추가했다면, 어떤 테스트 케이스를 추가했는지 설명하세요.

## 스크린샷 (UI 변경 사항이 있는 경우)
- UI가 변경되었다면, 변경된 UI의 스크린샷을 첨부하세요.

## 기타
- 이 PR을 병합하는데 주의해야 할 사항이 있다면 적으세요.

## 체크리스트 (PR시 필수 체크해야 할 사항을 기입하세요)
- [ ] 변경 사항과 관련 문서를 모두 업데이트 했습니다.
- [ ] 모든 종속 변경사항이 병합되었습니다.
- [ ] 코드 리뷰어를 지정했습니다.

Reference

728x90
반응형

'GitHub' 카테고리의 다른 글

GitHub 멀티 Account 설정하기  (0) 2022.07.21

+ Recent posts