HTTP Cloud Functions ใน Python

HTTP Cloud Functions ใน Python

เกี่ยวกับ Codelab นี้

subjectอัปเดตล่าสุดเมื่อ มี.ค. 27, 2024
account_circleเขียนโดย Laurent Picard & Dustin Ingram

1 บทนำ

b158ce75c3cccd6d.png

Python เป็นภาษาโปรแกรมโอเพนซอร์สยอดนิยมที่ใช้โดยนักวิทยาศาสตร์ข้อมูล นักพัฒนาเว็บแอปพลิเคชัน ผู้ดูแลระบบ และอื่นๆ

Cloud Functions เป็นแพลตฟอร์มการประมวลผลแบบ Serverless ที่ขับเคลื่อนด้วยเหตุการณ์ Cloud Functions ช่วยให้คุณเขียนโค้ดได้โดยไม่ต้องกังวลเกี่ยวกับการจัดสรรทรัพยากรหรือการปรับขนาดเพื่อจัดการกับข้อกำหนดที่เปลี่ยนแปลง

Cloud Function มี 2 ประเภทดังนี้

  • ฟังก์ชัน HTTP จะตอบสนองต่อคำขอ HTTP คุณจะต้องสร้าง 2 เวอร์ชันใน Codelab นี้
  • ฟังก์ชันเบื้องหลังจะทำงานเมื่อเหตุการณ์เกิดขึ้น เช่น ข้อความที่เผยแพร่ไปยัง Cloud Pub/Sub หรือไฟล์ที่อัปโหลดไปยัง Cloud Storage เราไม่ได้แก้ไขปัญหานี้ในห้องทดลองนี้ แต่คุณสามารถอ่านข้อมูลเพิ่มเติมได้ในเอกสารประกอบ

efb3268e3b74ed4f.png

Codelab นี้จะอธิบายการสร้าง Cloud Functions ของคุณเองใน Python

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะเผยแพร่ Cloud Function ที่เมื่อเรียกใช้ผ่าน HTTP จะมีสถานะ "Python ขับเคลื่อนโดย" โลโก้

a7aaf656b78050fd.png

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเขียน HTTP Cloud Function
  • วิธีเขียน HTTP Cloud Function ซึ่งใช้อาร์กิวเมนต์
  • วิธีทดสอบ HTTP Cloud Function
  • วิธีเรียกใช้เซิร์ฟเวอร์ Python HTTP ในเครื่องเพื่อลองใช้ฟังก์ชันนี้
  • วิธีเขียน HTTP Cloud Function ที่จะแสดงผลรูปภาพ

2 การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

  1. ลงชื่อเข้าใช้ Google Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • ชื่อโครงการคือชื่อที่แสดงของผู้เข้าร่วมโปรเจ็กต์นี้ เป็นสตริงอักขระที่ Google APIs ไม่ได้ใช้ โดยคุณจะอัปเดตวิธีการชำระเงินได้ทุกเมื่อ
  • รหัสโปรเจ็กต์จะไม่ซ้ำกันในทุกโปรเจ็กต์ของ Google Cloud และจะเปลี่ยนแปลงไม่ได้ (เปลี่ยนแปลงไม่ได้หลังจากตั้งค่าแล้ว) Cloud Console จะสร้างสตริงที่ไม่ซ้ำกันโดยอัตโนมัติ ปกติแล้วคุณไม่สนว่าอะไรเป็นอะไร ใน Codelab ส่วนใหญ่ คุณจะต้องอ้างอิงรหัสโปรเจ็กต์ (โดยปกติจะระบุเป็น PROJECT_ID) หากคุณไม่ชอบรหัสที่สร้างขึ้น คุณสามารถสร้างรหัสแบบสุ่มอื่นได้ หรือคุณจะลองดำเนินการเองแล้วดูว่าพร้อมให้ใช้งานหรือไม่ คุณจะเปลี่ยนแปลงหลังจากขั้นตอนนี้ไม่ได้และจะยังคงอยู่ตลอดระยะเวลาของโปรเจ็กต์
  • สำหรับข้อมูลของคุณ ค่าที่ 3 คือหมายเลขโปรเจ็กต์ ซึ่ง API บางตัวใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าทั้ง 3 ค่าได้ในเอกสารประกอบ
  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร/API ของระบบคลาวด์ การใช้งาน Codelab นี้จะไม่มีค่าใช้จ่ายใดๆ หากมี หากต้องการปิดทรัพยากรเพื่อหลีกเลี่ยงการเรียกเก็บเงินที่นอกเหนือจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่คุณสร้างหรือลบโปรเจ็กต์ได้ ผู้ใช้ Google Cloud ใหม่มีสิทธิ์เข้าร่วมโปรแกรมช่วงทดลองใช้ฟรี$300 USD

