Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 실습 도구 모음

이 저장소의 실습이 공통으로 쓰는 도구와 설치 방법입니다. 랩마다 목록을 복제하지 않고 이 문서 하나를 갱신합니다.

## 컨테이너로 갖추기 (권장)

`.devcontainer/devcontainer.json`이 저장소 전체의 기본 설정입니다. 별도로 고를 것이 없습니다.

- **Codespaces**: 저장소에서 **Code > Codespaces > Create codespace**
- **로컬 VS Code**: **Dev Containers: Reopen in Container**

컨테이너는 도구만 갖춰 줍니다. 로그인과 각 랩의 준비 명령은 실습 문서를 따라 직접 실행합니다. 무엇이 실행되는지 가려지지 않도록 컨테이너가 랩 명령을 대신 실행하지 않습니다.

## 도구 목록

| 도구 | 쓰임 | 컨테이너에서 |
|---|---|---|
| `az` | Azure 리소스 조회·조작, 로그 쿼리 | `azure-cli` feature (`log-analytics`, `containerapp` 확장 포함) |
| `azd` | 랩 환경 프로비저닝(`azd up`)과 삭제(`azd down`) | `azure-dev/azd` feature |
| `gh` | GitHub 저장소·이슈 확인 | `github-cli` feature |
| `python3` | 랩의 Python 도구 실행 | `python` feature (3.12) |
| `uv` | Python 의존성 설치 | `python` feature의 `toolsToInstall` |
| `jq` | JSON 출력 파싱 | 베이스 이미지 |
| `curl` | 애플리케이션 엔드포인트 호출 | 베이스 이미지 |

## 로컬에 직접 설치하기

컨테이너를 쓰지 않는다면 아래를 설치합니다.

**macOS (Homebrew)**

```bash
brew install azure-cli azure-dev gh python@3.12 uv jq
```

**Ubuntu / Debian**

```bash
sudo apt-get update && sudo apt-get install -y jq curl python3
curl -sSL https://aka.ms/InstallAzureCLIDeb | sudo bash
curl -fsSL https://aka.ms/install-azd.sh | bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

`gh`는 [GitHub CLI 설치 안내](https://github.com/cli/cli/blob/trunk/docs/install_linux.md)를 따릅니다.

`az` 확장은 별도로 추가합니다. 랩에서 `az monitor log-analytics query`를 쓰려면 필요합니다.

```bash
az extension add --name log-analytics
az extension add --name containerapp
```

사내 프록시 환경이라면 `uv`가 프록시로 구성된 인덱스를 그대로 씁니다. 랩의 Python 환경 준비 스크립트는 공개 PyPI로 폴백하지 않으므로, `uv`가 없으면 설치 안내와 함께 실패합니다.

## 로그인

두 CLI는 자격 증명을 따로 관리하므로 각각 로그인합니다.

```bash
az login --use-device-code
azd auth login
```

## 참고

- [Dev Containers 사양](https://containers.dev/implementors/json_reference/)
- [Codespaces 문서](https://docs.github.com/ko/codespaces)
- [azd 설치](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd)
- [uv 설치](https://docs.astral.sh/uv/getting-started/installation/)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Azure SRE Agent Event Lab",
"name": "Azure DevGuide Sample",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {
Expand Down Expand Up @@ -27,9 +27,5 @@
]
}
},
"postCreateCommand": "cd monitor/sre-agent-event-lab && ./scripts/setup-venv.sh",
"postAttachCommand": {
"next-steps": "echo 'Next: az login --use-device-code, then cd monitor/sre-agent-event-lab && source ./scripts/lab-env.sh'"
},
"remoteUser": "vscode"
Comment thread
hellices marked this conversation as resolved.
}
52 changes: 25 additions & 27 deletions monitor/sre-agent-event-lab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Azure SRE Agent는 이 실습이 만들지 않습니다. 미리 만들어 둔 Ag
이 실습은 **본인 fork에서** 진행합니다. Agent에 저장소를 연결하면 조사 결과 이슈가 그 저장소에 생성되므로, 원본을 연결하면 참가자 전원의 이슈가 한곳에 쌓이고 쓰기 권한도 없습니다.

1. 이 저장소를 본인 계정으로 fork합니다.
2. fork에서 **Code > Codespaces > New with options**를 열고 dev container로 `Azure SRE Agent Event Lab`을 고릅니다. `az`, `azd`, `gh`, Python, `uv`가 설치되고 `postCreateCommand`가 `setup-venv.sh`를 실행해 `app/.venv`까지 만듭니다.
2. fork에서 **Code > Codespaces > Create codespace**를 엽니다. 저장소 기본 dev container가 `az`, `azd`, `gh`, Python, `uv`, `jq`를 갖춰 줍니다. 도구 목록과 로컬 설치 방법은 [.devcontainer/README.md](../../.devcontainer/README.md)에 있습니다.
3. 터미널에서 로그인한 뒤 환경을 한 번 읽습니다.

```bash
Expand All @@ -47,11 +47,11 @@ source ./monitor/sre-agent-event-lab/scripts/lab-env.sh

