• AWS Lambda 操作 RDS 示例


    实现目标

    创建一个 Lambda 接收调用时传入的数据, 写入 RDS 数据库 Post 表存储文章信息. 表结构如下:

    idtitlecontentcreate_date
    1我是标题我是正文内容2023-10-21 15:20:00

    AWS 资源准备

    • RDS 控制台创建 MySQL 实例, 不允许 Public access (后面 Lambda 需要通过 VPC 访问)
    • Secrets Manager 控制台创建 Credentials for Amazon RDS database 类型密码, 关联上面创建好的 RDS 实例, 起名为 mydb-secret
    • 从 VPC 内的跳板机手动连接 RDS 创建数据库
    mysql -h [RDS 实例 Endpoint] -u admin -p
    
    MySQL [(none)]> create database lambdaDB;
    MySQL [(none)]> use lambdaDB;
    MySQL [(lambdaDB)]> CREATE TABLE post (
        id INT AUTO_INCREMENT PRIMARY KEY,
        title VARCHAR(255),
        content TEXT,
        create_date DATETIME
    );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • Lambda 控制台创建函数 rds-test, Runtime 使用 Python 3.10 和开发环境保持一致, 使用默认选项 Create a new role with basic Lambda permissions 自动为新建函数创建对应的 IAM Role, 展开 Advanced settings, 勾选 Enable VPC, 选择和 RDS 相同的 VPC, 勾选两个不同 AZ 的 Private Subnet (因为是通过内网访问), 选择能访问 RDS 的安全组.

    在这里插入图片描述

    撸码环节

    开发环境为 WSL2 + VSCode

    # 创建项目文件夹
    mkdir lambda
    cd lambda
    # 创建虚拟环境
    virtual env
    source ./env/bin/active
    # 安装依赖
    pip install pymysql peewee boto3
    # 启动 VSCode
    code .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    VSCode 中创建 rds_lambda.py

    from peewee import *
    import json
    from datetime import datetime
    import boto3
    from botocore.exceptions import ClientError
    
    
    def get_secret():
        """从 Secrets Manager 获取 RDS 密码"""
        secret_name = "mydb-secret"
        region_name = "cn-northwest-1"
    
        # Create a Secrets Manager client
        session = boto3.session.Session()
        client = session.client(service_name="secretsmanager", region_name=region_name)
    
        try:
            get_secret_value_response = client.get_secret_value(SecretId=secret_name)
        except ClientError as e:
            raise e
    
        # Decrypts secret using the associated KMS key.
        secret = get_secret_value_response["SecretString"]
        return json.loads(secret)
    
    
    secret = get_secret()
    
    # 定义 RDS 连接
    db = MySQLDatabase(
        database="lambdaDB",
        host=secret["host"],
        user=secret["username"],
        password=secret["password"],
        port=secret["port"],
    )
    
    
    # 定义基础模型
    class BaseModel(Model):
        class Meta:
            database = db
    
    
    # 定义数据模型
    class Post(BaseModel):
        title = CharField()
        content = TextField()
        create_date = DateTimeField(default=datetime.now)
    
    
    # Lambda 入口函数
    def lambda_handler(event, context):
        """
        Lambda 入口函数, 调用时传入 event 应当符合以下 JSON 格式:
            {
                "title": "我是标题",
                "content": "我是正文内容"
            }
        """
    
        # 解析调用函数时传入的参数
        try:
            Post.create(**event)
        except:
            raise {"code": 1, "message": "添加数据失败"}
    
        return {"code": 0, "message": "添加数据成功"}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    由于函数中用到了额外的依赖, 所以我们可以连同依赖和函数代码一块打包成 ZIP 文件, 通过 AWSCLI 进行上传部署. 官方操作文档

    # 确认当前 Virtualenv 环境下安装的依赖位置
    (venv) lpwm@Beijing:~/lambda$ pip show peewee
    Name: peewee
    Version: 3.17.0
    Summary: a little orm
    Home-page: https://github.com/coleifer/peewee/
    Author: Charles Leifer
    Author-email: coleifer@gmail.com
    License: MIT License
    Location: /home/lpwm/lambda/venv/lib/python3.11/site-packages
    Requires: 
    Required-by:
    
    # 退出 Virtualenv 并将依赖的所有包进行打包
    lpwm@Beijing:~/lambda$ deactivate 
    lpwm@Beijing:~/lambda$ cd venv/lib/python3.11/site-packages/
    lpwm@Beijing:~/lambda/venv/lib/python3.11/site-packages$ zip -r ../../../../deployment_package.zip .
    # 返回项目主文件夹中, 检查依赖的包打好了
    lpwm@Beijing:~/lambda/venv/lib/python3.11/site-packages$ cd ../../../../
    lpwm@Beijing:~/lambda$ ls
    deployment_package.zip  rds_lambda.py  venv
    # 将 rds_lambda.py 再添加到 ZIP 包里面
    lpwm@Beijing:~/lambda$ zip deployment_package.zip rds_lambda.py 
      adding: rds_lambda.py (deflated 49%)
    # 检查确认 rds_lambda.py 添加成功
    lpwm@Beijing:~/lambda$ unzip -l deployment_package.zip | tail
         1759  2023-10-21 14:57   s3transfer-0.7.0.dist-info/METADATA
            4  2023-10-21 14:57   s3transfer-0.7.0.dist-info/INSTALLER
           83  2023-10-21 14:57   s3transfer-0.7.0.dist-info/NOTICE.txt
           92  2023-10-21 14:57   s3transfer-0.7.0.dist-info/WHEEL
           11  2023-10-21 14:57   s3transfer-0.7.0.dist-info/top_level.txt
         2679  2023-10-21 14:57   s3transfer-0.7.0.dist-info/RECORD
        11358  2023-10-21 14:57   s3transfer-0.7.0.dist-info/LICENSE.txt
         1596  2023-10-21 15:17   rds_lambda.py
    ---------                     -------
    102887926                     4266 files
    
    # 上传 ZIP 包到 Lambda
    lpwm@Beijing:~/lambda$ aws lambda update-function-code --function-name rds-test --zip-file fileb://deployment_package.zip
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    上传命令执行后会返回 Lambda 函数的信息, 显示上传正在进行
    在这里插入图片描述
    期间可以检查上传状态和结果

    aws lambda get-function --function-name rds-test
    
    • 1

    上传成功
    在这里插入图片描述
    回到 Lambda 控制台, 通过 ZIP 部署的函数将不再能从浏览器直接编辑代码, 另外留意 Handler 这里用的还是之前创建时默认的入口函数, 需要修改成和我们代码一致的 rds_lambda.lambda_handler
    在这里插入图片描述
    在这里插入图片描述
    创建测试
    在这里插入图片描述
    测试结果报错:
    在这里插入图片描述
    这是由于当前 Lambda 的 Execution Role 并没有访问 Secrets Manager 的权限. 到 Configuration - Permissions 中找到当前使用的 Role, 跳转到 IAM 控制台
    在这里插入图片描述
    Add permissions - Create inline policy
    在这里插入图片描述
    参考 文档 编写权限 JSON, 允许对特定 Secret 只读的权限

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "secretsmanager:GetResourcePolicy",
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:DescribeSecret",
                    "secretsmanager:ListSecretVersionIds"
                ],
                "Resource": [
                    "arn:arn:aws-cn:secretsmanager:cn-northwest-1:888888888888:secret:mydb-secret-lNuRmj"
                ]
            },
            {
                "Effect": "Allow",
                "Action": "secretsmanager:ListSecrets",
                "Resource": "*"
            }
        ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    再次测试 Lambda 调用成功.
    在这里插入图片描述

    回到跳板机中检查数据库可以看到进来的数据.

    MariaDB [lambdaDB]> select * from post;
    +----+-----------+---------+---------------------+
    | id | title     | content | create_date         |
    +----+-----------+---------+---------------------+
    |  1 | I'm title | Hello   | 2023-10-21 08:30:25 |
    +----+-----------+---------+---------------------+
    1 row in set (0.001 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    Kyligence李栋:从数据湖到指标中台,提升数据分析ROI
    矩阵分解算法
    JS数组转为字符串如何实现?
    如何在Linux服务器上部署Vue项目
    Vue3+TypeScript+Element Plus前端项目构建入门
    SpringBoot集成Mybatis项目实操
    9月客户文章盘点——累计IF 103.2
    JVM总结全
    SpringBoot SpringBoot 开发实用篇 4 数据层解决方案 4.7 SpringBoot 操作 Redis 客户端实现技术切换【jedis】
    Factorial Divisibility(多个数的阶乘之后是否整除另一个数的阶乘)
  • 原文地址:https://blog.csdn.net/lpwmm/article/details/133961250