aws lambda 理解RIC和RIE构建和测试容器镜像并通过cdk部署lambda函数

news2024/11/17 12:50:51

参考资料

  • AWS Lambda 的新功能 — 容器映像支持

  • 快速构建基于 Lambda 容器镜像的 OCR 应用

  • 利用 Lambda 容器镜像搭建分布式压测引擎

lambda容器镜像构建

可以将 Lambda 函数打包和部署最大 10 GB容器映像,轻松构建和部署依赖于大量依赖项的更大型工作负载

aws为所有支持的lambda运行时提供了基础镜像,以及基于amazonlinux的自定义镜像。甚至可以自行安装lambda runtime api(RIC运行时接口客户端)对其他的基础镜像(apline或debian)进行扩展

使用lambda容器镜像的先决条件

  • 镜像中安装lambda runtime api
  • 容器必须能够在只读系统上运行,可写的目录(/tmp)大小从512MB到10GB不等
  • lambda用户有权限运行lambda函数和所需文件
  • 仅支持linux容器,每个镜像针对单一架构

注意:lambda容器镜像仅支持以下dockerfile参数:ENTRYPOINT,CMD,WORKDIR,ENV ,并且会忽略 Dockerfile 中任何不支持的容器镜像设置的值。指定 ENTRYPOINT 或 CMD需要指定绝对路径

aws发布了Lambda Runtime Interface Emulator(运行时接口模拟器RIE),方便再本地对容器镜像进行测试。预装在基础镜像中。RIE是一个轻量级 Web 服务器,它将 HTTP 请求转换为 JSON 事件以传递给容器镜像中的 Lambda 函数

使用RIE的注意事项

  • RIE不支持lambda的iam模拟
  • RIE区分不同架构(x86_64和arm64)
  • 不支持xray或其他lambda集成

将RIE打包到镜像中,以下entry_script.sh脚本通过判断环境变量AWS_LAMBDA_RUNTIME_API决定是否运行RIE

#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
  exec /usr/local/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $@
else
  exec /usr/local/bin/python -m awslambdaric $@
fi

下载RIE并添加到dockerfile中

COPY ./entry_script.sh /entry_script.sh
ADD aws-lambda-rie-x86_64 /usr/local/bin/aws-lambda-rie
ENTRYPOINT [ "/entry_script.sh" ]

当然也可以不将RIE构建到镜像中,直接在本地测试。将RIE下载安装到本地

mkdir -p ~/.aws-lambda-rie
curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie 
chmod +x ~/.aws-lambda-rie/aws-lambda-rie

使用以下命令运行lambda函数

docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
  --entrypoint /aws-lambda/aws-lambda-rie hello-world:latest <image entrypoint> \
      <(optional) image command>

测试发送事件

curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

官方底包构建lambda镜像

aws的基础lambda镜像提供了以下环境变量

  • LAMBDA_TASK_ROOT=/var/task
  • LAMBDA_RUNTIME_DIR=/var/runtime
FROM public.ecr.aws/lambda/python:3.8
COPY app.py ${LAMBDA_TASK_ROOT}
COPY requirements.txt  .
RUN  pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"
CMD [ "app.handler" ] 

备选底包构建lambda镜像

Lambda 支持所有 Linux 发行版,例如 Alpine、Debian 和 Ubuntu,例如以下实例通过多阶段构建安装程序依赖包和ric接口

