iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0
Cloud Native

AWS AI交易室實戰系列 第 7

Day 7 - AWS Lambda in Python

  • 分享至 

  • xImage
  •  

~ 最高境界,無伺服器勝有伺服器 ~
AWS Event Services

相關程式碼:https://github.com/slindevel/modern-aws-marathon

Lambda 是什麼?

AWS Lambda 是一項運算服務,可讓您執行程式碼,無需佈建或管理伺服器。

Lambda 在高可用性的運算基礎設施上執行您的程式碼,並執行所有運算資源的管理,包括伺服器與作業系統維護、容量佈建與自動擴展以及記錄。使用 Lambda,您唯一需要做的就是在 Lambda 支援的其中一種語言執行期中提供您的程式碼。 ~ by AWS ~

這段話說明得很精確,但如果初學的人還是不知道他在說什麼吧

在計算機科學和程式領域,Lambda常常用來表示匿名函數或Lambda函數,也稱為函數字面量或函數值。 Lambda函數是一種無需定義名稱的函數,通常用於「編寫簡短而緊湊的程式碼」

AWS Lambda 服務就是可以讓你跑簡短而緊湊的程式碼的服務。

所謂「簡短而緊湊的代碼」,是指相對於模組而言,舉個例來說,我們今天想完成一件事情需要10個步驟,雲服務會希望你把這「10個步驟」包上去,而不是把「完成一件事」包上去,未來在完成另一件相關的事情的時候,很大機會會用到這「10個步驟」,設計可重用簡短的程式碼讓服務得以重用我認為是雲端原生工程師一個很重要的課題。往後可能還有機會介紹到 API Gateway 的服務應該就更有感覺了,他可以掛上一個 HTTP Restful API 對外服務,後面接著一個 lambda service(更精確的說法:lambda handler),一個 HTTP Get 端點,對應到一個 lambda function。

我們先從一個簡單的 Python lambda handler 開始吧,

  • 先準備 python 3.11 的環境,因為我們後面幾天會用到 AI 的東西,裝上 anaconda 管理 python 版本會比較方便,不過我們 lambda 上執行的話,必須要把整個 python project folder 封裝成 zip 檔案,這會需要這個 project folder 是完全獨立的,筆者是**使用 conda 管理 python 版本後再使用此版本建立 virtual env **的做法,建立 python virtual env 指令:進入專案目錄下 python -m venv .venv

  • 使用 Python 建置 Lambda 函數
    網路上有很多 step-by-step 的教學,都有附圖很好上手,我們都是武林高手,自然要用 AWS CLI 做啦

# create the role for execution of lambda
$ aws iam create-role --role-name marathon-lambda-ex \
--assume-role-policy-document file://trust-policy.json

# add lambda execution permissions to the role
$ aws iam attach-role-policy \
--role-name marathon-lambda-ex \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# get role info
$ aws iam get-role --role-name marathon-lambda-ex
$ aws iam list-role-policies --role-name marathon-lambda-ex
$ aws iam list-attached-role-policies --role-name marathon-lambda-ex
  • 然後我們建立一個 python project “MarathonLambdaFunction”
$ mkdir MarathonLambdaFunction && cd MarathonLambdaFunction
$ python -m venv .venv
$ vi lambda_function.py

# lambda_function.py
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Marathon Lambda!')
    }

# package it to zip format
$ zip function.zip lambda_function.py

# aws cli create-function
# query 'marathon-lambda-ex' role ARN first
$ aws iam get-role --role-name marathon-lambda-ex
$ aws lambda create-function \
--function-name marathon-function \
--zip-file fileb://function.zip \
--handler lambda_function.lambda_handler --runtime python3.11 \
--role <marathon-lambda-ex arn>

# then testing it, will output to out.log file
$ aws lambda invoke --function-name marathon-function out.log --log-type Tail

# update function to response new body 'Hello from New Marathon Lambda!'
$ zip function.zip lambda_function.py && \
aws lambda update-function-code \
--function-name marathon-function \
--zip-file fileb://function.zip
  • 不知道 role 的 ARN 也可以進 web console 查詢
    Role ARN

  • 然後我們加一些 python package 進去我們的專案,只有一種最陽春的形式:python package folder

    • 如果我們使用 virtual env
    • 注意 lambda_handler_2 只有使用 boto3 (AWS S3 Python SDK) package,由於AWS Lambda Python 3.11 Runtime 內建 boto3 package ,跟上例一樣只需要 zip lambda_function.py 就可以了(即使如此 AWS 還是建議我們自行安裝所有的相關套件)
# lambda_function.py
import json
import boto3
import requests

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from New Marathon Lambda!')
    }

def lambda_handler_2(event, context):
    bucket_list = ""
    s3 = boto3.resource('s3')
    for bucket in s3.buckets.all():
        bucket_list = bucket_list + ', ' + bucket.name
    return {
        'statusCode': 200,
        'body': json.dumps('all buckets: ' + bucket_list)
    }

def lambda_handler_3(event, context):
    r = requests.get('https://www.google.com.tw/')
    return {
        'statusCode': 200,
        'body': json.dumps('all buckets: ' + str(r.status_code))
    }

