Sohaib walks you through attaching
a second ENI to your instance automatically

secondENI_thumbnail

Je souhaite attacher automatiquement une deuxième ENI quand la fonctionnalité Auto Scaling active une nouvelle instance lors d'un ajustement à la hausse ou de remplacements des vérifications de l'état.

Auto Scaling ne prend pas directement en charge ce scénario, mais le recours à une combinaison de hooks de cycle de vie Auto Scaling, d'événements Amazon CloudWatch et de fonctions AWS Lambda remplit une fonction similaire. Réalisez la configuration suivante :

  • Créez un hook de cycle de vie qui envoie l'événement « EC2 Instance-launch Lifecycle Action » quand Auto Scaling lance une nouvelle instance.
  • Configurez cet événement pour qu'il déclenche une fonction Lambda.
  • Configurez la fonction Lambda de sorte à attacher automatiquement la deuxième ENI à l'instance lorsque cette dernière présente l'état wait.

Dans la console AWS Lambda, créez une fonction Lambda qui ajoute automatiquement une deuxième ENI à une instance quand Auto Scaling lance cette dernière :

1.    Sélectionnez Create a Lambda function. Lorsque vous êtes invité à sélectionner un plan, cliquez sur Skip.

2.    Indiquez Attach_Second_ENI_ASG dans le champ Name et ajoutez ce qui suit dans la champ Lambda function code :

import boto3

import botocore

from datetime import datetime

 

ec2_client = boto3.client('ec2')

asg_client = boto3.client('autoscaling')

 

def lambda_handler(event, context):

 

    if event["detail-type"] == "EC2 Instance-launch Lifecycle Action":

        instance_id = event["detail"]["EC2InstanceId"]

        subnet_id = get_subnet_id(instance_id)

        interface_id = create_interface(subnet_id)

        attachment = attach_interface(interface_id, instance_id)

 

        if interface_id and attachment == None:

        log("Removing network interface {} after attachment failed.".format(interface_id))

        delete_interface(interface_id)

   

        try:

            asg_client.complete_lifecycle_action(

                LifecycleHookName = event['detail']['LifecycleHookName'],

                AutoScalingGroupName = event['detail']['AutoScalingGroupName'],

                LifecycleActionToken = event['detail']['LifecycleActionToken'],

                LifecycleActionResult = 'CONTINUE'

                )

                if attachment:

                    log('{"Error": "0"}')

                else:

                    log('{"Error": "1"}')

        except botocore.exceptions.ClientError as e:

            log("Error completing life cycle hook for instance {}: {}".format(instance_id, e.response['Error']['Code']))

            log('{"Error": "1"}')

   

   

def get_subnet_id(instance_id):

    try:

        result = ec2_client.describe_instances(InstanceIds=[instance_id])

        vpc_subnet_id = result['Reservations'][0]['Instances'][0]['SubnetId']

        log("Subnet id: {}".format(vpc_subnet_id))

   

    except botocore.exceptions.ClientError as e:

        log("Error describing the instance {}: {}".format(instance_id, e.response['Error']['Code']))

        vpc_subnet_id = None

   

    return vpc_subnet_id

def create_interface(subnet_id):

    network_interface_id = None

   

    if subnet_id:

            try:

                network_interface = ec2_client.create_network_interface(SubnetId=subnet_id)

                network_interface_id = network_interface['NetworkInterface']['NetworkInterfaceId']

                log("Created network interface: {}".format(network_interface_id))

            except botocore.exceptions.ClientError as e:

                log("Error creating network interface: {}".format(e.response['Error']['Code']))

   

    return network_interface_id

   

def attach_interface(network_interface_id, instance_id):

    attachment = None

   

    if network_interface_id and instance_id:

        try:

            attach_interface = ec2_client.attach_network_interface(

                NetworkInterfaceId=network_interface_id,

                InstanceId=instance_id,

                DeviceIndex=1

            )

            attachment = attach_interface['AttachmentId']

            log("Created network attachment: {}".format(attachment))

        except botocore.exceptions.ClientError as e:

            log("Error attaching network interface: {}".format(e.response['Error']['Code']))

   

    return attachment

   

def delete_interface(network_interface_id):

    try:

        ec2_client.delete_network_interface(

            NetworkInterfaceId=network_interface_id

        )

    except botocore.exceptions.ClientError as e:

        log("Error deleting interface {}: {}".format(network_interface_id, e.response['Error']['Code']))

   

