디지털오션의 12일 (4일차) – 디지털오션 함수를 이용한 생일 알림 배포

4일차 디지털오션의 12일에 오신 것을 환영합니다! 어제, 우리는 생일 알림 서비스에 Twilio SMS 알림 기능을 추가했습니다. 이로 인해 오늘의 생일을 위한 문자 메시지를 보낼 수 있게 되었습니다. 🎂

오늘은 디지털오션 함수에 우리의 스크립트를 배포하여 한 단계 더 발전시킬 것입니다. 이렇게 하면 전용 서버 없이도 클라우드에서 서비스를 실행할 수 있어, 우리의 앱은 가볍고 확장 가능하며 자동화에 준비가 되어 있습니다.

이 설정으로 인해 컴퓨터가 꺼져 있거나 인터넷에 연결되어 있지 않아도 생일 알림을 받을 수 있습니다. 더 이상 머신에서 스크립트를 수동으로 실행할 필요가 없습니다. 🎉

왜 디지털오션 함수인가요?

때로는 가끔 실행되는 간단한 스크립트만 있으면 충분합니다. 그런 것을 위한 인프라 관리는 과할 수 있습니다. 바로 그때 Functions가 등장합니다. 이는 서버리스 플랫폼으로, 필요할 때만 실행되는 코드를 배포할 수 있으며, 사용한 만큼만 비용을 지불합니다. 우리의 사용 사례인 생일 확인 및 매일 알림 전송에 완벽합니다.

🚀 배우게 될 내용

오늘이 끝날 무렵, 다음을 할 수 있게 될 것입니다:

  1. DigitalOcean의 doctl CLI 도구 설정하기.
  2. 서버리스 네임스페이스에 연결하기 (DigitalOcean의 함수 정리 방식).
  3. 생일 알림 서비스를 DigitalOcean Functions에 패키징하고 배포하기.
  4. 클라우드에서 배포된 함수를 테스트하기.

🛠 필요한 사항

시작하기 전에, 다음이 준비되어 있는지 확인하세요:

🧑‍🍳 4일차: DigitalOcean Functions에 배포하기 위한 레시피

1단계: doctl CLI 설정

이미 머신에 doctl을 설정했다면 이 단계를 건너뛸 수 있습니다. 설정이 필요한 분들은 다음 지침을 따르세요:

시작하기 전에 doctl에 대해 간단히 이야기해봅시다. 이는 DigitalOcean의 공식 커맨드라인 인터페이스 도구로, 터미널에서 클라우드 리소스를 관리할 수 있도록 해줍니다. 우리는 이를 사용하여 네임스페이스(서버리스 함수용 폴더)를 생성하고, 우리의 Python 스크립트를 배포하며, 함수를 테스트할 것입니다.

설정은 간단합니다:

  1. 설치 doctl: 운영 체제에 맞는 설치 가이드를 따르세요.

  2. 인증 doctl: 다음 명령어를 실행하여 DigitalOcean 계정에 연결합니다:

    doctl auth init
    
  3. 설치 확인: 다음 명령어를 실행하여 모든 것이 작동하는지 확인합니다:

    doctl account get
    

성공적으로 실행되면 이 명령어는 귀하의 DigitalOcean 계정에 대한 세부정보, 예를 들어 이메일 및 계정 ID를 반환합니다.

단계 2: 서버리스 소프트웨어 설치

DigitalOcean Functions 는 서버리스 지원 소프트웨어가 필요하며, 이를 설치해야 합니다. 이는 일회성 설정이므로 설치가 완료되면 앞으로의 프로젝트에 대해 다시 설치할 필요가 없습니다.

다음 명령어를 실행하세요:

doctl serverless install

설치 상태를 확인하려면:

doctl serverless status

다음과 같은 오류가 발생하면:

Error: serverless support is installed but not connected to a functions namespace

걱정하지 마세요—이는 아직 네임스페이스를 생성하거나 연결하지 않았다는 의미입니다. 다음 단계에서 처리하겠습니다.

단계 3: 네임스페이스 생성 및 연결

네임스페이스는 서버리스 함수 정리를 위한 폴더와 같습니다. 생일 알림 서비스를 위해 하나 만들어 보겠습니다:

  1. 새 네임스페이스 생성:

    doctl serverless namespaces create --label "my-birthday-reminder-namespace" --region "nyc1"
    

  2. 네임스페이스에 연결:

    doctl serverless connect my-birthday-reminder-namespace
    

  3. 연결 확인:

    doctl serverless status
    

