Bazen .NET uygulamaları üretimde çöküyor ve kimse nedenini bilmiyor, çünkü günlükleri ve metrikler iyidir.Bu oldukça rahatsız edici ve denetlemeyi çok rahatsız ediyor.Bu gibi durumlarda, bellek atıkları denetlemeyi basitleştirebilir ve sorun giderme süresini günlerden dakikaya düşürebilir. Bu makalede, dağıtılan .NET uygulamaları için dumps nasıl yapılandırılır ve daha sonra en uygun ve güvenli şekilde geliştirme ekibine iletir. AWS ECS Fargate Bu makalede, AWS kaynaklarını oluşturacağız ve belirli durumlarda AWS belgelerine atıfta bulunacağım. IAC bizim odak noktamız olmayacak. Bununla birlikte, eğer Terraform'ı benim kadar çok seviyorsanız, her makale bölümünde açık kaynaklı AWS modülleri kullanabilirsiniz. https://github.com/cloudposse https://github.com/terraform-aws-modules Bu makalede, AWS kaynaklarını oluşturacağız ve belirli durumlarda AWS belgelerine atıfta bulunacağım. IAC bizim odak noktamız olmayacak. Bununla birlikte, eğer Terraform'ı benim kadar çok seviyorsanız, her makale bölümünde açık kaynaklı AWS modülleri kullanabilirsiniz. https://github.com/cloudposse https://github.com/terraform-aws-modules https://github.com/cloudposse https://github.com/terraform-aws-modules çözüm mimarisi Arkitektürümüze bir göz atma zamanı geldi. Başlangıçta, geliştirme ekibinin, karmaşıklığı nedeniyle EBS veya EFS gibi depolardan .NET dump'larını çekmeyi düşünmediğini varsayarak başlayacağım. S3 geliştiricilerin herhangi bir dosya türünü almak için çok daha basittir ve beklentilerimizi mükemmel bir şekilde karşılamaktadır. Buna ek olarak, yeni bir .NET dump oluşturulduğunda proaktif bildirim almak oldukça değerli olacaktır. Örneğin, Slack kullanacağım, ancak diğer seçenekler Teams, Mattermost, WhatsApp ve benzeri içerir. bildirim iletisini göndermek için Lambda ve S3 tetikleyicileri kullanacağız. Son olarak, EFS, DataSync ve sidecar ECS konteyner / Lambda işlevi üzerine kurulan bir middleware tabakası oluşturacağız. EFS tüm ECS görevlerimiz için bir ara dosya depolama olarak kullanılacak, Datasync EFS'den S3'e otomatik olarak verileri aktaracak ve bir sidecar konteyner veya Lambda EFS'den eski verileri temizleyecektir. Diagramı kısa sürede inceleyelim: 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. Adım Adım Uygulama ECS Fargat Görev Oluşturma Bu bölümde, örnek bir .NET uygulamasını kullanarak bir ECS Fargate Görevini oluşturmamız gerekir. Ön koşullar Devam etmeden önce, tamamlanması gereken birkaç adım var: 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 iş yükü için bir Amazon ECS kümesi oluşturma AWS Kılavuzu Bu minimum Uygulama için yeterli olacaktır: Trust policy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } Minimal olarak da : permissions policy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] } Görev tanımını oluşturun Tüm ön koşullar hazır olduğunda, örnek bir .NET uygulaması ile minimum bir Fargate görevi oluşturma zamanıdır. , ve bu görev tanımlaması json dosyası kullanın: AWS Resmi Kılavuzu AWS Resmi Kılavuzu { "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 Kullanımı Varsayılan olarak, .NET uygulamaları herhangi bir dump oluşturmaz. onu yapılandırmak için aşağıdaki çevre değişkenlerini ayarlamalıyız: # 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 Bu değişkenler doğrudan Dockerfile'e eklenebilir veya ECS Task Definition json'da çevre değişkenleri olarak tanımlanabilir. Örneklerimizde bunları ECS görev özelliklerine enjekte edelim. Bunu yapmak için bunları ekleyeceğiz. Aşağıda gösterildiği gibi: 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" } ] Gördüğünüz gibi, COMPlus_DbgMiniDumpName'de birkaç yeraltı kullanıyorum. Dotnet otomatik olarak aşağıdaki yeraltıları atık dosya adında genişler: %e - Uygulama Adı %p - İşlem Kimliği %t - Zamanlama Bu iki bağlantı için daha fazla bilgi için .NET çarpışma çöp toplama ve analiz: Collect .NET Crash Dumps (Microsoft Öğren) Dotnet Dump ile .NET Core bellek sorunlarının çözümü (Linux'ta) Gördüğünüz gibi, COMPlus_DbgMiniDumpName'de birkaç yeraltı kullanıyorum. Dotnet otomatik olarak aşağıdaki yeraltıları atık dosya adında genişler: %e - Uygulama Adı %p - İşlem Kimliği %t - Zamanlama Bu iki bağlantı için daha fazla bilgi için .NET çarpışma çöp toplama ve analiz: Collect .NET Crash Dumps (Microsoft Öğren) Dotnet Dump ile .NET Core bellek sorunlarının çözümü (Linux'ta) Collect .NET Crash Dumps (Microsoft Learn) Dotnet Dump ile .NET Core bellek sorunlarının çözümü (Linux'ta) EFS depolama oluşturun ve ECS Fargate Görevine monte edin Bu makalenin başında belirttiğim gibi, bir ECS işine bir S3 kavanozu takmak oldukça zordur; bunun yerine, kullanacağız Bir dizi ECS görevine kolayca monte edilebilen .NET dump dosyaları için geçici depolama olarak. Amazon EFS (Elastic File System) EFS depolama oluşturmak için, resmi AWS kılavuzunu izleyin: Amazon ECS Eğitimi: Amazon EFS Dosya Sistemleri Kullanımı EFS depolama oluşturmak için, resmi AWS kılavuzunu izleyin: Amazon ECS Eğitimi: Amazon EFS Dosya Sistemleri Kullanımı Amazon ECS Eğitimi: Amazon EFS Dosya Sistemleri Kullanımı Resmi belgelere eklemek için özel bir şey yok. sadece emin olun: EFS ve ECS Cluster aynı VPC'de EFS, NFS (port 2049/tcp) üzerinden ECS görevleri tarafından erişilebilir. EFS dosya sistemini ECS görevine monte etmek için, gerekli izinleri ECS görevine vermeniz gerekir. IAM rolü (ortaklara dikkat edin): 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>" } ] } Son adım olarak, EFS hacimleri tanımlayın ve ECS görevi tanımlamanız (change fileSystemId) with your real File System Id after bootstrapping): fs-xxxxxx "volumes": [ { "name": "dotnet-dumps", "efsVolumeConfiguration": { "fileSystemId": "fs-xxxxxx", "rootDirectory": "/" } } ] "mountPoints": [ { "containerPath": "/dumps", "readOnly": false, "sourceVolume": "dotnet-dumps" } ] AWS DataSync'i EFS dosyalarını S3'e aktarmak için yapılandırın DataSync servisi, verileri çeşitli depolama türleri arasında aktarmak için AWS standart bir araçtır. bizim durumumuzda, bize EFS'ten S3'e move.NET'i atmaya yardımcı olacaktır. Hedefimize ulaşmak için, şunları yapmalıyız: 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 this official doc this official doc AWS Lambda'ya dayalı Slack Alerts oluşturun Daha önce de belirtildiği gibi, new.NET dumps hakkında uyarılar geliştirme ekibi için son derece yararlıdır. Mimarlık açısından uyarılar farklı şekillerde oluşturulabilir: Basit bir lambda fonksiyonu, API üzerinden Slack'a mesaj gönderir ve S3 olayları tarafından tetiklenir. Mesajlar, yapılandırılmış S3 olay bildirimleri kullanılarak bir SNS konuya yayınlanır ve bu bildirimler, olayları Slack'a göndermek için bir Lambda işlevini tetikler. 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: SNS ve Lambda Stack'ı dağıtmak için Terraform Modül S3 olaylarını SNS'e yapılandırmak için bir kılavuz SNS ve Lambda Stack'ı dağıtmak için Terraform Modül S3 olaylarını SNS'e yapılandırmak için bir kılavuz Bu makalede sadece S3 dosyasına bir bağlantı göndereceğiz, ancak bazı durumlarda tüm dosyayı göndermek için gereklidir. Slack API bir süre önce değişti ve dosya gönderme biraz karmaşık olabilir. Bu makalede sadece S3 dosyasına bir bağlantı göndereceğiz, ancak bazı durumlarda tüm dosyayı göndermek için gereklidir. Slack API bir süre önce değişti ve dosya gönderme biraz karmaşık olabilir. » Makale Uploading files to Slack with Python Uploading files to Slack with Python Lütfen adım adım uyarı oluşturalım: 1. Create Slack secret AWS Secret Manager'ın Gizli Oluşturulması Bir alan için: Bu anahtar Slack webhook'a bir bağlantı içermelidir (Slack webhook kontrolü hakkında daha fazla bilgi edinmek için) ) için kvendingoldo-dotnet-crash-dump-demo slack_webhook_url Resmi rehber Resmi rehber 2. Configure AWS Lambda AWS Lambda'nın oluşturulması hakkında derinlemesine çalışmayacağız, ancak bazı önemli noktaları vurgulayacağız. . the official guide Resmi rehber Lambda IAM rolünün S3'ten okuma izni olduğundan emin olun: { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::kvendingoldo-dotnet-demo-crash/*" } 2.2: AWS Secret manager'dan veri almak için AWS Lambda yapılandırmasında bir çevre değişkenini belirtmeliyiz: SECRET_NAME=kvendingoldo-dotnet-demo-crash 2.3: Python kodunu Lambda'ya yükleyin 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 bucket için S3 olay bildirimlerini yapılandırın. Seçiniz » ". aşağıdaki seçenekleri kullanarak olayı yapılandırın: bucket -> mülkler -> Olay bildirimleri Olay bildirimi oluşturma Event name: kvendingoldo-dotnet-demo-crash Etiket arşivi: dumps Etkinlik türü: s3:ObjectCreated:* Hedef: <Your Lambda function Name> EFS depolama temizliği Mükemmel, .NET dump dağıtım zinciri hazır, ama eski dump hakkında ne? EFS bize yaşam döngüsü politikaları kullanarak eski dosyaları silmemize izin vermez; sadece gereksiz erişim depolama türüne aktarabiliriz, bu da gereksiz alan için ödeme yapmak istemiyorsak yeterli değildir. Bu sorunu çözmek için iki seçenek vardır: Başlangıç aşamasında eski EFS dosyalarını temizleyecek bir ECS sidecar konteyneri oluşturun EFS'i monte edecek Lambda veya ECS görevini oluşturun ve eski dosyaları CRON tarafından temizleyin. İkisini de kontrol edelim. Seçenek 1: AWS Lambda Bu en iyi çözüm çünkü ECS görevlerinin yaşam döngüsü ve diğer faktörler tarafından etkilenmez.Bu strateji uygulamak için, monte edilmiş bir EFS depolama ile bir Lambda fonksiyonu oluşturmanız gerekir (bir dosya sistemi Lambda'ya monte etme hakkında daha fazla bilgi edinin Aşağıdaki Python kodunu kullanın: Resmi doc Resmi doc 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!") } Gördüğünüz gibi, bu, bir günden daha eski olan montajlı depolama dosyalarını silen basit bir koddur. Lambda hazır olduğunda, fonksiyonu düzenli olarak çalıştırmak için CRON trigger'ı da yapılandırmalıyız. Cloudwatch Kuralları Tüm bu adımların ardından, EFS depolamanız CRON programınız tarafından otomatik olarak temizlenecektir. Seçenek 2: ECS sidecar konteyner. Bu seçeneği uygulamak için görev tanımımıza yeni bir konteyner eklemeniz gerekir: { "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 } } Bu görevin arkasındaki mantık: Yeni bir ECS görevini iki konteynerle başlatın: app ve janitor Janitor konteynerindeki eski EFS dosyalarını temizleyin ve çıkın.Ne olursa olsun, görev ECS seçeneği "özellikle": yanlış nedeniyle kesilmeyecek veya durdurulmayacaktır. Gördüğünüz gibi, bu teknik oldukça basittir ve özelleştirebileceğiniz bul komutuna dayanır. Örneğin, 10080 dakikadan daha eski (7 gün) dosyaları siler. Tabii ki, bu strateji uzun ömürlü ECS görevleri ile uğraşırken ilkinden daha az arzu edilir, ancak kısa ömürlü ECS görevleri veya prototipleme için daha uygun olabilir. Test Zamanı Bu bölümde, .NET uygulama yapısına derin bir dalış yapmayacağız. test amaçlı olarak, uygulamayı değiştirebilirsiniz Başlangıçta kullandığımız Örnek Aspnetapp Örnek Aspnetapp .NET'in çöküşüne neden olmanın en basit yolu Bu yöntem genellikle simüle etmek için kullanılır. . Environment.FailFast() Ağır çarpışmalar Kaza simülasyonunu yapalım: Environment.FailFast("kvendingoldo-dotnet-demo-crash .NET örneği çöküşü"); dotnet-docker/samples/aspnetapp/aspnetapp/Program.cs dosyasını ekle. Yeni bir dokunmatik görüntü oluşturun ve ECS görevini yeniden oluşturun. ECS Task will terminate, but first generate a.NET crash dump, which will be available on S3 in a few seconds. Son aşamada, Slack'ınızda şöyle bir mesaj alacaksınız: 📦 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 Potansiyel iyileştirmeler Makaleyi çevirmeden önce, potansiyel değişiklikler hakkında bazı yorumlar vermek istiyorum: S3 nesneler için önceden imzalanmış URL'ler oluşturmak iyi bir fikir olacaktır Set lifecycle policies for S3 bucket to delete old dumps automatically from the bucket Yeni S3 nesneler hakkında iletileri çoklu hedeflere göndermek için SNS kullanın Sonuç Üretim ortamlarında, arızaların hızlı görünürlüğü çok önemlidir. otomatik dump teslimatı MTTR (Mean Time To Resolution) azaltır ve kaza yanıtını iyileştirir. Gördüğünüz gibi, bu prosedürün uygulanması beklediğiniz kadar zor değildir.Evet, bu görevleri gerçekleştirmek için birçok AWS hizmetini kullandık, ancak daha derinlemesine baktığımızda hepsi önemlidir. Umarım bu makale size kişisel bir çöp teslimat zinciri kurmanıza yardımcı oldu ve geliştirme ekibinizi daha mutlu etti. Önerilen yaklaşımı değiştirmekten çekinmeyin ve herhangi bir sorunuz varsa lütfen bana ulaşın. Mutlu bir kodlama!