Terraform部署AWS时子网与安全组销毁卡顿问题求助
问题描述
1. 资源销毁卡顿
从自定义VPC(CIDR 10.0.0.0/16)切换到默认VPC后,执行terraform apply时,aws_subnet.main和aws_security_group.lambda_security_group一直卡在「Still destroying...」循环,无法完成资源销毁或更新。
2. 网络配置需求
需要实现两个核心访问能力:
- Lambda函数对RDS Postgres实例的读写访问
- 本地通过pgAdmin连接RDS实例
当前使用的Terraform配置片段如下:
基础VPC与子网配置
provider "aws" { region = var.aws_region access_key = var.aws_access_key secret_key = var.aws_secret_key } data "aws_vpc" "default" { default = true } resource "aws_db_subnet_group" "rds_subnet_group" { name = "scrapr-rds-subnet-group" subnet_ids = [aws_subnet.main.id, aws_subnet.secondary.id] } resource "aws_subnet" "main" { vpc_id = data.aws_vpc.default.id cidr_block = "10.0.1.0/24" availability_zone = "eu-central-1a" } resource "aws_subnet" "secondary" { vpc_id = data.aws_vpc.default.id cidr_block = "10.0.2.0/24" availability_zone = "eu-central-1b" }
安全组配置
resource "aws_security_group" "rds_security_group" { name = "scrapr_rds_security_group" description = "Security group for Scrapr RDS instance" vpc_id = data.aws_vpc.default.id ingress { from_port = 5432 to_port = 5432 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 5432 to_port = 5432 protocol = "tcp" } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group" "lambda_security_group" { name = "scrapr_lambda_security_group" description = "Security group for Scrapr Lambda function" vpc_id = data.aws_vpc.default.id # Allow outbound connections to the RDS instance egress { from_port = 0 to_port = 0 protocol = "-1" } }
RDS与Lambda配置
resource "aws_db_instance" "scrapr_rds_instance" { identifier = "scrapr-rds-instance" engine = "postgres" engine_version = "14.7" instance_class = "db.t3.micro" allocated_storage = 20 storage_type = "gp2" username = var.db_username password = var.db_password db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name vpc_security_group_ids = [aws_security_group.rds_security_group.id] publicly_accessible = false } resource "aws_lambda_function" "processing_lambda" { function_name = "processing_lambda" ... vpc_config { subnet_ids = [aws_subnet.main.id] security_group_ids = [aws_security_group.lambda_security_group.id] } }
卡顿环节日志
>aws_security_group.lambda_security_group: Still destroying... [4m0s elapsed] >aws_security_group.lambda_security_group: Still destroying... [4m10s elapsed] >aws_subnet.main: Still destroying... [4m10s elapsed] >aws_subnet.main: Still destroying... [4m20s elapsed] >aws_security_group.lambda_security_group: Still destroying... [4m20s elapsed] >aws_security_group.lambda_security_group: Still destroying... [4m30s elapsed] >aws_subnet.main: Still destroying... [4m30s elapsed] >aws_security_group.lambda_security_group: Still destroying... [4m40s elapsed] >aws_subnet.main: Still destroying... [4m40s elapsed] >aws_security_group.lambda_security_group: Still destroying... [4m50s elapsed] >aws_subnet.main: Still destroying... [4m50s elapsed]
解决方案
一、先解决资源销毁卡顿问题
卡顿的核心原因是资源被占用无法释放,按以下步骤修复:
- 解除Lambda对目标资源的占用
临时修改Lambda的Terraform配置,注释掉vpc_config块,执行terraform apply让Lambda退出VPC,不再占用子网和安全组。 - 单独销毁卡顿资源
执行命令:terraform destroy -target aws_subnet.main -target aws_security_group.lambda_security_group - 避免后续重复问题
不要在默认VPC中创建自定义子网,直接用默认VPC自带的默认子网,减少资源依赖复杂度;如果必须自定义子网,确保Terraform依赖关系清晰,必要时用depends_on显式声明。
二、配置Lambda访问RDS + 本地pgAdmin连接
核心配置逻辑
- RDS安全组:只允许Lambda安全组的5432端口流量(PostgreSQL),以及你的本地公网IP流量(用于pgAdmin)。
- Lambda安全组:允许出站到RDS的5432端口,同时允许出站到S3(因为Lambda要读写S3)。
- RDS需开启
publicly_accessible = true,才能让本地pgAdmin通过公网连接。
修正后的完整Terraform配置
1. 基础VPC与子网(使用默认VPC的默认子网)
provider "aws" { region = var.aws_region access_key = var.aws_access_key secret_key = var.aws_secret_key } data "aws_vpc" "default" { default = true } # 获取默认VPC的所有默认子网 data "aws_subnets" "default" { filter { name = "vpc-id" values = [data.aws_vpc.default.id] } filter { name = "default-for-az" values = ["true"] } } resource "aws_db_subnet_group" "rds_subnet_group" { name = "scrapr-rds-subnet-group" subnet_ids = data.aws_subnets.default.ids }
2. 安全组配置
resource "aws_security_group" "rds_security_group" { name = "scrapr_rds_security_group" description = "Security group for Scrapr RDS instance" vpc_id = data.aws_vpc.default.id # 允许Lambda安全组访问PostgreSQL端口 ingress { from_port = 5432 to_port = 5432 protocol = "tcp" security_groups = [aws_security_group.lambda_security_group.id] } # 允许本地公网IP访问(替换成你的本地公网IP,比如114.xxx.xxx.xxx/32,生产环境不要用0.0.0.0/0) ingress { from_port = 5432 to_port = 5432 protocol = "tcp" cidr_blocks = ["你的本地公网IP/32"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group" "lambda_security_group" { name = "scrapr_lambda_security_group" description = "Security group for Scrapr Lambda function" vpc_id = data.aws_vpc.default.id # 允许出站到RDS的PostgreSQL端口 egress { from_port = 5432 to_port = 5432 protocol = "tcp" security_groups = [aws_security_group.rds_security_group.id] } # 允许出站到S3(Lambda读写S3必须) egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } }
3. RDS、Lambda与IAM权限配置
resource "aws_db_instance" "scrapr_rds_instance" { identifier = "scrapr-rds-instance" engine = "postgres" engine_version = "14.7" instance_class = "db.t3.micro" allocated_storage = 20 storage_type = "gp2" username = var.db_username password = var.db_password db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name vpc_security_group_ids = [aws_security_group.rds_security_group.id] # 开启公网访问,允许本地pgAdmin连接 publicly_accessible = true backup_retention_period = 7 # 可选:启用自动备份 } resource "aws_lambda_function" "processing_lambda" { function_name = "processing_lambda" # 填充你的Lambda代码、运行时等配置 ... vpc_config { subnet_ids = data.aws_subnets.default.ids security_group_ids = [aws_security_group.lambda_security_group.id] } role = aws_iam_role.lambda_exec_role.id } # Lambda所需的IAM角色(必须配置,否则无法访问VPC、RDS、S3) resource "aws_iam_role" "lambda_exec_role" { name = "lambda-exec-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } } ] }) } # 附加Lambda基础执行权限 resource "aws_iam_role_policy_attachment" "lambda_basic_execution" { role = aws_iam_role.lambda_exec_role.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" } # 附加Lambda VPC访问权限 resource "aws_iam_role_policy_attachment" "lambda_vpc_access" { role = aws_iam_role.lambda_exec_role.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" } # 自定义权限:允许Lambda读写S3和连接RDS resource "aws_iam_role_policy" "lambda_s3_rds_access" { name = "lambda-s3-rds-access" role = aws_iam_role.lambda_exec_role.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = ["s3:GetObject", "s3:PutObject"] Resource = "arn:aws:s3:::你的S3桶名称/*" }, { Effect = "Allow" Action = ["rds-db:connect"] Resource = "arn:aws:rds-db:${var.aws_region}:${data.aws_caller_identity.current.account_id}:dbuser:${aws_db_instance.scrapr_rds_instance.resource_id}/${var.db_username}" } ] }) } data "aws_caller_identity" "current" {}
三、验证步骤
- 执行
terraform apply后,在AWS控制台查看RDS实例的端点和端口。 - 打开pgAdmin,新建服务器,输入RDS端点、端口、用户名密码,验证是否能成功连接。
- 上传测试CSV到触发S3桶,查看Lambda的CloudWatch日志,确认是否能完成数据清洗并写入RDS。
内容的提问来源于stack exchange,提问作者TheSoma300
相关产品推荐
相关产品推荐

