dailyFocus - Backend

 


: Serverless web application 개발 흐름을 가볍게 이해할수 있도록 진행한 프로젝트로 가이드가 되도록  작성하였습니다.


<목차>

  • Web Application 소개
  • AWS 계정 설정
  • Back-end 계획하기
  • Back-end 구현하기
  • Back-end 배포하기
  • Back-end 자동 배포하기
  • 참고

Web Application 소개

DailyFocus

링크 : http://kd-sp3-dailyfocus.s3-website.ap-northeast-2.amazonaws.com/

Github : https://github.com/jgcman3/dailyfocus-app-backend


가이드를 위해 만든 Web App 은 'Daily Focus' 입니다.

  • 몰입을 돕는 시간관리 툴
  • "한가지 일에 집중하라"
  • 역활 1 : 하나의 mission 을 생성하고  mission 완료시 몰입한 시간을 기록한다.
  • 역활 2 : 진행한 mision 들을 보여준다.  

UX/UI 화면















AWS 계정 설정

AWS Account 생성

IAM User 생성

  1.  Access type 으로 Programmatic access 필수 선택 하세요.
  2. User에 따른 권한 할당 하세요.
  3. 생성된 Access key ID 와 Secret access key 를 소중히 보관하세요. 노출시 매우 위험합니다.  누군가 몰래 사용한다면 비용 폭탄을 맞을 수 있어요.

AWS CLI 설정

pip를 이용해서  AWS CLI 설치 하세요.

$ sudo pip install awscli

AWS CLI 에 당신의 Access Key ID 와 Secret key를 입력 하세요.

$ aws configure

AWS IAM 으로 계정을 분리 하는 이유 :

  1. 이력 추적 : cloud Trail 서비스를 통해 누가 어떤 작업들을 진행했는지 이력확인을 할 수 있습니다. 
  2. 보안 강화 : 각각 스스로 access key 를 관리 하므로, 보안을 강화합니다.   
  3. 비용 관리 : cloud 공급자를 통한 서버 구축은 간단한 조작하나가 비용으로 직결됩니다. 개인에게 할당된 access key는 노출시 비용 폭탄( ? ) 발생 할 수 있습니다. 



Back-end 계획하기

구현 요소

  • 가입 / 로그인
  • 미션 Create / Read / Update / Delete



회원 및 인증 관리

  • 가입시 요청사항
    • 아이디는 email 입력
    • 비밀번호 입력
    • email 로 전송되 Code 입력

데이터 베이스 : 수집할 항목

  • userId : 사용자 식별값
  • noteId : 미션의 식별값
  • createdAt : 미션 생성 시간
  • completedAt :  미션 완료 시간
  • content : 미션 내용

요청 창구 : REST API 구성 

  • path : /notes
    • POST method : 미션 Create 동작
    • GET method : 미션 목록 Read 동작
  • path : /notes/{noteId}
    • GET method : 미션 Read 동작
    • PUT method : 미션 Update 동작
    • DELETE method : 미션 Delete 동작

요청 처리 

  • 미션 Creat 동작 : create()
  • 미션 목록 Read 동작 : list()
  • 미션 Read 동작 : get()
  • 미션 Update 동작 : update()
  • 미션 Delete 동작 : delete()




Back-end 구현하기

구성 요소

AWS 에서는 serverless 아키텍처로 제공하는 서비스들을 이용하여 구성할 수 있습니다.

사용한 AWS 서비스 소개



Web Console 로 Backend 구성하는 방법

아래 순서와 이름으로 생성할 계획입니다.




이번에는 더욱 손쉽게 Serverless Backend를 구성할 수 있는 framework 을 이용하겠습니다.

Serverless Framework 'Serverless' 로 Backend 구성하는 방법

Serverless Framework 로 backend를 구성한다는 것은 Serverless 인프라를 코드로 관리하는 것입니다. 

Serverless framework 으로 많이 알려진 것이 'AWS SAM(Serverless Application Model)' 과 'Serverless' 가 있습니다.

이중에 'Serverless'를 사용하겠습니다.

아래와 같이 구성하려고 합니다.



