Elastic Compute Service (ECS) publie des événements de changement d'état via Cloud Monitor chaque fois qu'une instance passe d'un état à un autre, que ce soit déclenché par des actions dans la console, des appels API, des opérations SDK, des politiques Auto Scaling, des impayés ou des exceptions système. En acheminant ces événements vers Simple Message Queue (anciennement MNS), vous pouvez mettre en place des réponses automatisées telles que l'enregistrement du cycle de vie des instances, le redémarrage des instances arrêtées ou la suppression des instances spot d'un équilibreur de charge avant leur libération.
Cette rubrique présente trois scénarios d'automatisation utilisant Python et une file d'attente MNS comme mécanisme de distribution des événements.
Fonctionnement
Cloud Monitor capture tous les événements de changement d'état des instances ECS et les transmet à une file d'attente Simple Message Queue (anciennement MNS). Un consommateur Python interroge la file d'attente, analyse chaque événement et le distribue aux écouteurs enregistrés en fonction du nom de l'événement (par exemple, Instance:StateChange ou Instance:PreemptibleInstanceInterruption). Chaque écouteur implémente une action d'automatisation spécifique.
Cloud Monitor prend en charge quatre méthodes pour traiter les alertes déclenchées par des événements :
|
Méthode |
Cas d'utilisation |
|
Simple Message Queue (anciennement MNS) |
Traitement asynchrone avec une logique de consommateur personnalisée (utilisée dans cette rubrique) |
|
Function Compute (FC) |
Gestion des événements sans serveur sans gestion de l'infrastructure |
|
Rappel URL |
Transfert des événements vers un endpoint HTTP externe |
|
Simple Log Service (SLS) |
Journalisation et analyse centralisées des événements |
Prérequis
Avant de commencer, assurez-vous d'avoir :
Une file d'attente (par exemple,
ecs-cms-event) créée dans la console Simple Message Queue (anciennement MNS)Une règle d'alerte déclenchée par un événement système configurée dans la console Cloud Monitor (ancienne version)
Python 3.7 ou une version ultérieure installé
Le SDK MNS pour Python et le SDK ECS pour Python installés
Les variables d'environnement
ALIBABA_CLOUD_ACCESS_KEY_IDetALIBABA_CLOUD_ACCESS_KEY_SECRETdéfinies
Pour plus de détails sur l'installation du SDK, consultez la section Installer le SDK Python. Pour les autres langages de programmation, reportez-vous à la référence du SDK MNS et à la vue d'ensemble du SDK ECS.
Étape 1 : Créer le fichier de configuration
Définissez l'endpoint MNS, les identifiants, la région et le nom de la file d'attente dans un fichier de configuration partagé. Les trois scénarios réutilisent cette configuration.
import os
class Conf:
endpoint = 'http://<id>.mns.<region>.aliyuncs.com/'
access_key = os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID']
access_key_secret = os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
region_id = 'cn-beijing'
queue_name = 'ecs-cms-event'
vserver_group_id = '<your-vserver-group-id>'
Remplacez les espaces réservés suivants par les valeurs réelles :
|
Espace réservé |
Description |
Exemple |
|
|
Votre ID de compte Alibaba Cloud |
|
|
|
La région de votre file d'attente MNS |
|
|
|
L'ID du groupe de serveurs virtuels dans Server Load Balancer (SLB), requis uniquement pour le scénario 3 |
|
Retrouvez l'endpoint MNS sur la page Queue Details sous la section Endpoint . Les endpoints Internet Access et Internal Access sont disponibles.
Ne codez jamais en dur les identifiants AccessKey dans le code source. L'exemple ci-dessus lit les identifiants à partir des variables d'environnement. Pour les charges de travail de production, utilisez des identifiants temporaires Security Token Service (STS).
Étape 2 : Construire le consommateur MNS
Créez un client MNS réutilisable qui interroge la file d'attente, distribue les événements aux écouteurs enregistrés et supprime les messages traités. Les trois scénarios partagent ce consommateur.
# -*- coding: utf-8 -*-
import json
import logging
from mns.mns_exception import MNSExceptionBase
from mns.account import Account
from . import Conf
class MNSClient(object):
def __init__(self):
self.account = Account(Conf.endpoint, Conf.access_key, Conf.access_key_secret)
self.queue_name = Conf.queue_name
self.listeners = dict()
def regist_listener(self, listener, eventname='Instance:StateChange'):
if eventname in self.listeners.keys():
self.listeners.get(eventname).append(listener)
else:
self.listeners[eventname] = [listener]
def run(self):
queue = self.account.get_queue(self.queue_name)
while True:
try:
message = queue.receive_message(wait_seconds=5)
event = json.loads(message.message_body)
if event['name'] in self.listeners:
for listener in self.listeners.get(event['name']):
listener.process(event)
queue.delete_message(receipt_handle=message.receipt_handle)
except MNSExceptionBase as e:
if e.type == 'QueueNotExist':
logging.error('Queue %s not exist, please create queue before receive message.', self.queue_name)
else:
logging.error('No Message, continue waiting')
class BasicListener(object):
def process(self, event):
pass
Le consommateur utilise l'interrogation longue (wait_seconds=5) pour récupérer les messages. Lorsqu'un message arrive, il analyse le corps JSON, recherche les écouteurs enregistrés par nom d'événement et appelle la méthode process de chaque écouteur. Après le traitement, il supprime le message de la file d'attente.
Structure de la charge utile de l'événement
Les événements de changement d'état utilisent la structure suivante :
|
Champ |
Description |
Exemple |
|
|
Identifiant du type d'événement |
|
|
|
État actuel de l'instance |
|
|
|
ID de l'instance ECS |
|
Scénario 1 : Journaliser les événements de création et de libération d'instances
Suivez le cycle de vie complet des instances ECS en journalisant les changements d'état Created et Deleted. Les instances libérées n'apparaissent plus dans la console ECS ; l'enregistrement de ces événements fournit une piste d'audit pour la planification de la capacité et l'analyse post-incident.
Créer l'écouteur
# -*- coding: utf-8 -*-
import logging
from .mns_client import BasicListener
class ListenerLog(BasicListener):
def process(self, event):
state = event['content']['state']
resource_id = event['content']['resourceId']
if state == 'Created':
logging.info(f'The instance {resource_id} state is {state}')
elif state == 'Deleted':
logging.info(f'The instance {resource_id} state is {state}')
Exécuter le consommateur
mns_client = MNSClient()
mns_client.regist_listener(ListenerLog())
mns_client.run()
Vérifier le résultat
Créez ou libérez une instance ECS dans la console.
Vérifiez les journaux du consommateur pour un message tel que
The instance i-bp1abc... state is Created.
En production, stockez les événements dans une base de données ou Simple Log Service (SLS) au lieu de les journaliser sur stdout. Cela permet de rechercher et d'auditer les données historiques du cycle de vie des instances.
Scénario 2 : Redémarrer automatiquement les instances arrêtées
Une instance ECS peut s'arrêter de manière inattendue en raison d'exceptions système ou d'impayés. Cet écouteur surveille les événements Stopped et appelle l'API ECS StartInstance pour redémarrer l'instance concernée.
Créer l'écouteur
Réutilisez le consommateur MNS de l'étape 2 et enregistrez un nouvel écouteur :
# -*- coding: utf-8 -*-
import logging
from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
from alibabacloud_ecs20140526.models import StartInstanceRequest
from alibabacloud_tea_openapi.models import Config
from .config import Conf
from .mns_client import BasicListener
class ECSClient(object):
def __init__(self, client):
self.client = client
def start_instance(self, instance_id):
logging.info(f'Start instance {instance_id} ...')
request = StartInstanceRequest(
instance_id=instance_id
)
self.client.start_instance(request)
class ListenerStart(BasicListener):
def __init__(self):
ecs_config = Config(
access_key_id=Conf.access_key,
access_key_secret=Conf.access_key_secret,
endpoint=f'ecs.{Conf.region_id}.aliyuncs.com'
)
client = Ecs20140526Client(ecs_config)
self.ecs_client = ECSClient(client)
def process(self, event):
detail = event['content']
instance_id = detail['resourceId']
if detail['state'] == 'Stopped':
self.ecs_client.start_instance(instance_id)
Exécuter le consommateur
mns_client = MNSClient()
mns_client.regist_listener(ListenerStart())
mns_client.run()
Vérifier le résultat
Arrêtez manuellement une instance ECS en cours d'exécution.
Vérifiez les journaux du consommateur pour
Start instance i-bp1abc... ....Confirmez que l'état de l'instance revient à
Runningdans la console ECS.
En production, surveillez les transitions d'état ultérieures (Starting,RunningouStopped) après l'émission de la commande de démarrage. Utilisez des minuteurs et des compteurs de nouvelles tentatives pour gérer les cas où le redémarrage échoue.
Scénario 3 : Supprimer une instance spot de SLB avant sa libération
Environ cinq minutes avant la récupération d'une instance spot, Cloud Monitor envoie un événement Instance:PreemptibleInstanceInterruption . Profitez de cette fenêtre pour supprimer proactivement l'instance du groupe de serveurs backend d'une instance Server Load Balancer (SLB), plutôt que d'attendre que SLB détecte passivement la libération.
Créer l'écouteur
Réutilisez le consommateur MNS de l'étape 2 et enregistrez un écouteur pour l'événement d'interruption d'instance spot :
# -*- coding: utf-8 -*-
from alibabacloud_slb20140515.client import Client as Slb20140515Client
from alibabacloud_slb20140515.models import RemoveVServerGroupBackendServersRequest
from alibabacloud_tea_openapi.models import Config
from .config import Conf
from .mns_client import BasicListener
class SLBClient(object):
def __init__(self):
self.client = self.create_client()
def create_client(self):
config = Config()
config.access_key_id = Conf.access_key
config.access_key_secret = Conf.access_key_secret
config.endpoint = 'slb.aliyuncs.com'
return Slb20140515Client(config)
def remove_vserver_group_backend_servers(self, vserver_group_id, instance_id):
request = RemoveVServerGroupBackendServersRequest(
region_id=Conf.region_id,
vserver_group_id=vserver_group_id,
backend_servers="[{'ServerId':'" + instance_id + "','Port':'80','Weight':'100'}]"
)
response = self.client.remove_vserver_group_backend_servers(request)
return response
class ListenerSLB(BasicListener):
def __init__(self, vserver_group_id):
self.slb_caller = SLBClient()
self.vserver_group_id = Conf.vserver_group_id
def process(self, event):
detail = event['content']
instance_id = detail['instanceId']
if detail['action'] == 'delete':
self.slb_caller.remove_vserver_group_backend_servers(self.vserver_group_id, instance_id)
Le nom de l'événement pour les interruptions d'instances spot diffère des événements de changement d'état. Enregistrez cet écouteur avec le nom d'événement Instance:PreemptibleInstanceInterruption :
mns_client = MNSClient()
mns_client.regist_listener(ListenerSLB(Conf.vserver_group_id), 'Instance:PreemptibleInstanceInterruption')
mns_client.run()
Structure de l'événement d'interruption d'instance spot
Les événements d'interruption d'instance spot utilisent des noms de champs différents de ceux des événements de changement d'état :
|
Champ |
Description |
Exemple |
|
|
Identifiant du type d'événement |
|
|
|
ID de l'instance ECS |
|
|
|
Action d'interruption |
|
Vérifier le résultat
Attendez un événement d'interruption d'instance spot (ou simulez-en un dans un environnement de test).
Confirmez que l'instance est supprimée du groupe de serveurs virtuels SLB avant la libération.
En production, demandez une instance spot de remplacement et attachez-la immédiatement à l'instance SLB pour maintenir la disponibilité du service.
Exécuter tous les écouteurs ensemble
Enregistrez les trois écouteurs sur un seul consommateur MNS pour gérer plusieurs types d'événements simultanément :
mns_client = MNSClient()
# Scenario 1: Log lifecycle events
mns_client.regist_listener(ListenerLog())
# Scenario 2: Auto-restart stopped instances
mns_client.regist_listener(ListenerStart())
# Scenario 3: Remove spot instances from SLB before release
mns_client.regist_listener(ListenerSLB(Conf.vserver_group_id), 'Instance:PreemptibleInstanceInterruption')
mns_client.run()
Référence des types d'événements
|
Nom de l'événement |
Déclencheur |
Champs clés |
|
|
Transitions d'état de l'instance (Created, Starting, Running, Stopped, Deleted) |
|
|
|
Instance spot programmée pour la libération (~5 min avant la récupération) |
|