เริ่มต้น Cloud Shell

แม้ว่าคุณจะดำเนินการ Google Cloud จากระยะไกลได้จากแล็ปท็อป แต่คุณจะใช้ Cloud Shell ใน Codelab ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์

เปิดใช้งาน Cloud Shell

  1. คลิกเปิดใช้งาน Cloud Shell 853e55310c205094.png จาก Cloud Console

3c1dabeca90e44e5.png

หากเริ่มต้นใช้งาน Cloud Shell เป็นครั้งแรก คุณจะเห็นหน้าจอตรงกลางที่อธิบายว่านี่คืออะไร หากระบบแสดงหน้าจอตรงกลาง ให้คลิกต่อไป

9c92662c6a846a5c.png

การจัดสรรและเชื่อมต่อกับ Cloud Shell ใช้เวลาเพียงไม่กี่นาที

9f0e51b578fecce5.png

เครื่องเสมือนนี้โหลดด้วยเครื่องมือการพัฒนาทั้งหมดที่จำเป็น โดยมีไดเรกทอรีหลักขนาด 5 GB ถาวรและทำงานใน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก งานส่วนใหญ่ใน Codelab นี้สามารถทำได้โดยใช้เบราว์เซอร์

เมื่อเชื่อมต่อกับ Cloud Shell แล้ว คุณควรเห็นข้อความตรวจสอบสิทธิ์และโปรเจ็กต์ได้รับการตั้งค่าเป็นรหัสโปรเจ็กต์แล้ว

  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว
gcloud auth list

เอาต์พุตจากคำสั่ง

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคำสั่ง gcloud รู้เกี่ยวกับโปรเจ็กต์ของคุณ
gcloud config list project

เอาต์พุตจากคำสั่ง

[core]
project = <PROJECT_ID>

หากไม่ใช่ ให้ตั้งคำสั่งด้วยคำสั่งนี้

gcloud config set project <PROJECT_ID>

เอาต์พุตจากคำสั่ง

Updated property [core/project].

ตรวจสอบว่าได้เปิดใช้ Cloud Functions และ Cloud Build API แล้ว

เรียกใช้คำสั่งต่อไปนี้จาก Cloud Shell เพื่อตรวจสอบว่าได้เปิดใช้ Cloud Functions และ Cloud Build API แล้ว

gcloud services enable \
  cloudfunctions.googleapis.com \
  cloudbuild.googleapis.com

หมายเหตุ: คำสั่ง gcloud functions deploy เรียกใช้ Cloud Build และจะสร้างโค้ดลงในอิมเมจคอนเทนเนอร์โดยอัตโนมัติ

ดาวน์โหลดซอร์สโค้ด

จากเทอร์มินัล Cloud Shell ให้เรียกใช้คำสั่งต่อไปนี้

REPO_NAME="codelabs"
REPO_URL="https://github.com/GoogleCloudPlatform/$REPO_NAME"
SOURCE_DIR="cloud-functions-python-http"

git clone --no-checkout --filter=blob:none --depth=1 $REPO_URL
cd $REPO_NAME
git sparse-checkout set $SOURCE_DIR
git checkout
cd $SOURCE_DIR

ตรวจสอบเนื้อหาของไดเรกทอรีต้นทาง

ls

คุณควรมีไฟล์ต่อไปนี้

main.py  python-powered.png  test_main.py  web_app.py

3 ขอแนะนำ HTTP Cloud Functions

HTTP Cloud Functions ใน Python จะมีการเขียนเป็นฟังก์ชัน Python ปกติ ฟังก์ชันดังกล่าวต้องยอมรับอาร์กิวเมนต์ flask.Request เดี่ยว ซึ่งปกติเรียกว่า request

main.py