serverless 기본 설정 및 확인

  • serverless 설치

    ubuntu:~/environment $ npm install serverless -g
  • serverles 의 hello-world 프로젝트 생성

    ubuntu:~/environment $ serverless create --template hello-world --path hello-world
    Serverless: Generating boilerplate...
    Serverless: Generating boilerplate in "/home/ubuntu/environment/hello-world"
     _______                             __
    |   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
    |   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
    |____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
    |   |   |             The Serverless Application Framework
    |       |                           serverless.com, v1.63.0
     -------'
     
    Serverless: Successfully generated boilerplate for template: "hello-world"
    ubuntu:~/environment $ ls
    README.md  hello-world
    ubuntu:~/environment $ cd hello-world/
    ubuntu:~/environment/hello-world $ ls
    handler.js  serverless.yml
  • serverless.yml 파일 보고 이해하기

    # Welcome to serverless. Read the docs
    # https://serverless.com/framework/docs/
     
    # Serverless.yml is the configuration the CLI
    # uses to deploy your code to your provider of choice
     
    # The `service` block is the name of the service
    service: hello-world
     
    # The `provider` block defines where your service will be deployed
    provider:
      name: aws
      runtime: nodejs12.x
     
    # The `functions` block defines what code to deploy
    functions:
      helloWorld:
        handler: handler.helloWorld
        # The `events` block defines how to trigger the handler.helloWorld code
        events:
          - http:
              path: hello-world
              method: get
              cors: true
  • handler.js 람다 파일 보고 이해하기

    'use strict';
     
    module.exports.helloWorld = (event, context, callback) => {
      const response = {
        statusCode: 200,
        headers: {
          'Access-Control-Allow-Origin''*'// Required for CORS support to work
        },
        body: JSON.stringify({
          message: 'Go Serverless v1.0! Your function executed successfully!',
          input: event,
        }),
      };
     
      callback(null, response);
    };
  • 로컬로 handler.js 람다 응답 테스트 하기 ( Serverless invoke local --function helloWorld )

    ubuntu:~/environment/hello-world $ serverless invoke local --function helloWorld
    {
        "statusCode"200,
        "headers": {
            "Access-Control-Allow-Origin""*"
        },
        "body""{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":\"\"}"
    }
    ubuntu:~/environment/hello-world $
  • 자신의 AWS Account 계정에 배포하기( serverless deploy -v )

    $ serverless deploy -v
    Serverless: Packaging service...
    Serverless: Excluding development dependencies...
    Serverless: Creating Stack...
    Serverless: Checking Stack create progress...
    ........
    Serverless: Stack create finished...
    Serverless: Uploading CloudFormation file to S3...
    Serverless: Uploading artifacts...
    Serverless: Uploading service hello-world.zip file to S3 (404 B)...
    Serverless: Validating template...
    Serverless: Updating Stack...
    Serverless: Checking Stack update progress...
    .................................
    Serverless: Stack update finished...
    Service Information
    service: hello-world
    stage: dev
    region: us-east-1
    stack: hello-world-dev
    resources: 12
    api keys:
      None
    endpoints:
      GET - https://sz6hgeny56.execute-api.us-east-1.amazonaws.com/dev/hello-world
    functions:
      helloWorld: my-project-dev-helloWorld
    layers:
      None
    Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.


