Понекад .NET апликације падају у производњу, а нико не зна зашто, јер су дневници и метрике у реду.То је прилично досадно и чини дебаггирање веома непријатно.У таквим случајевима, пропуснице меморије могу поједноставити дебаггирање и смањити време решавања проблема од дана до минута. Овај чланак објашњава како да конфигуришете депоне за .NET апликације које су распоређене на а затим их пренесите тиму за развој на најпогоднији и најсигурнији начин. AWS ECS Fargate U ovom članku ćemo kreirati AWS resurse, a ja ću se odnositi na AWS dokumentaciju u određenim situacijama. IAC neće biti u našem fokusu. Međutim, ako uživate u programu Terraform koliko i ja, možete koristiti AWS module otvorenog koda za svaki odeljak članka. https://github.com/cloudposse https://github.com/terraform-aws-modules U ovom članku ćemo kreirati AWS resurse, a ja ću se odnositi na AWS dokumentaciju u određenim situacijama. IAC neće biti u našem fokusu. Međutim, ako uživate u programu Terraform koliko i ja, možete koristiti AWS module otvorenog koda za svaki odeljak članka. https://github.com/cloudposse https://github.com/terraform-aws-modules https://github.com/cloudposse https://github.com/terraform-aws-modules Архитектура решења Време је да погледамо нашу архитектуру. Почнићу претпостављајући да развојни тим не размишља о повлачењу .НЕТ-а из складишта као што су ЕБС или ЕФС због своје сложености. С3 је много једноставнији за програмере да добију било који тип датотеке, и савршено одговара нашим очекивањима. Осим тога, примање проактивних обавештења када се генерише нови .NET демп би било прилично вредно. На пример, користићу Слацк, али друге опције укључују Тимес, Маттермост, ВхатсАпп, и тако даље. И последња, али не и најмање важна напомена. прилично је компликовано прикључити С3 букет нативно на ЕЦС. Из тог разлога ћемо креирати средњи слој који је изграђен на EFS, DataSync и sidecar ECS контејнер / Lambda функцију. EFS ће се користити као интермедијарно складиште за све наше ЕЦС задатке, Datasync ће аутоматски преносити податке из ЕФС у С3, а бочни контејнер или Ламбда ће очистити старе податке из ЕФС-а. Хајде да брзо прегледамо дијаграм: AWS Lambda deletes old EFS files by the schedule configured in EventBridge. Alternatively, during ECS Task bootstrap phase, sidecar container removes outdated dumps from EFS and quits. janitor During .NET application crash, a new dump is created at EFS filesystem, and only after that the process is terminated. DataSync moves data to S3 after a new file is uploaded to EFS. When an S3 hook detects a newly uploaded file, AWS Lambda is triggered. AWS Lambda uses IAM to obtain the necessary secrets from AWS Secret Manager. AWS Lambda sends a message to Slack via API. Korak po korak implementacija Kreirajte ECS Fargate zadatak У овом одељку морамо да креирамо задатак ECS Fargate користећи примјерну .NET апликацију. Предуслови Пре него што наставимо, постоји неколико корака који морају бити завршени: Setup ECS cluster via AWS Console, or Terraform. An official AWS guide: Creating an Amazon ECS cluster for Fargate workloads Create an IAM execution role for ECS task. To do it, you can follow . In the scope of this article I will use name for IAM execution role. this AWS guide kvendingoldo-dotnet-crash-dump-demo Креирање Амазон ЕЦС кластера за Fargate радне оптерећења Ovaj AWS vodič Овај минимални За извршну улогу ће бити довољно: Trust policy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } Такође, минимална : permissions policy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] } Kreirajte definiciju zadatka Када су сви предуслови спремни, време је да креирате минимални задатак Fargate са примером .NET апликације. , и користите ову дефиницију задатака json датотеке: Званични AWS водич Званични AWS водич { "containerDefinitions": [ { "cpu": 0, "essential": true, "image": "mcr.microsoft.com/dotnet/samples:aspnetapp", "mountPoints": [], "name": "app", "portMappings": [ { "containerPort": 8000, "hostPort": 8000, "protocol": "tcp" } ], "systemControls": [], "volumesFrom": [] } ], "cpu": "256", "executionRoleArn": "kvendingoldo-dotnet-crash-dump-demo", "family": "kvendingoldo-dotnet-crash-dump-demo", "memory": "512", "networkMode": "awsvpc", "placementConstraints": [], "requiresCompatibilities": ["FARGATE"], "volumes": [], "tags": [] } Конфигуришите .NET dumps Подразумевано, .NET апликације не генеришу никакве бубњеве. Да бисмо је конфигурисали, морамо поставити следеће променљиве окружења: # Forces the runtime to generate a stack dump on unhandled exceptions. COMPlus_StackDumpOnUnhandledException=1 # Enable mini dump generation on crash COMPlus_DbgEnableMiniDump=1 # Choose dump type: # 1 = Mini, # 2 = Full (use carefully) # 4 = Triage (includes stack, threads, and some heap info — a good balance for debugging). COMPlus_DbgMiniDumpType=2 # Target path for dump file (EFS is mounted here) COMPlus_DbgMiniDumpName=/dumps/dump-%e-%p-%t.dmp Ове променљиве се могу додати директно у Доцкерфиле или дефинисати као променљиве окружења у ЕЦС дефиницији задатака. У нашем примеру, убацимо их у спецификацију задатака ЕЦС. Да бисмо то урадили, додаћемо их у Као што је испод приказано: containerDefinitions[0].environment "environment": [ { "name": "COMPlus_StackDumpOnUnhandledException", "value": "1" }, { "name": "COMPlus_DbgMiniDumpType", "value": "4" }, { "name": "COMPlus_DbgEnableMiniDump", "value": "1" }, { "name": "COMPlus_DbgMiniDumpName", "value": "/dumps/%t-kvendingoldo-dotnet-demo-crash.dmp" } ] Као што видите, користим неколико држача места у COMPlus_DbgMiniDumpName. Dotnet аутоматски проширује следеће држаче места у име датотеке за отпад: %e - извршно име %p - ID процеса %t - timestamp Погледајте ове две везе за додатне информације о прикупљању и анализирању .NET колапса: Прикупљање .NET Crash Dumps (Microsoft Learn) Debugging .NET Core memory issues (on Linux) with dotnet dump Као што видите, користим неколико држача места у COMPlus_DbgMiniDumpName. Dotnet аутоматски проширује следеће држаче места у име датотеке за отпад: %e - извршно име %p - ID процеса %t - временска ознака Погледајте ове две везе за додатне информације о прикупљању и анализирању .NET колапса: Прикупљање .NET Crash Dumps (Microsoft Learn) Debugging .NET Core memory issues (on Linux) with dotnet dump Прикупљање .NET Crash Dumps (Microsoft Learn) Debugging .NET Core memory issues (on Linux) with dotnet dump Креирајте ЕФС складиште и монтирајте га на задатак ECS Fargate Као што сам поменуо на почетку овог чланка, причвршћивање С3 букета на ЕЦС посао је прилично тешко; уместо тога, користићемо као средње складиште за .NET демп датотеке, које се лако могу монтирати на скуп ЕЦС задатака. Amazon EFS (Elastic File System) Да бисте креирали ЕФС складиште, пратите званични АВС водич: Амазон ЕЦС туториал: Коришћење Амазон ЕФС фајл система Да бисте креирали ЕФС складиште, пратите званични АВС водич: Амазон ЕЦС туториал: Коришћење Амазон ЕФС фајл система Амазон ЕЦС туториал: Коришћење Амазон ЕФС фајл система Нема ништа посебно да додате у званичну документацију. само будите сигурни да: ЕФС и ЕЦС кластер су у истом ВПЦ EFS se može pristupiti pomoću ECS zadataka preko NFS (port 2049/tcp). Omogućite ulazni pristup NFS portovima u EFS bezbednosnoj grupi da biste to učinili. Да бисмо монтирали ЕФС датотечни систем у задатак ЕЦС морамо да дамо потребне дозволе за ИАМ улога (пазите на држаоце места): kvendingoldo-dotnet-crash-dump-demo { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowEFSAccess", "Effect": "Allow", "Action": [ "elasticfilesystem:ClientMount", "elasticfilesystem:ClientWrite", "elasticfilesystem:ClientRootAccess" ], "Resource": "arn:aws:elasticfilesystem:<region>:<account-id>:file-system/<filesystem-id>" } ] } Као завршни корак, дефинишите ЕФС томове и тачке за монтирање у дефиницији задатака ЕЦС-а (change fileSystemId) са вашим стварним идентитетом система датотека након покретања): fs-xxxxxx "volumes": [ { "name": "dotnet-dumps", "efsVolumeConfiguration": { "fileSystemId": "fs-xxxxxx", "rootDirectory": "/" } } ] "mountPoints": [ { "containerPath": "/dumps", "readOnly": false, "sourceVolume": "dotnet-dumps" } ] Конфигуришите AWS DataSync да бисте пренели EFS датотеке на S3 ДатаСинц сервис је стандардни АВС алат за пренос података између различитих типова складишта. У нашем случају, то ће нам помоћи да поместе.НЕТ из ЕФС-а у С3. Da bismo postigli svoj cilj, moramo: Create an S3 bucket to store our.NET dumps. Further in this article I’ll use S3 bucket name kvendingoldo-dotnet-demo-crash Use to create a bucket. this official doc Create DataSync Use to create DataSync. this official doc Some service parameters I'll be using: Source: EFS Destination: S3 bucket (e.g., ) s3://kvendingoldo-dotnet-demo-crash/ Include path filters like /dumps/* Schedule sync every minute Овај званични доц Овај званични доц Create slack alerts based on AWS Lambda Као што је раније речено, упозорења о new.NET отпаду су изузетно корисна за развојни тим. Са архитектурне тачке гледишта, упозорења се могу изградити на различите начине: Једноставна ламбда функција која шаље поруке Слацку преко АПИ-ја и изазива догађаје С3. Поруке се објављују на тему СНС-а користећи конфигурисане обавештења о догађајима С3, које затим покрећу функцију Ламбда за слање догађаја у Слацк. Since we don't expect a high load, the first option is better for us. In case, if you want to implement the second option use these two links: Терраформ модул за распоређивање СНС и Ламбда стека Водич за конфигурисање догађаја С3 у СНС Терраформ модул за распоређивање СНС и Ламбда стека Водич за конфигурисање догађаја С3 у СНС У овом чланку ћемо послати само везу до С3 датотеке, али у неким случајевима је потребно послати целу датотеку. Slack API се променио пре неког времена, а слање датотека може бити мало компликовано. У овом чланку ћемо послати само везу до С3 датотеке, али у неким случајевима је потребно послати целу датотеку. Slack API се променио пре неког времена, а слање датотека може бити мало компликовано. Преузимање датотека у Slack са Python-ом У реду, хајде да изградимо упозорење корак по корак: 1. Create Slack secret Креирајте AWS Secret Manager secret У једном пољу: Овај кључ треба да садржи везу до вашег Слацк вебхоок (да бисте сазнали више о Слацк вебхоок провери ) kvendingoldo-dotnet-crash-dump-demo slack_webhook_url Званични водич Званични водич 2. Configure AWS Lambda Nećemo ući u dubinu o stvaranju AWS Lambda, ali ćemo istaknuti neke ključne tačke. . Званични водич Званични водич Побрините се да улога Ламбда ИАМ има дозволу за читање са С3: { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::kvendingoldo-dotnet-demo-crash/*" } 2.2: Да бисмо добили податке из AWS Secret менаџера морамо да одредимо променљиву окружења у AWS Lambda конфигурацији: SECRET_NAME=kvendingoldo-dotnet-demo-crash 2.3: Уплоад Питон кода у Ламбда import json import urllib3 import os import boto3 def get_secret(secret_name): client = boto3.client("secretsmanager") try: response = client.get_secret_value(SecretId=secret_name) if "SecretString" in response: secret = response["SecretString"] try: return json.loads(secret) except json.JSONDecodeError: return secret else: return response["SecretBinary"] except Exception as e: print(f"Error retrieving secret: {e}") return None def lambda_handler(event, context): print("Event received:", json.dumps(event)) secret_name = os.environ.get('SECRET_NAME', '') if secret_name == "": return { 'statusCode': 500, 'body': json.dumps("SECRET_NAME env variable is empty") } secret = get_secret(secret_name) slack_webhook_url = secret["slack_webhook_url"] for record in event['Records']: bucket_name = record['s3']['bucket']['name'] file_name = record['s3']['object']['key'] region = record['awsRegion'] if ".aws" in file_name: print(f"Skipping internal file: {file_name}") continue message = ( f":package: *New .NET dump is uploaded!*\n\n" f":cloud: Bucket: `{bucket_name}`\n" f":floppy_disk: File: `{file_name}`\n" f":link: Link: https://{bucket_name}.s3.{region}.amazonaws.com/{file_name}" ) http = urllib3.PoolManager() slack_resp = http.request( "POST", slack_webhook_url, body=json.dumps({ "text": message }), headers={ "Content-Type": "application/json" } ) if slack_resp.status != 200: raise Exception( f"Slack webhook request failed with status {slack_resp.status}: {slack_resp.data.decode('utf-8')}") return { "statusCode": 200, "body": json.dumps("Message has been sent successfully!") } 2.4: Подесите обавештења о догађају S3 за вашу кутију S3. and select " ". Конфигуришите догађај користећи следеће опције: Bucket -> Properties -> Obaveštenja o događaju Kreirajte obaveštenje o događaju Назив догађаја: kvendingoldo-dotnet-demo-crash Префикс: Думпс / Тип догађаја: s3:ObjectCreated:* Циљ: <Ваше име функције Lambda> Конфигуришите ЕФС складиштење чишћење Idealno, lanac isporuke .NET damps je spreman, ali šta je sa starim dampom? EFS nam ne dozvoljava da izbrišemo stare datoteke koristeći politike životnog ciklusa; možemo ih samo preneti na tip skladišta Retki pristup koji nije dovoljan ako ne želimo da platimo za nepotrebni prostor. Да би се решио овај проблем, постоје две опције: Креирајте ЕЦС бочни контејнер који ће очистити старе ЕФС датотеке у фази иницијализације Креирајте Ламбда или ЕЦС задатак који ће монтирати ЕФС и очистити старе датотеке од стране ЦРОН-а. Хајде да проверимо обоје. Опција 1: AWS Lambda Ово је најбоље решење, јер га не утиче животни циклус ЕЦС задатака и других фактора. Да бисте имплементирали ову стратегију, потребно је да креирате функцију Ламбда са монтираним ЕФС складиштењем (прочитајте више о монтирању датотечног система на Ламбда од i sledeći Python kod: Званични доц Званични доц import os import time import json def lambda_handler(event, context): # Note: you can only mount the filesystem to the /mnt/ directory. directory = '/mnt/dumps' # File pattern to match pattern = 'crash.dmp' # Time in minutes (by default 1d) minutes_old = 1440 # Convert minutes to seconds age_seconds = minutes_old * 60 # Current time now = time.time() for root, dirs, files in os.walk(directory): for file in files: if pattern in file: file_path = os.path.join(root, file) file_mtime = os.path.getmtime(file_path) if now - file_mtime > age_seconds: print(f"Found a file that older than {minutes_old} minutes: {file_path}") try: os.remove(file_path) except Exception as e: print(f"Failed to delete {file_path}: {e}") return { "statusCode": 200, "body": json.dumps("EFS clean-up completed successfully!") } Као што видите, ово је једноставан код који брише датотеке из монтираног складишта који су старији од једног дана. Када је ваш Ламбда спреман, такође морамо да конфигуришемо ЦРОН триггер да бисте периодично покренули функцију. → → → Cloudwatch правила догађаја То је све, након свих ових корака, ваше ЕФС складиштење ће се аутоматски очистити по вашем ЦРОН распореду. Опција 2: ЕЦС сидекар контејнер. Да бисмо имплементирали ову опцију морамо додати нови контејнер на нашу дефиницију задатака: { "essential": false, "name": "janitor", "image": "public.ecr.aws/amazonlinux/amazonlinux:2", "command": [ "bash", "-lc", "find /dumps -name '*crash.dmp*' -type f -mmin +10080 -print -delete" ], "mountPoints": [ { "containerPath": "/dumps", "readOnly": false, "sourceVolume": "dotnet-dumps" } ], "linuxParameters": { "initProcessEnabled": true } } Logika iza ovog zadatka: Иницирајте нови ЕЦС задатак са два контејнера: апликација и janitor Чистите застареле ЕФС датотеке у контејнеру janitor и изађите.Независно од тога, задатак неће бити прекинут или заустављен због ЕЦС опције "суштински": лажно. Као што видите, ова техника је прилично једноставна и ослања се на команду наћи, коју можете прилагодити. На пример, она брише датотеке старије од 10080 минута (7 дана). Наравно, ова стратегија је мање пожељна од прве када се бави дуготрајним ЕЦС задацима, али може бити погоднија за краткотрајне ЕЦС задатке или прототипирање. Време тестирања У овом одељку нећемо дубоко уронити у изградњу апликација .NET. За тестирање, можете модификовати које смо користили на почетку. sample aspnetapp sample aspnetapp Најједноставнији начин да се изазове .NET колапс је . This method is commonly used to simulate . Environment.FailFast() Тешки колапс Хајде да симулирамо несрећу: Додајте Environment.FailFast("kvendingoldo-dotnet-demo-crash .NET example crash"); ред до датотеке dotnet-docker/samples/aspnetapp/aspnetapp/Program.cs. Изградите нову слику доцкер-а и поново креирајте задатак ЕЦС-а. ECS zadatak će biti okončan, ali će prvo generisati .NET crash dump, koji će biti dostupan na S3 za nekoliko sekundi. У завршној фази, добићете поруку на Слацк-у овако: 📦 New .NET dump is uploaded! ☁️ Bucket: kvendingoldo-dotnet-demo-crash 💾 File: 1739104252-kvendingoldo-dotnet-demo-crash.dmp 🔗 Link: https://kvendingoldo-dotnet-demo-crash.s3.us-east-2.amazonaws.com/1739104252-kvendingoldo-dotnet-demo-crash.dmp Moguća poboljšanja Before wrapping-up the article, I'd like to provide some comments on potential changes: Биће добра идеја генерисати унапред потписане УРЛ-ове за С3 објекте Подесите политике животног циклуса за С3 букет да бисте аутоматски избрисали старе отпад из букета Користите СНС за слање обавештења о новим С3 објектима на више дестинација Закључак U proizvodnim okruženjima, brza vidljivost grešaka je ključna.Automatizovana isporuka otpada smanjuje MTTR (Mean Time To Resolution) i poboljšava odgovor na incidente. Као што видите, имплементација ове процедуре није тако тешка као што бисте могли очекивати.Да, користили смо многе АВС услуге за обављање ових задатака, али када погледамо дубље, сви су важни. Надам се да вам је овај чланак помогао да изградите лични ланац за испоруку отпада и учините свој развојни тим срећнијим. Слободно промените предложени приступ, и молимо вас да ме контактирате у било ком тренутку ако имате било каквих питања. Srećan kod!