import flask


def hello_world(request: flask.Request) -> flask.Response:
   
"""HTTP Cloud Function.

   
Returns:
   
- "Hello World! 👋"
    """

   
response = "Hello World! 👋"

   
return flask.Response(response, mimetype="text/plain")

# ...

คุณสามารถเปิดไฟล์ด้วยตัวแก้ไขบรรทัดคำสั่งที่ต้องการ (nano, vim หรือ emacs) คุณเปิดไดเรกทอรีดังกล่าวใน Cloud Shell Editor ได้หลังจากตั้งค่าไดเรกทอรีแหล่งที่มาเป็นพื้นที่ทำงานแล้ว โดยทำตามขั้นตอนดังนี้

cloudshell open-workspace .

มาทำให้ฟังก์ชันนี้ใช้งานได้เป็น HTTP Cloud Function โดยใช้คำสั่ง gcloud functions deploy กัน

FUNCTION_NAME="hello_world"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

เอาต์พุตจากคำสั่ง:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

หมายเหตุเกี่ยวกับตัวเลือก gcloud functions deploy

  • --runtime: ระบุรันไทม์ของภาษา สำหรับ Python ค่านี้อาจเป็น python37, python38, python39, python310 หรือ python312 ดูรันไทม์
  • --trigger-http: ระบบจะกำหนดปลายทางให้กับฟังก์ชันนี้ คำขอ HTTP (POST, PUT, GET, DELETE และ OPTIONS) ไปยังปลายทางจะทริกเกอร์การเรียกใช้ฟังก์ชัน
  • --allow-unauthenticated: ฟังก์ชันนี้จะเป็นแบบสาธารณะ ซึ่งช่วยให้ผู้โทรทุกคนได้โดยไม่ต้องตรวจสอบการตรวจสอบสิทธิ์
  • ดูข้อมูลเพิ่มเติมได้ที่การทำให้ฟังก์ชัน gcloud ใช้งานได้

หากต้องการทดสอบฟังก์ชัน ให้คลิก URL httpsTrigger.url ที่แสดงในเอาต์พุตคำสั่งด้านบน นอกจากนี้ คุณยังสามารถเรียก URL แบบเป็นโปรแกรม และเรียกใช้ฟังก์ชันด้วยคำสั่งต่อไปนี้

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

คุณควรได้ผลลัพธ์ต่อไปนี้

Hello World! 👋

4 การเขียน HTTP Cloud Function เพื่อรับอาร์กิวเมนต์

ฟังก์ชันจะทำงานได้หลากหลายกว่าเมื่อยอมรับอาร์กิวเมนต์ ลองกำหนดฟังก์ชันใหม่ hello_name ซึ่งรองรับพารามิเตอร์ name

main.py

# ...

def hello_name(request: flask.Request) -> flask.Response:
   
"""HTTP Cloud Function.

   
Returns:
   
- "Hello {NAME}! 🚀" if "name=NAME" is defined in the GET request
   
- "Hello World! 🚀" otherwise
    """

   
name = request.args.get("name", "World")
   
response = f"Hello {name}! 🚀"

   
return flask.Response(response, mimetype="text/plain")

# ...

มาทำให้ฟังก์ชันใหม่นี้ใช้งานได้กัน

FUNCTION_NAME="hello_name"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

เอาต์พุตจากคำสั่ง:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

หากต้องการทดสอบฟังก์ชัน ให้คลิก URL httpsTrigger.url ที่แสดงในเอาต์พุตคำสั่งด้านบน นอกจากนี้ คุณยังสามารถเรียก URL แบบเป็นโปรแกรม และเรียกใช้ฟังก์ชันด้วยคำสั่งต่อไปนี้

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

คุณควรได้รับผลลัพธ์เริ่มต้น:

Hello World! 🚀

คุณได้รับผลลัพธ์เริ่มต้นเนื่องจากยังไม่ได้ตั้งค่าอาร์กิวเมนต์ name เพิ่มพารามิเตอร์ลงใน URL

curl -w "\n" $URL?name=YOUR%20NAME

คราวนี้คุณจะได้รับการตอบกลับที่กำหนดเองดังนี้

Hello YOUR NAME! 🚀

