AWS Lambda, SAM 및 Rust의 개인 노트

36955 단어 AWSRustLambdasamtech
얼마 전에 저는 Rust에서 Lambda 함수를 성공적으로 만들었는데 의외로 Rust와 Lambda의 상성이 좋지 않습니까?API Gateway를 포함한 콘텐츠도 AWS SAM으로 설정하고 싶다고 생각한다.
やりたいこと
하고 싶은 게 이런 느낌이야.
  • Rust로 Lambda 함수 만들기
  • API Gateway->Lamba 함수의 조합
  • Lambda 함수에서 Lightsail에 생성된 DB 서버에 액세스
  • Lightsail 피어싱 연결
    Lightsail에 왜 데이터베이스 서버를 만들었는지는 돈의 문제입니다(´.ω・‘)
  • 가난한 사람들은 RDS를 사용할 예산이 없다.더욱이 EC2에 DB 서버를 구축하는 것도 비싸다.
    이번에 개인용 노트가 절반 정도밖에 남지 않아 내용을 이해하기 어렵다고 생각한다.양해해 주십시오

    Rust 쪽은...


    DB 연결 대상은 환경 변수에서 가져옵니다.또 이 프로그램은 무의미한 느낌을 준다.

    Cargo.toml


    필요 없는 기중기가 있을 수도 있어요.DB에 접근할 때 sqlx를 사용합니다.
    [package]
    name = "test-lambda"
    version = "0.1.0"
    authors = ["XXXXXXXX <[email protected]>"]
    edition = "2018"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    [dependencies]
    aws_lambda_events = "0.4.0"
    config = "0.11.0"
    dotenv = "0.15.0"
    http = "0.2.3"
    lambda_http = "0.3.0"
    lambda_runtime = "0.3.0"
    lazy_static = "1.4.0"
    log = "0.4.14"
    serde = "1.0.124"
    serde_derive = "1.0.124"
    serde_json = "1.0.64"
    simple_logger = "1.11.0"
    sqlx = { version="0.5.1", features = ["runtime-tokio-rustls", "any", "postgres", "sqlite", "macros", "migrate", "chrono"] }
    tokio = { version = "1.4.0", features = ["full"] }
    
    [[bin]]
    name = "bootstrap"
    path = "src/main.rs"
    

    config.rs


    환경 변수에서 가져올 설정 정보(데이터베이스 연결 정보) 만들기
    https://qiita.com/tiohsa/items/d694dfbfce52da09ea53
    그러니까 완전 복사하고 붙이는 것도 지나치지 않아요.이것은 매우 얻기 어려운 보도다.
    use serde::Deserialize;
    use config::ConfigError;
    use dotenv::dotenv;
    use lazy_static::lazy_static;
    
    #[derive(Deserialize, Debug)]
    pub struct Config {
        pub database_url: String,
    }
    
    impl Config {
        /// 環境変数からデータを読み込む
        pub fn from_env() -> Result<Self, ConfigError> {
            let mut cfg = config::Config::new();
            cfg.merge(config::Environment::new())?;
            cfg.try_into()
        }
    }
    
    lazy_static! {
        pub static ref CONFIG: Config = {
            dotenv().ok();
            Config::from_env().unwrap()
        };
    }
    

    main.rs


    지난번과 달리'aws lambda 이벤트'를 사용했습니다.
    APIGateway의 데이터 요청 및 응답에 대한 데이터 유형을 정의합니다.편리합니다!
    사실 lambda.http라는 것도 있지만, 이쪽은 잘 움직이지 않아서 이 형식으로 변했다.
    프로그램의 내용은 ApiGateway가 접근한 경로와 DB의 표 일람표를 되돌려주는 것입니다.
    mod config;
    
    use http::HeaderMap;
    use lambda_runtime::{handler_fn, Context, Error};
    
    use log::LevelFilter;
    use serde_derive::Serialize;
    use simple_logger::SimpleLogger;
    use sqlx::{Any, AnyPool, Pool};
    
    use crate::config::CONFIG;
    
    use aws_lambda_events::event::apigw::{ApiGatewayProxyResponse, ApiGatewayProxyRequest };
    
    #[derive(Serialize, Clone)]
    struct CustomOutput {
        path: String,
        result: Vec<String>
    }
    
    #[tokio::main]
    async fn main() -> Result<(), Error> {
    
    
        SimpleLogger::new()
            .with_level(LevelFilter::Info)
            .init()
            .unwrap();
    
    
        let db_pool = AnyPool::connect(&CONFIG.database_url).await.unwrap();
    
        let func = handler_fn(move |e, c| {
            log::info!("lambda start---!!!");
            my_handler(e, c, db_pool.clone())
        });
        lambda_runtime::run(func).await?;
    
        Ok(())
    }
    
    async fn my_handler(req: ApiGatewayProxyRequest, _: Context, db_pool: Pool<Any>) -> Result<ApiGatewayProxyResponse, Error> {
        let tables = db_access(&db_pool).await;
        
        let x = CustomOutput {path: req.path.unwrap_or("".to_string()), result: tables};
        let x = serde_json::to_string(&x).unwrap();
        Ok(
            ApiGatewayProxyResponse {
                status_code: 200,
                body: Some(x.into()),
                is_base64_encoded: None,
                headers: HeaderMap::new(),
                multi_value_headers: HeaderMap::new()
            }
        )
    }
    
    async fn db_access(db_pool: &Pool<Any>) -> Vec<String> {
        let sql = if CONFIG.database_url.starts_with("sqlite:") {
            "select tbl_name from sqlite_master;"
        } else {
            "select table_name from information_schema.tables;"
        };
        
        sqlx::query_as::<_, (String,)>(sql)
            .fetch_all(db_pool)
            .await
            .unwrap().into_iter().map(|i| i.0 ).collect()
    }
    

    스크립트 작성


    나는 아래의 물건을 만들었다.
    cross build --release --target x86_64-unknown-linux-musl
    zip -j bootstrap.zip target/x86_64-unknown-linux-musl/release/bootstrap
    

    AWS SAM에 대한 이야기


    이번 구축은 구축 스크립트를 사용하기 때문에sam build 명령을 사용하지 않습니다.sambuild로 구축할 수 있는 방법도 있지만 처리에 오랜 시간이 걸렸고 제 환경에서도 불안정해서 사용을 포기했습니다.

    template.yml

  • Lambda 함수를 생성하고 API Gateway
  • 를 할당합니다.
  • Lambda 함수에 VPC
  • 할당
  • Lambda 함수에 대한 역할 생성
  • CloudWath로 출력된 로그 그룹의 기한을 30일
  • 로 설정합니다.
  • 환경 변수에서 VSC 설정 및 데이터베이스 연결 정보 얻기
  • 이런 일을 하면서.
    또한 Rust를 Lambda로 설계할 때 가장 중요한 것은
          CodeUri: ./bootstrap.zip
          Handler: bootstrap.is.real.handler
          Runtime: provided.al2
    
    의 부분.CodeUri에 작성된 zip 파일의 경로를 쓰고 Runtime에서provided를 사용합니다.AL2를 지정합니다.핸들러는 뭐든 될 것 같아서요.
    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: >
      sam-app
    
      Sample SAM Template for sam-app
    
    Parameters:
      DataBaseURL:
        Type: String
      SecurityGroupIds:
        Type: CommaDelimitedList
      SubnetIds:
        Type: CommaDelimitedList
    
    # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
    Globals:
      Function:
        Timeout: 3
        Environment:
          Variables:
            DATABASE_URL: !Ref DataBaseURL
        VpcConfig:
          SecurityGroupIds: !Ref SecurityGroupIds
          SubnetIds: !Ref SubnetIds
              
    Resources:
      HelloWorldFunction:
        Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
        Properties:
          FunctionName: HelloRust
          CodeUri: ./bootstrap.zip
          Handler: bootstrap.is.real.handler
          Runtime: provided.al2
          Role: !GetAtt LambdaRole.Arn
          Events:
            ProxyApi:
              Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
              Properties:
                Path: /test/{proxy+}
                Method: ANY
         
      HelloWorldFunctionLogGroup:
        Type: AWS::Logs::LogGroup
        Properties:
          LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
          RetentionInDays: 30
    
      LambdaRole:
        Type: AWS::IAM::Role
        Properties:
          AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Principal:
                  Service: lambda.amazonaws.com
                Action: "sts:AssumeRole"
          ManagedPolicyArns:
            - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
            - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    
    

    samconfig.toml


    처음에sam deploy-guided 명령으로 적절하게 디버깅한 내용을 약간 수정하고 있습니다.
    parameter_오버라이드에 실제 설정을 기록합니다.(이번에는 VPC 설정 및 데이터베이스 연결 정보)
    version = 0.1
    [default]
    [default.deploy]
    [default.deploy.parameters]
    stack_name = "sam-app"
    s3_bucket = "[みせられないよ!!]"
    s3_prefix = "sam-app"
    region = "ap-northeast-1"
    capabilities = "CAPABILITY_IAM"
    parameter_overrides = "DataBaseURL=postgresql://xxxxx:[email protected]/postgres SecurityGroupIds=sg-xxxxxxxx SubnetIds=subnet-xxxxxa,subnet-xxxxxb,subnet-xxxxxc"
    

    프로그램 정보


    일반적으로 Rust의 구축을 하고sam deploy로 설계를 한다.겨우 스파로 만들어져서 처음 했을 때 감동적이었어요.

    기타


    저는 Serverless Framework에도 관심이 많아서 한번 써보려고 했는데 Serverless Rust 쓰고 갔지만 빌딩에서 실패할 수가 없어서 전진할 수가 없었어요...

    좋은 웹페이지 즐겨찾기