$ zip function.zip lambda_function.py && \
aws lambda update-function-code \
--function-name marathon-function \
--zip-file fileb://function.zip

# need to update lambda configuration to use lambda_handler_2
$ aws lambda update-function-configuration --function-name marathon-function \
--handler lambda_function.lambda_handler_2

# fail becaouse lambda no permission to s3
$ aws lambda invoke --function-name marathon-function out.log --log-type Tail

# attach policy to lambda execution role & invoke again
$ aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess --role-name marathon-lambda-ex
$ aws lambda invoke --function-name marathon-function out.log --log-type Tail

# use python virtual env
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install requests
$ pip install boto3
$ pip show pip # find where is the package installed, here is '.venv/lib/python3.11/site-packages'
$ pushd .venv/lib/python3.11/site-packages && zip -r ../../../../function.zip . && popd
$ zip function.zip lambda_function.py
$ aws lambda update-function-code \
--function-name marathon-function \
--zip-file fileb://function.zip
$ aws lambda update-function-configuration --function-name marathon-function \
--handler lambda_function.lambda_handler_3
$ aws lambda invoke --function-name marathon-function out.log --log-type Tail
# 執行以下指令移除一些不必要的檔案
$ find . | grep -E "(/__pycache__$|\.pyc$|\.pyo$)" | xargs rm -rf
  • 上面的 lambda_handler_3 大家會發現一個小秘密,預設 lambda 是可以連外的,一般說來建立 lambda 會建議需要設定 vpc ,才能決定你的 lambda 住哪邊吧,之後才能由 vpc 掌握可以連線的 resouces,包含外網,這部分我們會在明天 lambda 進階探討

  • 最後我們看看 function.zip 的內容吧
    ├── function (folder)
    ├── lambda_function.py (file)
    ├  ├── requests (folder)
    ├  ├── boto3 (folder)

  • 使用 credentials 在本機端執行
    上面的取得 S3 bucket list 的 handler 也可以在本機端執行唷,記得我們在之前瘋狂使用本機端的 AWS CLI 執行一堆指令吧,關鍵在於我們有設定本機端的Credential,同樣地,我們也可以使用 Python 程式碼取得本機端的 Credential 來執行 AWS 服務相關的程式碼,直接來看範例吧(AWS_PROFILE_NAME可以在 ~/.aws/credentials 裡面找到

# Can be execution on local environment
def lambda_handler_3(event, context):
    session = boto3.Session(profile_name='{YOUR_AWS_PROFILE_NAME}')
    s3_client = session.client('s3')
    response = s3_client.list_buckets()
    bucket_list = ""
    for bucket in response['Buckets']:
        bucket_list = bucket_list + ', ' + bucket['Name']
    return {
        'statusCode': 200,
        'body': json.dumps('all buckets: ' + bucket_list)
    }
  • 我們在之後會介紹 SAM 的開發模式,使用 SAM 可以模擬 AWS 的執行環境,也有方便的指令可以取得真實AWS 輸入給 Lambda 的 input json 內容,有了這些訊息&方法,已足夠我們撰寫幾乎擬真於AWS 執行環境的測試程式碼,關於撰寫 Lambda 的測試碼又是另一門重要的議題了。(查過網路上數十篇文章,每一篇的情境與方法都不同,這部分只有標準工具,並沒有標準做法)

AWS Lambda 之禪

Lambda 這個概念的出現,讓我們重新思考**何謂架構**,說到底其實我們**其實不需要架構**,**只需要**有人可以幫我們執行我們要的指令**完成我們要的功能**而已,因為要**快速、穩定、正確**大量執行我們的指令,數十年的資訊架構演進都是**為了實現這一件事情**,執行者需要處理租用機房,採購設備,部署指令,維持運作等等工作,而今天 AWS Lambda **只需要我們提供指令**以及**足夠的執行資訊(環境變數)**給他就行了,**有需要的時候幫忙找環境執行,不需要的時候不佔用資源**,多麽優雅美妙!

Cloud Native 意指雲端原生應用,強調原生的背後很有可能是呼籲回歸本質? Native 一詞我認為相當有趣,資訊的進步腳步太快,項目五花八門,今日我們似乎看到了應用的終點,用程式寫個人出來做事 — AI,但我們仍然在創造一堆困難艱澀的名詞,回歸 Native,邁向收斂看起來才像是個終點,另一方面 Cloud,應該是因為實現 Native的解答在雲端上面的意思吧,而 Lambda 是我認為最能闡述體會出這個概念的服務

參考資料

https://aws.amazon.com/tw/blogs/compute/introducing-aws-lambda-destinations/
https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
https://dev.to/aws-builders/simple-aws-20-advanced-tips-for-lambda-1oif
https://awstip.com/how-to-add-external-python-libraries-to-aws-lambda-baa8cb8dd7e1
https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html


上一篇
Day 6 - EC2 & EC2 Instance Connect Endpoint
下一篇
Day 8 - Lambda Best Practices
系列文
AWS AI交易室實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言