콘텐츠로 이동

인프라

1. 개요

mayu·inferplaned를 각각 정적 바이너리로 빌드해 별도의 distroless 이미지로 배포합니다. 게이트웨이 Helm 차트는 ConfigMap 설정과 선택적 Bedrock IRSA ServiceAccount를 구성합니다.

2. 구성 요소

구성 경로 역할
Dockerfile Dockerfile CGO_ENABLED=0 다단계 빌드와 비루트 distroless
제어 영역 Dockerfile Dockerfile.inferplaned 별도 정적 inferplaned 이미지
Docker 제외 .dockerignore 테스트·문서·차트 빌드 컨텍스트 제외
Helm 차트 charts/inferplane/ Deployment, 데이터·관리 Service, 계정, ConfigMap, 선택적 정책 ConfigMap·Ingress·PVC, NOTES
GovernancePolicy CRD deploy/crd/ v1alpha1 구조 스키마·CEL, Kubernetes 1.25+. 컨트롤러 watch는 후속 과제
차트 값 charts/inferplane/values.yaml 이미지, 로컬=1·공유 다중 복제, Secret·IRSA·Ingress·영속성·OTLP 예제
Grafana deploy/grafana/inferplane.json 패널 9개의 Prometheus 대시보드
제품 문서 mkdocs.yml, docs/assets/, scripts/docs_hooks.py Material·static-i18n, 한영 가이드·메뉴·검색·저장소 링크
문서 전달 .github/workflows/docs.yml 엄격한 빌드, 번역 누락·최신성, 링크 검증. 제한된 배포 권한으로 main의 Pages 게시