Serverless로 back-end 구현하기

  • backend 소스 코드 다운로드

    $ git clone https://github.com/jgcman3/dailyfocus-app-backend
  • aws-sdk package 설치하기

    $ npm install aws-sdk --save
  • 의존성 npm package들 설치

    ( aws-sdk 패키지를 설치하기 위한 목적입니다.  $npm install aws-sdk --save dev 로 대신할 수 있습니다. )

    $ npm install
  • serverless.yml 코드 ( serverless.yml )

    service: dailyfocus-app-backend
     
    # Create an optimized package for our functions
    package:
      individually: true
     
    plugins:
      - serverless-bundle # Package our functions with Webpack
      - serverless-offline
      - serverless-dotenv-plugin # Load .env as environment variables
     
    custom:
      projectName: dailyfocus
      # Our stage is based on what is passed in when running serverless
      # commands. Or fallsback to what we have set in the provider section.
      stage: ${opt:stage, self:provider.stage}
      # Set the table name here so we can use it while testing locally
      tableName: ${self:custom.stage}-${self:custom.projectName}
      # region
      region: ${opt:region, self:provider.region}
     
    provider:
      name: aws
      runtime: nodejs10.x
      stage: dev
      region: ap-northeast-2
     
      # These environment variables are made available to our functions
      # under process.env.
      environment:
        tableName: ${self:custom.tableName}
     
      'iamRoleStatements' defines the permission policy for the Lambda function.
      # In this case Lambda functions are granted with permissions to access DynamoDB.
      iamRoleStatements:
        - Effect: Allow
          Action:
            - dynamodb:DescribeTable
            - dynamodb:Query
            - dynamodb:Scan
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:UpdateItem
            - dynamodb:DeleteItem
          # Restrict our IAM role permissions to
          # the specific table for the stage
          Resource:
            "Fn::GetAtt": [NotesTable, Arn]
     
    functions:
      # Defines an HTTP API endpoint that calls the main function in create.js
      # - path: url path is /notes
      # - method: POST request
      # - cors: enabled CORS (Cross-Origin Resource Sharing) for browser cross
      #     domain api call
      # - authorizer: authenticate using the AWS IAM role
      create:
        handler: create.main
        events:
          - http:
              path: notes
              method: post
              cors: true
              authorizer: aws_iam
      get:
        # Defines an HTTP API endpoint that calls the main function in get.js
        # - path: url path is /notes/{id}
        # - method: GET request
        handler: get.main
        events:
          - http:
              path: notes/{id}
              method: get
              cors: true
              authorizer: aws_iam
      list:
        # Defines an HTTP API endpoint that calls the main function in list.js
        # - path: url path is /notes
        # - method: GET request
        handler: list.main
        events:
          - http:
              path: notes
              method: get
              cors: true
              authorizer: aws_iam
      update:
        # Defines an HTTP API endpoint that calls the main function in update.js
        # - path: url path is /notes/{id}
        # - method: PUT request
        handler: update.main
        events:
          - http:
              path: notes/{id}
              method: put
              cors: true
              authorizer: aws_iam
      delete:
        # Defines an HTTP API endpoint that calls the main function in delete.js
        # - path: url path is /notes/{id}
        # - method: DELETE request
        handler: delete.main
        events:
          - http:
              path: notes/{id}
              method: delete
              cors: true
              authorizer: aws_iam
      complete:
        # Defines an HTTP API endpoint that calls the main function in update.js
        # - path: url path is /notes/{id}
        # - method: PUT request
        handler: complete.main
        events:
          - http:
              path: notes/{id}/complete
              method: put
              cors: true
              authorizer: aws_iam
      getfocus:
        # Defines an HTTP API endpoint that calls the main function in update.js
        # - path: url path is /notes/{id}
        # - method: PUT request
        handler: getfocus.main
        events:
          - http:
              path: notes/focus
              method: get
              cors: true
              authorizer: aws_iam
     
    # Create our resources with separate CloudFormation templates
    resources:
      # API Gateway Errors
      - ${file(resources/api-gateway-errors.yml)}
      # DynamoDB
      - ${file(resources/dynamodb-table.yml)}
      # S3
      - ${file(resources/s3-bucket.yml)}
      # Cognito
      - ${file(resources/cognito-user-pool.yml)}
      - ${file(resources/cognito-identity-pool.yml)}
  • 람다에서 사용할 DynamoDB lib 모듈 ( libs/dynamodb-lib.js )

    import AWS from "aws-sdk";
     
    export function call(action, params) {
      const dynamoDb = new AWS.DynamoDB.DocumentClient();
     
      return dynamoDb[action](params).promise();
    }
  • 람다에서 사용할 Response lib 모듈 ( libs/dynamodb-lib.js )

    export function success(body) {
      return buildResponse(200, body);
    }
     
    export function failure(body) {
      return buildResponse(500, body);
    }
     
    function buildResponse(statusCode, body) {
      return {
        statusCode: statusCode,
        headers: {
          "Access-Control-Allow-Origin""*",
          "Access-Control-Allow-Credentials"true
        },
        body: JSON.stringify(body)
      };
    }
  • Create 람다 함수 ( create.js )

    import * as dynamoDbLib from "./libs/dynamodb-lib";
    import { success, failure } from "./libs/response-lib";
     
    export async function main(event, context) {
      const data = JSON.parse(event.body);
      const params = {
        TableName: process.env.tableName,
        Item: {
          userId: event.requestContext.identity.cognitoIdentityId,
          noteId: Date.now(),
          content: data.content,
          createdAt: Date.now(),
          completedAt: 0
        }
      };
     
      try {
        await dynamoDbLib.call("put", params);
        return success(params.Item);
      catch (e) {
        return failure({ status: false });
      }
    }
  • List 람다 함수 ( list.js )

    import * as dynamoDbLib from "./libs/dynamodb-lib";
    import { success, failure } from "./libs/response-lib";
     
    export async function main(event, context) {
      const params = {
        TableName: process.env.tableName,
        // 'KeyConditionExpression' defines the condition for the query
        // - 'userId = :userId': only return items with matching 'userId'
        //   partition key
        // 'ExpressionAttributeValues' defines the value in the condition
        // - ':userId': defines 'userId' to be Identity Pool identity id
        //   of the authenticated user
        KeyConditionExpression: "userId = :userId",
        ExpressionAttributeValues: {
          ":userId": event.requestContext.identity.cognitoIdentityId
        }
      };
     
      try {
        const result = await dynamoDbLib.call("query", params);
        // Return the matching list of items in response body
        return success(result.Items);
      catch (e) {
        return failure({ status: false });
      }
    }
  • Get 람다 함수 ( get.js )

    import * as dynamoDbLib from "./libs/dynamodb-lib";
    import { success, failure } from "./libs/response-lib";
     
    export async function main(event, context) {
      const params = {
        TableName: process.env.tableName,
        // 'Key' defines the partition key and sort key of the item to be retrieved
        // - 'userId': Identity Pool identity id of the authenticated user
        // - 'noteId': path parameter
        Key: {
          userId: event.requestContext.identity.cognitoIdentityId,
          noteId: Number(event.pathParameters.id)
        }
      };
     
      try {
        const result = await dynamoDbLib.call("get", params);
        if (result.Item) {
          // Return the retrieved item
          return success(result.Item);
        else {
          return failure({ status: false, error: "Item not found." });
        }
      catch (e) {
        return failure({ status: false });
      }
    }
  • Update 람다 함수 ( update.js )

    import * as dynamoDbLib from "./libs/dynamodb-lib";
    import { success, failure } from "./libs/response-lib";
     
    export async function main(event, context) {
      const data = JSON.parse(event.body);
      const params = {
        TableName: process.env.tableName,
        // 'Key' defines the partition key and sort key of the item to be updated
        // - 'userId': Identity Pool identity id of the authenticated user
        // - 'noteId': path parameter
        Key: {
          userId: event.requestContext.identity.cognitoIdentityId,
          noteId: Number(event.pathParameters.id)
        },
        // 'UpdateExpression' defines the attributes to be updated
        // 'ExpressionAttributeValues' defines the value in the update expression
        UpdateExpression: "SET content = :content",
        ExpressionAttributeValues: {
          ":content": data.content || null
        },
        // 'ReturnValues' specifies if and how to return the item's attributes,
        // where ALL_NEW returns all attributes of the item after the update; you
        // can inspect 'result' below to see how it works with different settings
        ReturnValues: "ALL_NEW"
      };
     
      try {
        await dynamoDbLib.call("update", params);
        return success({ status: true });
      catch (e) {
        return failure({ status: false });
      }
    }
  • Delete 람다 함수 ( delete.js )

    import * as dynamoDbLib from "./libs/dynamodb-lib";
    import { success, failure } from "./libs/response-lib";
     
    export async function main(event, context) {
      const params = {
        TableName: process.env.tableName,
        // 'Key' defines the partition key and sort key of the item to be removed
        // - 'userId': Identity Pool identity id of the authenticated user
        // - 'noteId': path parameter
        Key: {
          userId: event.requestContext.identity.cognitoIdentityId,
          noteId: Number(event.pathParameters.id)
        }
      };
     
      try {
        await dynamoDbLib.call("delete", params);
        return success({ status: true });
      catch (e) {
        return failure({ status: false });
      }
    }
  • DynamoDB 테이블 생성 cloudFormation templete 코드 ( resources/dynamodb-table.yml )

    Resources:
      NotesTable:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: ${self:custom.tableName}
          AttributeDefinitions:
            - AttributeName: userId
              AttributeType: S
            - AttributeName: noteId
              AttributeType: N
          KeySchema:
            - AttributeName: userId
              KeyType: HASH
            - AttributeName: noteId
              KeyType: RANGE
          # Set the capacity to auto-scale
          BillingMode: PAY_PER_REQUEST
  • Cognito user pool 생성 cloudFormation templete 코드 ( resources/cognito-user-pool.yml )

    Resources:
      CognitoUserPool:
        Type: AWS::Cognito::UserPool
        Properties:
          # Generate a name based on the stage
          UserPoolName: ${self:custom.stage}-${self:custom.projectName}-user-pool
          # Set email as an alias
          UsernameAttributes:
            - email
          AutoVerifiedAttributes:
            - email
     
      CognitoUserPoolClient:
        Type: AWS::Cognito::UserPoolClient
        Properties:
          # Generate an app client name based on the stage
          ClientName: ${self:custom.stage}-${self:custom.projectName}-user-pool-client
          UserPoolId:
            Ref: CognitoUserPool
          ExplicitAuthFlows:
            - ADMIN_NO_SRP_AUTH
          GenerateSecret: false
     
    # Print out the Id of the User Pool that is created
    Outputs:
      UserPoolId:
        Value:
          Ref: CognitoUserPool
     
      UserPoolClientId:
        Value:
          Ref: CognitoUserPoolClient
  • Cognito identity pool 생성 cloudFormation templete 코드 ( resources/cognito-identity-pool.yml )

    Resources:
      # The federated identity for our user pool to auth with
      CognitoIdentityPool:
        Type: AWS::Cognito::IdentityPool
        Properties:
          # Generate a name based on the stage
          IdentityPoolName: ${self:custom.stage}${self:custom.projectName}IdentityPool
          # Don't allow unathenticated users
          AllowUnauthenticatedIdentities: false
          # Link to our User Pool
          CognitoIdentityProviders:
            - ClientId:
                Ref: CognitoUserPoolClient
              ProviderName:
                Fn::GetAtt: [ "CognitoUserPool""ProviderName" ]
                 
      # IAM roles
      CognitoIdentityPoolRoles:
        Type: AWS::Cognito::IdentityPoolRoleAttachment
        Properties:
          IdentityPoolId:
            Ref: CognitoIdentityPool
          Roles:
            authenticated:
              Fn::GetAtt: [CognitoAuthRole, Arn]
               
      # IAM role used for authenticated users
      CognitoAuthRole:
        Type: AWS::IAM::Role
        Properties:
          Path: /
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Principal:
                  Federated: 'cognito-identity.amazonaws.com'
                Action:
                  'sts:AssumeRoleWithWebIdentity'
                Condition:
                  StringEquals:
                    'cognito-identity.amazonaws.com:aud':
                      Ref: CognitoIdentityPool
                  'ForAnyValue:StringLike':
                    'cognito-identity.amazonaws.com:amr': authenticated
          Policies:
            - PolicyName: 'CognitoAuthorizedPolicy'
              PolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Effect: 'Allow'
                    Action:
                      'mobileanalytics:PutEvents'
                      'cognito-sync:*'
                      'cognito-identity:*'
                    Resource: '*'
                   
                  # Allow users to invoke our API
                  - Effect: 'Allow'
                    Action:
                      'execute-api:Invoke'
                    Resource:
                      Fn::Join:
                        ''
                        -
                          'arn:aws:execute-api:'
                          - Ref: AWS::Region
                          ':'
                          - Ref: AWS::AccountId
                          ':'
                          - Ref: ApiGatewayRestApi
                          '/*'
                   
                  # Allow users to upload attachments to their
                  # folder inside our S3 bucket
                  - Effect: 'Allow'
                    Action:
                      's3:*'
                    Resource:
                      - Fn::Join:
                        ''
                        -
                          - Fn::GetAtt: [AttachmentsBucket, Arn]
                          '/private/'
                          '$'
                          '{cognito-identity.amazonaws.com:sub}/*'
       
    # Print out the Id of the Identity Pool that is created
    Outputs:
      IdentityPoolId:
        Value:
          Ref: CognitoIdentityPool
  • API Gateway error 에 대한 CORS 헤더 추가 CloudFormation templete 코드 ( resources/api-gateway-errors.yml )

    Resources:
      GatewayResponseDefault4XX:
        Type: "AWS::ApiGateway::GatewayResponse"
        Properties:
          ResponseParameters:
            gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
            gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
          ResponseType: DEFAULT_4XX
          RestApiId:
            Ref: "ApiGatewayRestApi"
      GatewayResponseDefault5XX:
        Type: "AWS::ApiGateway::GatewayResponse"
        Properties:
          ResponseParameters:
            gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
            gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
          ResponseType: DEFAULT_5XX
          RestApiId:
            Ref: "ApiGatewayRestApi"

    ( 클라이언트에서 " No 'Access-Control-Allow-Origin' header is present on the requested resource " 와 같은 오류 메시지를 발생할 수 있습니다. )



Back-end 배포하기

web console 에서 배포 하기

  • web console 에서 생성 및 설정 하는 것 자체가 배포 입니다 (웃음)

IAC 로 관리한 코드를 AWS CloudFormation 통해서 배포하기

  • 여기서는 serverless framework 으로 구성한 serverless.yml 파일을 이용하겠습니다.
  •  dailyfocus-app-backend 폴더로 이동

    $ cd dailyfocus-app-backend
  • 한번에 모두 배포하기

    $ serverless deploy -v
  • 람다 하나씩 배포하기

    $ serverless deploy -v -f {함수명}
  • 배포 결과 보기

    Service Information
    service: dailyfocus-app-backend2
    stage: dev
    region: us-east-2
    stack: dailyfocus-app-backend2-dev
    resources: 57
    api keys:
      None
    endpoints:
      POST - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes
      GET - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes/{id}
      GET - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes
      PUT - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes/{id}
      DELETE - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes/{id}
      PUT - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes/{id}/complete
      GET - https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev/notes/focus
    functions:
      create: dailyfocus-app-backend2-dev-create
      get: dailyfocus-app-backend2-dev-get
      list: dailyfocus-app-backend2-dev-list
      update: dailyfocus-app-backend2-dev-update
      delete: dailyfocus-app-backend2-dev-delete
      complete: dailyfocus-app-backend2-dev-complete
      getfocus: dailyfocus-app-backend2-dev-getfocus
    layers:
      None
     
    Stack Outputs
    GetfocusLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-getfocus:2
    UpdateLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-update:2
    CompleteLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-complete:2
    ListLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-list:1
    ServerlessDeploymentBucketName: dailyfocus-app-backend2-serverlessdeploymentbuck-jw9u0vve4h4l
    AttachmentsBucketName: dailyfocus-app-backend2-dev-attachmentsbucket-co885cne6cf0
    UserPoolClientId: { ^^ }
    UserPoolId: { ^^ }
    DeleteLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-delete:2
    CreateLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-create:1
    GetLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-2:{ Account-Id }:function:dailyfocus-app-backend2-dev-get:2
    IdentityPoolId: { ^^ }
    ServiceEndpoint: https://{ ^^ }.execute-api.us-east-2.amazonaws.com/dev
  • 배포 확인 하기

AWS Web console 의 'CloudFormation' 에  스택에 생성되어 있음을 확인하세요.

해당 스택으로 각각의 리소스들( Lambda, API Gateway, DynamoDB )이 생성되어 있습니다.



Back-end 자동 배포하기

CI/CD pipelines for Serverless apps


'Seed' 를 이용해 자동 배포하기

  • 회원가입 : https://seed.run/
  • 앱 추가 
    1. Connect a repo : 저장소 선택
    2. Add a service  :  templete 파일 지정
    3. Configure the stages : stage 정보와 AWS IAM Access key, Secret key 입력


  • 배포 관리 화면

  • dev stage로 자동 배포 하기

    $ npm version patch
    $ git push



  • prod stage 로 배포 하기
    1. Promote 버튼 선택
    2. prod stage 에 배포되는 리소스 내용 확인
    3. Promote to production 버튼 선택





참고

링크

댓글

이 블로그의 인기 게시물

dailyFocus - Frontend

CDK - Assets

About VPC