ARG FUNCTION_DIR="/function"
FROM python:buster as build-image
RUN apt-get update && apt-get install -y g++ make cmake unzip libcurl4-openssl-dev
ARG FUNCTION_DIR
RUN mkdir -p ${FUNCTION_DIR}
COPY app/* ${FUNCTION_DIR}
RUN pip install --target ${FUNCTION_DIR} awslambdaric
# 多阶段构建
FROM python:buster
ARG FUNCTION_DIR
WORKDIR ${FUNCTION_DIR}
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
ENTRYPOINT [ "/usr/local/bin/python", "-m", "awslambdaric" ]
CMD [ "app.handler" ]

官方的生成PDF文件的简单项目

创建应用程序,通过PDFKit 模块创建pdf文件,使用faker填充随机内容

const PDFDocument = require('pdfkit');
const faker = require('faker');
const getStream = require('get-stream');

exports.lambdaHandler = async (event) => {

    const doc = new PDFDocument();

    const randomName = faker.name.findName();

    doc.text(randomName, { align: 'right' });
    doc.text(faker.address.streetAddress(), { align: 'right' });
    doc.text(faker.address.secondaryAddress(), { align: 'right' });
    doc.text(faker.address.zipCode() + ' ' + faker.address.city(), { align: 'right' });
    doc.moveDown();
    doc.text('Dear ' + randomName + ',');
    doc.moveDown();
    for(let i = 0; i < 3; i++) {
        doc.text(faker.lorem.paragraph());
        doc.moveDown();
    }
    doc.text(faker.name.findName(), { align: 'right' });
    doc.end();

    pdfBuffer = await getStream.buffer(doc);
    pdfBase64 = pdfBuffer.toString('base64');

    const response = {
        statusCode: 200,
        headers: {
            'Content-Length': Buffer.byteLength(pdfBase64),
            'Content-Type': 'application/pdf',
            'Content-disposition': 'attachment;filename=test.pdf'
        },
        isBase64Encoded: true,
        body: pdfBase64
    };
    return response;
};

生成依赖文件package.json

npm init -y
npm install pdfkit
npm install faker
npm install get-stream

创建dockerfile,CMD中指定lambda入口

FROM amazon/aws-lambda-nodejs:16
COPY app.js package*.json ./
RUN npm install
CMD [ "app.lambdaHandler" ]

构建容器

docker build -t random-letter .

运行测试,响应成功,可见amazon镜像自带RIE和RIC

docker run -p 9000:8080 random-letter:latest
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
output:
{"statusCode":200,"headers":{"Content-Length":2572,"Content-Type":"application/pdf","Content-disposition":"attachment;filename=test.pdf"},"isBase64Encoded":true,"body":"JVBERi0xLjMKJf//....."}

将构建好的容器上传到ecr中,略去

创建lambda函数并选择容器镜像即可

在这里插入图片描述

通过这个脚本将bese64结果还原成pdf,可见函数创建成功

在这里插入图片描述

基于自定义镜像影响构建lambda镜像

参考:https://aws.amazon.com/cn/blogs/china/new-for-aws-lambda-container-image-support/

初始化项目

pipenv --python 3.9
pipenv install faker
pipenv requirements > requirements.txt

创建一个简单的app.py,用faker造一些数据

import sys
from faker import Faker
def handler(event, context): 
    fake = Faker()
    play = {"name":fake.name(),"address":fake.address,"dialogue":fake.text()}
    print(play)
    return 'Hello from AWS Lambda using Python' + sys.version + '!'

创建入口文件entry.sh,这个之前解释过了,略去

#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
    exec /usr/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric
else
    exec /usr/local/bin/python -m awslambdaric
fi

创建dockerfile,注意:在第2阶段需要使用gcc编译和关联ric的依赖项

ARG FUNCTION_DIR="/home/app/"
ARG RUNTIME_VERSION="3.9"
ARG DISTRO_VERSION="3.12"
#stage 1
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS python-alpine
RUN apk add --no-cache libstdc++
#stage 2
FROM python-alpine AS build-image
RUN apk add --no-cache build-base libtool autoconf automake libexecinfo-dev make cmake libcurl
ARG FUNCTION_DIR
ARG RUNTIME_VERSION
RUN mkdir -p ${FUNCTION_DIR}
COPY ./* ${FUNCTION_DIR}
RUN ls ${FUNCTION_DIR}
RUN python${RUNTIME_VERSION} -m pip install -r ${FUNCTION_DIR}/requirements.txt --target ${FUNCTION_DIR}
RUN python${RUNTIME_VERSION} -m pip install awslambdaric --target ${FUNCTION_DIR} -i https://pypi.douban.com/simple/
#stage 3
FROM python-alpine
ARG FUNCTION_DIR
WORKDIR ${FUNCTION_DIR}
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie
COPY entry.sh /
# ENTRYPOINT [ "/entry.sh" ]
ENTRYPOINT [ "/usr/local/bin/python", “-m”, “awslambdaric” ]
CMD [ "app.handler" ]

手动上传image到ecr中创建lambda函数之后,测试通过

在这里插入图片描述

本地测试

docker build -t sayhello .
docker run -p 9000:8080 sayhello
docker run -it --rm -p 9000:8080 sayhello
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

由于RIE是可选的,我们可以将RIE安装在本地进行测试

注释dockerfile中的RIE,修改ENTRYPOINTENTRYPOINT [ "/usr/local/bin/python", “-m”, “awslambdaric” ],运行以下命令测试

docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
       --entrypoint /aws-lambda/aws-lambda-rie sayhello
       /lambda-entrypoint.sh app.handler

遇到的错误

(1)在本地运行时出现以下报错

KeyError: 'AWS_LAMBDA_RUNTIME_API'

当函数部署到lambda服务时,运行时会从 AWS_LAMBDA_RUNTIME_API 环境变量获取 API 终端节点,本地测试无法获取AWS_LAMBDA_RUNTIME_API环境变量所以报错,需要使用RIE入口的entry.sh构建

https://docs.amazonaws.cn/lambda/latest/dg/runtimes-api.html

(2)在本地通过RIE请求测试出现以下报错

Traceback (most recent call last):
  File "/home/app/awslambdaric/__main__.py", line 15, in main
    handler = args[1]
IndexError: list index out of range

检查发现入口文件可能有点问题,修改如下

#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
    exec /usr/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $@
else
    exec /usr/local/bin/python -m awslambdaric $@
fi

通过cdk打包上传oci镜像创建lambda函数

https://docs.aws.amazon.com/cdk/api/v2/python/index.html

lambda-from-container-demo

初始化cdk项目(python)

cdk init --language=python

复制示例项目中的堆栈代码,略作修改

#!/usr/bin/env python3
import os
import typing
import aws_cdk as cdk
from aws_cdk import (
    aws_lambda,
    aws_ecr,
    Aws, Duration, Stack, Construct
)
# from lambdafromcontainer.lambdafromcontainer_stack import LambdafromcontainerStack

class LambdaContainerFunctionStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        image_name    = "lambdaContainerFunction"
        # if use pre_existing image
        use_pre_existing_image = False
        if (use_pre_existing_image):
            ecr_repository = aws_ecr.Repository.from_repository_attributes(self,
                id              = "ECR",
                repository_name = image_name
            )
            
            ecr_image = typing.cast("aws_lambda.Code", aws_lambda.EcrImageCode(
                repository = ecr_repository
            ))
        else:
            ecr_image = aws_lambda.EcrImageCode.from_asset_image(
                directory = os.path.join(os.getcwd(), "lambda-image")
            )

        aws_lambda.Function(self,
            id            = "lambdaContainerFunction",
            description   = "Sample Lambda Container Function",
            code          = ecr_image,
            handler       = aws_lambda.Handler.FROM_IMAGE,
            runtime       = aws_lambda.Runtime.FROM_IMAGE,
            environment   = {"hello":"world"},
            function_name = "sampleContainerFunction",
            memory_size   = 128,
            reserved_concurrent_executions = 10,
            timeout       = Duration.seconds(10),
        )

app = cdk.App()
LambdaContainerFunctionStack(app, "LambdafromcontainerStack",
    env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),
    )
app.synth()

通过directory = os.path.join(os.getcwd(), "lambda-image")

项目结构有,app还是用之前的pdf应用

$ tree 
├── app.py
├── cdk.json
├── lambda-image
│   ├── app.js
│   ├── Dockerfile
│   └── package.json
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── source.bat
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_lambdafromcontainer_stack.py

最后生成的cfn模板如下

Resources:
  lambdaContainerFunctionServiceRole5E36DB3C:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  lambdaContainerFunction5815FD88:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ImageUri:
          Fn::Sub: xxxxxxxxx.dkr.ecr.cn-north-1.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-xxxxxxxxx-cn-north-1:64c8e7a88147f47764a7d9704e172e6ee65c807bc0157fac194da92f82afadcd
      Role:
        Fn::GetAtt:
          - lambdaContainerFunctionServiceRole5E36DB3C
          - Arn
      Description: Sample Lambda Container Function
      Environment:
        Variables:
          hello: world
      FunctionName: sampleContainerFunction
      MemorySize: 128
      PackageType: Image
      ReservedConcurrentExecutions: 10
      Timeout: 10
    DependsOn:
      - lambdaContainerFunctionServiceRole5E36DB3C

注意,lambda-image目录下的dockerfile的名称必须首字母大写Dockerfile

直接部署lambda函数

cdk deploy

以上命令会自动构建镜像并以该镜像创建lambda函数,减少了很多工作量

在这里插入图片描述

在lambda控制台测试成功

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/137707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java核心技术】创建多线程

1、多线程的概述 什么是线程&#xff1f; 线程(thread)是一个程序内部的一条执行路径。 我们之前启动程序执行后&#xff0c;main方法的执行其实就是一条单独的执行路径。 public static void main(String[] args) {// 代码...for (int i 0; i < 10; i) {System.out.prin…

《柳叶刀》:约20%中国男性死亡可归因于吸烟

*仅供医学专业人士阅读参考 吸烟喝酒可谓众所周知的两大“健康刺客”。一首歌名为《给我一杯酒》中的歌词唱到“给我一杯酒&#xff0c;再给我一只烟&#xff0c;说走就走&#xff0c;我有的是时间”&#xff0c;传唱度极高&#xff0c;甚至还一度成为短视频平台的最热门的BGM之…

概论_第2章_重点内容__随机变量函数的概率分布

一 定义 概括地说&#xff1a; 随机变量Y是随机变量X的函数。 设g(x) 是一给定的连续函数&#xff0c; 称Yg(X) 为随机变量X的一个函数&#xff0c; Y也是一个随机变量。当X取值 时&#xff0c;Y取值 . ~~~~~~~~~~~~~~ 本文讨论连续型随机变量函数。 定理1: 设X为连续型…

Appium环境搭建及元素定位

01 Appium简介 Appium是一个开源测试自动化框架&#xff0c;可用于原生&#xff0c;混合和移动Web应用程序测试。它使用WebDriver 协议驱动iOS&#xff0c;Android和Windows应用程序。 01 环境搭建步骤 Appium环境安装&#xff1a; 第一步 安装 appium 桌面版客户端 Appium…

Linux挂载磁盘命令

需求&#xff1a; 只有一个硬盘&#xff0c;创建多个挂载点 参考&#xff1a;linux如何实现挂载—linux_是小明同学啊的博客-CSDN博客_linux挂载 1 查看当前挂载情况 执行 df -h&#xff0c; 查看当前 / 根目录下挂载的分区名&#xff0c;在下图中为倒数第三行&#xff0c; …

html练习

1. 2. 3. <h1>各科小常识</h1> <h3>语文</h3> <p> 三国演义是中国四大古典名著之一&#xff0c;元末明初小说家罗贯中所著。是中国第一部章回体历史演义的小说&#xff0c;描写了从东汉末年到西晋初年近100年的历史风云。</p> <hr&g…

Ubuntu20.04 LTS 安装 ros Noetic 树莓派4/PC

Ubuntu 20.04 LTS 安装树莓派系统. 主要参考了这两篇文章&#xff1a; https://blog.csdn.net/liangforcold/article/details/126385774 https://blog.csdn.net/yangcunbiao/article/details/123056806 https://blog.csdn.net/duping812/article/details/110391081 1、下载安…

【前端-NPM私服】内网使用verdaccio搭建私有npm服务器-docker搭建verdaccio流程

目录一、npm私服是什么1. 定义2. 为什么需要npm私服二、npm私服如何使用1. 链接到npm私服2. 注册私服账号3. 发布组件到私服4. 关联LDAP服务5. 提高下载速度三、私服搭建方案四、docker搭建Verdaccio流程1. 拉镜像2. 创建卷3. 启动容器4. 软链接卷到统一的目录5. 配置Verdaccio…

【node.js】npm包管理工具的使用

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;node.jsx中npm包管理工具的基础使用&#xff0c;包与依赖关系的介绍 下图为本文的核心 目…

rmq 主备自动切换模式

https://rocketmq.apache.org/zh/docs/deploymentOperations/16autoswitchdeploy/ https://github.com/apache/rocketmq/blob/develop/docs/cn/controller/design.md controller 端 leader选举 主备自动切换模式就是controller模式&#xff0c;controller可以嵌入name serve…

ccc-sklearn-12-线性回归(2)

一、非线性问题&#xff1a;多项式回归 主要探讨&#xff1a;通过线性回归解决非线性问题 数据的线性与非线性 通常情况下&#xff0c;分类问题中决策函数往往是一个分段函数&#xff0c;这个函数明显不满足可以用一条直线进行表示的属性&#xff0c;因此分类问题中特征与标签[…

若依整合第三方登录

0&#xff1a;以gitee为例&#xff0c;首先开通gitee第三方登录&#xff1a;&#xff08;在设置里面的第三方应用里面新建&#xff09; 0.1&#xff1a;后端引入JustAuth第三方登陆框架&#xff1a; <dependency><groupId>me.zhyd.oauth</groupId><artif…

H5UI库、加密技术和二维码

一、H5UI库 1. 使用方法&#xff1a; ​ &#xff08;1&#xff09;页面中引入css文件 ​ h5ui.css &#xff08;h5ui.min.css&#xff09; ​ &#xff08;2&#xff09;页面中引入js文件 ​ ​ jquery.min.js ​ ​ h5ui.min.js 2. 组件…

十五、Kubernetes中Pod生命周期详解、实例

1、概述 我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期&#xff0c;它主要包含下面的过程&#xff1a; pod创建过程 运行初始化容器&#xff08;init container&#xff09;过程 运行主容器&#xff08;main container&#xff09; 容器启动后钩子&#xff0…

对于负载均衡服务器一致性哈希算法一些简单的想法

文章目录一致性哈希负载均衡的介绍一致性哈希负载均衡的介绍 负载均衡这个概念可以抽象为&#xff1a;从n个候选服务器中选择一个进行通信。 负载均衡算法有&#xff1a;随机&#xff0c;轮询&#xff0c;最小连接数等。今天的“猪脚”是一致性哈希负载均衡算法&#xff1b; 一…

Java语法:枚举

1.枚举是什么&#xff1f; 枚举是Java中的一种特殊类型。 2.枚举的作用 是为了做信息的标志和分类。 3.枚举的语法 定义语法&#xff1a; 修饰符 enum 枚举名称 {第一行都是罗列枚举类实例的名称。 } /*** 枚举类*/ public enum Season {//枚举的第一行必须罗列枚举类的…

流量劫持的危害及应对方法

流量劫持总体来说属于中间人攻击的一种&#xff0c;本质上攻击者在通信两端之间对通信内容进行嗅探和篡改&#xff0c;以达到插入数据和获取关键信息的目的。目前互联网上发生的流量劫持基本是两种手段来实现的: 域名劫持&#xff1a;通过劫持掉域名的DNS解析结果&#xff0c;…

那些年,我们crush的爆款小游戏大盘点

小游戏&#xff0c;即小程序游戏&#xff0c;是小程序的一个子类目&#xff0c;其最大的特点就是“即点即玩”&#xff0c;具备出色的用户体验。如今大家的生活逐渐向快节奏发展&#xff0c;在各种压力下&#xff0c;人们更倾向于方便快捷的娱乐方式&#xff0c;而这正推动了小…

一年时间,拿到了人生中的第一个20万

目录一、2021年度博客之星评选第二名二、博客新星导师三、哪吒社区四、粉丝群五、付费专栏六、Java学习路线总结&#xff0c;搬砖工逆袭Java架构师七、关于读书八、你好2023一、2021年度博客之星评选第二名 2022年&#xff0c;是哪吒收获的一年&#xff0c;收获了人生中的第一…

Java虚拟机(JVM)面试专题 下(初级程序员P6)

Java虚拟机&#xff08;JVM&#xff09;面试专题 下&#xff08;初级程序员P6&#xff09; 六、四种引用 1. 强引用 普通变量赋值即为强引用&#xff0c;如 A a new A(); 通过 GC Root 的引用链&#xff0c;如果强引用不到该对象&#xff0c;该对象才能被回收 2. 软引用&a…