def log(message):

    print (datetime.utcnow().isoformat() + 'Z ' + message)

3.    Pour Role, choisissez un tôle IAM qui permet à Lambda de décrire, de créer et d'attacher une interface à une instance, ou sélectionnez Basic execution role.

Si vous sélectionnez Basic execution role, une fenêtre de console IAM dans laquelle vous êtes invité à définir une stratégie pour lambda_basic_execution, s'affiche. Développez le menu déroulant Policy Document et ajoutez la stratégie suivante :

{

    "Statement": [

        {

            "Action": [

                "logs:CreateLogGroup",

                "logs:CreateLogStream",

                "logs:PutLogEvents"

            ],

            "Effect":"Allow",

            "Resource": "arn:aws:logs:*:*:*"

        },

        {

            "Action": [

                "ec2:CreateNetworkInterface",

                "ec2:DescribeNetworkInterfaces",

                "ec2:DetachNetworkInterface",

                "ec2:DeleteNetworkInterface",

                "ec2:AttachNetworkInterface",

                "ec2:DescribeInstances",

                "autoscaling:CompleteLifecycleAction"

            ],

            "Effect":"Allow",

            "Resource": "*"

        }

    ],

    "Version":"2012-10-17"

}}

4.    Sélectionnez Allow. Le fenêtre de la console IAM se ferme et le rôle lambda_basic_execution est sélectionné dans le menu déroulant Role.

5.    Sélectionnez Next.

6.    Sélectionnez Create function.

Créez un hook de cycle de vie pour déclencher l'événement avec la commande CLI suivante :

aws autoscaling put-lifecycle-hook \

    --lifecycle-hook-name my-lifecycle-launch-hook \

    --auto-scaling-group-name my-asg \

    --lifecycle-transition autoscaling:EC2_INSTANCE_LAUNCHING \

    --heartbeat-timeout 300 \

    --default-result CONTINUE

Ouvrez la console CloudWatch et créez une règle CloudWatch Events pour déclencher la fonction Lambda en suivant les étapes ci-dessous :

1.    Dans le volet de navigation, sélectionnez Events.

2.    Sélectionnez Create rule.

3.    Dans le menu déroulant Select event source, sélectionnez Auto Scaling.

4.    Sélectionnez Specific instance event(s), puis EC2 Instance-launch Lifecycle Action.

5.    Sélectionnez Specific group name(s), puis le ou les groupes Auto Scaling auxquels vous souhaitez attacher automatiquement une deuxième ENI au lancement.

6.    A droite de l'écran, sélectionnez Add target. La fonction Lambda est automatiquement choisie dans la liste de cibles prédéfinies.

7.    Sélectionnez Configure details.

Si elle est configurée correctement, quand Auto Scaling lance une nouvelle instance, la deuxième ENI que vous avez spécifiée est attachée à la nouvelle instance.

Remarque : si vous n'utilisez pas l'AMI Amazon Linux dans la configuration de lancement, vous devrez peut-être effectuer une configuration supplémentaire au niveau du système d'exploitation pour afficher l'autre interface.

Vous devez également écrire un extrait de code qui supprime la deuxième ENI quand Auto Scaling résilie l'instance pour éviter d'épuiser les adresses IP privées du sous-réseau et pour éviter d'atteindre la limite d'ENI de votre compte. Une approche similaire permet d'utiliser un hook de cycle de vie de résiliation et de déclencher une fonction Lambda via CloudWatch Events ou Amazon Simple Notification Service (Amazon SNS) pour détacher et supprimer l'interface avec DeviceIndex > 0. Vous pouvez aussi écrire un script boto qui supprime périodiquement toutes les interfaces inutilisées de votre compte.

Vous avez également la possibilité d'utiliser SNS au lieu de CloudWatch Events pour invoquer la fonction lambda en configurant --notification-target-arn lors de la création du hook. Cette approche convient particulièrement si vous aspirez à une prise en charge entre comptes ou entre régions, ce que CloudWatch n'offre pas.

Pour plus d'informations, consultez la section Utilisation d'AWS Lambda avec Amazon SNS à partir de différents comptes.

Elastic Network Interface (ENI), Auto Scaling, CloudWatch, Lambda


Cette page vous a-t-elle été utile ? Oui | Non

Retour au Centre de connaissances AWS Support

Vous avez besoin d'aide ? Consultez le site du Centre AWS Support

Date de publication : 29/04/2016