Traffine I/O

Bahasa Indonesia

2023-03-13

Mendeploy AWS Lambda dengan AWS CLI

Pengantar

Dalam artikel ini, saya akan memperkenalkan kode untuk mendeploy AWS Lambda menggunakan AWS CLI. Kode yang kita perkenalkan akan memungkinkan Anda untuk mencapai hal-hal berikut:

Struktur Direktori

Kita akan menulis kode sesuai dengan struktur direktori berikut.

├── Dockerfile
├── Makefile
├── deploy
│   ├── config
│   │   ├── policy.json
│   │   └── role.json
│   ├── push-ecr.sh
│   ├── provision-api-gateway.sh
│   ├── provision-ecr.sh
│   ├── provision-lambda.sh
│   └── update-lambda.sh
└── src/ # source code

Menetapkan Variabel Lingkungan

Atur variabel lingkungan berikut.

  • AWS_ACCOUNT_ID
  • AWS_REGION
  • IMAGE_NAME
  • LAMBDA_ALIAS
  • PROVISIONED_CONCURRENCY
# AWS account ID
$ export AWS_ACCOUNT_ID=123456789123

# AWS region
$ export AWS_REGION=ap-northeast-1

# ECR image and lambda name
$ export IMAGE_NAME=my-program

# Lambda alias
$ export LAMBDA_ALIAS=prod

# Number of Lambda Provisioned Concurrency
$ export PROVISIONED_CONCURRENCY=1

Kode Terkait ECR

Buat sebuah skrip shell deploy/provision-ecr.sh untuk membuat sebuah repository ECR.

deploy/provision-ecr.sh
#!/bin/sh

# Create ECR repository
aws ecr create-repository --repository-name ${IMAGE_NAME} --region ${AWS_REGION}

Kemudian, buat skrip shell deploy/push-ecr.sh untuk menjalankan hal-hal berikut:

  1. Masuk ke ECR
  2. Membangun gambar Docker dari Dockerfile
  3. Mendorong gambar Docker yang telah dibangun ke ECR.
deploy/push-ecr
#!/bin/bash

# ECR repository URI
ECR_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_NAME:latest

# ECR login
aws ecr get-login-password | docker login --username AWS --password-stdin https://$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

# Build docker image
docker build -t $ECR_URI .

# Push docker image to ECR
docker push $ECR_URI

Kode Terkait Lambda

Buat file JSON untuk IAM Role dan Policy untuk memberikan izin kepada Lambda.

deploy/config/policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
deploy/config/role.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Kemudian, buat skrip shell provision-lambda.sh untuk menjalankan hal-hal berikut:

  1. Membuat IAM Policy untuk Lambda dari deploy/config/policy.json
  2. Membuat IAM Role untuk Lambda dari deploy/config/role.json
  3. Melampirkan Policy ke Role
  4. Membuat Lambda (menggunakan gambar dari ECR sebagai sumber)
  5. Membuat versi Lambda dan alias (untuk digunakan dengan Provisioned Concurrency)
  6. Menetapkan Provisioned Concurrency pada Lambda.
deploy/provision-lambda.sh
#!/bin/bash

# Create IAM policy for lambda
aws iam create-policy --policy-name AWSLambdaBasicExecutionRole-${IMAGE_NAME} --policy-document file://deploy/config/policy.json

# Create IAM role for lambda
aws iam create-role --role-name ${IMAGE_NAME}-lambda-role --assume-role-policy-document file://deploy/config/role.json

# Sleep for waiting provision of policy and role creation
sleep 10

# Attach policy to role
aws iam attach-role-policy \
--role-name ${IMAGE_NAME}-lambda-role \
--policy-arn arn:aws:iam::${AWS_ACCOUNT_ID}:policy/AWSLambdaBasicExecutionRole-${IMAGE_NAME}

# Sleep for waiting attachment
sleep 10