ขั้นตอนถัดไปคือการเพิ่มการทดสอบ 1 หน่วยเพื่อให้แน่ใจว่าฟังก์ชันของคุณยังคงทำงานได้ตามที่ตั้งใจไว้เมื่อมีการอัปเดตซอร์สโค้ด

5 ข้อสอบการเขียน

ฟังก์ชันระบบคลาวด์ HTTP ใน Python ได้รับการทดสอบโดยใช้โมดูล unittest จากไลบรารีมาตรฐาน คุณไม่จำเป็นต้องเรียกใช้โปรแกรมจำลองหรือการจำลองอื่นๆ เพื่อทดสอบฟังก์ชัน เพียงแต่ใช้โค้ด Python ปกติเท่านั้น

การทดสอบสำหรับฟังก์ชัน hello_world และ hello_name มีลักษณะดังนี้

test_main.py

import unittest
import unittest.mock

import main


class TestHello(unittest.TestCase):
   
def test_hello_world(self):
       
request = unittest.mock.Mock()

       
response = main.hello_world(request)
       
assert response.status_code == 200
       
assert response.get_data(as_text=True) == "Hello World! 👋"

   
def test_hello_name_no_name(self):
       
request = unittest.mock.Mock(args={})

       
response = main.hello_name(request)
       
assert response.status_code == 200
       
assert response.get_data(as_text=True) == "Hello World! 🚀"

   
def test_hello_name_with_name(self):
       
name = "FirstName LastName"
       
request = unittest.mock.Mock(args={"name": name})

       
response = main.hello_name(request)
       
assert response.status_code == 200
       
assert response.get_data(as_text=True) == f"Hello {name}! 🚀"
  1. การทดสอบ Python จะเขียนในลักษณะเดียวกับไฟล์ Python อื่นๆ โดยเริ่มจากชุดการนำเข้า จากนั้นจึงกำหนดคลาสและฟังก์ชัน
  2. การประกาศการทดสอบอยู่ในรูปแบบ class TestHello(TestCase) โดยต้องเป็นคลาสที่รับค่าจาก unittest.TestCase
  3. คลาสการทดสอบมีเมธอด ซึ่งแต่ละแบบต้องขึ้นต้นด้วย test_ ซึ่งแสดงถึงกรอบการทดสอบแต่ละรายการ
  4. กรอบการทดสอบแต่ละรายการจะทดสอบฟังก์ชันใดฟังก์ชันหนึ่งของเราโดยจำลองพารามิเตอร์ request (เช่น แทนที่ด้วยออบเจ็กต์ปลอมด้วยข้อมูลที่เจาะจงที่จำเป็นสำหรับการทดสอบ)
  5. หลังจากเรียกใช้แต่ละฟังก์ชันแล้ว การทดสอบจะตรวจสอบการตอบสนอง HTTP เพื่อให้แน่ใจว่าเป็นสิ่งที่เราคาดหวัง

เนื่องจาก main.py ขึ้นอยู่กับ flask โปรดตรวจสอบว่าได้ติดตั้งเฟรมเวิร์ก Flask ในสภาพแวดล้อมการทดสอบแล้ว ดังนี้

pip install flask

การติดตั้ง Flask จะแสดงผลลัพธ์ที่คล้ายกับข้อความต่อไปนี้

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

เรียกใช้การทดสอบเหล่านี้ในเครื่อง

python -m unittest

หน่วยการทดสอบ 3 หน่วยควรผ่าน:

...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

ถัดไป คุณจะต้องสร้างฟังก์ชันใหม่ซึ่งส่งคืนฟังก์ชัน "Python ขับเคลื่อนโดย" โลโก้

6 การเขียน &quot;Python ขับเคลื่อนโดย&quot; ฟังก์ชัน HTTP ระบบคลาวด์

มาสร้างฟังก์ชันใหม่ให้สนุกยิ่งขึ้นโดยการส่งคืน "Python ขับเคลื่อนโดย" รูปภาพสำหรับทุกคำขอ:

a7aaf656b78050fd.png

รายชื่อต่อไปนี้จะแสดงรหัสที่จะทำให้เกิดขึ้นจริง

main.py

# ...

def python_powered(request: flask.Request) -> flask.Response:
   
"""HTTP Cloud Function.

   
Returns:
   
- The official "Python Powered" logo
    """

   
