7.6 KiB
배포 정의
이 디렉터리는 배포될 대상을 정의한다. 빌드·이미지·배포 실행 방식은 사내 표준 CI/CD가 담당하며 이 저장소가 정하지 않는다.
Helm Chart
helm/mcp-server/가 유일한 배포 정의다. values는 두 축으로 나뉜다.
| 파일 | 소유하는 것 |
|---|---|
values.yaml |
배포 토폴로지. 어떤 MCP가 어떤 Tool Service를 보는가, 공개 path, 가용성 등급 |
values-{dev,test,prod}.yaml |
환경 차이. namespace, 이미지, 공개 host·허용 CIDR, 등급별 replica·PDB, 리소스 |
설치할 때 두 번째 축을 -f로, 첫 번째 축에서 고를 배포 하나를 --set deploymentKey=로 지정한다.
helm upgrade --install processing-critical-mcp helm/mcp-server -f helm/mcp-server/values-dev.yaml --set deploymentKey=processing-critical -n <namespace>
deploymentKey에는 기본값이 없다. 지정을 빠뜨리면 렌더링 단계에서 멈춘다.
엉뚱한 배포가 조용히 설치되는 것보다 낫다.
공유 host와 배포별 path
ADR-0009에 따라 한 환경은 하나의 공개 host를 사용하고, 각 Helm release는 고유 path의 OpenShift Route를 만든다. Route는 Service만 선택하고 공개 path를 그대로 전달하며, 컨테이너가 같은 path를 직접 처리한다.
https://mcp-dev.apps.example.internal/mcp/processing-critical -> processing-critical-mcp:8080/mcp/processing-critical
https://mcp-dev.apps.example.internal/mcp/information-standard -> information-standard-mcp:8080/mcp/information-standard
공개 URL은 각각 독립된 MCP다. Agent Builder는 URL별로 등록하고 initialize하며, 한 Route나 MCP Pod의 장애가 다른 path의 Deployment로 전파되지 않는다.
MCP 하나는 Tool Service 하나만 본다
ADR-0007의 결정이다. 대상을 늘리는 방법은 bundle 목록을 늘리는 것이 아니라 배포를 하나 더 만드는 것이다.
deployments:
processing-critical:
name: processing-critical-mcp
service: processing-critical-tools # ← 이름만. 주소는 template이 만든다
namePrefix: "processing." # ← 업무 단위. 등급을 넣지 않는다
tier: critical
publicPath: /mcp/processing-critical # ← 환경 host 안에서 유일
배포가 10개든 20개든 파일 수는 늘지 않는다. 전체 매핑을 한 화면에서 검토할 수 있고,
--set으로 고르는 값 하나만 배포마다 달라진다.
MCP Server와 Tool Service는 같은 namespace에 배포하므로 values에는 서비스 이름만 적고 주소는 template이 조립한다. 환경마다 URL을 반복하지 않으므로 오타로 다른 대상을 호출할 수 없다.
identity도 {배포 이름}-{global.env}로 template이 조립한다. 현재 Redis cache 구현이 이 값을
사용하지만, key namespace와 공유 정책은 아직 확정되지 않았다.
가용성 등급
배포를 업무 × 중요도로 나누는 목적은 중요 등급에만 비용을 쓰기 위해서다.
tiers:
critical: { replicas: 3, podDisruptionBudget: true, spreadAcrossNodes: true }
standard: { replicas: 2, podDisruptionBudget: false, spreadAcrossNodes: false }
test와 prod의 critical은 replica 2 이상, PodDisruptionBudget, 노드 분산 설정이 필수다. replica가
1이면 rolling update 중 반드시 공백이 생기고, PDB가 없으면 노드 drain이 마지막 Pod을 내릴 수 있다.
HelmDeploymentContractTest는 values와 template의 정적 규칙을 검사한다. dev는 배포마다 Pod 1개로
운영하므로 이 검사 대상이 아니다.
정적 테스트는 Helm 렌더러를 실행하지 않는다. 실제 배포 파이프라인은 사용하는 환경과 등급별로
helm lint와 helm template을 실행해 병합된 values와 생성 YAML을 확인해야 한다.
helm lint helm/mcp-server -f helm/mcp-server/values-prod.yaml --set deploymentKey=processing-critical
helm template processing-critical-mcp helm/mcp-server -f helm/mcp-server/values-prod.yaml --set deploymentKey=processing-critical
helm template processing-standard-mcp helm/mcp-server -f helm/mcp-server/values-prod.yaml --set deploymentKey=processing-standard
나누는 것만으로 가용성이 생기지는 않는다. 같은 노드 배치, namespace 쿼터, 공통 Redis·클러스터 장애는 분할로 막히지 않는다. 남은 작업은 extension-points.md의 "운영 적용 전 필수 보완"에서 관리한다.
dev에서 MCP에 연결되지 않을 때
먼저 Tool Service가 떠 있는지 확인한다. readiness가 usable snapshot을 요구하므로, Tool Service가 없으면 MCP Pod은 Ready가 되지 못하고 Service endpoint에서 빠진다. dev는 배포마다 Pod 1개라 그 순간 그 MCP로는 아예 연결되지 않는다. "MCP가 죽었다"가 아니라 "읽을 Tool이 없다"는 뜻이다.
kubectl get pod -l app=<배포 이름> # 0/1 Ready이면 이 경우다
kubectl describe pod <pod> # Readiness probe 실패 사유
kubectl port-forward <pod> 9090:9090 # /actuator/toolBundles로 bundle 상태 확인
Tool Service가 뜨면 다음 refresh 주기(기본 30초) 안에 스스로 Ready가 된다. 재기동할 필요가 없다.
/actuator/toolBundles는 management 포트라 NetworkPolicy가 관제 namespace로 제한하므로,
개발자는 위처럼 port-forward로 본다.
확정 전 임시값
values.yaml의 Tool Service 이름·이미지 경로와 values-{env}.yaml의 namespace·공개 host·Route 허용 CIDR은 자리표시자다.
각 파일의 TODO 주석을 참고해 확정 시 교체하고, 존재하지 않는 배포는 deployments에서 삭제한다.
배포 시 알아야 할 앱 제약
아래는 이 애플리케이션의 동작에서 나온 사실이다. 각 항목의 정본은 링크한 문서이며 값을 여기 옮겨 적지 않는다.
| 제약 | 정본 |
|---|---|
| readiness·liveness는 management 포트에서 제공한다 | architecture.md |
| readiness는 첫 Tool 조회 시도 완료 후 usable snapshot이 있을 때만 UP이다 | architecture.md |
terminationGracePeriodSeconds는 Spring drain보다 길어야 한다 |
architecture.md의 요청 시간 예산 |
| NetworkPolicy는 필수다. 비활성화 스위치를 두지 않았다 | ADR-0006 |
| 공개 path는 Route와 컨테이너 endpoint가 동일하게 사용한다 | ADR-0009 |
| Redis key·TTL·공유 정책은 확정 전이다 | extension-points.md |
| bundle은 정확히 하나다 | ADR-0007 |
Route IP allowlist와 NetworkPolicy는 특히 중요하다. 이 서버는 인증·인가를 하지 않으므로 /mcp에
도달할 수 있다는 것이 곧 인가다. Route는 Agent Builder 고정 egress CIDR만 받고, NetworkPolicy는 Route
backend인 ingress controller와 명시한 Agent Builder namespace만 업무 포트에 허용한다.
미확정 항목
배포 정의를 이 저장소가 어디까지 소유하는지, namespace·registry 명명 규칙은 아직 확정되지 않았다. docs/extension-points.md에서 관리한다.