[칼럼] 나의 람다는 왜 나의 람다를 못 불렀는가
람다에 VPC를 설정했어야 하는 이유
이번에 스마트 무통장 주문 취소 개선을 하게 되면서, 람다에서 Elastic Cache에 접근해야 하는 상황이 발생했습니다. 따라서 Elastic Cache가 속해 있는 VPC에 람다를 넣어야 했습니다. 왜 Elastic Cache에 접근하려면 같은 VPC안에 있어야 하는지는 아래 공식 문서의 이미지에서 확인할 수 있습니다.
Networking and VPC configurations
VPC 설정하기
람다에 VPC를 설정하기 위해서는 여러 방법이 존재합니다. 두 가지 설정을 하기 전에, 우선 람다의 역할에 다음과 같이 Network Interface를 만들 수 있는 권한을 줘야 합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeNetworkInterfaces",
"ec2:CreateNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:DescribeInstances",
"ec2:AttachNetworkInterface"
],
"Resource": "*"
}
]
}
콘솔에서 설정하기
콘솔에서 구성으로 들어가서 Elastic Search와 동일한 VPC로 설정을 해줍니다.
여기서 중요한 것은, Elastic Cache에서 특정 보안 그룹을 허용하고 있다면, 해당 보안 그룹으로 설정을 해줘야합니다.
SAM을 사용한다면
SAM을 사용하면 template.yaml을 통해 Funtion 설정 하위에 설정합니다.
VpcConfig:
SubnetIds:
- subnet-
- subnet-
- subnet-
- subnet-
SecurityGroupIds:
- !Sub security-group-id
VPC에 속하려면 꼭 하나 이상의 보안 그룹이 필요합니다.
문제 발생
이렇게 람다에 VPC를 설정 후, 여러 람다를 invoke 해주는 람다를 실행하니 다음과 같은 문제가 발생했습니다.
다른 람다를 Invoke하는 로직에서 Lambda timeout까지 DB 락이 걸린 채로 멈춰 서버렸습니다. 왜 이런 일이 발생한 것일까요? 이것을 알기 위해서는 우선 Lambda의 VPC 환경에 대해서 이해해야 합니다.
람다의 VPC
람다는 기본 생성 시, AWS에서 완전 관리되는 특별한 VPC에서 생성이 됩니다. 이를 AWS에서는 AWS Lambda Service VPC라고 부릅니다. 람다의 호출은 오직 Lambda API를 통해 이루어집니다.
앞서 말했듯, 특정 AWS 서비스(Elastic Cache, MQ 등)를 호출하려면 해당 서비스가 속한 VPC 설정이 필요합니다. 하지만 여기서 간과해서는 안 되는 중요한 사실이 존재합니다. 람다에 VPC 설정을 하더라도, 해당 람다는 설정한 VPC 내부에서 실행되는 것이 아니라는 점 입니다.
람다에 VPC 설정을 하게 되면 해당 VPC에 ENI가 만들어지고, 이 ENI를 통해서 람다는 개인 리소스로 접근을 할 수 있게 됩니다. 즉, 여전히 람다는 독자적인 Lambda Service VPC에서 Lambda API를 통해서만 실행됩니다.
VPC의 ENI에 접근하기 위해 AWS Hyperplane(Network Load Balancer 및 NAT 게이트웨이에 사용되는 Network Function Virtualization 플랫폼)을 사용해 여러 람다의 ENI 연결을 매핑해줍니다.
이를 통해서 람다는 정상적으로 Elastic Cache에 접근이 가능해집니다. 그런데 왜 다른 람다를 invoke 하지 못했을까요? 연결된 서브넷들은 모두 퍼블릭 서브넷인데 말입니다.
VPC 설정이 된 람다가 VPC 설정을 하지 않은 람다를 호출하지 못하는 이유
결론부터 말하자면 VPC 설정을 하면, 이 함수는 지정된 VPC의 네트워크 구성을 따르게 되기 때문입니다. 즉, VPC 설정 이후에는 해당 VPC를 통해, 네트워크를 통해서만 다른 리소스에 엑세스가 가능합니다. 따라서 외부 인터넷이나, VPC 외부의 AWS 서비스에 접근하려면 추가 구성이 필요합니다.
예를 들면 NAT 게이트웨이나 인터넷 게이트웨이, VPC 엔드포인트와 같이 private 서브넷에서 외부로 통신하기 위해 설정이 필요한 맥락과 같습니다.
명심해야 할 것이, ECS의 fargate에 생성되는 ENI와, 람다가 VPC에 접근하기 위해 생성하는 ENI는 다릅니다. 처음에 저는 이렇게 생각했습니다. ‘아니 ECS에서는 별 다른 설정 없이 다른 Lambda에 접근이 가능한데, 왜 VPC 설정이 된 람다는 람다를 부르지 못하는거지?
이유는 다음과 같습니다. 람다의 VPC 설정을 통해 생성된 ENI는 해당 VPC에 접근이 가능하게 해주기 위한 ENI이고, ECS의 ENI는 외부로 나가게 하기 위한 ENI입니다.
해결 방법
따라서 VPC 설정을 한 람다에서 하지 않은 람다를 invoke하기 위해서는 NAT gateway, instance 등등을 설정해야 합니다. 하지만 NAT Gateway나 instance를 설정할 때 가격적인 요소를 고려를 해야합니다.
다른 방법으로는 아예 람다를 VPC 환경에 넣지 않는 것인데요, 실제로 Lambda를 VPC 설정을 하게 되면 colde start 시간이 증가합니다. AWS Hyperplane를 사용하게 되면서 ENI를 생성하는 시간을 많이 줄여주었지만, 언제까지나 지연율을 ‘줄여주는 것’ 입니다. 기존의 네트워크 인터페이스에 접근하고 해당 네트워크를 통해 통신이 되기 때문에 VPC가 설정되지 않은 람다보다 느린 것 입니다.
정 써야한다면 Elastic Cache Severless를 버전을 사용하면 된다고 합니다.
저의 경우에는 RDS에 테이블을 하나 만들어, 데이터를 공유하는 방법을 택했습니다. DynamoDB를 사용하는 것도 좋은 방법이라고 생각이 듭니다.