return flask.send_file("python-powered.png")

ทำให้ฟังก์ชัน python_powered ใหม่ใช้งานได้:

FUNCTION_NAME="python_powered"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

เอาต์พุตจากคำสั่ง:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

หากต้องการทดสอบฟังก์ชัน ให้คลิก URL httpsTrigger.url ที่แสดงในเอาต์พุตของคำสั่งด้านบน หากทุกอย่างทำงานได้อย่างถูกต้อง คุณจะเห็นปุ่ม "Python ขับเคลื่อนโดย" โลโก้ในแท็บใหม่ของเบราว์เซอร์

ถัดไป คุณจะต้องสร้างแอปเพื่อให้สามารถเรียกใช้และลองใช้ฟังก์ชันในเครื่องก่อนทำให้ใช้งานได้

7 การเรียกใช้ฟังก์ชันในเครื่อง

คุณเรียกใช้ฟังก์ชัน HTTP ในเครื่องได้โดยสร้างเว็บแอปและเรียกใช้ฟังก์ชันในเส้นทาง คุณจะเพิ่มไฟล์ในไดเรกทอรีเดียวกันกับฟังก์ชันได้ ไฟล์ชื่อ web_app.py มีเนื้อหาต่อไปนี้

web_app.py

import flask

import main

app = flask.Flask(__name__)


@app.get("/")
def index():
   
return main.python_powered(flask.request)


if __name__ == "__main__":
   
# Local development only
   
# Run "python web_app.py" and open http://localhost:8080
   
app.run(host="localhost", port=8080, debug=True)
  1. ไฟล์นี้จะสร้างแอปพลิเคชัน Flask
  2. โดยจะบันทึกเส้นทางใน URL ฐาน ซึ่งจัดการด้วยฟังก์ชันชื่อ index()
  3. จากนั้นฟังก์ชัน index() จะเรียกฟังก์ชัน python_powered และส่งต่อคำขอปัจจุบัน

ตรวจสอบว่าได้ติดตั้งเฟรมเวิร์ก Flask ในสภาพแวดล้อมการพัฒนาแล้ว ดังนี้

pip install flask

การติดตั้ง Flask จะแสดงผลลัพธ์ที่คล้ายกับข้อความต่อไปนี้

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

หากต้องการเรียกใช้แอปพลิเคชันนี้ในเครื่อง ให้เรียกใช้คำสั่งต่อไปนี้

python web_app.py

ใช้ Cloud Shell Web Preview เพื่อทดสอบเว็บแอปในเบราว์เซอร์ ใน Cloud Shell ให้คลิก "ตัวอย่างเว็บ" แล้วเลือก "ดูตัวอย่างบนพอร์ต 8080"

6c9ff9e5c692c58e.gif

Cloud Shell จะเปิด URL ตัวอย่างบนบริการพร็อกซีในหน้าต่างเบราว์เซอร์ใหม่ ตัวอย่างเว็บจะจำกัดให้บัญชีผู้ใช้ของคุณเข้าถึงผ่าน HTTPS เท่านั้น หากทุกอย่างถูกต้อง คุณควรเห็นหน้าต่าง "Python ขับเคลื่อนโดย" โลโก้

8e5c3ead11cfd103.png

8 ยินดีด้วย

b158ce75c3cccd6d.png

คุณได้ทำให้ Cloud Functions ของ HTTP ใช้งานได้โดยใช้ฟังก์ชันที่ไม่ซ้ำกันที่จัดการคำขอเว็บด้วยเฟรมเวิร์ก Flask

ราคาของ Cloud Functions จะอิงตามความถี่ที่เรียกใช้ฟังก์ชัน รวมถึงรุ่นฟรีสำหรับฟังก์ชันที่ไม่ได้เรียกใช้บ่อย เมื่อทดสอบ Cloud Functions เสร็จสิ้นแล้ว คุณลบฟังก์ชันได้โดยใช้ gcloud

gcloud functions delete hello_world --quiet
gcloud functions delete hello_name --quiet
gcloud functions delete python_powered --quiet

นอกจากนี้ คุณยังลบฟังก์ชันออกจากคอนโซล Google Cloud ได้ด้วย

เราหวังว่าคุณจะสนุกกับการใช้ Cloud Functions ใน Python