使用 CDK 打造 Docker Image 建置 Lambda

POSTED BY   Chris
2021 年 5 月 17 日
使用 CDK 打造 Docker Image 建置 Lambda

從去年底 AWS re:invent 2020 公佈 lambda 支持使用 docker image 建置,這個算是大消息,也是一個突破,一來 docker image 支持上限到 10G,二來在 deploy 之前,可以在本地啟動 docker 來測試 lambda,相當吸引人,可以參考一下這篇 AWS Blog Post ,再來大概介紹一下 CDK 怎麼建置

 

CDK IaC 建置

一般 Lambda 都會搭配 Event Bridge (CloudWatch event) 來當作觸發點,剛好最近碰到一個需求,就是 IAM 建立新帳號時,要自動寄信且信件內容包含 username、password,或是 cli 使用的 credential,這邊就以這個例子來看一下程式碼

TypeScript
const lambdaFunc = new lambda.DockerImageFunction(
      this,
      'CodepipelineEventLambda',
      {
        code: lambda.DockerImageCode.fromImageAsset(
          path.join(__dirname, '../lambda'),
          {
            cmd: ['app.handler'],
          }
        ),
        environment: {
          EMAIL_FROM: props.emailFrom,
          SSM_PARAMETER_LIST_PREFIX_FOR_EMAIL:
            props.ssmParameterListPrefixForEmail,
          STAGE: props.stage,
          SMTP_USERNAME: `${smtpUserName}`,
          SMTP_PASSWORD: `${smtpPassword}`,
          AWS_ACCOUNT_ID: cdk.Aws.ACCOUNT_ID,
          REGION: cdk.Aws.REGION,
        },
      }
    );

    // 監聽 CloudTrail 在 IAM 新建 user 時觸發
    cloudtrail.Trail.onEvent(this, 'MyCloudWatchEvent', {
      target: new eventTargets.LambdaFunction(lambdaFunc),
      ruleName: 'email-when-iam-user-created',
      eventPattern: {
        source: ['aws.iam'],
        detailType: ['AWS API Call via CloudTrail'],
        detail: {
          eventSource: ['iam.amazonaws.com'],
          eventName: ['CreateUser'],
        },
      },
    });

 

細節就不說明了,之後有時間再專門寫一篇介紹自動寄信這件事,這邊重點在於

TypeScript
        code: lambda.DockerImageCode.fromImageAsset(
          path.join(__dirname, '../lambda'),
          {
            cmd: ['app.handler'],
          }
        ),

 

使用 docker image 建置 CDK 真的很方便,就這短短幾行,當然再來還有一個重點,依此例子為例,就是上一層目錄的 lamba 資料夾要準備的東西,既然用 docker image,當然需要來個 Dockerfile,其餘檔案就看 lambda 使用哪種語言 (runtime),會有所不同,這邊以 Python 為例,Dockerfile 如下

Dockerfile
FROM public.ecr.aws/lambda/python:3.8

COPY app.py requirements.txt ./

RUN pip install --user --no-cache-dir --upgrade pip && \
  pip install --user --no-cache-dir -r requirements.txt

CMD ["app.handler"]    

 

重點在第一行,這是 AWS 提供的官方 runtime docker image,當然其他語言也有,如果是 node version 14 ,就是 public.ecr.aws/lambda/nodejs:14,當然也支援自訂的 image

上述的 Dockerfile 準備好後,以此例子就剩下 app.py (requirements.txt 就不介紹了),最簡單測試的 app.py 如下

Python
import json

def handler(event, context):
  print("Received event: " + json.dumps(event, indent=2))

 

到此,最簡單的配置即完成,最後在 cdk deploy 後,在 CDK deploy 階段時,cdk 會 pull 此 docker image 下來 build,之後推上 AWS ECR,然後 AWS Management Console 中的 lambda code 就會顯示來源是 ECR 的某個 tag,這邊 tag 是 CDK 自行產生的 hash code,目的在於每次修改 lambda 後,CDK 發現有變動後,就會再推一個新版到 ECR tag

 

本地 docker image 測試

要在本地測試 docker image 也是很容易的,先使用 cli 把目錄切到 lambda 所在位置,也就是有 Dockerfile 的地方,依此 Dockerfile 來建置和啟動 docker ,如下指令

Dockerfile
	docker build -t email-app:latest .
	docker run -p 9000:8080 \
	--env AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
	--env AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
	--env AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} \
	email-app:latest

 

這邊注意到,有帶 3 個環境變數,也就是在本機執行此 lambda 時需要哪些權限,可以參考 AWS 官方文件 可知道還有哪些環境變數可以用

若順利,此時本機已經監聽 9000 port,再來就是用 curl 來測試 lambda function,如下

curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"detail":{"requestParameters":{"userName": "new-user"}}}' 

 

-d 後方就是 event payload,會依不同 event bridge 事件而有不同,這邊是以 CloudTrail 為例,當有新的 IAM user 被建立時,此時 user name 會傳入 lambda 中來做後續處理

到此,若一切正常,就會看到 lambda 上 print 出來的訊息,而這段應該也可以寫成 shell script,放在 CI 流程中測試 lambda 是否正常,當作一個 e2e test

 

補充 (2021/5/24)

AWS 官方 Python Docker image 中,如果想要使用 pipenv,Dockerfile 可以考慮這樣寫

Dockerfile
FROM public.ecr.aws/lambda/python:3.8

COPY . .

RUN pip install --user --no-cache-dir --upgrade pip && \
  pip install --user --no-cache-dir pipenv

ENV PATH="${PATH}:/root/.local/bin"

RUN pipenv --python 3.8 && \
  pipenv install --system

CMD ["app.handler"]    

原因在於 public.ecr.aws/lambda/python 所提供的 Python 虛擬環境預設不是用 pipenv,所以才需要用 –system 參數來指定安裝,雖然 pipenv 的 –system 參數是不被建議的,在這個 issue 有說明,但目前找不到更好的方式,只好先這樣用

歡迎留言
0

您可能也想看

Workaround for AWS Grafana alerting
2023 年 8 月 3 日
AWS, DevOps
AWS VPC Endpoint 使用場景
2022 年 3 月 14 日
AWS, CDK, Network
CDK 指定 Physical names 運作方式
2021 年 12 月 4 日
AWS, CDK, Cloudformation