이제 네임스페이스에 연결되었다는 확인 메시지가 표시되어야 합니다.

전문가 팁: 사용 가능한 모든 네임스페이스 목록을 보려면 다음 명령어를 사용하세요:

doctl serverless namespaces list

여러 프로젝트를 관리하거나 방금 생성한 네임스페이스를 확인하고 싶을 때 유용합니다.

4단계: 프로젝트 구조 초기화 및 설정

DigitalOcean Functions는 서버리스 배포를 위한 특정 프로젝트 구조를 예상합니다. 이 구조는 doctl serverless init를 사용하여 시작할 수 있으며, 수동으로 생성하거나 스타터 리포지토리를 클론할 수도 있습니다. 간단하게 진행하기 위해 doctl serverless init를 사용하여 설정하겠습니다:

  1. 다음 명령어를 실행하여 프로젝트를 초기화하세요:

    doctl serverless init --language python birthday-reminder-service
    

    이 명령어는 다음과 같은 기본 구조를 가진 my-birthday-reminder-service라는 로컬 프로젝트 디렉토리를 생성합니다:

    my-birthday-reminder-service/
    ├── packages
    │   └── sample
    │       └── hello
    │           └── hello.py
    └── project.yml
    

  2. 프로젝트 디렉토리로 이동하기:

    cd my-birthday-reminder-service
    
  3. 폴더 이름을 우리의 사용 사례에 맞게 변경하기:

    mv packages/sample packages/reminders
    mv packages/reminders/hello packages/reminders/birthdays
    mv packages/reminders/birthdays/hello.py packages/reminders/birthdays/__main__.py
    
  4. 필요한 파일 만들기:

    • 프로젝트 루트에 빈 .env 파일을 만드세요:
    touch .env
    

    이 파일은 데이터베이스 및 Twilio 자격 증명을 보관합니다. 파일은 my-birthday-reminder-service 폴더의 루트에 위치하게 됩니다.

    • requirements.txt 파일을 birthdays 폴더에 만드세요:
    touch packages/reminders/birthdays/requirements.txt
    

    이 파일은 함수에 필요한 Python 종속성을 나열합니다. packages/reminders/birthdays 아래에 위치하게 됩니다.

    • birthdays 폴더에 build.sh 파일을 만드세요:
    touch packages/reminders/birthdays/build.sh
    chmod +x packages/reminders/birthdays/build.sh
    

    build.sh 스크립트는 외부 종속성을 가진 함수를 배포하는 데 필요합니다. chmod 명령은 Mac/Linux 시스템에서 스크립트가 실행 가능하도록 보장합니다.

업데이트된 구조: 이 단계를 완료하면 프로젝트 구조는 다음과 같아야 합니다:

my-birthday-reminder-service/
├── project.yml
├── .env
├── packages
│   └── reminders
│       └── birthdays
│           ├── __main__.py
│           ├── requirements.txt
│           ├── build.sh
├── .gitignore

전문가 팁: 폴더 이름을 잘못 지정한 경우, 명령을 다시 실행하거나 파일 탐색기에서 수동으로 이름을 바꿀 수 있습니다.

5단계: 파일 업데이트하기

구조가 준비되었으니 필요한 파일로 채워봅시다. 좋아하는 코드 편집기에서 my-birthday-reminder-service 디렉토리를 엽니다.

1. project.yml 업데이트

project.yml 파일은 서버리스 프로젝트의 구조, 환경 변수 및 기능을 정의하는 구성 파일입니다. 이 파일의 내용을 다음으로 교체하세요:

packages:
  - name: reminders
    shared: false
    environment:
      DO_DB_NAME: "${DB_NAME}"
      DO_DB_USER: "${DB_USER}"
      DO_DB_PASSWORD: "${DB_PASSWORD}"
      DO_DB_HOST: "${DB_HOST}"
      DO_DB_PORT: "${DB_PORT}"
      TWILIO_ACCOUNT_SID: "${TWILIO_ACCOUNT_SID}"
      TWILIO_AUTH_TOKEN: "${TWILIO_AUTH_TOKEN}"
      TWILIO_PHONE_FROM: "${TWILIO_PHONE_FROM}"
      TWILIO_PHONE_TO: "${TWILIO_PHONE_TO}"
    functions:
      - name: birthdays
        runtime: python:default

이 파일은 리마인더 패키지를 설정하고 환경 변수를 DigitalOcean Functions에 매핑합니다. 각 변수는 데이터베이스 및 Twilio 통합에 필요한 자격 증명에 해당합니다.