3. 주요 결정

  • Go 1.26.10 이상으로 빌드하며, 두 Docker 빌더는 1.26.10으로 고정합니다. golang.org/x/net v0.60.0의 HTTP/2 보안 수정은 Go 1.26 이상을 요구합니다.
  • CGO를 끈 정적 바이너리여서 libc 없이 비루트 distroless 실행이 가능합니다.
  • 관리 콘솔 정적 자산은 go:embed로 바이너리에 포함됩니다(ADR-001).
  • 설정 재로드: 설정 수정 후 kill -HUP <pid>로 공급자·모델·가격을 원자적으로 교체합니다. 거버넌스 카운터·키·감사는 유지하고 오류 시 이전 설정을 유지합니다. 리스너·TLS·드레인·팀 정책 한도는 재시작이 필요합니다.
  • 차트는 기본 설정의 해시를 Pod 템플릿에 넣으므로 재시작이 필요한 설정을 Helm으로 변경하면 Pod가 교체됩니다. 별도 정책 파일은 계속 감시합니다. 기본 관리 토큰 참조는 기존 Secret의 INFERPLANE_ADMIN_TOKEN을 읽습니다. 다른 인증 구성에는 server.admin_auth를 명시적으로 교체하세요.
  • 게이트웨이 startup probe는 동기 재생에 기본 10분을 허용한 뒤 liveness 검사를 시작합니다. 보관 이력에 맞춰 startupProbe를 조정하세요. Pod fsGroup은 기본 65532이며 nonroot 데이터 볼륨 쓰기 권한에 사용합니다. 기존 PVC·CSI 드라이버도 해당 소유권을 지원해야 합니다.
  • 형식이 정의된 설정은 알 수 없는 필드, 음수 한도, 잘못된 on_exceeded, 범위를 벗어난 금전 한도를 거부합니다. 비활성 주석 _comment, _comment_*, _*_example은 허용하며 맵 이름·분류기 옵션은 자유 형식입니다. 0이 아닌 quota.tokens_per_month는 지원하지 않습니다. 월별 tokenQuota 집행은 공유 Postgres 프로파일이 필요합니다.
  • mayu config validate --config config.json은 LoadRaw를 통해 오프라인 스키마·비밀 참조를 검증합니다. 런타임 저장소를 열거나 공급자·AWS 자격 증명을 구성하거나 업스트림에 접속하지 않습니다. 선언이 유효해도 런타임 준비 상태를 증명하지 않으며 해당 의존성은 serve에서 검사합니다.
  • 두 게이트웨이 리스너에는 요청 헤더를 읽는 10초 제한이 있습니다. 긴 SSE 스트림을 끊는 전체 응답 시간 제한은 없습니다.
  • server.max_request_bytes(기본 64 MiB)는 요청 본문 하나를 제한합니다. server.max_inflight_request_bytes(기본 0, 꺼짐. 켜면 요청당 한도 이상)는 모든 데이터 영역 요청이 동시에 보유하는 본문 바이트를 제한합니다. 요청마다 Content-Length만큼, 길이를 선언하지 않으면 요청당 한도 전체를 핸들러가 끝날 때까지 예약하며 스트림은 끝날 때까지 유지합니다. 들어가지 못한 생성 요청은 수신 형식의 503과 Retry-After: 2를 받고, count 요청은 4바이트당 1토큰의 로컬 추정치로 HTTP 200을 유지합니다. 수신 경로는 본문마다 여러 사본을 보유하므로(2026-10-27 실측 약 5.5배) 예산은 (메모리 한도 − 유휴 RSS) / 6로 잡고 GOMEMLIMIT과 컨테이너·systemd 메모리 한도도 설정하세요. 본문이 느리게 도착하거나 멈춘 요청은 본문이 끝나거나 클라이언트가 포기하거나 연결이 닫힐 때까지 예약을 유지하므로(본문 읽기 제한 시간은 없습니다) 예산은 server.max_request_bytes의 여러 배로 잡으세요. 같은 값이면 멈춘 업로드 하나가 다른 모든 요청을 거부하게 만듭니다. inferplane_inflight_refusals_total{route}를 확인하세요.
  • 로컬 기본은 복제본 하나입니다. ADR-046 공유 Postgres는 여러 게이트웨이를 지원하며 차트가 잘못된 로컬 복제를 거부합니다. 영속 공유는 독립 PVC의 StatefulSet·필수 안티어피니티·중단 예산입니다. 공유 거버넌스를 참고하세요.
  • 영속성: 로컬은 기존 Deployment·PVC 동작, 공유는 키·카운터를 Postgres에 두고 복제본별 PVC에 감사 구간을 저장합니다. WAL을 공유하지 마세요.
  • 차트는 existingSecret만 참조하고 비밀을 만들지 않습니다.
  • Ingress는 기본 비활성입니다. 켜더라도 관리 경로는 ingress.admin.enabled: true를 추가로 지정해야 합니다. 데이터 영역 활성화가 관리 노출을 자동으로 허용하지 않습니다.
  • 수집 신호 다섯 가지(OTLP는 둘): 메트릭은 :9090/metrics Prometheus이며 OTLP 메트릭 내보내기는 없습니다. 중복 계측·원장 불일치를 피하기 위함입니다. gen_ai_* 이름도 전송은 Prometheus입니다. 트레이스는 선택적 config.otel과 traces를 허용한 정책 기반 exporter가 HTTP 4318·gRPC 4317로 전송합니다. GenAI, 캐시 read/5m/1h, 정수 비용·가격 누락, 부분 스트림 필드를 포함합니다. HTTP 200을 이미 보낸 부분 스트림도 span은 Error입니다. 정책 기반 로그는 config.observability.exporters에 선언된 exporter가 observability 정책 규칙이 고른 팀·사용자의 감사 기록 사본과 송신 본문을 OTLP 로그(/v1/logs 또는 gRPC logs 서비스)로 보냅니다. 최선 노력이고 크기가 제한되며, 증거의 원본은 WAL 체인입니다(정책 기반 내보내기). 선택적 observability.console 블록은 state_file(mayu가 쓰는 런타임 내보내기 한도)과 policy_file(콘솔이 소유하는 observability 규칙, policies 항목에도 포함되어야 하며 control_plane과 함께 쓸 수 없음)을 지정하며, 둘 다 쓰기 가능한 볼륨에 있어야 합니다. 차트는 데이터 볼륨을 /var/lib/inferplane에 마운트하고(persistence.enabled가 아니면 emptyDir), /etc/inferplane/policies의 policies ConfigMap 마운트는 읽기 전용입니다. 두 파일은 콘솔 카운터와 마찬가지로 mayu 프로세스 하나에 속합니다. 복제본이 둘 이상이면 편집은 그 요청을 처리한 복제본에만 적용되고(상태 응답의 instance가 그 복제본을 나타냄), 기본 emptyDir에서는 새로 만든 파드가 파일 없이 시작해 일시 중지가 풀립니다. state_file을 설정했다면 persistence.enabled를 켜고(공유 프로필에서는 복제본마다 클레임 하나를 만듦), 편집 대상마다 복제본을 하나만 두거나 복제본마다 편집하세요. 사용량 윈도는 inferplaned /v1alpha1/usage의 자체 프로토콜이며 OTLP 수신기가 처리하지 않습니다. 감사 기록은 차트 기본값이 컨테이너 stdout(최선 노력 저장 대상, WAL은 데이터 볼륨, 로컬 분석 인덱스 비활성)으로 내보내며, 노드 collector의 filelog 수신기가 컨테이너 로그를 읽어 본문을 다시 직렬화하지 않고 그대로 내보냅니다. 해시 체인이 줄의 정확한 바이트를 기준으로 하기 때문입니다(예제, 수집).
  • 수집기에 메트릭·트레이스·감사 로그 파이프라인과 각각 batch 처리기를 구성하세요. 메트릭은 인증이 없고 비밀·key_id가 없지만 비용 정보이므로 클러스터 내부에 둡니다. 차트는 운영자 모니터링 스택의 CRD인 ServiceMonitor·PodMonitor를 제공하지 않으며 이름이 admin인 포트로 수집하면 됩니다.
  • NOTES.txt는 실제 Ingress 주소 또는 port-forward, 첫 키 명령, Claude Code 환경 변수를 출력해 values에서 다시 계산하지 않고 시작할 수 있게 합니다.