# Create lambda
aws lambda create-function  \
  --function-name ${IMAGE_NAME} \
  --package-type Image \
  --code ImageUri=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${IMAGE_NAME}:latest \
  --timeout 600 \
  --memory-size 10240 \
  --ephemeral-storage Size=2048 \
  --role arn:aws:iam::${AWS_ACCOUNT_ID}:role/${IMAGE_NAME}-lambda-role


# Wait for Lambda function to be created
while true; do
  LAMBDA_STATUS=$(aws lambda get-function --function-name ${IMAGE_NAME} --query "Configuration.State" --output text)

  if [[ ${LAMBDA_STATUS} == "Active" ]]; then
    break
  elif [[ ${LAMBDA_STATUS} == "Failed" ]]; then
    echo "Lambda creation failed" >&2
    exit 1
  else
    echo "Waiting for Lambda function to be created..."
    sleep 10
  fi
done

echo "Lambda function created."

# Create lambda version and alias
LAMBDA_VERSION=$(aws lambda publish-version --function-name ${IMAGE_NAME} --region ${AWS_REGION} --query 'Version' --output text)

aws lambda create-alias \
  --function-name ${IMAGE_NAME} \
  --name ${LAMBDA_ALIAS} \
  --function-version ${LAMBDA_VERSION} \
  --region ${AWS_REGION}

# Add provisioned concurrency to lambda
aws lambda put-provisioned-concurrency-config \
  --function-name ${IMAGE_NAME} \
  --qualifier ${LAMBDA_ALIAS} \
  --provisioned-concurrent-executions "$PROVISIONED_CONCURRENCY" \
  --region ${AWS_REGION}

# Wait for provisioned concurrency to be configured
while true; do
  CONCURRENCY_STATUS=$(aws lambda get-provisioned-concurrency-config \
    --function-name ${IMAGE_NAME} \
    --qualifier ${LAMBDA_ALIAS} \
    --query "Status" --output text)

  if [[ ${CONCURRENCY_STATUS} == "READY" ]]; then
    break
  elif [[ ${CONCURRENCY_STATUS} == "FAILED" ]]; then
    echo "Provisioned concurrency addition failed" >&2
    exit 1
  else
    echo "Waiting for provisioned concurrency to be configured..."
    sleep 10
  fi
done

echo "Provisioned concurrency added to the Lambda function."

Buat skrip shell update-lambda.sh untuk terus memperbarui Lambda. Hal-hal berikut akan dijalankan dalam update-lambda.sh:

  1. Memperbarui Lambda dari gambar ECR yang ditentukan
  2. Memperbarui alias Lambda (memperbarui alias juga memperbarui Provisioned Concurrency)
deploy/update-lambda.sh
# !/bin/bash

# Update lambda
aws lambda update-function-code --function-name ${IMAGE_NAME} --image ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${IMAGE_NAME}:latest

while true; do
  LAST_UPDATE_STATUS=$(aws lambda get-function --function-name ${IMAGE_NAME} --region ${AWS_REGION} --query 'Configuration.LastUpdateStatus' --output text)

  if [ ${LAST_UPDATE_STATUS} != "InProgress" ]; then
    break
  fi

  echo "Waiting for Lambda function update to complete..."
  sleep 10
done


NEW_LAMBDA_VERSION=$(aws lambda publish-version --function-name $IMAGE_NAME --region $AWS_REGION --query 'Version' --output text)

# Update lambda alias
aws lambda update-alias \
  --function-name $IMAGE_NAME \
  --name $LAMBDA_ALIAS \
  --function-version $NEW_LAMBDA_VERSION \
  --region $AWS_REGION

# Wait for provisioned concurrency to be configured
while true; do
  CONCURRENCY_STATUS=$(aws lambda get-provisioned-concurrency-config \
    --function-name ${IMAGE_NAME} \
    --qualifier ${LAMBDA_ALIAS} \
    --query "Status" --output text)

  if [[ ${CONCURRENCY_STATUS} == "READY" ]]; then
    break
  elif [[ ${CONCURRENCY_STATUS} == "FAILED" ]]; then
    echo "Provisioned concurrency addition failed" >&2
    exit 1
  else
    echo "Waiting for provisioned concurrency to be configured..."
    sleep 10
  fi
