Python Lambda functions with container images Deployment Automation

Tran Que An
4 min readJan 13, 2024

--

1. Introduction

This is the follow-up tutorial of my previous one. As you may see, our deployment pipeline in the last article involves many manual steps. Let see how we can automate the entire process.

If you have not read the previous article, it would be helpful to check it out here.

Code is available at this repo.

2. Deployment steps

2.1. Prerequisite

2.2 Terraform script

There are a few components in terraform script which are there to declare used variables, etc. If you want to know more about it, please check out the code in my repo. I will only talk about the most important file which is ./infra/aws_lambda/main.tf

# IAM role which dictates what other AWS services the Lambda function may access.
resource "aws_iam_role" "lambda_exec" {
name = "${var.app}-${var.env}-iam_role"

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

# Get ECR repository info in terraform
data "aws_ecr_repository" "function_ecr_repo" {
name = "${var.app}-${var.env}"
}

# Apply the image to lambda function
resource "aws_lambda_function" "lambda_function" {
function_name = "${var.app}-${var.env}"
timeout = var.timeout
memory_size = var.memory_size
image_uri = "${data.aws_ecr_repository.function_ecr_repo.repository_url}:${var.app_version}"
package_type = "Image"

role = aws_iam_role.lambda_exec.arn

environment {
variables = {
ENV = var.env
APP = var.app
}
}
}
  • aws_iam_role is to create an execution role for AWS Lambda function
  • aws_ecr_repository is to get information from the ECR repo
  • aws_lambda_function is to apply all configurations to the Lambda Function e.g. applying the image uri and execution role we declared above

2.3 Uploading Image script

I have mentioned about this script in the previous article. However, in this tutorial, there will be a small change in URI name. We are now choosing to tag the image with version name instead of the env. Hence, we accept one more input as version and change env to version in image_uri.

# Step 1: Configure AWS credentials and application-related values such as application name, environment (e.g., dev, sqa, uat, and prod), and AWS account number
aws_profile="$1"
aws_region="$2"
env="$3"
app="$4"
aws_account="$5"
version="$6" # New Change

# Step 2: Formulate ECR values
ecr_repo="$app-$env"
base_uri="$aws_account.dkr.ecr.$aws_region.amazonaws.com"
image_uri="$base_uri/$ecr_repo:$version" # New Change

# Step 3: Upload docker image to ECR
# Step 3.1: Docker Image Built
echo "Docker Image Built"
docker build --platform linux/amd64 -t $ecr_repo:$env ../

# Step 3.2: Login into AWS ECR
export ecr_password=$(aws ecr get-login-password --region $aws_region --profile $aws_profile)
eval $ecr_password
echo "Successful ECR Login"
docker login --username AWS --password $ecr_password $base_uri

# Step 3.3: Tag the Docker image
docker tag $ecr_repo:$env $image_uri
echo "Successfully tagged the ECR image"

# Step 3.4: Push the Docker image to ECR repository
docker push $image_uri
echo "Successfully pushed the Docker image to ECR"

2.4 Deployment script

I have also mentioned about this script in the last article. However, the previous script stops at uploading the image to ECR repo. In this new script, we will add the part running terraform script.

# Step 1: Get the environment
if [ -z "$1" ]; then
env="dev"
else
env=$(awk '{print tolower($0)}' <<< "$1")
fi

# Step 2: Specify your aws credentials and app name
aws_profile="AdministratorAccess-007985056474"
app="lambda-docker"
aws_account="007985056474"
aws_region="ap-southeast-1"
version="0.0.1"

# Step 3: Run uploading image script
source ./upload_image.sh $aws_profile $aws_region $env $app $aws_account $version

# Step 4: Configure variable for terraform script
export TF_VAR_aws_profile=$aws_profile
export TF_VAR_env=$env
export TF_VAR_app=$app
export TF_VAR_app_version=$version


# Step 5: Run terraform script
cd ../infra/$env
terraform init
# Generate and show an execution plan
terraform plan -var-file=tfvariables.tfvars
# Apply the changes
terraform apply -auto-approve -var-file=tfvariables.tfvars

If you notice, we also added version variable in this deployment script to match with the uploading script.

2.5. Create repository in ECR

Please refer to point 3.5 in my previous article.

2.6 Deploy

After creating ECR repo, you should be able to deploy your code to Lambda function with created deployment script.

  • Navigate the ternimal to deployment folder
  • Run `deploy.sh` file with the command bash deploy.sh

Here is the result:

3. Redeployment

After you changed the handler code and updated all dependencies, simply run the script like what we have done in step 2.6. Please make sure that you change the code version inside the script.

4. Deploy to different environment

If you are following my code folder structure, you may notice that this facilitate to deployment to different enviroment e.g. sqa. I will demonstrate how we can deploy the current code to sqa environment.

  • Create duplicate version of ./infra/dev and rename it sqa. Because there is no configuration change between our environments, we do not need to change anything in sqa folder. Make sure that you delete all cache files/folder in the folder such as .terraform, .terraform.lock.hcl, terraform.tfstate, terraform.tfstate.backup.
  • Create a new ECR repo for the new environment e.g. lambda-docker-sqa. Please refer to step 2.5.
  • Repeat step 2.6 with a new command bash deploy.sh sqa

Here is what you get out of it:

5. What’s next

In the next article, we will develop a complete solution for text masking service utilizing Presidio. Stay tuned for my next articles.

--

--