2. .env 파일 업데이트

1일차: 생일 리마인더를 위한 PostgreSQL 데이터베이스 설정을 참조하여 데이터베이스 자격 증명을 확인하고 3일차: 생일 확인 및 SMS 알림 전송을 참조하여 다음 값을 입력하세요:

# 데이터베이스 자격 증명 (1일차)
DB_HOST=<your-database-hostname>
DB_NAME=<your-database-name>
DB_USER=<your-database-username>
DB_PASSWORD=<your-database-password>
DB_PORT=5432  # 기본 PostgreSQL 포트

# Twilio 자격 증명 (3일차)
TWILIO_ACCOUNT_SID=<your-twilio-account-sid>
TWILIO_AUTH_TOKEN=<your-twilio-auth-token>
TWILIO_PHONE_FROM=<your-twilio-phone-number>
TWILIO_PHONE_TO=<your-personal-phone-number>

메모: .env 파일은 민감한 자격 증명을 안전하게 저장하는 데 사용됩니다. 이러한 값은 project.yml 파일에 의해 읽혀지며 배포 중 서버리스 환경에 매핑되어 클라우드에서 함수에 접근할 수 있게 됩니다.

3. 의존성 추가

다음 의존성으로 requirements.txt 파일을 업데이트하십시오:

pg8000  
python-dotenv  
twilio  

pg8000: 순수 파이썬 PostgreSQL 클라이언트 라이브러리입니다.

python-dotenv: .env 파일에서 환경 변수를 로드하는 데 사용됩니다.

twilio: SMS 메시지를 보내기 위한 Twilio 파이썬 라이브러리입니다.

4. build.sh

build.sh 파일에 다음 스크립트를 추가하십시오:

#!/bin/bash
set -e

# 디버깅을 위한 현재 작업 디렉토리 출력
echo "Current working directory: $(pwd)"

# requirements.txt 파일 존재 확인
if [[ -f "requirements.txt" ]]; then
  echo "Found requirements.txt in $(pwd)"
else
  echo "Error: requirements.txt not found in $(pwd)"
  exit 1
fi

# 가상 환경 생성
virtualenv --without-pip virtualenv

# requirements.txt에서 종속성 설치
pip install -r requirements.txt --target virtualenv/lib/python3.9/site-packages

이 스크립트는 모든 종속성이 함수와 함께 올바르게 패키지화되도록 보장합니다. 4단계의 chmod +x 명령은 실행 가능하도록 합니다.

5. __main__.py 업데이트

이것은 당신의 생일 알림 서비스에 대한 주요 스크립트입니다. 우리는 본질적으로 3일차에 구축한 생일 알림을 보내는 스크립트를 사용하고 있습니다. 하지만 DigitalOcean Functions와 호환되도록 하기 위해 몇 가지 작은 조정을 해야 합니다.

다음 내용으로 __main__.py 파일을 업데이트하세요:

# 생일 알림 서비스/__main__.py

from datetime import datetime
import pg8000
from dotenv import load_dotenv
from twilio.rest import Client
import os

# 환경 변수 로드
load_dotenv()

def main(params):
    """DigitalOcean Functions entry point."""
    try:
        # 데이터베이스에 연결
        connection = pg8000.connect(
            host=os.getenv("DO_DB_HOST"),
            database=os.getenv("DO_DB_NAME"),
            user=os.getenv("DO_DB_USER"),
            password=os.getenv("DO_DB_PASSWORD"),
            port=int(os.getenv("DO_DB_PORT"))
        )
        cursor = connection.cursor()

        # 오늘의 월과 일 가져오기
        today = datetime.now()
        today_month = today.month
        today_day = today.day

        # 오늘 날짜와 일치하는 생일이 있는 연락처 쿼리
        cursor.execute(
            """
            SELECT first_name, last_name, birthday
            FROM contacts
            WHERE EXTRACT(MONTH FROM birthday) = %s
              AND EXTRACT(DAY FROM birthday) = %s;
            """,
            (today_month, today_day)
        )
        rows = cursor.fetchall()

        # 일치하는 각 연락처에 알림 전송
        if rows:
            account_sid = os.getenv("TWILIO_ACCOUNT_SID")
            auth_token = os.getenv("TWILIO_AUTH_TOKEN")
            client = Client(account_sid, auth_token)

            for row in rows:
                first_name, last_name, _ = row
                message = client.messages.create(
                    body=f"🎉 It's {first_name} {last_name or ''}'s birthday today! 🎂",
                    from_=os.getenv("TWILIO_PHONE_FROM"),
                    to=os.getenv("TWILIO_PHONE_TO")
                )
                print(f"Message sent for {first_name} {last_name}. Message SID: {message.sid}")
        else:
            print("No birthdays today.")

        # 커서 및 연결 종료
        cursor.close()
        connection.close()

    except Exception as e:
        print(f"An error occurred: {e}")

