때때로 .NET 애플리케이션은 생산에 실패하며 왜 로그와 계수가 괜찮기 때문에 아무도 알지 못합니다.이것은 꽤 불편하고 디버깅을 매우 불쾌하게합니다.이러한 경우 메모리 덤프는 디버깅을 단순화하고 문제 해결 시간을 몇 일에서 몇 분으로 줄일 수 있습니다. 이 문서에서는 설치된 .NET 응용 프로그램에 대한 덤프를 구성하는 방법을 설명합니다.This article explains how to configure dumps for .NET applications deployed to 그리고 가장 편리하고 안전한 방법으로 개발 팀에 전달합니다. AWS ECS Fargate 이 문서에서는 AWS 리소스를 만들고 특정 상황에서 AWS 문서를 참조하겠습니다.IAC는 우리의 초점이 아닙니다.그러나 만약 당신이 Terraform를 나만큼 좋아한다면 각 문서 섹션에 대해 오픈 소스 AWS 모듈을 사용할 수 있습니다. https://github.com/cloudposse https://github.com/terraform-aws-modules 이 문서에서는 AWS 리소스를 만들고 특정 상황에서 AWS 문서를 참조하겠습니다.IAC는 우리의 초점이 아닙니다.그러나 만약 당신이 Terraform를 나만큼 좋아한다면 각 문서 섹션에 대해 오픈 소스 AWS 모듈을 사용할 수 있습니다. https://github.com/cloudposse https://github.com/terraform-aws-modules https://github.com/cloudposse https://github.com/terraform-aws-modules 솔루션 아키텍처 이제 우리의 아키텍처를 살펴볼 시간입니다.나는 개발 팀이 복잡성 때문에 EBS 또는 EFS와 같은 저장소에서 .NET 덤프를 끌어내는 것을 고려하지 않는다고 가정하여 시작할 것입니다. S3는 개발자가 모든 유형의 파일을 얻는 것이 훨씬 간단하며 우리의 기대에 완벽하게 부합합니다. 예를 들어 Slack을 사용하지만 다른 옵션은 Teams, Mattermost, WhatsApp 등을 포함합니다. 그리고 마지막이지만 가장 중요한 메모지입니다. S3 버킷을 ECS에 기본적으로 첨부하는 것은 매우 복잡합니다.이 때문에 우리는 EFS, DataSync 및 sidecar ECS 컨테이너 / Lambda 함수 위에 구축 된 미드웨어 레이어를 만들 것입니다. EFS는 모든 ECS 작업에 중간 파일 저장소로 사용됩니다.Datasync는 EFS에서 S3로 데이터를 자동으로 전송하고 sidecar 컨테이너 또는 Lambda는 EFS에서 오래된 데이터를 청소합니다. 차트를 신속하게 살펴보자: 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. Step-by-step 구현 ECS Fargate 작업 만들기 이 섹션에서는 샘플 .NET 응용 프로그램을 사용하여 ECS Fargate Task를 만들 필요가 있습니다. 전제조건 진행하기 전에 완료해야 할 몇 가지 단계가 있습니다. 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 워크로드를 위한 Amazon ECS 클러스터 만들기 AWS 가이드 이 최소한의 실행 역할을 위해 충분할 것입니다 : 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": "*" } ] } Task Definition 만들기 모든 전제 조건이 준비되면 샘플 .NET 앱을 사용하여 최소한의 Fargate 작업을 만들 때입니다. , 그리고 이 작업 정의 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 덤프 설정 기본적으로 .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 이러한 변수는 Dockerfile에 직접 추가하거나 ECS Task Definition json에서 환경 변수로 정의할 수 있습니다. 우리의 예에서, 우리는 그들을 ECS 작업 사양에 주입합니다.이를 달성하기 위해, 우리는 그들을 추가합니다. 아래에서 보여주는 것처럼: 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 - 타임스탬프 이 두 링크를 참조하여 .NET 충돌 덤프의 수집 및 분석에 대한 자세한 내용을 참조하십시오. Collect .NET Crash Dumps (마이크로소프트 학습) 도트넷 덤프로 .NET Core 메모리 문제 (Linux) 디버깅 보시다시피, COMPlus_DbgMiniDumpName에서 몇 개의 위치 보유자를 사용합니다. Dotnet은 덤프 파일 이름에서 다음 위치 보유자를 자동으로 확장합니다. %e - 실행 가능한 이름 %p - 프로세스 ID %t - 타임스탬프 이 두 링크를 참조하여 .NET 충돌 덤프의 수집 및 분석에 대한 자세한 내용을 참조하십시오. Collect .NET Crash Dumps (마이크로소프트 학습) 도트넷 덤프로 .NET Core 메모리 문제 (Linux) 디버깅 Collect .NET Crash Dumps (마이크로소프트 학습) 도트넷 덤프로 .NET Core 메모리 문제 (Linux) 디버깅 EFS 스토리지 만들고 ECS Fargate Task에 설치하세요. 이 문서의 시작에서 언급했듯이, ECS 작업에 S3 버킷을 붙이는 것은 매우 어렵습니다. .NET 덤프 파일을 위한 중간 저장소로서, ECS 작업 집합에 쉽게 조립할 수 있다. Amazon EFS (Elastic File System) EFS 스토리지 만들려면 공식 AWS 가이드를 따르십시오: Amazon ECS 튜토리얼: Amazon EFS 파일 시스템 사용 EFS 스토리지 만들려면 공식 AWS 가이드를 따르십시오: Amazon ECS 튜토리얼: Amazon EFS 파일 시스템 사용 Amazon ECS 튜토리얼: Amazon EFS 파일 시스템 사용 공식 문서에 추가 할 특별한 것은 없습니다. EFS와 ECS 클러스터는 동일한 VPC에 있습니다. NFS (포트 2049/tcp)를 통해 ECS 작업에 의해 EFS에 액세스할 수 있습니다.Allow inbound access to NFS ports in the EFS security group to do this. EFS 파일 시스템을 ECS 작업에 설치하려면 필요한 권한을 제공해야 합니다.To mount EFS file system into the ECS task we must grant the necessary permissions to the IAM 역할 (지위 보유자에주의를 기울이기): 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>" } ] } 마지막 단계로, EFS 볼륨을 정의하고 ECS 작업 정의 (change fileSystemId)에서 몬트 포인트를 설정합니다. Bootstrapping 후 실제 파일 시스템 ID와 함께): fs-xxxxxx "volumes": [ { "name": "dotnet-dumps", "efsVolumeConfiguration": { "fileSystemId": "fs-xxxxxx", "rootDirectory": "/" } } ] "mountPoints": [ { "containerPath": "/dumps", "readOnly": false, "sourceVolume": "dotnet-dumps" } ] AWS DataSync를 구성하여 EFS 파일을 S3로 전송합니다. DataSync 서비스는 다양한 유형의 스토리지 사이에 데이터를 전송하는 AWS 표준 도구입니다.우리의 경우, 그것은 EFS에서 S3로 move.NET dumps를 도울 것입니다. 우리의 목표를 달성하기 위해, 우리는해야합니다 : 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 이 공식 DOC 이 공식 DOC AWS Lambda를 기반으로 Slack Alerts 만들기 이전에 언급했듯이 new.NET 덤프에 대한 경고는 개발 팀에게 매우 유용합니다. 아키텍처 관점에서 알림은 여러 가지 방법으로 구축될 수 있습니다: From the architecture point of view, alerts can be built in a different way: 간단한 lambda 함수는 API를 통해 Slack에 메시지를 보냅니다. 메시지는 구성된 S3 이벤트 알림을 사용하여 SNS 테마에 게시되며, 이 메시지는 Lambda 함수를 촉발하여 이벤트를 Slack로 전송합니다. 우리는 높은 부하를 기대하지 않기 때문에, 첫 번째 옵션은 우리에게 더 나은 경우에, 당신은 두 번째 옵션을 구현하려면이 두 링크를 사용 : SNS 및 Lambda 스택을 배포하기 위한 Terraform 모듈 S3 이벤트를 SNS로 구성하는 가이드 SNS 및 Lambda 스택을 배포하기 위한 Terraform 모듈 S3 이벤트를 SNS로 구성하는 가이드 우리는 Python을 사용하여 Slack로 메시지를 보낼 것입니다.이 문서에서는 S3 파일에 대한 링크만 보낼 것입니다.하지만 일부 경우에는 전체 파일을 보낼 필요가 있습니다.Slack API는 얼마 전에 변경되었으며 파일 보내기가 조금 복잡 할 수 있습니다.더 많은 것을 알고 싶다면 "Python로 Slack로 파일을 업로드" 문서를 참조하십시오. 우리는 Python을 사용하여 Slack로 메시지를 보낼 것입니다.이 기사에서는 S3 파일에 대한 링크 만 보낼 것입니다.하지만 일부 경우에는 전체 파일을 보낼 필요가 있습니다.Slack API는 얼마 전에 변경되었으며 파일 보내기가 조금 복잡 할 수 있습니다. » 기사 파일 업로드 Slack with Python 파일 업로드 Slack with Python OK, 우리는 단계별 경고를 구축하자 : 1. Create Slack secret AWS Secret Manager Secret 만들기 하나의 필드 : 이 키에는 Slack webhook에 대한 링크가 포함되어야 합니다(Slack webhook 체크에 대해 자세히 알아보려면 ) kvendingoldo-dotnet-crash-dump-demo slack_webhook_url 공식 가이드 공식 가이드 2. Configure AWS Lambda AWS Lambda 설치에 대한 더 근본적인 정보를 얻으려면, AWS Lambda 설치에 대한 자세한 내용을 참조하십시오. . 공식 가이드 공식 가이드 Lambda IAM 역할이 S3에서 읽을 수 있는 권한이 있는지 확인하십시오. { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::kvendingoldo-dotnet-demo-crash/*" } 2.2: AWS Secret Manager에서 데이터를 얻으려면 AWS Lambda 구성에서 환경 변수를 지정해야 합니다. SECRET_NAME=kvendingoldo-dotnet-demo-crash 2.3: Lambda에 Python 코드를 업로드 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 이벤트 알림을 구성합니다. 선택하기 > ". 다음 옵션을 사용하여 이벤트를 구성합니다.Configure the event using the following options: Bucket -> Properties -> 이벤트 알림 이벤트 알림 만들기 Event name: kvendingoldo-dotnet-demo-crash 상품명 : dumps 이벤트 유형: s3:ObjectCreated:* 대상: <Your Lambda function Name> EFS 스토리지 청소 완벽하게, .NET 덤프 배달 체인은 준비가되었지만, 오래된 덤프에 대해 어떻게합니까? EFS는 생명주기 정책을 사용하여 오래된 파일을 삭제하는 것을 허용하지 않습니다; 우리는 불필요한 공간을 지불하지 않으려면 충분하지 않은 희귀 액세스 저장 유형으로 전송 할 수 있습니다. 이 문제를 해결하기 위해, 두 가지 옵션이 있습니다 : 초기화 단계에서 오래된 EFS 파일을 청소할 ECS sidecar 컨테이너 만들기 EFS를 설치할 Lambda 또는 ECS 작업을 만들고 CRON에 의해 오래된 파일을 청소합니다. 둘 다 확인해 보자. 옵션 1: AWS Lambda 이것은 ECS 작업의 수명주기 및 기타 요인에 영향을 미치지 않기 때문에 최선의 솔루션입니다.이 전략을 구현하려면 EFS 저장소를 장착한 Lambda 함수를 만들 필요가 있습니다 (파일 시스템을 Lambda에 장착하는 방법에 대해 자세히 알아보십시오. 다음과 같은 Python 코드가 있습니다: 공식 DOC 공식 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!") } 보시다시피, 이것은 하루 이상 오래된 몬스터 스토리지에서 파일을 삭제하는 간단한 코드입니다. Lambda가 준비되면 CRON 트리거를 정기적으로 실행하도록 구성해야 합니다. Cloudwatch 이벤트 규칙 이 모든 단계를 수행 한 후에 EFS 스토리지는 CRON 스케줄에 의해 자동으로 청소됩니다. 옵션 2: ECS sidecar 컨테이너. 이 옵션을 구현하려면 작업 정의에 새 컨테이너를 추가해야 합니다.To implement this option we have to add new container to our task definition: { "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 } } 이 작업 뒤에있는 논리 : 두 개의 컨테이너를 사용하여 새로운 ECS 작업을 초기화하십시오: app 및 janitor janitor 컨테이너에서 오래된 EFS 파일을 청소하고 출력하십시오.Independently, the task will not be interrupted or stopped due to ECS option "essential": false. 당신이 볼 수 있듯이,이 기술은 매우 간단하고 당신이 사용자 정의 할 수있는 찾기 명령에 의존합니다.예를 들어, 그것은 10080 분 (7 일) 이상의 파일을 삭제합니다.물론,이 전략은 긴 ECS 작업을 처리 할 때 첫 번째보다 덜 바람직하지만, 짧은 ECS 작업이나 프로토 타입 작업에 더 편리 할 수 있습니다. 시험시간 이 섹션에서는 .NET 애플리케이션 빌드에 깊은 다이빙을 하지 않을 것입니다.Testing purposes, you can modify the .NET application build. 처음에 사용했던 것. sample aspnetapp 샘플 Aspnetapp .NET 충돌을 일으키는 가장 쉬운 방법은 이 방법은 일반적으로 시뮬레이션을 위해 사용됩니다. . Environment.FailFast() 단단한 crashes 충돌을 시뮬레이션해 보자: Environment.FailFast("kvendingoldo-dotnet-demo-crash .NET 예제 충돌"); dotnet-docker/samples/aspnetapp/aspnetapp/Program.cs 파일에 라인을 추가합니다. 새 도커 이미지를 만들고 ECS 작업을 다시 만듭니다. ECS Task는 종료되지만 먼저 몇 초 안에 S3에서 사용할 수 있는 .NET 충돌 덤프를 생성합니다. 마지막 단계에서 Slack에서 다음과 같은 메시지를 받게됩니다: 📦 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 가능한 개선 기사를 포장하기 전에 잠재적 인 변화에 대한 몇 가지 의견을 제공하고 싶습니다 : S3 개체에 대한 사전 서명 URL을 생성하는 것이 좋을 것입니다. S3 버킷의 수명주기 정책을 설정하여 버킷에서 오래된 버킷을 자동으로 삭제합니다.Set life cycle policies for S3 bucket to delete old dumps automatically from the bucket SNS를 사용하여 새로운 S3 개체에 대한 알림을 여러 목적지로 보내기 결론 생산 환경에서 오류에 대한 빠른 가시성은 중요합니다.자동 덤프 배달은 MTTR (Mean Time To Resolution)를 줄이고 사고 반응을 향상시킵니다. 보시다시피, 이 절차를 구현하는 것은 예상했던 것만큼 어렵지 않습니다.예, 우리는 이러한 작업을 수행하기 위해 많은 AWS 서비스를 사용했지만, 더 깊이 살펴보면 그들은 모두 중요합니다. 나는이 기사가 당신에게 개인적인 쓰레기 배달 체인을 구축하고 당신의 개발 팀을 더 행복하게 만들 수 있도록 도와주기를 바랍니다. 제안 된 접근 방식을 수정하는 것을 자유롭게 느끼고, 질문이 있으면 언제든지 저에게 연락하십시오. 행복한 코딩!