진단만 하고 배포하지 않는 AWS DevOps 에이전트 구축
요약
CI/CD 파이프라인 실패 시 진단 과정을 자동화하는 AWS DevOps 에이전트 구축 방법을 소개합니다. 이 에이전트는 GitHub Actions의 실패 로그를 가져와 Amazon Bedrock과 Claude를 이용해 분석하고, 발견된 문제점과 수정 제안(diff)을 PR 댓글로 남깁니다.
핵심 포인트
- CI/CD 실패 진단 자동화는 시간 절약에 효과적입니다.
- 로그 전체 대신 '롤링 윈도우' 추출 기법이 중요합니다.
- Bedrock 전송 시 로그 정제 및 컨텍스트 축소가 필수입니다.
- AWS 키 대신 GitHub OIDC 페더레이션을 사용해야 합니다.
대부분의 CI/CD 파이프라인 실패는 수정하는 것보다 진단하는 데 시간이 더 오래 걸립니다. IAM 역할에 업데이트 후 누락된 액션이 있습니다. 취소된 작업 후 Terraform 상태 잠금이 해제되지 않았습니다. 아키텍처 불일치로 컨테이너 레이어 캐시가 손상되었습니다. 수정 자체는 보통 두 줄의 패치이지만, 그것을 찾는다는 것은 GitHub Actions에서 거대한 원본 터미널 로그를 기다리고 오류 라인을 찾아다니는 것을 의미합니다.
저는 복잡한 장치를 추가하지 않으면서 그 분류(triage) 단계를 자동화하고 싶었습니다. GitHub Actions 실행이 실패하면, 경량 워크플로우가 실패 로그를 가져와 Amazon Bedrock을 사용하여 Claude로 처리하고, 진단과 제안된 diff를 풀 리퀘스트에 댓글로 남깁니다. 구현은 순수한 Python, GitHub Actions, AWS OIDC 페더레이션, 그리고 Bedrock으로 이루어져 있습니다. 코드는 GitHub의 github.com/sharma-the-karma/aws-devops-agent에서 확인할 수 있습니다.
작동 방식
이 분류 작업은 파이프라인이 실패할 때만 실행되므로, 저장소 비밀에 영구적인 인프라나 장기 실행 AWS 키가 없습니다.
flowchart LR
A[GitHub Actions CI 워크플로우] -->|실패| B[분류 트리거]
B --> C[로그 정제 엔진]...
순서는 간단합니다:
- 풀 리퀘스트에서 CI 작업이 실패하여
workflow_run이벤트를 통해 분류 워크플로우가 트리거됩니다. - 러너는 GitHub의 OIDC 제공자로부터 임시 토큰을 요청하고 AWS에서 IAM 역할을 가정(assume)합니다.
- Python 스크립트가 실패한 단계의 로그를 다운로드하고, ANSI 색상 코드를 제거하며, 실패 시그니처 주변 라인을 추출합니다.
- 정제된 조각(snippet)이 Bedrock의 Converse API로 전송됩니다.
- 진단 결과는 풀 리퀘스트에 다시 게시되며, 이미 댓글이 존재하는 경우 이전 댓글을 수정합니다.
제가 배운 점
원본 로그가 모델 추론을 망친다
전체 원본 콘솔 로그를 LLM에 입력하는 것은 효과적이지 않습니다. 일반적인 CI 실행은 실패 지점에 도달하기 전에 수천 줄의 패키지 다운로드, 컨테이너 빌드 단계, 환경 설정 등을 출력합니다. 테스트 과정에서 이 전체 출력을 보내면 프롬프트가 수만 토큰으로 부풀어 올랐습니다. 모델은 실제 치명적 오류(fatal error)보다는 로그 초반에 있는 무해한 컴파일러 경고에 자주 집착했으며, 불필요하게 15~20초의 지연 시간까지 추가했습니다.
이 문제를 해결하기 위해 작은 증류 유틸리티(src/log_distiller.py)를 사용했습니다. 이 유틸리티는 ANSI 포맷팅을 제거하고 AccessDeniedException, Python 트레이스백, Terraform 오류, 그리고 0이 아닌 종료 코드와 같은 일반적인 실패 마커를 스캔합니다. 일치하는 항목을 발견하면, 그 전후로 각각 15줄과 35줄의 '롤링 윈도우(rolling window)'를 추출하여 사용합니다:
import re
from typing import Dict, Any
...
이를 통해 페이로드 크기는 수만 토큰에서 약 500~800 토큰의 고신호 컨텍스트로 줄어듭니다. 응답 시간은 몇 초대로 떨어지고, 모델은 주변 빌드 노이즈가 아닌 실제 실패에 집중할 수 있습니다.
에이전트에게 영구 키를 부여하지 마세요
CI/CD 러너(runner)를 위해 정적 AWS 액세스 키(AKIA...)를 생성하는 것을 피하세요. 풀 리퀘스트(pull request)가 워크플로우 파일을 수정하거나 신뢰할 수 없는 스크립트를 실행하는 경우, 저장된 비밀 정보가 노출될 수 있습니다.
대신, GitHub Actions용 AWS IAM OIDC Identity Provider를 구성하세요. 러너는 짧은 수명의 GitHub 토큰을 임시 STS 자격 증명(credentials)으로 교환합니다.
data "aws_iam_policy_document" "github_oidc_trust" {
statement {
effect = "Allow"
...
workflow_run 트리거 실행은 기본 브랜치(default branch)의 컨텍스트에서 실행되기 때문에, sub 클레임(claim)을 와일드카드를 사용하는 대신 ref:refs/heads/main으로 고정할 수 있습니다. 해당 역할의 정책은 bedrock:InvokeModel만 허용하고 그 외는 아무것도 부여하지 않습니다. 에이전트는 S3를 읽거나, 보안 그룹을 수정하거나, 인프라를 변경할 수 없습니다.
Converse API를 사용하세요
Amazon Bedrock은 Converse API를 제공하며, 이는 파운데이션 모델 전반에 걸쳐 시스템 프롬프트(system prompts), 메시지(messages), 추론 매개변수(inference parameters)를 표준화합니다.
import boto3
SYSTEM_PROMPT = """You are an AWS DevOps and Infrastructure Architect.
...
저는 여기에 anthropic.claude-3-5-sonnet-20241022-v2:0를 사용했지만, 단순히 빠른 스택 트레이스 해석만 필요한 표준 CI 실패 분류(triage)의 경우, anthropic.claude-3-5-haiku-20241022-v1:0가 더 빠르고 저렴하며 컴파일러 오류도 똑같이 효과적으로 처리합니다. 온도(temperature)를 0.2로 설정하면 실행 간 진단 출력이 일관되게 유지됩니다.
새로운 댓글을 추가하는 대신 PR 댓글 업데이트하기
개발자들이 문제가 있는 브랜치를 문제 해결하면서 여러 커밋을 푸시할 때, 봇 댓글이 풀 리퀘스트(pull request)를 쉽게 범람하게 할 수 있습니다.
이를 방지하기 위해 에이전트는 각 댓글에 숨겨진 HTML 마커(<!-- aws-devops-agent-triage -->)를 태그하고 게시 전에 기존 댓글을 검사합니다. 만약 이전에 보고서가 존재한다면, 해당 댓글을 제자리에서 수정합니다:
COMMENT_TAG = "<!-- aws-devops-agent-triage -->"
def post_or_update_pr_triage_comment(repo, pr_number: int, analysis_markdown: str):
...
참고로, 워크플로우의 GITHUB_TOKEN은 이 단계에 대해 pull-requests: write 권한이 필요합니다.
에이전트가 인프라 변경을 적용하도록 절대 두지 마세요
에이전트가 코드를 자동으로 커밋하거나 terraform apply를 실행하는 것은 위험합니다.
간단한 예시가 그 이유를 보여줍니다. ECS 서비스 업데이트가 서브넷(subnet) 구성 오류 때문에 실패했다고 가정해 봅시다. 에이전트는 서브넷 불일치를 올바르게 식별하고 적절한 구성을 제안할 수 있습니다. 하지만 특정 AWS 리소스의 서브넷 속성 변경은 교체(replacement)를 트리거하여 새 리소스를 생성하기 전에 기존 리소스를 파괴합니다. 이러한 변경을 스스로 실행하는 자동화된 에이전트는 의도치 않은 다운타임이나 데이터 손실을 쉽게 초래할 수 있습니다.
에이전트의 역할은 실패 원인을 진단하고, 영향 범위(blast radius)를 설명하며, diff를 제공하는 것입니다. 엔지니어가 이 diff를 검토하고 언제 어떻게 배포할지 결정합니다.
보고서가 어떤 모습인지
IAM 권한 문제로 ECS 서비스 업데이트가 실패했을 때, 에이전트가 풀 리퀘스트에 게시하는 대표적인 예시는 다음과 같습니다:
AWS DevOps Agent 트리아지 보고서
1. 근본 원인 분석 (Root Cause Breakdown)
ecs:UpdateServicePrimaryTaskSet호출 중AccessDeniedException으로 배포가 실패했습니다. CI 러너가 가정하는 실행 역할(execution role)에 첨부된 정책에 이 액션이 누락되어 있습니다. 이는 인프라/IAM 권한 문제입니다.2. 즉각적인 수정 / 패치 (Immediate Fix / Patch)
infra/iam_deployer.tf의 CI 배포자(deployer) 정책에 누락된 액션을 추가하십시오:statement { actions = [ "ecs:UpdateService", ...3. 예방 조치 및 영향 범위 (Preventive Action & Blast Radius)
ECS 서비스에 CodeDeploy 또는 blue/green 태스크 세트를 도입할 때는 항상 배포 정책을 검토하십시오. 이 변경 사항을 적용하는 것은 비파괴적(non-destructive)이며 리소스 재구축이 필요하지 않습니다.
직접 시도해 보기
저장소 클론하기:
git clone https://github.com/sharma-the-karma/aws-devops-agent.git
cd aws-devops-agent
IAM 역할 배포하기:
cd infra
terraform init
terraform apply -var="github_org=sharma-the-karma" -var="github_repo=aws-devops-agent"
출력된 역할을 AWS_ROLE_ARN으로 설정하고, 저장소 비밀(repository secrets)에 추가하십시오 (Settings > Secrets and variables > Actions).
실제 호출 없이 샘플 로그를 대상으로 로컬에서 테스트하려면:
cd src
pip install -r requirements.txt
python triage_agent.py --log-file sample_failure.log --dry-run
이 설정의 다음 단계는 CloudWatch 알람 웹훅(webhooks)에 연결하여, CI 파이프라인 실패뿐만 아니라 런타임 ECS 태스크 충돌 및 Lambda 오류에도 동일한 트리아지 흐름이 작동하도록 하는 것입니다.
완전한 코드, Terraform 구성, 샘플 로그는 GitHub에서 확인할 수 있습니다: github.com/sharma-the-karma/aws-devops-agent.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기