AWS Lambda Churn Prediction¶
Install packages
Import packages
Architecture diagram
Directory Structure
.
├── app
│  ├── Dockerfile
│  ├── event.json
│  ├── lambda_function.py
│  ├── model_C=10.bin
│  ├── pyproject.toml
│  ├── README.md
│  └── uv.lock
├── aws-lambda-churn-prediction.ipynb
├── diagrams_image.png
└── infra
├── main.tf
├── terraform.tfstate
└── terraform.tfstate.backup
3 directories, 12 files
Application code
Dockerfile
| app/Dockerfile | |
|---|---|
Terraform
| infra/main.tf | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | |
Copy model artifact into app directory
Terraform initialization
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of kreuzwerker/docker from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed kreuzwerker/docker v3.6.2
- Using previously-installed hashicorp/aws v5.100.0
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Terraform validation
Terraform plan
data.aws_region.current: Reading...
data.aws_ecr_authorization_token.ecr: Reading...
data.aws_caller_identity.current: Reading...
data.aws_region.current: Read complete after 0s [id=us-east-1]
data.aws_caller_identity.current: Read complete after 0s [id=544244312696]
data.aws_ecr_authorization_token.ecr: Read complete after 1s [id=us-east-1]
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_ecr_lifecycle_policy.cleanup will be created
+ resource "aws_ecr_lifecycle_policy" "cleanup" {
+ id = (known after apply)
+ policy = jsonencode(
{
+ rules = [
+ {
+ action = {
+ type = "expire"
}
+ description = "Keep last 2 images"
+ rulePriority = 1
+ selection = {
+ countNumber = 2
+ countType = "imageCountMoreThan"
+ tagStatus = "any"
}
},
]
}
)
+ registry_id = (known after apply)
+ repository = "churn-prediction-lambda"
}
# aws_ecr_repository.lambda_repo will be created
+ resource "aws_ecr_repository" "lambda_repo" {
+ arn = (known after apply)
+ force_delete = true
+ id = (known after apply)
+ image_tag_mutability = "MUTABLE"
+ name = "churn-prediction-lambda"
+ registry_id = (known after apply)
+ repository_url = (known after apply)
+ tags_all = (known after apply)
+ image_scanning_configuration {
+ scan_on_push = true
}
}
# aws_iam_role.lambda_role will be created
+ resource "aws_iam_role" "lambda_role" {
+ arn = (known after apply)
+ assume_role_policy = jsonencode(
{
+ Statement = [
+ {
+ Action = "sts:AssumeRole"
+ Effect = "Allow"
+ Principal = {
+ Service = "lambda.amazonaws.com"
}
},
]
+ Version = "2012-10-17"
}
)
+ create_date = (known after apply)
+ force_detach_policies = false
+ id = (known after apply)
+ managed_policy_arns = (known after apply)
+ max_session_duration = 3600
+ name = "churn-prediction-lambda-role"
+ name_prefix = (known after apply)
+ path = "/"
+ tags_all = (known after apply)
+ unique_id = (known after apply)
+ inline_policy (known after apply)
}
# aws_iam_role_policy_attachment.basic_logs will be created
+ resource "aws_iam_role_policy_attachment" "basic_logs" {
+ id = (known after apply)
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
+ role = "churn-prediction-lambda-role"
}
# aws_lambda_function.churn_lambda will be created
+ resource "aws_lambda_function" "churn_lambda" {
+ architectures = (known after apply)
+ arn = (known after apply)
+ code_sha256 = (known after apply)
+ function_name = "churn-prediction"
+ id = (known after apply)
+ image_uri = (known after apply)
+ invoke_arn = (known after apply)
+ last_modified = (known after apply)
+ memory_size = 1024
+ package_type = "Image"
+ publish = false
+ qualified_arn = (known after apply)
+ qualified_invoke_arn = (known after apply)
+ reserved_concurrent_executions = -1
+ role = (known after apply)
+ signing_job_arn = (known after apply)
+ signing_profile_version_arn = (known after apply)
+ skip_destroy = false
+ source_code_hash = (known after apply)
+ source_code_size = (known after apply)
+ tags_all = (known after apply)
+ timeout = 30
+ version = (known after apply)
+ ephemeral_storage (known after apply)
+ logging_config (known after apply)
+ tracing_config (known after apply)
}
# docker_image.lambda_image will be created
+ resource "docker_image" "lambda_image" {
+ id = (known after apply)
+ image_id = (known after apply)
+ name = (known after apply)
+ repo_digest = (known after apply)
+ build {
+ cache_from = []
+ context = "./../app"
+ dockerfile = "Dockerfile"
+ extra_hosts = []
+ platform = "linux/amd64"
+ remove = true
+ security_opt = []
+ tag = []
# (12 unchanged attributes hidden)
}
}
# docker_registry_image.lambda_image will be created
+ resource "docker_registry_image" "lambda_image" {
+ id = (known after apply)
+ insecure_skip_verify = false
+ keep_remotely = true
+ name = (known after apply)
+ sha256_digest = (known after apply)
}
Plan: 7 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ ecr_repository_url = (known after apply)
+ lambda_name = "churn-prediction"
───────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.
Terraform apply
data.aws_region.current: Reading...
data.aws_ecr_authorization_token.ecr: Reading...
data.aws_caller_identity.current: Reading...
data.aws_region.current: Read complete after 0s [id=us-east-1]
data.aws_caller_identity.current: Read complete after 0s [id=544244312696]
data.aws_ecr_authorization_token.ecr: Read complete after 0s [id=us-east-1]
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_ecr_lifecycle_policy.cleanup will be created
+ resource "aws_ecr_lifecycle_policy" "cleanup" {
+ id = (known after apply)
+ policy = jsonencode(
{
+ rules = [
+ {
+ action = {
+ type = "expire"
}
+ description = "Keep last 2 images"
+ rulePriority = 1
+ selection = {
+ countNumber = 2
+ countType = "imageCountMoreThan"
+ tagStatus = "any"
}
},
]
}
)
+ registry_id = (known after apply)
+ repository = "churn-prediction-lambda"
}
# aws_ecr_repository.lambda_repo will be created
+ resource "aws_ecr_repository" "lambda_repo" {
+ arn = (known after apply)
+ force_delete = true
+ id = (known after apply)
+ image_tag_mutability = "MUTABLE"
+ name = "churn-prediction-lambda"
+ registry_id = (known after apply)
+ repository_url = (known after apply)
+ tags_all = (known after apply)
+ image_scanning_configuration {
+ scan_on_push = true
}
}
# aws_iam_role.lambda_role will be created
+ resource "aws_iam_role" "lambda_role" {
+ arn = (known after apply)
+ assume_role_policy = jsonencode(
{
+ Statement = [
+ {
+ Action = "sts:AssumeRole"
+ Effect = "Allow"
+ Principal = {
+ Service = "lambda.amazonaws.com"
}
},
]
+ Version = "2012-10-17"
}
)
+ create_date = (known after apply)
+ force_detach_policies = false
+ id = (known after apply)
+ managed_policy_arns = (known after apply)
+ max_session_duration = 3600
+ name = "churn-prediction-lambda-role"
+ name_prefix = (known after apply)
+ path = "/"
+ tags_all = (known after apply)
+ unique_id = (known after apply)
+ inline_policy (known after apply)
}
# aws_iam_role_policy_attachment.basic_logs will be created
+ resource "aws_iam_role_policy_attachment" "basic_logs" {
+ id = (known after apply)
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
+ role = "churn-prediction-lambda-role"
}
# aws_lambda_function.churn_lambda will be created
+ resource "aws_lambda_function" "churn_lambda" {
+ architectures = (known after apply)
+ arn = (known after apply)
+ code_sha256 = (known after apply)
+ function_name = "churn-prediction"
+ id = (known after apply)
+ image_uri = (known after apply)
+ invoke_arn = (known after apply)
+ last_modified = (known after apply)
+ memory_size = 1024
+ package_type = "Image"
+ publish = false
+ qualified_arn = (known after apply)
+ qualified_invoke_arn = (known after apply)
+ reserved_concurrent_executions = -1
+ role = (known after apply)
+ signing_job_arn = (known after apply)
+ signing_profile_version_arn = (known after apply)
+ skip_destroy = false
+ source_code_hash = (known after apply)
+ source_code_size = (known after apply)
+ tags_all = (known after apply)
+ timeout = 30
+ version = (known after apply)
+ ephemeral_storage (known after apply)
+ logging_config (known after apply)
+ tracing_config (known after apply)
}
# docker_image.lambda_image will be created
+ resource "docker_image" "lambda_image" {
+ id = (known after apply)
+ image_id = (known after apply)
+ name = (known after apply)
+ repo_digest = (known after apply)
+ build {
+ cache_from = []
+ context = "./../app"
+ dockerfile = "Dockerfile"
+ extra_hosts = []
+ platform = "linux/amd64"
+ remove = true
+ security_opt = []
+ tag = []
# (12 unchanged attributes hidden)
}
}
# docker_registry_image.lambda_image will be created
+ resource "docker_registry_image" "lambda_image" {
+ id = (known after apply)
+ insecure_skip_verify = false
+ keep_remotely = true
+ name = (known after apply)
+ sha256_digest = (known after apply)
}
Plan: 7 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ ecr_repository_url = (known after apply)
+ lambda_name = "churn-prediction"
aws_ecr_repository.lambda_repo: Creating...
aws_iam_role.lambda_role: Creating...
aws_ecr_repository.lambda_repo: Creation complete after 1s [id=churn-prediction-lambda]
aws_ecr_lifecycle_policy.cleanup: Creating...
docker_image.lambda_image: Creating...
aws_iam_role.lambda_role: Creation complete after 1s [id=churn-prediction-lambda-role]
aws_iam_role_policy_attachment.basic_logs: Creating...
aws_ecr_lifecycle_policy.cleanup: Creation complete after 1s [id=churn-prediction-lambda]
aws_iam_role_policy_attachment.basic_logs: Creation complete after 1s [id=churn-prediction-lambda-role-20260104184406582500000001]
docker_image.lambda_image: Still creating... [00m10s elapsed]
docker_image.lambda_image: Still creating... [00m20s elapsed]
docker_image.lambda_image: Still creating... [00m30s elapsed]
docker_image.lambda_image: Creation complete after 32s [id=sha256:c8c0790d688fa293b6d2806471ff3da2603e76b7f8f30eb1f7d69f27b4bf969c544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f]
docker_registry_image.lambda_image: Creating...
docker_registry_image.lambda_image: Still creating... [00m10s elapsed]
docker_registry_image.lambda_image: Still creating... [00m20s elapsed]
docker_registry_image.lambda_image: Still creating... [00m30s elapsed]
docker_registry_image.lambda_image: Still creating... [00m40s elapsed]
docker_registry_image.lambda_image: Still creating... [00m50s elapsed]
docker_registry_image.lambda_image: Still creating... [01m00s elapsed]
docker_registry_image.lambda_image: Still creating... [01m10s elapsed]
docker_registry_image.lambda_image: Creation complete after 1m17s [id=sha256:9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b]
aws_lambda_function.churn_lambda: Creating...
aws_lambda_function.churn_lambda: Still creating... [00m10s elapsed]
aws_lambda_function.churn_lambda: Still creating... [00m20s elapsed]
aws_lambda_function.churn_lambda: Creation complete after 22s [id=churn-prediction]
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
Outputs:
ecr_repository_url = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda"
lambda_name = "churn-prediction"
Terraform destroy
data.aws_region.current: Reading...
data.aws_caller_identity.current: Reading...
data.aws_ecr_authorization_token.ecr: Reading...
aws_ecr_repository.lambda_repo: Refreshing state... [id=churn-prediction-lambda]
aws_iam_role.lambda_role: Refreshing state... [id=churn-prediction-lambda-role]
data.aws_region.current: Read complete after 0s [id=us-east-1]
data.aws_caller_identity.current: Read complete after 0s [id=544244312696]
data.aws_ecr_authorization_token.ecr: Read complete after 1s [id=us-east-1]
aws_ecr_lifecycle_policy.cleanup: Refreshing state... [id=churn-prediction-lambda]
aws_iam_role_policy_attachment.basic_logs: Refreshing state... [id=churn-prediction-lambda-role-20260104184406582500000001]
docker_image.lambda_image: Refreshing state... [id=sha256:c8c0790d688fa293b6d2806471ff3da2603e76b7f8f30eb1f7d69f27b4bf969c544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f]
docker_registry_image.lambda_image: Refreshing state... [id=sha256:9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b]
aws_lambda_function.churn_lambda: Refreshing state... [id=churn-prediction]
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_ecr_lifecycle_policy.cleanup will be destroyed
- resource "aws_ecr_lifecycle_policy" "cleanup" {
- id = "churn-prediction-lambda" -> null
- policy = jsonencode(
{
- rules = [
- {
- action = {
- type = "expire"
}
- description = "Keep last 2 images"
- rulePriority = 1
- selection = {
- countNumber = 2
- countType = "imageCountMoreThan"
- tagStatus = "any"
}
},
]
}
) -> null
- registry_id = "544244312696" -> null
- repository = "churn-prediction-lambda" -> null
}
# aws_ecr_repository.lambda_repo will be destroyed
- resource "aws_ecr_repository" "lambda_repo" {
- arn = "arn:aws:ecr:us-east-1:544244312696:repository/churn-prediction-lambda" -> null
- force_delete = true -> null
- id = "churn-prediction-lambda" -> null
- image_tag_mutability = "MUTABLE" -> null
- name = "churn-prediction-lambda" -> null
- registry_id = "544244312696" -> null
- repository_url = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda" -> null
- tags = {} -> null
- tags_all = {} -> null
- encryption_configuration {
- encryption_type = "AES256" -> null
# (1 unchanged attribute hidden)
}
- image_scanning_configuration {
- scan_on_push = true -> null
}
}
# aws_iam_role.lambda_role will be destroyed
- resource "aws_iam_role" "lambda_role" {
- arn = "arn:aws:iam::544244312696:role/churn-prediction-lambda-role" -> null
- assume_role_policy = jsonencode(
{
- Statement = [
- {
- Action = "sts:AssumeRole"
- Effect = "Allow"
- Principal = {
- Service = "lambda.amazonaws.com"
}
},
]
- Version = "2012-10-17"
}
) -> null
- create_date = "2026-01-04T18:44:06Z" -> null
- force_detach_policies = false -> null
- id = "churn-prediction-lambda-role" -> null
- managed_policy_arns = [
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
] -> null
- max_session_duration = 3600 -> null
- name = "churn-prediction-lambda-role" -> null
- path = "/" -> null
- tags = {} -> null
- tags_all = {} -> null
- unique_id = "AROAX5N35FJ4DHGOFYRAG" -> null
# (3 unchanged attributes hidden)
}
# aws_iam_role_policy_attachment.basic_logs will be destroyed
- resource "aws_iam_role_policy_attachment" "basic_logs" {
- id = "churn-prediction-lambda-role-20260104184406582500000001" -> null
- policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" -> null
- role = "churn-prediction-lambda-role" -> null
}
# aws_lambda_function.churn_lambda will be destroyed
- resource "aws_lambda_function" "churn_lambda" {
- architectures = [
- "x86_64",
] -> null
- arn = "arn:aws:lambda:us-east-1:544244312696:function:churn-prediction" -> null
- code_sha256 = "9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b" -> null
- function_name = "churn-prediction" -> null
- id = "churn-prediction" -> null
- image_uri = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f" -> null
- invoke_arn = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:544244312696:function:churn-prediction/invocations" -> null
- last_modified = "2026-01-04T18:45:59.721+0000" -> null
- layers = [] -> null
- memory_size = 1024 -> null
- package_type = "Image" -> null
- publish = false -> null
- qualified_arn = "arn:aws:lambda:us-east-1:544244312696:function:churn-prediction:$LATEST" -> null
- qualified_invoke_arn = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:544244312696:function:churn-prediction:$LATEST/invocations" -> null
- reserved_concurrent_executions = -1 -> null
- role = "arn:aws:iam::544244312696:role/churn-prediction-lambda-role" -> null
- skip_destroy = false -> null
- source_code_size = 0 -> null
- tags = {} -> null
- tags_all = {} -> null
- timeout = 30 -> null
- version = "$LATEST" -> null
# (8 unchanged attributes hidden)
- ephemeral_storage {
- size = 512 -> null
}
- logging_config {
- log_format = "Text" -> null
- log_group = "/aws/lambda/churn-prediction" -> null
# (2 unchanged attributes hidden)
}
- tracing_config {
- mode = "PassThrough" -> null
}
}
# docker_image.lambda_image will be destroyed
- resource "docker_image" "lambda_image" {
- id = "sha256:c8c0790d688fa293b6d2806471ff3da2603e76b7f8f30eb1f7d69f27b4bf969c544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f" -> null
- image_id = "sha256:c8c0790d688fa293b6d2806471ff3da2603e76b7f8f30eb1f7d69f27b4bf969c" -> null
- name = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f" -> null
- repo_digest = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda@sha256:9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b" -> null
- build {
- build_args = {} -> null
- cache_from = [] -> null
- context = "./../app" -> null
- cpu_period = 0 -> null
- cpu_quota = 0 -> null
- cpu_shares = 0 -> null
- dockerfile = "Dockerfile" -> null
- extra_hosts = [] -> null
- force_remove = false -> null
- label = {} -> null
- labels = {} -> null
- memory = 0 -> null
- memory_swap = 0 -> null
- no_cache = false -> null
- platform = "linux/amd64" -> null
- pull_parent = false -> null
- remove = true -> null
- security_opt = [] -> null
- shm_size = 0 -> null
- squash = false -> null
- suppress_output = false -> null
- tag = [] -> null
# (12 unchanged attributes hidden)
}
}
# docker_registry_image.lambda_image will be destroyed
- resource "docker_registry_image" "lambda_image" {
- id = "sha256:9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b" -> null
- insecure_skip_verify = false -> null
- keep_remotely = true -> null
- name = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f" -> null
- sha256_digest = "sha256:9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b" -> null
}
Plan: 0 to add, 0 to change, 7 to destroy.
Changes to Outputs:
- ecr_repository_url = "544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda" -> null
- lambda_name = "churn-prediction" -> null
aws_ecr_lifecycle_policy.cleanup: Destroying... [id=churn-prediction-lambda]
aws_iam_role_policy_attachment.basic_logs: Destroying... [id=churn-prediction-lambda-role-20260104184406582500000001]
aws_lambda_function.churn_lambda: Destroying... [id=churn-prediction]
aws_lambda_function.churn_lambda: Destruction complete after 1s
docker_registry_image.lambda_image: Destroying... [id=sha256:9bce8fc227d08878d336be1c28d18a40a472d1b8c9dceb024ffa55a2b2202d9b]
docker_registry_image.lambda_image: Destruction complete after 0s
docker_image.lambda_image: Destroying... [id=sha256:c8c0790d688fa293b6d2806471ff3da2603e76b7f8f30eb1f7d69f27b4bf969c544244312696.dkr.ecr.us-east-1.amazonaws.com/churn-prediction-lambda:0f2bacac0942f7715c68395bc5249170ba3dd9ca68e4a85a148977ad654d069f]
aws_iam_role_policy_attachment.basic_logs: Destruction complete after 1s
aws_iam_role.lambda_role: Destroying... [id=churn-prediction-lambda-role]
aws_ecr_lifecycle_policy.cleanup: Destruction complete after 1s
docker_image.lambda_image: Destruction complete after 0s
aws_ecr_repository.lambda_repo: Destroying... [id=churn-prediction-lambda]
aws_ecr_repository.lambda_repo: Destruction complete after 0s
aws_iam_role.lambda_role: Destruction complete after 0s
Destroy complete! Resources: 7 destroyed.