在您的子网中用完了IP地址,这是大多数团队如今面临的真实问题。大多数时候,这些IP是保留但未使用的!
此博客将解决未使用的弹性网络接口的问题,以及如何释放我们的IP地址池中的其他服务。
该解决方案将由每天触发的lambda函数和一个CloudWatch警报,以提醒我们我们的lambda生成的任何错误。
首先,我将浏览解决方案以及如何使用AWS控制台创建它,然后我将执行相同的解决方案,但使用基础架构为代码(Terraform)。
创建lambda
在浏览代码之前,让我们设置一些配置参数:
1-最重要的是超时,请确保它超过1分钟(这取决于您的工作负载)
2-内存:200 MB应该足够。
3-无需将lambda放入VPC。
使用Python的Lambda代码:
首先,导入python的AWS SDK(boto3):
ps: 要了解有关AWS SDK的更多信息,请查看this link
import boto3
client = boto3.client('ec2')
下一步:具有特定标签的导入子网。
key = type
值=私有
有多种方法。我的方式是:
1-根据标签描述所有资源
2-在资源类型和标签(键和值)上添加过滤器
# Get Subnets that have a Specific Tag.
tags = client.describe_tags(
Filters = [
{
'Name' : 'resource-type',
'Values' : [
'subnet'
]
},
{
'Name' : 'tag:type',
'Values': [
'private'
]
}
]
)
这种方法的格式输出:
{
"Tags":[
{
"Key":"type",
"ResourceId":"subnet-062715a13f1fffa54",
"ResourceType":"subnet",
"Value":"private"
},
{
"Key":"type",
"ResourceId":"subnet-0ee66ce86ffe0c073",
"ResourceType":"subnet",
"Value":"private"
}
],
"ResponseMetadata":{}
}
接下来,通过解析数据来获取结果字典中的子网ID。示例:
# Get Subnets that have a Specific Tag.
list_subnets = []
i = 0
while i < len(tags['Tags']):
list_subnets.append(tags['Tags'][i]['ResourceId'])
i = i+1
现在我们拥有子网ID,下一步是检索所有网络接口并删除它们。
要将我们的结果缩小到只需要的结果,需要添加过滤器。那是:
1-从特定子网获取eNIS
过滤器
2-滤波器要获得未使用的ENI(可用)
请注意,在值中,您需要将其检索到
之前的子网ID
eni = client.describe_network_interfaces(
Filters=[
{
'Name': 'subnet-id',
'Values': [
subnetid,
]
},
{
'Name': 'status',
'Values': [
'available'
]
},
]
)
i = 0
while i < len(eni["NetworkInterfaces"]):
network_interface = client.NetworkInterface(eni["NetworkInterfaces"][i]['NetworkInterfaceId'])
network_interface.delete()
i = i+1
对于处理程序,我们将不得不致电并同步以前的两个功能,以使lambda正常工作。
# Delete Available Network Interfaces in Specific Subnets
def lambda_handler(event, context):
list_subnet = get_tagged_subnets()
i = 0
while i < len(list_subnet):
delete_available_eni(list_subnet[i])
i = i+1
return {
"statusCode": 200,
}
lambda的角色
特定的许可lambda必须必须正常运行。
遵循最低特权原则的IAM政策是:
{
"Statement": [
{
"Action": [
"ec2:DescribeTags",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface"
],
"Effect": "Allow",
"Resource": "*",
"Sid": "1"
}
],
"Version": "2012-10-17"
}
lambda触发器
使用Amazon EventBridge调用Lambda分为两个步骤:
1-创建一个规则,该规则每次都会触发
2-将lambda分配为规则
SNS的任何错误
如果lambda发生任何生成的错误,则必须收到电子邮件解决错误。
需要3个AWS服务:
- SNS主题
- SNS订阅
- CloudWatch警报
创建SNS主题非常简单。
选择标准一个,命名,然后将其余作为默认值。
对于SNS订阅,这甚至更容易!
选择您要订阅的主题和协议并添加您的电子邮件!
对于CloudWatch警报,下面的屏幕截图说明了如何设置它们:
基础架构作为代码
受益于一致性,速度和减少人为错误。让我们使用Terraform部署我们的基础架构:
lambda函数:
ps: 您的python代码 main.py.py 将在与您的Terraform项目同一目录中的SRC目录下。
module "lambda_clean_eni" {
source = "terraform-aws-modules/lambda/aws"
function_name = format("clean_eni")
description = "Delete Unused Available ENIs in Subnets that contains EKS Clusters"
handler = "main.lambda_handler"
runtime = "python3.9"
publish = true
role_name = "Lambda-Clean-ENI"
memory_size = 200
timeout = 600
attach_cloudwatch_logs_policy = true
attach_policy_jsons = true
number_of_policy_jsons = 1
policy_jsons = [
data.aws_iam_policy_document.clean_eni.json,
]
source_path = "${path.module}/src"
hash_extra = filesha256("${path.module}/src/main.py")
allowed_triggers = {
EveryHourRule = {
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.clean_eni.arn
}
}
attach_network_policy = true
}
lambda iam角色策略:
data "aws_iam_policy_document" "clean_eni" {
statement {
sid = "1"
actions = [
"ec2:DeleteNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeTags",
]
effect = "Allow"
resources = ["*"]
}
}
eventbridge:
resource "aws_cloudwatch_event_rule" "clean_eni" {
name = "Clean-Eni-Lambda-Rule"
description = "Fires once everyday"
schedule_expression = "rate(1 day)"
}
resource "aws_cloudwatch_event_target" "clean_eni" {
rule = aws_cloudwatch_event_rule.clean_eni.name
arn = module.lambda_clean_eni.lambda_function_arn
}
CloudWatch警报:
module "alarm_lambda_clean_eni" {
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
create_metric_alarm = true
alarm_name = "Lambda-clean-eni-error"
alarm_description = "Lambda error rate is too high"
comparison_operator = "GreaterThanOrEqualToThreshold"
insufficient_data_actions = []
evaluation_periods = 1
threshold = 1
alarm_actions = [aws_sns_topic.alarm_error.arn]
metric_query = [{
id = "1"
return_data = true
label = "Error Count"
metric = [{
namespace = "AWS/Lambda"
metric_name = "Errors"
period = 60
stat = "Sum"
unit = "Count"
dimensions = {
FunctionName = module.lambda_clean_eni.lambda_function_name
}
}]
}]
}
sns主题和订阅:
resource "aws_sns_topic" "alarm-error" {
name = "alarm-error"
}
resource "aws_sns_topic_subscription" "alarm-error-sub" {
topic_arn = aws_sns_topic.alarm-error.arn
protocol = "email"
endpoint = "your@email.com"
}
摘要:使用此解决方案,我们能够成功减轻子网中的IP地址的问题。
旁注:您可以根据自己喜欢自定义过滤器,因此请随时探索如何使它们适合您的环境!