如何用Terraform的for_each动态创建Lambda函数及Docker容器?
问题解决:Terraform动态创建Lambda函数报错处理
问题原因
- 多余的空Lambda模块:你在
main.tf里声明了一个完全未配置参数的module "lambda",这个模块会默认生成IAM角色和策略,但因为没指定合理的命名参数,导致名称不符合AWS IAM的命名规则(仅允许[\w+=,.@-]这类字符),直接触发报错。 - 无效打包流程触发:这个空模块还会默认执行代码打包逻辑,但根本没设置
source_path,所以出现Could not locate source_path "null"的错误。 - 硬编码AWS账号ID和区域的做法不够灵活,容易因环境变化出错。
修复步骤
1. 删除多余的空Lambda模块
打开main.tf,删掉这段无意义的代码:
module "lambda" { source = "terraform-aws-modules/lambda/aws" version = "6.0.0" }
这是触发大部分报错的核心原因。
2. 用数据源替换硬编码的AWS账号和区域
在main.tf里添加两个数据源,自动获取当前账号ID和区域:
data "aws_caller_identity" "current" {} data "aws_region" "current" {}
然后更新docker provider的地址:
provider "docker" { registry_auth { address = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com" username = data.aws_ecr_authorization_token.token.user_name password = data.aws_ecr_authorization_token.token.password } }
同时修改lambda_build.tf里的image_uri:
image_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com/${each.value}:${var.commit_sha}"
这样就不用手动维护账号ID和区域了。
3. 确保函数名符合IAM命名规则
如果你的函数名(比如function1这类)本身包含特殊字符,需要先过滤处理,在lambda_function模块里修改角色和策略名称:
role_name = "${regexreplace(each.value, "[^\\w+=,.@-]", "")}_role" policy_name = "${regexreplace(each.value, "[^\\w+=,.@-]", "")}_policy"
如果函数名本身都是合法字符,这一步可以跳过。
4. 验证输入变量的有效性
确保GitHub Actions传递的directories变量格式正确(比如function1,function2,function3),且没有空值。local.lambda_dirs的过滤逻辑已经处理了空项,这部分没问题。
修改后的完整代码
main.tf
terraform { required_version = ">= 0.15" required_providers { aws = { source = "hashicorp/aws" version = ">= 4.63" } docker = { source = "kreuzwerker/docker" version = ">= 3.0" } } backend "s3" { encrypt = true bucket = "my-bucket-for-tfstate" key = "terraform.tfstate" region = "REGION" } } provider "aws" { region = "us-east-1" } data "aws_ecr_authorization_token" "token" {} data "aws_caller_identity" "current" {} data "aws_region" "current" {} provider "docker" { registry_auth { address = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com" username = data.aws_ecr_authorization_token.token.user_name password = data.aws_ecr_authorization_token.token.password } } locals { lambda_dirs = [for item in split(",", var.directories) : item if length(item) > 0] }
lambda_build.tf
module "docker_build" { source = "terraform-aws-modules/lambda/aws//modules/docker-build" for_each = toset(local.lambda_dirs) create_ecr_repo = true ecr_repo = each.value image_tag = var.commit_sha source_path = "${path.module}/../functions/${each.value}/" docker_file_path = "${path.module}/../functions/${each.value}/Dockerfile" } module "lambda_function" { source = "terraform-aws-modules/lambda/aws" for_each = toset(local.lambda_dirs) function_name = each.value description = "Lambda function for ${each.value}" image_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com/${each.value}:${var.commit_sha}" package_type = "Image" memory_size = 10000 timeout = 900 role_name = "${each.value}_role" policy_name = "${each.value}_policy" depends_on = [module.docker_build] }
内容的提问来源于stack exchange,提问作者Steven Burgess
相关产品推荐
相关产品推荐