변경된 내용은 다음과 같습니다:

  1. main(params) 함수 추가: DigitalOcean Functions는 main이라는 이름의 진입점 함수가 필요하며, 이 함수는 params 인수를 받습니다. 여기서 함수 실행이 시작됩니다.
  2. main 함수 내부로 스크립트 로직 이동:
    Day 3의 코드는 이 요구 사항에 맞게 main 함수 내부로 감싸졌습니다.
  3. 모든 것은 동일하게 유지됩니다:
    데이터베이스 연결 논리, 생일 확인 및 SMS 알림 논리는 변경되지 않았습니다.

5단계: 패키징 및 배포

모든 준비가 완료되면 프로젝트를 DigitalOcean Functions에 배포하십시오:

  1. 프로젝트 배포:
doctl serverless deploy my-birthday-reminder-service

함수가 네임스페이스에 성공적으로 배포되었는지 확인하려면:

  1. DigitalOcean 제어판을 방문하고 왼쪽 사이드바에서 Functions로 이동합니다.
  2. 네임스페이스(예: my-birthday-reminder-namespace)를 찾습니다.
  3. 함수가 네임스페이스 아래에 나타나는지 확인하고, 일반적으로 reminders/birthdays로 나열됩니다.
  4. 함수 이름을 클릭하여 로그, 구성 및 호출 기록을 포함한 세부 정보를 확인합니다.

6단계: 배포된 함수 테스트하기

함수가 배포되면 이제 테스트할 시간입니다. 함수를 수동으로 호출하여 예상대로 작동하는지 확인할 수 있습니다. 이를 수행하는 방법에는 두 가지가 있습니다:

옵션 1: DigitalOcean CLI 사용

doctl serverless functions invoke reminders/birthdays

모든 설정이 올바르게 되어 있다면, 귀하의 함수는 클라우드에서 실행되어 오늘의 생일을 확인하고 SMS 알림을 보냅니다.

![https://doimages.nyc3.cdn.digitaloceanspaces.com/006Community/12-Days-of-DO/Postgressql-birthday/birthday_reminder_service_text_message.jpeg]

옵션 2: DigitalOcean 대시보드 사용

  1. DigitalOcean 제어판으로 이동합니다.
  2. Functions으로 이동하여 알림/생일 함수를 찾습니다.
  3. 수동으로 실행하려면 실행을 클릭합니다.
  4. 콘솔에서 직접 출력 및 로그를 확인합니다.

이 방법은 시각적 인터페이스를 선호하거나 깔끔하고 읽기 쉬운 형식으로 로그를 확인하고 싶을 때 특히 유용합니다.

테스트 팁

함수를 호출하면 오늘 날짜와 일치하는 생일을 확인합니다. 일치하는 경우, 세부 정보가 포함된 문자 메시지를 받게 됩니다. 함수를 효과적으로 테스트하려면:

  • 현재 날짜와 일치하는 하나 이상의 생일을 데이터베이스에 추가하세요.
  • 콘솔이나 CLI 로그를 확인하여 함수가 성공적으로 실행되었는지 확인하세요.

🎁 마무리

오늘 우리가 달성한 것은 다음과 같습니다:

doctl을 설정하고 프로젝트를 위한 네임스페이스를 생성했습니다.
✅ 배포를 위해 Python 스크립트를 리팩토링했습니다.
✅ 생일 알림 서비스를 DigitalOcean Functions에 패키징하고 배포했습니다.
✅ CLI와 DigitalOcean 대시보드를 사용하여 클라우드에서 함수를 테스트했습니다.

다음 단계: 이것은 큰 진전이지만, 우리는 여전히 함수를 수동으로 실행하고 있습니다. 다음 포스트에서는 생일 알림 서비스가 매일 특정 시간에 자동으로 실행되도록 이 과정을 자동화할 것입니다. 손가락 하나 까딱하지 않고 문자 알림을 받는 상상을 해보세요—내일 그것을 실현해 봅시다! 🚀

Source:
https://www.digitalocean.com/community/tutorials/deploying-birthday-notifications-with-digitalocean-functions