CloudWatch est un moyen pratique de collecter des journaux pour votre système AWS. Au travail, j'installe CloudWatch Agent sur mon instance EC2 pour diffuser les journaux d'accès et les journaux d'erreurs de diverses applications (Nginx, Tomcat, etc.) vers CloudWatch Logs.
Cependant, le stockage des journaux dans CloudWatch Logs est assez coûteux, je voudrais donc déplacer régulièrement les anciens journaux vers S3. Dans cet article, je vais donc résumer comment déplacer régulièrement les journaux CloudWatch vers S3 à l'aide de Lambda.
Tout d'abord, accordez à Lambda les autorisations appropriées pour déployer le code qui effectue le déplacement. Définissez le rôle IAM avec les autorisations suivantes dans Lambda.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "cloudwatch:*",
"Resource": "*"
},
{
"Action": [
"s3:Get*",
"s3:Put*",
"s3:List*",
],
"Resource": [
"*"
],
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:CreateExportTask",
"logs:DescribeLogGroups",
"logs:Get*"
],
"Resource": "*"
}
]
}
Donnez à S3 les autorisations de lecture et d'écriture, lisez les journaux CloudWatch et créez des tâches.
Quand j'écris le code en Python, cela ressemble à ceci: Autre que la bibliothèque standard, boto3 est utilisé, donc lors du déploiement, téléchargez-le dans un fichier zip avec le code suivant.
import boto3
import datetime
import time
#Requête lors de la recherche de groupes de journaux
PREFIX = 'test-'
#Seau S3 pour stocker les journaux
S3_BUCKET = 'test_bucket'
#Répertoire de s3 pour stocker les journaux
S3_DIR = 'logs'
def main(event,context):
'''
Fonction appelée en main
'''
#client boto3
client = boto3.client('logs')
#Obtenir une liste des groupes de journaux
log_groups = get_log_group_list(client)
#Stocker le contenu du journal dans s3
move_logs(client,log_groups)
def get_log_group_list(client):
'''
Obtenir une liste d'informations sur les groupes de journaux
'''
should_continue = True
next_token = None
log_groups=[]
#Il peut ne pas être possible de tout supprimer en même temps, alors acquérez-le à plusieurs reprises.
while should_continue:
if next_token == None:
#Pour la première demande
response = client.describe_log_groups(
logGroupNamePrefix=PREFIX,
limit=50
)
else:
#Pour la deuxième demande et les suivantes
response = client.describe_log_groups(
logGroupNamePrefix=PREFIX,
limit=50,
nextToken=next_token
)
#Ajouter le résultat obtenu à la liste
for log in response['logGroups']:
log_groups.append(log)
#Déterminez également si une demande doit être faite
if 'nextToken' in response.keys():
next_token = response['nextToken']
else:
should_continue = False
return log_groups
def create_export_task(client,log_groups):
'''
Déplacer le contenu du journal vers s3
'''
#Obtenir l'heure actuelle et convertir en heure UNIX
time_now = datetime.datetime.now()
unix_time_now = int(time_now.timestamp())
#Répétez pour le nombre de groupes de journaux
for log in log_groups:
for x in range(20):
try:
response = client.create_export_task(
fromTime=0,
to=unix_time_now,
logGroupName=log['logGroupName'],
destination=S3_BUCKET,
destinationPrefix=S3_DIR
)
except:
#Si vous avez déjà une tâche, attendez un moment et réessayez
time.sleep(20)
continue
Dans la variable PREFIX définie en haut, spécifiez la première chaîne de caractères du groupe de journaux vers lequel vous souhaitez migrer les journaux. Ici, le journal du groupe de journaux commençant par "test-" est défini pour être déplacé vers S3.
La fonction main () est appelée au moment de l'exécution. Cette fonction appelle les deux fonctions suivantes dans l'ordre.
Enfin, définissez le compartiment de S3 vers lequel vous souhaitez exporter le journal. Définissez le json suivant comme stratégie.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logs.ap-northeast-1.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"Service": "logs.ap-northeast-1.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "*"
}
]
}
Si vous oubliez de le spécifier, vous obtiendrez l'erreur ** "Une erreur s'est produite (InvalidParameterException) lors de l'appel de l'opération CreateExportTask: l'appel GetBucketAcl sur le bucket donné a échoué. Veuillez vérifier si CloudWatch Logs a reçu l'autorisation d'effectuer cette opération." ** , Se produit lors de l'exécution de fonctions Lambda. J'étais confus car le message d'erreur était trompeur, comme s'il s'agissait d'un problème avec les paramètres CloudWatch Logs.
Si vous utilisez le cron de CloudWatch pour définir la fonction Lambda créée à exécuter régulièrement, par exemple, vous pouvez déplacer les journaux CloudWatch vers S3 chaque jour.
Cependant, il y a une mise en garde. La tâche d'exportation de journaux prend du temps, ce qui signifie que si vous essayez d'exporter plus de 10 groupes de journaux à la fois, cela prendra plus de 15 minutes, ce qui correspond au temps d'exécution maximal de Lambda. C'est gênant.
Si vous souhaitez déplacer un grand nombre de journaux vers s3 à la fois, il peut être préférable de l'exécuter en tant que tâche cron dans EC2 au lieu d'utiliser Lambda.
Recommended Posts