[PYTHON] Transférer l'état de disponibilité des instances potentiellement coûteuses dans Lambda vers Slack

Pourquoi tu veux faire ça

Pendant le développement, vous pouvez lancer des instances de haut niveau dans divers tests, mais en de rares occasions, vous pouvez oublier par inadvertance de les supprimer et de revenir. Eh bien, si vous le remarquez le lendemain, les dégâts seront minimes. Mais que faire si vous ne l'avez pas remarqué pendant un moment, comme avant les vacances? On ne peut pas dire qu’une somme décente d’argent sera accumulée et, dans certains cas, ce ne sera pas un gâchis d’écrire une disposition.

AWS dispose d'un mécanisme pour lancer des alertes en fonction du montant facturé, mais ce n'est pas une mesure préventive, il vous indique simplement que vous vous êtes déjà empilé au point où c'est dangereux. Si vous dépensez le budget d'un mois en 3 jours, que faites-vous plus tard?

En premier lieu, c'est une histoire à vérifier avant de revenir, mais c'est une histoire de savoir si vous pouvez la protéger à 100% en établissant des règles et en établissant des listes de contrôle. N'y a-t-il pas un cas où la région confirmée est différente? Une créature appelée programmeur écrit un programme pour laisser une machine faire quelque chose qu'elle ne veut pas faire, non? Ouais, faisons-le.

AWS est AWS

Je sais qu'awscli peut prendre l'état d'une instance. Alors, où faites-vous cela? Vous pouvez cron sur le serveur de votre entreprise, mais vous ne pouvez pas le faire de toute façon sur AWS, Lambda une ou deux fois par jour.

Awscli avec Lambda

Pour connaître le savoir-faire de awscli avec Lambda, consultez Exécuter l'AWS CLI sur Lambda et S3 Sync. Je vais y faire référence.

Supposons qu'il existe un environnement python3 pour le moment.

> mkdir check-aws
> cd check-aws
> pip install awscli -t .

Le fichier aws est juste ça

#!/usr/bin/env python3

import sys
import awscli.clidriver
def main():
    return awscli.clidriver.main()
if __name__ == '__main__':
    result = main()
    sys.exit(result)

x Essayez-le

> chmot +x aws
> ./aws
<Abréviation>

Ensuite, dans lambda_function.py, si vous trouvez une instance de travail plus grande que large avec ec2 et rds, écrivez un processus pour la lancer dans Slack.

# -*- coding: utf-8 -*-

import subprocess
import json
import urllib.request

region_name = {
    'ap-northeast-1': 'Tokyo',
    'ap-northeast-2': 'Âme',
    'ap-southeast-1': 'Singapour'
}

check_result = []

def check_ec2(region):
    cmd = []
    cmd.append("./aws")
    cmd.append("ec2")
    cmd.append("describe-instances")
    cmd.append("--filter")
    cmd.append("Name=instance-state-name,Values=running")
    cmd.append("--region")
    cmd.append(region)

    result = subprocess.run(cmd, stdout = subprocess.PIPE)
    resjson = json.loads(result.stdout.decode('utf-8'))

    for resv in resjson['Reservations']:
        for ins in resv['Instances']:
            typ = ins['InstanceType'].split('.')[1]
            #Pardonne petit
            if typ in ['nano', 'micro', 'small', 'medium']:
                continue
            insName = 'Anonyme'
            for tag in ins['Tags']:
                if tag['Key'] == 'Name':
                    insName = tag['Value']
            insTyp = ins['InstanceType']
            insLnc = ins['LaunchTime']
            check_result.append('ec2 ' + region_name[region] + ' ' + insName + '(' + insTyp + ') ' + insLnc)

def check_rds(region):
    cmd = []
    cmd.append("./aws")
    cmd.append("rds")
    cmd.append("describe-db-instances")
    cmd.append("--region")
    cmd.append(region)

    result = subprocess.run(cmd, stdout = subprocess.PIPE)
    resjson = json.loads(result.stdout.decode('utf-8'))

    for ins in resjson['DBInstances']:
        typ = ins['DBInstanceClass'].split('.')[2]
        if typ in ['nano', 'micro', 'small', 'medium']:
            continue
        if ins['DBInstanceStatus'] != 'available':
            continue
        insName = ins['DBInstanceIdentifier']
        insTyp = ins['DBInstanceClass']
        check_result.append('rds ' + region_name[region] + ' ' + insName + '(' + insTyp + ')')

def lambda_handler(event, context):
    check_ec2('ap-southeast-1') #Singapour
    check_ec2('ap-northeast-1') #Tokyo
    check_rds('ap-northeast-1') #Tokyo

    if len(check_result) > 0:
        message = '\État d'opération d'instance égal ou supérieur à nlarge<@hogehoge> \n'
        for str in check_result:
            message += str
            message += '\n'
        print(message)
        url = 'https://hooks.slack.com/services/xxxx/yyyy/zzzzzzzz'
        method = 'POST'
        headers = {'Content-Type' : 'application/json'}
        payload = {'text' : message}
        json_data = json.dumps(payload).encode('utf-8')
        request = urllib.request.Request(url, data=json_data, method=method, headers=headers)
        with urllib.request.urlopen(request) as res:
            body = res.read()

if __name__ == '__main__':
    lambda_handler('','')

C'est une bonne idée de mentionner plusieurs messages de notification Slack à quelqu'un qui connaît la situation et peut supprimer l'instance (ceux qui n'ignorent pas la notification sont également importants de manière inattendue). Si vous n'utilisez pas Slack, vous pouvez l'organiser en tant que SNS. Cette fois-ci, nous n'avons ciblé que EC2 et RDS après les gros, mais je pense que nous pouvons également gérer le nombre d'instances et d'autres services. Je ne sais pas.

Eh bien, vérifions si cela fonctionne également à portée de main. Si vous pouvez y aller, déployez.

>zip -r check-aws *

J'aimerais le télécharger sous forme de fichier zip et le tester, mais il y a quelques mises en garde. ・ Avoir un rôle PowerUserAccess ・ Définir un peu plus de délai ・ Mettez un peu plus de mémoire Il semble que 128 Mo de mémoire suffisent, mais je pense qu'il est préférable de le régler à environ 1024 Mo car le processeur est si pauvre. Ajustement requis.

Testez-le et espérons (si cela ne fonctionne pas, voyez le message d'erreur et faites quelque chose à ce sujet) et configurez le déclencheur et vous avez terminé. Ne devrions-nous pas simplement faire quelque chose comme cron (0 9? * MON-FRI *) dans l'expression de planification dans EventBridge?

Puis.

Recommended Posts

Transférer l'état de disponibilité des instances potentiellement coûteuses dans Lambda vers Slack
Mettre TensorFlow dans une instance P2 avec pip3
Surveillance simple du serveur avec AWS Lambda (Python) et notification des résultats avec Slack
Exemple de notification Slack avec python lambda
Arrêter une instance avec une balise spécifique dans Boto3