部署 Lambda 函数以定期删除 EC2 实例

我是寺冈,一名基础设施工程师。
这次,我想总结一下我部署用于内部使用的 Lambda 函数的经验。

除了我们运营管理的客户服务器运行所在的 AWS 账户外,
我们还管理着内部工程师用于技术验证的账户。

此账户已定义登录安全设置规则(IAM 用户角色/MFA 身份验证),但
对于拥有必要权限的成员,账户内的操作通常不受限制。
规则过多会使其难以使用,尤其是在测试方面。

在我们的案例中,验证过程中创建频率最高的资源是 EC2 实例。
虽然可以随意创建,但也意味着忘记停止或删除这些实例的情况相当普遍。

当然,频繁发生此类事件会导致不必要的成本。
虽然原则上实例在使用后应该立即停止或删除,但
为了防止遗忘,我们还是实施了一种机制,利用 Lambda 函数定期自动删除 EC2 实例。

以下是我所做工作的总结。

创建 Lambda 函数

我用Python写的。
但我个人更熟悉Golang,所以我觉得我应该用Golang来写。

import json import boto3 import os import requests def terminate(event, context): EXCLUDE_TERMINATE_TAG = os.environ['EXCLUDE_TERMINATE_TAG'] CHATWORK_API_KEY = os.environ['CHATWORK_API_KEY'] CHATWORK_ROOM_ID = os.environ['CHATWORK_ROOM_ID'] CHATWORK_ENDPOINT = os.environ['CHATWORK_ENDPOINT'] ec2 = boto3.client('ec2') without_tag = ec2.describe_instances() with_tag = ec2.describe_instances( Filters=[{ 'Name': 'tag:' + EXCLUDE_TERMINATE_TAG, 'Values': ['true'] }] ) without_tag_set = set(ec2['InstanceId'] for resId in without_tag['Reservations'] for ec2 in resId['Instances']) with_tag_set = set(ec2['InstanceId'] for resId in with_tag['Reservations'] for ec2 in resId['Instances']) target_instances = without_tag_set - with_tag_set list_target_instances = list(target_instances) if len(list_target_instances) != 0: terminateInstances = ec2.terminate_instances( InstanceIds=list_target_instances ) notify_instances = '' if len(with_tag['Reservations']) != 0: for reservation in with_tag['Reservations']: for instance in reservation['Instances']: if len(instance['Tags']) != 0: instance_name = '' for在 instance['Tags'] 中:如果 tag['Key'] == 'Name':instance_name = tag['Value'] instance_state_enc = json.dumps(instance['State']) instance_state_dec = json.loads(instance_state_enc) 如果 instance_name != '':notify_instances += instance['InstanceId'] + ' -> ' + instance_name + '(' + instance_state_dec['Name'] + ')' + '\n' 否则:notify_instances += instance['InstanceId'] + ' -> ' + 'None' + '(' + instance_state_dec['Name'] + ')' + '\n' message = '[To:350118][To:1786285][info][title][Beyond POC] There are returned instances (devil)[/title]' + notify_instances + '[/info]' PostChatwork(CHATWORK_ENDPOINT,CHATWORK_API_KEY,CHATWORK_ROOM_ID,message) response = { "TerminateInstances": list_target_instances } print (response) return response def PostChatwork(ENDPOINT,API_KEY,ROOM_ID,MESSAGE): post_message_url = '{}/rooms/{}/messages'.format(ENDPOINT, ROOM_ID) headers = { 'X-ChatWorkToken': API_KEY } params = { 'body': MESSAGE } resp = requests.post(post_message_url, headers=headers, params=params)

我想你看了代码就能明白了。

  • 删除没有排除标签的实例
  • 通知 Chatwork 哪些实例已被排除在删除范围之外

这个过程由系统自动执行。
但是,由于未经询问就删除文件可能会造成问题,因此
在这种情况下,您应该添加排除标签“EXCLUDE_TERMINATE: true”
公司内部有一条规定,

Serverless Framework 配置

本次演讲将讲解如何将您编写的代码部署到 Lambda。

我们正在使用一个名为 Serverless Framework 的工具。https
://serverless.com

到 Lambda 等无服务器服务
一个 CLI 工具,它根据指定的配置文件将函数部署
;对于 Lambda,它与 CloudFormation 协同工作以执行部署。

准备一个名为 serverless.yml 的配置文件。

# 欢迎使用 Serverless!# # 此文件是您服务的主要配置文件。# 目前它非常简洁,使用默认值。# 您可以随时添加更多配置选项以获得更精细的控制。# 我们在此处提供了一些注释掉的配置示例。# 只需取消注释即可启用相应的配置选项。# # 有关完整的配置选项,请查看文档:# docs.serverless.com # # 祝您编码愉快!服务:beyond-poc 插件:- serverless-prune-plugin 提供程序:名称:aws 运行时:python3.8 配置文件:${opt:profile, ''} 区域:ap-northeast-1 角色:[IAM 角色名称] 环境变量:EXCLUDE_TERMINATE_TAG:EXCLUDE_TERMINATE CHATWORK_API_KEY:[ChatWark API 密钥] CHATWORK_ROOM_ID:[ChatWark 房间 ID] CHATWORK_ENDPOINT:https://api.chatwork.com/v2 超时:10 # 我的自定义环境变量 custom: prune: automatic: true number: 5 # 您可以在此处覆盖默认值 # stage: dev # region: us-east-1 # 您可以在此处添加打包信息 #package: # include: # - include-me.py # - include-me-dir/** # exclude: # - exclude-me.py # - exclude-me-dir/** functions: terminate-instance: handler: handler.terminate events: - schedule: cron(0 15 ? * * *) timeout: 120 memorySize: 128 reservedConcurrency: 1

在“环境”部分,我已将排除标签和 ChatWork 身份验证信息设置为环境变量。
在“函数”部分,我已实际设置了函数。
在“事件”部分,我设置了一个计划任务,该
任务将与 CloudWatch Events 同步,每天 15:00 (UTC) 定期运行。
在日本标准时间 (JST),这相当于午夜 (0:00)。

将要部署的代码保存到此配置文件所在的目录中。

$ sis deploy --profile [AWS Profile Name]

由 Serverless Framework 自动创建的
CloudFormation 堆栈

最后

我厚颜无耻地把它当成博客素材,但
实际上,我是公司里最经常忘记删除东西的人。真抱歉……

如果您觉得这篇文章对您有帮助,请点个“赞”!
1
加载中...
1票,平均分:1.00/11
2,831
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

寺冈由纪

我于 2016 年加入 Beyond,目前
担任基础设施工程师和 MSP(托管服务提供商)已有六年。我负责处理突发事件的故障排除,
并使用 AWS 等公有云设计和构建基础设施。最近,我一直在
Docker 和 Kubernetes 等容器基础设施。此外,
使用 HashiCorp 的 Terraform 和 Packer 等工具来构建和自动化
我还担任技术推广者的角色,在外部学习小组和研讨会上进行演讲。

・GitHub
https://github.com/nezumisannn

• 演讲邀约
:https://github.com/nezumisannn/my-profile

• 演示材料(SpeakerDeck)
https://speakerdeck.com/nezumisannn

・认证:
AWS认证解决方案架构师 - 助理级、
Google Cloud专业云架构师