Exploring AWS Lambda Function URL using .NET Container - Part 1

berviantoleo

Bervianto Leo Pratama

Posted on April 30, 2022

Exploring AWS Lambda Function URL using .NET Container - Part 1

Preparation

You will need several tools, like

  1. .NET SDK. Please download here
  2. AWS Lambda Templates for .NET. You may check here. Basically you need this template, using this command: dotnet new --install Amazon.Lambda.Templates::6.1.0
  3. Dotnet deployment tools (optional). Using this command: dotnet tool install -g Amazon.Lambda.Tools.
  4. Terraform CLI (optional). I will use Github Action and Terraform Cloud for the deployment of infrastructure.

Generate AWS Lambda Project from templates

There are many options that you may use and explore. In this article, I will use Web API with Container Image.

Template list

You may use this command to generate the project:



dotnet new serverless.image.AspNetCoreWebAPI --name Demo


Enter fullscreen mode Exit fullscreen mode

After that, please copy the folder/directory inside Demo to the root directory of the project. Previously you will have files like this:



Demo/src/Demo
Demo/test/Demo.Test


Enter fullscreen mode Exit fullscreen mode

Please move it, so become like this:



src/Demo
test/Demo.Test


Enter fullscreen mode Exit fullscreen mode

Well done! Let's move on to the next step.

Terraform

I use Terraform to manage my Lambda setup. Unfortunately, I still create/manage Amazon ECR manually, so I will not include the set up of ECR here. My configuration will be like this:

main.tf


resource "aws_iam_role" "iam_for_lambda" {
  name = "iam_for_lambda"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_lambda_function" "lambda_container_demo" {
  function_name = "lambda_container_demo"
  role          = aws_iam_role.iam_for_lambda.arn
  image_uri     = "<your image location in here>" # please update your image inside the quotes
  publish       = true
  package_type  = "Image"

  tags = {
    "env" = "dev"
  }
}

resource "aws_lambda_function_url" "lambda_container_demo_dev" {
  function_name      = aws_lambda_function.lambda_container_demo.function_name
  authorization_type = "NONE"
  cors {
    allow_credentials = true
    allow_origins     = ["*"]
    allow_methods     = ["GET", "POST", "PUT", "DELETE"]
    allow_headers     = ["date", "keep-alive"]
    expose_headers    = ["keep-alive", "date"]
    max_age           = 300
  }
}

resource "aws_lambda_function_url" "lambda_container_demo_prod" {
  function_name      = aws_lambda_function.lambda_container_demo.function_name
  authorization_type = "AWS_IAM"

  cors {
    allow_credentials = true
    allow_origins     = ["*"]
    allow_methods     = ["*"]
    allow_headers     = ["date", "keep-alive"]
    expose_headers    = ["keep-alive", "date"]
    max_age           = 86400
  }
}


Enter fullscreen mode Exit fullscreen mode

You may use that configuration or customize it. Please change the image_uri before you use it.

  • provider.tf


terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
  cloud {
    organization = "<org>" # change with your organization

    workspaces {
      name = "<workspace-name>" # please update the workspace name inside the quotes
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "ap-southeast-1" # you may use another region
}


Enter fullscreen mode Exit fullscreen mode

I store the Terraform scripts inside terraform directory. So it will look like this:



src/Demo
test/Demo.Test
terraform/


Enter fullscreen mode Exit fullscreen mode

Prepare your Amazon ECR and Github Action

I will cover the Github Action only. If you are curious to prepare the Amazon ECR, please visit this post.

"github/workflows/deploy.yml"


name: Deploy
on:
  push:
    branches: [ main ]
    tags:
      - v*
  pull_request:
env:
  IMAGE_NAME: 'lambda-sharp'
  PROJECT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
jobs:
  build-push-docker:
    runs-on: ubuntu-20.04
    steps:
    - uses: actions/checkout@v3
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.DEMO_ECR_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.DEMO_ECR_SECRET_KEY }}
        aws-region: ap-southeast-1
    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1
      with:
        registries: ${{ secrets.AWS_ACCOUNT_ID }}
    - name: Extract metadata (tags, labels) for Docker
      id: meta
      uses: docker/metadata-action@v3
      with:
        images: ${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
    - name: Build and push Docker images
      uses: docker/build-push-action@v2
      with:
        context: src/SimpleAPI
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
  terraform:
    name: 'Terraform'
    needs: build-push-docker
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
      - name: Terraform Format
        id: fmt
        run: terraform fmt -check
        working-directory: ./terraform
      - name: Terraform Init
        id: init
        run: terraform init
        working-directory: ./terraform
      - name: Terraform Validate
        id: validate
        run: terraform validate -no-color
        working-directory: ./terraform
      - name: Terraform Plan
        id: plan
        if: github.event_name == 'pull_request'
        run: terraform plan -no-color
        continue-on-error: true
        working-directory: ./terraform
      - name: Update Pull Request
        uses: actions/github-script@v6.0.0
        if: github.event_name == 'pull_request'
        env:
          PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
            #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
            #### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
            #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
            <details><summary>Show Plan</summary>
            \`\`\`\n
            ${process.env.PLAN}
            \`\`\`
            </details>
            *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: output
            })
      - name: Terraform Plan Status
        if: steps.plan.outcome == 'failure'
        run: exit 1
      - name: Terraform Apply
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        working-directory: ./terraform
        run: terraform apply -auto-approve


Enter fullscreen mode Exit fullscreen mode

So, I use two different jobs to deploy my Lambda. 1) I will deploy my Docker Image to ECR. 2) Provision and sync my AWS Lambda with terraform. Please check my architecture here:

Arch

Push to Github!

Yeah, if you have set up all of them. You may push it to Github. Note: Please set up the Terraform Cloud with AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. In the Github, you will need those credentials and Terraform API Key/Token (to store/check state in the Terraform Cloud.

Configuration

You may check my repository.

GitHub logo bervProject / lambda-sharp

Lambda use C# (.NET) Docker Image

Lambda Sharp Demo

Demo for Lambda Containerized .NET

LICENSE

MIT




Test our Lambda using Function URL

You may check the Lambda Function URL in Lambda Menu.

Lambda

Next, please visit the URL, and you may find it like this.

Root URL

After that, we may check another URL.

another API

Other Resources

You might want to know more about AWS Lambda Functions and Terraform. I suggest visiting an article How to Manage AWS Lambda Functions with Terraform.

Thank you

If you have some questions, please don't hesitate to ask me on Twitter or directly comment here.

Thank you.

WOW GIF

What's Next?

I will try to cover Lambda to connect with Amazon RDS (Relational Database Service). After that, I will cover Lambda to be called by any Frontend(s), and maybe I will use React. Stay tune!

💖 💪 🙅 🚩
berviantoleo
Bervianto Leo Pratama

Posted on April 30, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related