done

echo "Provisioned concurrency added to the Lambda function."

Kode Terkait API Gateway

Buat skrip shell provision-api-gateway.sh untuk menyiapkan API Gateway. provision-api-gateway.sh akan menjalankan hal-hal berikut:

  1. Membuat REST API
  2. Membuat metode POST
  3. Mengintegrasikan dengan Lambda
  4. Menetapkan izin untuk Lambda
  5. Mendeploy API Gateway
deploy/provision-api-gateway.sh
#!/bin/bash

LAMBDA_FUNCTION_ARN=arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT_ID}:function:${IMAGE_NAME}

# Create REST API
REST_API=$(aws apigateway create-rest-api --name $IMAGE_NAME)
REST_API_ID=$(echo $REST_API | python -c "import sys, json; print(json.load(sys.stdin)['id'])")

# Get root resource ID
RESOURCE=$(aws apigateway get-resources --rest-api-id $REST_API_ID)
RESOURCE_ID=$(echo $RESOURCE | python -c "import sys, json; print(json.load(sys.stdin)['items'][0]['id'])")

# Create POST method for the root resource
aws apigateway put-method \
    --rest-api-id $REST_API_ID \
    --resource-id $RESOURCE_ID \
    --http-method POST \
    --no-api-key-required \
    --authorization-type NONE

# Create integration for Lambda function
aws apigateway put-integration \
    --rest-api-id $REST_API_ID \
    --resource-id $RESOURCE_ID \
    --http-method POST \
    --type AWS \
    --integration-http-method POST \
    --uri "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${LAMBDA_FUNCTION_ARN}:${LAMBDA_ALIAS}/invocations"

aws apigateway put-method-response \
    --rest-api-id $REST_API_ID \
    --resource-id $RESOURCE_ID \
    --http-method POST \
    --status-code 200 \
    --response-models '{"application/json": "Empty"}'

aws apigateway put-integration-response \
    --rest-api-id $REST_API_ID \
    --resource-id $RESOURCE_ID \
    --http-method POST \
    --status-code 200 \
    --response-templates '{"application/json": ""}'

# Add Lambda permission
aws lambda add-permission \
    --function-name $IMAGE_NAME:${LAMBDA_ALIAS} \
    --statement-id apigateway-access \
    --action lambda:InvokeFunction \
    --principal apigateway.amazonaws.com \
    --source-arn "arn:aws:execute-api:${AWS_REGION}:${AWS_ACCOUNT_ID}:${REST_API_ID}/*/POST/"

# Deploy API Gateway
aws apigateway create-deployment \
    --rest-api-id $REST_API_ID \
    --stage-name prod

# Output API Gateway endpoint
echo "https://$REST_API_ID.execute-api.$AWS_REGION.amazonaws.com/prod"

Makefile

Buat sebuah Makefile seperti berikut:

Makefile
.PHONY: deploy-init deploy

deploy-init:
	sh deploy/provision-ecr.sh
	sh deploy/push-ecr.sh
	sh deploy/provision-lambda.sh
	sh deploy/provision-api-gateway.sh

deploy:
	sh deploy/push-ecr.sh
	sh deploy/update-lambda.sh

Deploy

Ketika Anda menjalankan perintah berikut, Lambda dan API Gateway akan di-deploy secara awal:

$ make deploy-init

Proses berikut akan dijalankan dalam make deploy-init:

  1. Membuat repository ECR
  2. Membangun Docker dan mendorong ke ECR
  3. Membuat Lambda
  4. Membuat API Gateway

Ketika Anda perlu memperbarui Lambda dengan gambar Docker yang diperbarui, jalankan perintah berikut:

$ make deploy

Proses berikut akan dijalankan dalam make deploy:

  1. Membangun Docker dan mendorong ke ECR
  2. Memperbarui Lambda

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!