사용자 앱을 위한 관측성 (Observability for User Apps)
사용자가 Fly.io에서 자신의 코드를 실행하도록 플랫폼을 운영할 때, 그 사용자 앱에 대한 실시간 관측성이 있으면 좋아요. 또한 그 앱에서 나오는 로그를 원래 개발자(최종 사용자)에게 다시 스트리밍해서 코드가 무엇을 하는지 볼 수 있게 해줄 수도 있어요. 이 문서는 Fly.io의 NATS 기반 텔레메트리를 활용하는 방법을 알려드려요.
출처: 문서
본문
개요
사용자가 Fly.io에서 자신의 코드를 실행하도록 플랫폼을 운영할 때—사용자별 개발 환경이나 AI/LLM 앱처럼—그 사용자 앱에 대한 실시간 관측성을 갖추는 것이 좋아요. 또한 그 앱에서 나오는 로그를 원래 개발자(여러분의 최종 사용자)에게 다시 스트리밍해서 그들의 코드가 무엇을 하는지 볼 수 있게 해줄 수도 있어요.
Fly.io는 이를 달성하기 위해 사용할 수 있는 NATS 기반 내장 텔레메트리를 제공해요. 대략적으로 말하면, Fly.io는 앱이 stdout에 쓰는 모든 것을 포착해 내부 NATS 로그 스트림으로 보내요. 이 NATS 클러스터 앞에 있는 프록시는 각 조직이 자기 앱의 로그에만 접근할 수 있도록 보장해요. flyctl logs 명령과 웹 대시보드의 "Live Logs" 모두 내부적으로 이 파이프라인을 사용해요. 우리도 같은 시스템을 사용할 수 있어요! 여러분의 Fly 조직의 사설 네트워크 안에서 NATS 클라이언트를 연결하면 로그 subject를 구독하고 실시간으로 필요한 곳 어디든 로그를 스트리밍할 수 있어요.
Fly Telemetry Forwarder 배포하기
여러분 자체 운영팀을 위한 전체적인(bird's-eye) 뷰를 원한다면, Fly는 fly-telemetry라는 오픈소스 참조 앱을 제공해요. 이를 배포하면 여러분의 Fly 조직에 관측성 스택을 빠르게 가동할 수 있어요. 이 앱은 텔레메트리 포워더 역할을 해요. 플랫폼의 NATS 로그(및 메트릭) 스트림을 구독하고 데이터를 저장해 줘요. 여기에는 가벼운 시계열 데이터베이스(메트릭용 VictoriaMetrics, 로그용 VictoriaLogs)와 사전 구성된 대시보드가 있는 Grafana 인스턴스가 포함되어 있어서, 앱의 로그와 메트릭을 시각적으로 탐색할 수 있어요.
빈 디렉터리에서 다음을 실행하세요:
fly launch --from https://github.com/superfly/fly-telemetry \
--yes \
--copy-config \
--org "$ORG" \
--env ORG="$ORG" \
--secret ACCESS_TOKEN="$(fly tokens create readonly "$ORG")" \
--flycast
배포가 끝난 후 WireGuard를 통해 또는 fly proxy로 앱의 사설 URL을 열면 바로 Grafana 대시보드를 볼 수 있어요.
이것은 SRE에게는 편리하지만, 여러분의 최종 사용자에게는 필수적이지 않아요.
Fly 앱 로그를 최종 사용자에게 스트리밍하기
라이브 로그를 사용자에게 바로 스트리밍하면 사용자가 자신의 코드가 무엇을 하는지 알 수 있어요. 개발자는 실시간으로 런타임이 보는 것과 똑같은 것을, 여러분의 제품을 벗어나거나 추가 도구를 설치하지 않고도 볼 수 있어요.
NATS 로그 스트림에 연결하기
모든 Fly 조직은 자기 앱의 로그를 운반하는 NATS에 접근할 수 있어요. 서버는 잘 알려진 주소 [fdaa::3]:4223에서 사용할 수 있어요. 이 엔드포인트에 연결하려면 Fly 네트워크 내부에서 해야 해요. 예를 들어 Fly 앱에서 실행되는 코드(여러분의 텔레메트리 포워더나 라우터 같은)나 WireGuard 연결을 통한 로컬 머신에서 말이죠.
NATS JavaScript 클라이언트를 사용하면 다음과 같이 연결할 수 있어요:
import { connect, StringCodec } from "nats";
const nc = await connect({
servers: "[fdaa::3]:4223",
user: "sandwich-expert", // your Fly org slug (example)
pass: process.env.ACCESS_TOKEN // your Fly access token (read-only)
});
// Now nc is a NATS connection that can subscribe to log subjects.
인증
여러분의 조직에 있는 Fly 앱에서 연결할 때는 액세스 토큰을 제공해야 해요. 수동으로 생성하려면 fly tokens create readonly <org>를 실행하고 이를 앱 시크릿으로 저장하세요. NATS 프록시는 토큰을 비밀번호로, 조직 이름을 사용자 이름으로 받아들여요.
로그 Subject와 필터링
NATS 스트림의 로그는 subject별로 구성돼요. Fly 로그의 subject 형식은 다음과 같아요:
logs.<app_name>.<region>.<machine_id>
예를 들어 panini-786이라는 이름의 앱이 dfw 리전에서 실행 중이라면 logs.panini-786.dfw.d896d7c609dd68 같은 subject를 볼 수 있어요(d896d7c609dd68은 Machine ID예요). NATS 와일드카드를 사용해 다양한 세분화 수준으로 구독할 수 있어요:
| Subject 패턴 | 설명 |
|---|---|
logs.> |
조직의 모든 앱에서 모든 로그 구독 (모든 리전, 모든 Machine) |
logs.<app>.*.> |
특정 앱의 모든 로그 구독 (모든 리전과 Machine에 걸쳐) |
logs.*.<region>.> |
특정 리전의 모든 로그 구독 |
logs.<app>.<region>.<machine> |
단일 Machine 구독 (정확한 전체 subject) |
실제로 특정 사용자 앱의 모든 로그를 스트리밍하려면 logs.<user-app-name>.> subject 패턴을 구독하면 돼요. 그러면 그 앱의 어떤 Machine, 어떤 리전에서 나온 로그 줄이든 포착돼요.
실제 예시
NATstream은 여러분의 Fly 앱에서 나온 로그를 브라우저로 바로 스트리밍하는 참조 앱이에요. 이 앱은 NATS에 연결해 그 이벤트를 Server-Sent Events(SSE)를 사용해 간단한 HTTP /logs 엔드포인트의 라이브 피드로 바꿔요. 개발자들은 별도의 로깅 도구나 Fly CLI 없이도 여러분의 제품에 로그인해 자기 앱의 로그가 실시간으로 흘러가는 것을 볼 수 있어요. 이 앱은 상위 수준의 가벼운 구현을 유지해요. 깊은 프레임워크 복잡성은 없고, Fly의 로그 파이프라인에 연결해 이벤트를 브라우저에 브로드캐스트하는 간단한 예시일 뿐이에요.
이것을 포크해서 여러분 자신의 개발자 대상 라이브 로그 스트리밍 서비스의 기반으로 삼거나, 관련 부분을 뜯어내 NATstream 구현을 가이드로 삼아 기존 앱에 이 로직을 구축할 수 있어요. 더 견고하게는, 사용자별·앱별로 인증과 스트리밍을 처리하는 별도의 로그 "라우터" 앱을 실행할 수도 있어요. 특히 로그를 CLI로 스트리밍할 때 유용해요.
중앙 로그 라우터 서비스 구축하기
Fly의 NATS 텔레메트리 스트림, 여러분의 제품, 그리고 여러분의 개발자 사이에 위치하는 Fly "로그 라우터" 앱을 만들어 보세요. 각 고객이 이미 자신의 Fly 앱을 가지고 있기 때문에, 모든 사용자의 로그가 고유한 subject(logs.<app>.>)에 나타나요. 따라서 멀티테넌시는 설계상 해결돼요. 요청하는 개발자의 앱과 일치하는 subject만 구독하면 사용자 간 데이터가 섞일 일이 없어요.
시작 시 라우터는 조직 범위의 읽기 전용 토큰으로 NATS 연결 하나를 엽니다. 개발자가 여러분의 대시보드나 CLI를 통해 로그인하면, 라우터는 그 사용자를 인증하고 그들의 Fly 앱 이름을 확인한 다음, 아직 듣고 있지 않다면 그 앱의 subject를 구독해요. 로그 항목이 도착하면 라우터는 라이브 채널(보통 웹소켓이나 Server-Sent Events 스트림)을 통해 직접 개발자의 브라우저나 CLI로 전달해요.
라우터 자체는 다음과 같은 작업을 하는 Fly 앱이에요:
- 시작 시 조직 전체 자격 증명으로 NATS 로그 스트림에 연결하기(앞서 보여드린 대로).
- 개발자가 로그 스트리밍을 요청하거나 연결할 때까지 대기하기(예: 개발자가 웹 UI를 열어 자기 앱의 라이브 로그를 보거나, 로그를 보는 명령을 실행).
- 특정 앱의 로그 요청을 받으면 그 앱의 로그 subject 구독하기(아직 구독하지 않았다면).
- 들어오는 로그 메시지를 요청한 개발자에게 실시간으로 스트리밍하기.
- 각 개발자가 자기 앱의 로그만 받도록 보장하기. 라우터는 app ← → user 매핑을 사용해 올바른 데이터를 올바른 출력 채널에 게시해야 해요(서로 다른 사용자의 데이터를 섞지 말아야 해요).
이 접근 방식은 사용자 앱당 하나의 NATS 구독을 사용해요. 이 경우 메시지는 사용자의 웹소켓에 그대로(JSON 문자열로) 전달되지만, 보내기 전에 변환할 수도 있어요(예: 보기 좋게 포맷하거나 특정 내부 로그를 걸러내는). 클라이언트 쪽에서는 웹소켓이나 SSE 스트림을 읽어 콘솔 뷰에 새 로그 줄을 추가하기만 하면 돼요.
관련 읽을거리
- 로깅 개요 여러분의 Fly 앱에서 플랫폼의 NATS 파이프라인으로 로그가 어떻게 흘러가는지에 대한 내용이에요.
- Logs API 옵션 구조화된 로그에 프로그램적으로 직접 접근하는 방법들을 다루는 가이드예요.
- fly-telemetry Fly.io 배포에 대해 빠르고 즉시 사용 가능한 관측성을 제공하는 가벼운 참조 구현이에요.