#python-3.x #amazon-web-services #amazon-cloudformation #boto3 #amazon-vpc
#python-3.x #amazon-веб-сервисы #aws-cloudformation #boto3 #amazon-vpc
Вопрос:
Я создал инфраструктуру aws с коллекцией EC2, Redshift, VPC и т.д. через CLOUDFORMATION. Теперь я хочу удалить его, в частности, в обратном порядке. Например. Все ресурсы зависят от VPC. VPC должен быть удален в конце. Но каким-то образом каждый стек удаляется, но стек VPC не удаляется через python BOTO3.Он показывает некоторую ошибку зависимости от подсети или сетевого интерфейса. Но когда я пытаюсь удалить через консоль, он успешно удаляет его. Кто-нибудь сталкивался с этой проблемой?
Я попытался удалить все, что связано с loadbalancer, которое к нему подключено. Но все равно VPC не удаляется.
Комментарии:
1. Консоль AWS выполняет работу по удалению зависимостей за вас. Не могли бы вы объяснить, что вы имеете в виду, говоря: «Я пытался удалить все, что связано с loadbalancer, который к нему подключен. Однако это не удаление» — loadbalancer не удаляет или VPC?
2. Я думаю, у вас, вероятно, есть какая-то виртуальная машина, сетевой адаптер которой находится в подсети внутри этого VPC. Попробуйте выяснить, какие сетевые карты находятся в этом VPC. Удаление Cloudformation обычно обеспечивает отслеживание зависимостей для вас, поэтому, вероятно, это что-то за пределами вашего стека cloudformation.
3. @gp42 я обновил queston. VPC не удаляет
4. Есть ли у вас лямбда-выражение, которое выполняется в VPC? Если да, то я могу предоставить вам лямбда-выражение, которое очистит все связанные сетевые интерфейсы. У меня была аналогичная проблема, и я создал этот лямбда-код, который запускается с использованием пользовательского ресурса
5. Да, @Biplob, у меня есть лямбда, который выполняется внутри VPC. Можете ли вы поделиться со мной этим сценарием? Может быть, я могу попробовать это.
Ответ №1:
AWS CloudFormation создает график зависимостей между ресурсами на основе DependsOn
ссылок в шаблоне и ссылок между ресурсами.
Затем он пытается развернуть ресурсы параллельно, но учитывает зависимости.
Например, подсеть может быть определена как:
Subnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.0.0/24
VpcId: !Ref ProdVPC
В этой ситуации существует явная ссылка на ProdVPC
, поэтому CloudFormation будет создана только Subnet1
после ProdVPC
того, как она была создана.
Когда стек CloudFormation удаляется, применяется обратная логика. В этом случае Subnet1
он будет удален до ProdVPC
того, как будет удален.
Однако CloudFormation не знает о ресурсах, созданных вне стека. Это означает, что если ресурс (например, экземпляр Amazon EC2) создается внутри Подсети, то удаление стека завершится неудачей, поскольку Подсеть не может быть удалена, пока ее использует экземпляр EC2 (или, точнее, к нему подключен ENI).
В таких ситуациях вам нужно будет вручную удалить ресурсы, которые вызывают «сбой удаления», а затем повторить попытку удалить команду.
Хороший способ найти такие ресурсы — заглянуть в раздел сетевых интерфейсов консоли управления EC2. Убедитесь, что к VPC не подключены никакие интерфейсы.
Комментарии:
1. 1 Иоанна. Итак, предположим, я удалил ресурсы, которые использовали VPC. Затем, каков будет правильный способ удаления VPC через python boto3 с такими зависимостями.
2. Вы должны иметь возможность снова попробовать удалить стек. Это должно удалить VPC. Однако, если стек был удален без удаления VPC, вы можете выполнить
delete_subnet()
delete_vpc()
команды and . AWS CloudFormation просто вызывает обычные API для создания / удаления ресурсов, поэтому вы можете сделать то же самое.3. Спасибо @John за ваш ответ. Проблема решена. Сначала я удалил все балансировщики нагрузки, а затем удалил правила и группы группы безопасности. Затем я устанавливаю time.sleep на 300 секунд для автоматического отключения сетевых интерфейсов. После этого он может успешно удалить VPC.
Ответ №2:
Поскольку вы указали, что у вас возникли проблемы с удалением VPC в стеках, содержащих лямбды, которые сами находятся в VPC, это, скорее всего, может быть связано с тем, что сетевые интерфейсы генерируются лямбдами для подключения к другим ресурсам в VPC.
Технически эти сетевые интерфейсы должны автоматически удаляться, когда лямбды не развертываются из стека, но, по моему опыту, я наблюдал потерянные ENI, которые не позволяют не развертывать VPC.
По этой причине я создал пользовательский лямбда-код с поддержкой ресурсов, который очищает ENI после того, как все лямбды в VPC были не развернуты.
Это часть формирования облака, в которой вы настраиваете пользовательский ресурс и передаете идентификатор VPC
##############################################
# #
# Custom resource deleting net interfaces #
# #
##############################################
NetInterfacesCleanupFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src
Handler: cleanup/network_interfaces.handler
Role: !GetAtt BasicLambdaRole.Arn
DeploymentPreference:
Type: AllAtOnce
Timeout: 900
PermissionForNewInterfacesCleanupLambda:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:invokeFunction
FunctionName:
Fn::GetAtt: [ NetInterfacesCleanupFunction, Arn ]
Principal: lambda.amazonaws.com
InvokeLambdaFunctionToCleanupNetInterfaces:
DependsOn: [PermissionForNewInterfacesCleanupLambda]
Type: Custom::CleanupNetInterfacesLambda
Properties:
ServiceToken: !GetAtt NetInterfacesCleanupFunction.Arn
StackName: !Ref AWS::StackName
VPCID:
Fn::ImportValue: !Sub '${MasterStack}-Articles-VPC-Ref'
Tags:
'owner': !Ref StackOwner
'task': !Ref Task
И это соответствующий лямбда. Это лямбда-выражение пытается 3 раза отсоединить и удалить потерянные сетевые интерфейсы, и если это не удается, если это невозможно, это означает, что все еще существует лямбда-выражение, которое генерирует новые сетевые интерфейсы, и для этого вам нужно выполнить отладку.
import boto3
from botocore.exceptions import ClientError
from time import sleep
# Fix this wherever your custom resource handler code is
from common import cfn_custom_resources as csr
import sys
MAX_RETRIES = 3
client = boto3.client('ec2')
def handler(event, context):
vpc_id = event['ResourceProperties']['VPCID']
if not csr.__is_valid_event(event, context):
csr.send(event, context, FAILED, validate_response_data(result))
return
elif event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
result = {'result': 'Don't trigger the rest of the code'}
csr.send(event, context, csr.SUCCESS, csr.validate_response_data(result))
return
try:
# Get all network intefaces for given vpc which are attached to a lambda function
interfaces = client.describe_network_interfaces(
Filters=[
{
'Name': 'description',
'Values': ['AWS Lambda VPC ENI*']
},
{
'Name': 'vpc-id',
'Values': [vpc_id]
},
],
)
failed_detach = list()
failed_delete = list()
# Detach the above found network interfaces
for interface in interfaces['NetworkInterfaces']:
detach_interface(failed_detach, interface)
# Try detach a second time and delete each simultaneously
for interface in interfaces['NetworkInterfaces']:
detach_and_delete_interface(failed_detach, failed_delete, interface)
if not failed_detach or not failed_delete:
result = {'result': 'Network interfaces detached and deleted successfully'}
csr.send(event, context, csr.SUCCESS, csr.validate_response_data(result))
else:
result = {'result': 'Network interfaces couldn't be deleted completely'}
csr.send(event, context, csr.FAILED, csr.validate_response_data(result))
# print(response)
except Exception:
print("Unexpected error:", sys.exc_info())
result = {'result': 'Some error with the process of detaching and deleting the network interfaces'}
csr.send(event, context, csr.FAILED, csr.validate_response_data(result))
def detach_interface(failed_detach, interface):
try:
if interface['Status'] == 'in-use':
detach_response = client.detach_network_interface(
AttachmentId=interface['Attachment']['AttachmentId'],
Force=True
)
# Sleep for 1 sec after every detachment
sleep(1)
print(f"Detach response for {interface['NetworkInterfaceId']}- {detach_response}")
if 'HTTPStatusCode' not in detach_response['ResponseMetadata'] or
detach_response['ResponseMetadata']['HTTPStatusCode'] != 200:
failed_detach.append(detach_response)
except ClientError as e:
print(f"Exception details - {sys.exc_info()}")
def detach_and_delete_interface(failed_detach, failed_delete, interface, retries=0):
detach_interface(failed_detach, interface)
sleep(retries 1)
try:
delete_response = client.delete_network_interface(
NetworkInterfaceId=interface['NetworkInterfaceId'])
print(f"Delete response for {interface['NetworkInterfaceId']}- {delete_response}")
if 'HTTPStatusCode' not in delete_response['ResponseMetadata'] or
delete_response['ResponseMetadata']['HTTPStatusCode'] != 200:
failed_delete.append(delete_response)
except ClientError as e:
print(f"Exception while deleting - {str(e)}")
print()
if retries <= MAX_RETRIES:
if e.response['Error']['Code'] == 'InvalidNetworkInterface.InUse' or
e.response['Error']['Code'] == 'InvalidParameterValue':
retries = retries 1
print(f"Retry {retries} : Interface in use, deletion failed, retrying to detach and delete")
detach_and_delete_interface(failed_detach, failed_delete, interface, retries)
else:
raise RuntimeError("Code not found in error")
else:
raise RuntimeError("Max Number of retries exhausted to remove the interface")
Ссылка на лямбда-выражение https://gist.github.com/revolutionisme/8ec785f8202f47da5517c295a28c7cb5
Дополнительные сведения о настройке лямбд в VPC — https://docs.aws.amazon.com/lambda/latest/dg/vpc.html
Комментарии:
1. Спасибо @Biplob за вашу передышку. Проблема решена. Сначала я удалил все балансировщики нагрузки, а затем удалил правила и группы группы безопасности. Затем я устанавливаю time.sleep на 300 секунд для автоматического отключения сетевых интерфейсов. После этого он может успешно удалить VPC.