`lab-env.sh`는 `azd`가 게시한 배포 출력만 읽어 리소스 그룹·구독·Container App·Storage 범위 등을 현재 셸에 export하고, 값이 하나라도 없으면 `LAB_READY=0`으로 알려 줍니다. 이후 가이드의 명령은 이 값들을 그대로 사용하므로 단계마다 다시 조회하지 않습니다. 비밀 값은 읽지도 출력하지도 않습니다.

로컬에서 진행한다면 아래 사전 조건을 직접 갖춘 뒤 같은 `source` 한 줄로 시작합니다. Codespaces에서는 dev container가 이미 갖춰 줍니다.
로컬에서 진행한다면 아래 사전 조건을 직접 갖춘 뒤 같은 `source` 한 줄로 시작합니다.

## 사전 조건

- `az`, `azd`, `jq`, `curl`, `python3`, [`uv`](https://docs.astral.sh/uv/getting-started/installation/) — `uv`는 `app/.venv`를 만드는 `scripts/setup-venv.sh`가 쓰는 유일한 도구이며, 사내 프록시로 구성된 인덱스 설정을 그대로 씁니다(공개 PyPI `pip` 폴백 없음).
- `az`, `azd`, `jq`, `curl`, `python3`, `uv` — 설치 명령은 [.devcontainer/README.md](../../.devcontainer/README.md)가 관리합니다. `uv`는 `app/.venv`를 만드는 `scripts/setup-venv.sh`가 쓰는 유일한 도구이며, 사내 프록시로 구성된 인덱스 설정을 그대로 씁니다(공개 PyPI `pip` 폴백 없음).
- `az extension add --name log-analytics` (`az monitor log-analytics query` 제공)
- `az login`과 `azd auth login` — 두 CLI는 자격 증명을 따로 관리합니다.
- 구독 Contributor, 역할 할당을 위한 Owner 또는 User Access Administrator
Expand All @@ -65,7 +65,7 @@ source ./monitor/sre-agent-event-lab/scripts/lab-env.sh
cd monitor/sre-agent-event-lab
```

로컬 검증만 먼저 해 보려면 다음을 실행합니다. Codespaces에서는 `setup-venv.sh`가 이미 실행된 상태입니다.
로컬 검증만 먼저 해 보려면 다음을 실행합니다. `setup-venv.sh`는 `azd up`의 postprovision 단계에서도 실행되므로, 배포를 먼저 한 경우에는 이미 준비된 상태입니다.

```bash
./scripts/setup-venv.sh
Expand Down Expand Up @@ -112,34 +112,24 @@ postprovision 단계가 실패하면 로컬 환경만 실패한 것입니다. `.

기본 실습에는 Logic App bridge를 배포하지 않습니다. 제품 표준 경로는 Azure Monitor를 incident platform으로 연결하는 것이고, 예전 실측에서 쓰던 Action Group + Logic App 인증 경로는 레거시 기록으로만 남아 있습니다([validation-results.md](validation-results.md)).

## 점검과 승인
## 정상 상태 확인과 승인

장애를 주입하기 전에 정상 부하가 Application Insights까지 도달하는지 확인하고, 그 사실을 기록해야 S1이 열립니다. 텔레메트리가 없는 워크로드에 장애를 넣으면 주입한 장애와 원래부터 안 보이던 상태를 구별할 수 없습니다. 명령은 [guides/01-agent-setup.md](guides/01-agent-setup.md)에 있습니다.

```bash
./scripts/lab.sh doctor
./scripts/lab.sh baseline
./scripts/lab.sh acknowledge agent-setup
python3 scripts/lab_state.py mark baseline_passed --evidence-dir "${EVIDENCE_DIR}"
python3 scripts/lab_state.py acknowledge-agent
```

`doctor`는 `CHECK<TAB>STATUS<TAB>DETAIL` 한 줄씩 출력하고 `FAIL`이 하나라도 있으면 종료 코드 1을 반환합니다. 저장소 연결, 지식 원본, incident platform, 응답 계획은 공식 안정 API로 읽을 수 없어 항상 `MANUAL`입니다. `Python environment` 행은 `app/.venv`와 Pillow가 캡처(`capture-scenario.sh`)에 쓸 준비가 됐는지 확인하며, `FAIL`이면 `./scripts/setup-venv.sh`를 다시 실행하라고 안내합니다.

`baseline`은 정상 부하를 넣고 Application Insights에 두 요청 종류가 모두 보일 때까지 최대 10분 기다립니다. `acknowledge agent-setup`은 대화형이며, 설정 값을 출력한 뒤 표준 입력으로 정확히 `acknowledge`를 입력해야 기록됩니다.
`acknowledge-agent`는 설정 값을 출력한 뒤 표준 입력으로 정확히 `acknowledge`를 입력해야 기록됩니다.

## 시나리오 실행

각 시나리오 문서는 **수동 실행**을 먼저 설명합니다. `az containerapp update`, `az role assignment delete`처럼 실제로 Azure에 적용되는 명령을 그대로 실행하면서 무엇이 바뀌는지 확인하는 경로입니다. 처음 진행할 때는 이 경로를 권장합니다.

같은 절차를 한 번에 실행하는 지름길도 각 문서 뒤쪽에 있습니다.
각 시나리오 문서는 실제로 Azure에 적용되는 명령을 그대로 실행하도록 안내합니다. `az containerapp update`, `az role assignment delete`처럼 무엇이 바뀌는지 보이는 명령만 씁니다. 시나리오를 대신 실행해 주는 스크립트는 없습니다. 장애를 넣고 되돌리는 일이 이 실습에서 배우는 내용이기 때문입니다.

```bash
./scripts/lab.sh run s1
./scripts/lab.sh capture s1
./scripts/lab.sh run s2
./scripts/lab.sh capture s2
./scripts/lab.sh run s3
./scripts/lab.sh capture s3
```
진행 상태는 현재 azd 환경에 묶인 `evidence/state.json`에 기록되며, 순서를 어기면 첫 단계의 `lab_state.py begin-run`이 거부합니다. 순서와 별개로, 어떤 시나리오든 실행이 `running`이나 `failed`로 남아 있으면 세 시나리오 모두 새 실행이 거부됩니다. 세 시나리오는 Container App 하나를 공유하므로, 끝나지 않은 실행 하나가 남은 실습 전체를 막습니다. 복구 명령은 운영자가 직접 완료해야 합니다.

`run-scenario.sh`와 `capture-scenario.sh`는 `scripts/common.sh`의 `load_lab_config`로 "명시적 환경 변수 > 현재 `azd env get-value` > 허용된 기본값" 순서로 설정을 읽으므로, 고정된 구독이나 리소스 그룹이 스크립트 안에 없습니다. 진행 상태는 현재 azd 환경에 묶인 `evidence/state.json`에 기록되며 순서를 어기면 실행이 거부됩니다. 순서와 별개로, 어떤 시나리오든 실행이 `running`이나 `failed`로 남아 있으면 세 시나리오 모두 새 실행이 거부됩니다. 세 시나리오는 Container App 하나를 공유하므로, 끝나지 않은 실행 하나가 남은 실습 전체를 막습니다. 수동 실행도 첫 단계에서 `lab_state.py begin-run`을 호출해 같은 게이트를 적용받습니다. 차이는 복구입니다. 지름길은 종료 트랩이 장애를 자동으로 되돌리지만, 수동 실행에서는 복구 명령을 직접 완료해야 합니다.
증거 수집에 쓰는 `scripts/query-evidence.sh`는 `scripts/common.sh`의 `load_lab_config`로 "명시적 환경 변수 > 현재 `azd env get-value` > 허용된 기본값" 순서로 설정을 읽으므로, 고정된 구독이나 리소스 그룹이 스크립트 안에 없습니다.

| 시나리오 | 주입하는 장애 | 안내 문서 |
|---|---|---|
Expand All @@ -150,7 +140,7 @@ postprovision 단계가 실패하면 로컬 환경만 실패한 것입니다. `.
## 결과 확인

```bash
./scripts/lab.sh score
app/.venv/bin/python scripts/score.py --evidence-root evidence
```

채점 기준, 사람이 채워야 하는 판정, 종합 판정 해석은 [guides/05-results.md](guides/05-results.md)에 있습니다.
Expand All @@ -166,7 +156,7 @@ azd down --purge
- predown hook `scripts/cleanup-external.sh --yes`: `evidence/agent-setup.json`에 기록된 구독 범위 Monitoring Contributor 할당만 제거합니다. 기록된 principal·역할·범위가 실제 할당과 모두 일치할 때만 삭제하고, 하나라도 어긋나면 아무것도 지우지 않습니다.
- postdown hook `scripts/cleanup-external.sh --reset-image-env --yes`: 기록된 `SRE_CONTAINER_IMAGE`와 `SRE_IMAGE_TAG`를 비웁니다. 삭제가 실제로 성공한 뒤에만 실행되어야 하므로 predown이 아니라 postdown입니다.

중요: predown hook은 `azd down`이 삭제 **확인** 프롬프트를 띄우기 **전에** 실행됩니다. 그 프롬프트에서 **취소**해도 이미 제거된 Monitoring Contributor 할당은 돌아오지 않습니다. 리소스 그룹은 남지만 Agent의 구독 범위 권한은 사라진 상태이므로, 계속 쓰려면 역할 할당을 다시 만들고 `evidence/agent-setup.json`을 새 할당 ID로 직접 갱신한 뒤 `./scripts/lab.sh acknowledge agent-setup`을 실행해야 합니다.
중요: predown hook은 `azd down`이 삭제 **확인** 프롬프트를 띄우기 **전에** 실행됩니다. 그 프롬프트에서 **취소**해도 이미 제거된 Monitoring Contributor 할당은 돌아오지 않습니다. 리소스 그룹은 남지만 Agent의 구독 범위 권한은 사라진 상태이므로, 계속 쓰려면 역할 할당을 다시 만들고 `evidence/agent-setup.json`을 새 할당 ID로 직접 갱신한 뒤 `python3 scripts/lab_state.py acknowledge-agent`를 실행해야 합니다.

hook이 실패해 손으로 다시 실행할 때는 아래를 직접 호출합니다. `--yes` 없이는 계획만 출력합니다.

Expand All @@ -175,11 +165,19 @@ hook이 실패해 손으로 다시 실행할 때는 아래를 직접 호출합
./scripts/cleanup-external.sh --reset-image-env --yes
```

azd 환경을 잃어버린 실습을 정리할 때만 `./scripts/cleanup.sh --legacy-delete-resource-group`으로 예전 삭제 경로를 씁니다. 이 경로도 구독 일치와 태그 확인을 거치며, 첫 명령은 dry-run입니다.
azd 환경을 잃어버려 `azd down`을 쓸 수 없다면 리소스 그룹을 직접 지웁니다. 반드시 태그로 대상을 먼저 확인하세요. 이 실습이 만든 그룹만 두 태그를 모두 가집니다.

```bash
az group list --subscription "${SUBSCRIPTION_ID}" \
--query "[?tags.purpose=='sre-agent-event-lab'].{name:name, env:tags.\"azd-env-name\"}" \
--output table

az group delete --subscription "${SUBSCRIPTION_ID}" --name "${RESOURCE_GROUP}" --yes
```

## 문제 해결

먼저 `./scripts/lab.sh doctor`를 실행해 어떤 검사가 `FAIL`인지 확인하세요. 각 명령의 실패 처리와 복구 절차는 해당 단계 문서에 있습니다.
각 명령의 실패 처리와 복구 절차는 해당 단계 문서에 있습니다.

| 증상 | 확인할 곳 |
|---|---|
Expand Down
50 changes: 40 additions & 10 deletions monitor/sre-agent-event-lab/guides/01-agent-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,26 +182,56 @@ jq -e \
}
```

## 점검과 승인
## 정상 상태 확인과 승인

장애를 주입하기 전에, 정상 상태의 요청이 Application Insights까지 도달하는지 확인합니다. 이 확인이 통과해야 S1을 시작할 수 있습니다. 텔레메트리가 도착하지 않는 워크로드에 장애를 넣으면, 주입한 장애와 원래부터 안 보이던 상태를 구별할 수 없기 때문입니다.

먼저 정상 부하를 넣습니다. 두 엔드포인트 모두 200이어야 합니다.

```bash
EVIDENCE_DIR="${PWD}/evidence/baseline-$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "${EVIDENCE_DIR}"

python3 scripts/loadgen.py "https://${APP_FQDN}/api/orders" \
--requests 30 --concurrency 4 --expect-status 200 \
--output "${EVIDENCE_DIR}/orders.json"

python3 scripts/loadgen.py "https://${APP_FQDN}/api/documents" \
--requests 10 --concurrency 2 --expect-status 200 \
--output "${EVIDENCE_DIR}/documents.json"
```

두 요청 종류가 워크스페이스에 보이는지 확인합니다. 수집에는 보통 2~5분이 걸리므로, 결과가 비어 있으면 잠시 뒤 다시 실행합니다.

```bash
./scripts/lab.sh doctor
./scripts/lab.sh baseline
./scripts/lab.sh acknowledge agent-setup
az monitor log-analytics query \
--workspace "${WORKSPACE_CUSTOMER_ID}" \
--analytics-query "AppRequests | where AppRoleName == '${TELEMETRY_SERVICE_NAME}' | where TimeGenerated > ago(30m) | summarize count() by Name" \
--output table
```

`doctor`가 출력하는 네 줄은 언제나 `MANUAL`입니다. 저장소 연결, 지식 원본, incident platform, 응답 계획을 읽을 수 있는 공식 안정 API가 없기 때문입니다. 나머지 검사에 `FAIL`이 남아 있으면 먼저 해결합니다.
`/api/orders`와 `/api/documents`가 모두 보이면 통과입니다. 그 사실을 기록해야 S1이 열립니다.

```bash
python3 scripts/lab_state.py mark baseline_passed --evidence-dir "${EVIDENCE_DIR}"
```

마지막으로 Agent 설정을 승인합니다. 이 명령은 설정 값을 출력한 뒤 표준 입력으로 정확히 `acknowledge`를 받아야 기록합니다. 어떤 환경 변수로도 대체할 수 없습니다. 값이 하나라도 다르면 그대로 중단하고 위 단계로 돌아가세요.

```bash
python3 scripts/lab_state.py acknowledge-agent
```

`acknowledge agent-setup`은 설정 값을 출력한 뒤 표준 입력으로 정확히 `acknowledge`를 받아야 기록합니다. 어떤 환경 변수로도 대체할 수 없습니다. 값이 하나라도 다르면 그대로 중단하고 위 단계로 돌아가세요.
저장소 연결, 지식 원본, incident platform, 응답 계획은 읽을 수 있는 공식 안정 API가 없으므로 위 표를 보고 포털에서 직접 확인하는 것이 유일한 방법입니다.

## 실패했을 때

| 증상 | 조치 |
|---|---|
| `doctor`의 `Python environment` 검사가 `FAIL` | `app/.venv`가 없거나 Pillow가 안 잡힙니다. 로컬 문제이며 클라우드 배포와는 무관하니 바로 실행: `./scripts/setup-venv.sh` |
| `doctor`의 Reader 검사가 `FAIL` | 두 principal ID가 근거 파일과 같은지 확인하고 리소스 그룹에 Reader를 다시 부여합니다 |
| `baseline`이 telemetry 없음으로 종료 | 10분 더 기다린 뒤 다시 실행합니다. 계속 실패하면 `azd env get-value AZURE_CONTAINER_APP_FQDN`으로 앱을 직접 호출해 봅니다 |
| `acknowledge`가 기록되지 않음 | 입력한 단어가 정확한지, `azd env select`로 올바른 환경을 골랐는지 확인합니다 |
| `app/.venv`가 없음 (다음 문서의 캡처 단계가 Pillow를 씁니다) | `azd up`의 postprovision 단계가 만들어 둡니다. 없거나 깨졌다면 로컬 문제이므로 바로 실행: `./scripts/setup-venv.sh` |
| 두 principal ID로 Reader 권한이 확인되지 않음 | 두 ID가 근거 파일과 같은지 확인하고 리소스 그룹에 Reader를 다시 부여합니다 |
| 쿼리에 요청이 보이지 않음 | 10분 더 기다린 뒤 다시 조회합니다. 계속 비어 있으면 `curl -sS -o /dev/null -w '%{http_code}\n' "https://${APP_FQDN}/healthz"`로 앱을 직접 호출해 봅니다 |
| `acknowledge-agent`가 기록되지 않음 | 입력한 단어가 정확한지, `azd env select`로 올바른 환경을 골랐는지 확인합니다 |
| 경고가 Agent에 도착하지 않음 | Monitoring Contributor 범위가 구독인지, 응답 계획이 `On`인지 확인합니다 |

## 다음 단계
Expand Down
Loading