數位海洋的12天(第4天) – 使用數位海洋函數部署生日通知

歡迎來到 第4天12天的DigitalOcean!昨天,我們為生日提醒服務添加了Twilio SMS通知,使其能夠發送今天的生日簡訊。🎂

今天,我們將進一步提升,將我們的腳本部署到 DigitalOcean Functions。這讓我們的服務可以在雲端運行,而不需要專用伺服器,讓我們的應用輕量化、可擴展,並準備好自動化。

通過這種設置,即使您的電腦關閉或未連接到互聯網,您仍然會收到生日提醒—不再需要在您的機器上手動運行腳本了。🎉

為什麼選擇DigitalOcean Functions?

有時候,你只需要一個偶爾運行的簡單腳本。管理這樣的基礎設施可能會過於繁瑣。這就是 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 資料夾的根目錄下。

    • birthdays 資料夾中建立一個 requirements.txt 檔案:
    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 通知 獲取 Twilio 憑證以填充以下值:

# 數據庫憑證(來自第 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:一個純 Python 的 PostgreSQL 客戶端庫。

python-dotenv:用於從 .env 檔案加載環境變數。

twilio:用於發送 SMS 訊息的 Twilio Python 庫。

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

這是您的生日提醒服務的主腳本。我們基本上使用了第三天構建的腳本來發送生日通知。然而,為了使其與 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 函數內:
    第 3 天的代碼已被包裝在 main 函數內,以符合這一要求。

  3. 其他部分保持不變:
    資料庫連接邏輯、生日檢查和簡訊通知邏輯均未更改。

步驟 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. 導航至 函數 並找到您的提醒/生日函數。
  3. 點擊 運行 以手動運行它。
  4. 直接在控制台查看輸出和日誌。

如果您更喜歡可視界面或想以乾淨、易讀的格式檢查日誌,這種方法特別有幫助。

測試提示

當你調用這個函數時,它會檢查與今天日期匹配的生日。如果有匹配,你將收到一條包含詳細信息的短信。為了有效測試這個函數:

  • 在你的數據庫中添加一個或多個與當前日期匹配的生日。
  • 檢查控制台或CLI日誌以確認函數成功執行。

🎁 總結

今天我們完成了以下工作:

✅ 設置了doctl並為我們的項目創建了一個命名空間。
✅ 重構了Python腳本以便部署。
✅ 將生日提醒服務打包並部署到DigitalOcean Functions。
✅ 使用CLI和DigitalOcean儀表板在雲端測試了該函數。

接下來:雖然這是一大步,但我們仍然手動運行該函數。在下一篇文章中,我們將自動化這個過程,使生日提醒服務每天在特定時間自動運行。想像一下,醒來時收到一條短信提醒,卻無需動手——讓我們明天實現這一點!🚀

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