4. 코드 위치

  • Dockerfile: 빌드·런타임 단계.
  • charts/inferplane/templates/deployment.yaml: Pod와 8080·9090 포트.
  • charts/inferplane/templates/configmap.yaml: config.json 렌더링.
  • charts/inferplane/templates/ingress.yaml: 선택적 데이터·관리 Ingress.
  • charts/inferplane/templates/pvc.yaml: 로컬 키 저장소 영속 볼륨.
  • charts/inferplane/templates/NOTES.txt: 설치 후 빠른 시작.

5. 관련 문서

라우팅 배포 · ADR-043

sensitiveData·context 활성화 전에 모든 mayu, inferplaned, 사용하는 CRD를 업그레이드합니다. 경로·가격·검증된 경계와 기능을 먼저 설치하세요. 로컬 정책은 토폴로지 조립 후 리스너 시작 전에, CP ApplyWire는 각 데이터 영역에서 목적지를 검사합니다. 첫 요청부터 보호하려면 require_sync, 정책 나이 제한에는 max_policy_age를 사용합니다. 준비되지 않거나 오래된 상태에서도 계산은 로컬/200입니다. 빠른 시작 디렉터리 대신 독립 policy-routing 예제를 사용하세요. Shadow는 컨텍스트 선호에만 적용하고 개인정보는 이미 집행합니다. 이 라우팅 기능만으로 HA·내구성이 좋아지는 것은 아닙니다. 운영자 가이드를 참고하세요.

ADR-044의 정책 결정·유한 어피니티는 로컬입니다. 기본 결정적 검사는 네트워크 의존성이 없지만 선택적 HTTP 분류기는 엔드포인트 가용성·시간 제한에 의존하며 Enforce에서 onUninspectable을 적용합니다. 폴백은 승인된 개인정보·비용 제약 안에서만 동작합니다. CP 장애 중에도 유효 권한이 있는 동안 설치된 규칙을 쓰며 만료된 하드 리스는 거부합니다. ADR-045는 Postgres 전역 금전 권한, 교체 가능한 CP 복제본, 비공개 영속 노드 저널을 추가합니다. CP 준비 상태는 DB를 검사하고 데이터 영역은 장애 중 이미 확정된 유한 잔액만 유지합니다. 복제 DB와 안정적인 CP 주소를 운영하세요. ADR-045는 로컬 키·요청률·토큰을 전역화하지 않으며 별도 동기 공유 승인은 ADR-046입니다. 배포·실패 동작을 참고하세요.