Kubernetes에서 MCP 서버 중앙화 배포: 아키텍처, 인증 및 비밀 관리
팀 전체에 AI 인프라를 확장할 때 패키지 매니저나 컨테이너를 통해 MCP 서버를 로컬에서 실행하는 것은 빠르게 병목 현상이 됩니다. 분산된 런타임, 통제되지 않은 자격 증명 확산, 단일 진입점 부재는 언어 모델을 기업 환경에 안전하게 통합하는 데 걸림돌이 됩니다. 이 글에서는 sidecar 프록시, JWT 검증, 비밀 오케스트레이션을 활용한 고립된 인스턴스에서 중앙화된 Kubernetes 아키텍처로의 실용적인 이전 경로를 설명합니다.
아키텍처 진화: 로컬 프로세스에서 컨테이너화로
Model Context Protocol 도입 초기 단계에서는 벤더의 기성 원격 엔드포인트를 사용하는 것으로 충분합니다. 클라이언트 앱에서 URL만 지정하면 제공자가 인증과 스케일링을 처리합니다. 하지만 내부 시스템(Kubernetes, Grafana, 데이터베이스) 통합에는 서버를 독립적으로 실행해야 합니다.
로컬 npx, uvx 호출이나 컴파일된 바이너리를 사용하는 표준 접근 방식은 종속성 관리 문제를 일으킵니다. 각 통합마다 자체 런타임이 필요해 버전 충돌이 발생하고, 신규 팀원 온보딩이 복잡해집니다. 프로덕션 액세스 토큰을 로컬 설정 파일에 저장하는 것도 핵심 정보 보안 원칙을 위반합니다.
컨테이너화는 환경 격리를 해결합니다. 각 MCP 서버를 환경 변수 패스스루와 함께 자체 컨테이너에서 실행하면 워크스테이션 수준에서 배포를 표준화할 수 있습니다. 고립된 실행을 위한 예시 설정:
{
"mcpServers": {
"grafana": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-e", "GRAFANA_URL",
"-e", "GRAFANA_SERVICE_ACCOUNT_TOKEN",
"grafana/mcp-grafana",
"-t", "stdio"
],
"env": {
"GRAFANA_URL": "https://grafana.example.com",
"GRAFANA_SERVICE_ACCOUNT_TOKEN": "<token>"
}
}
}
}
더 나은 격리에도 불구하고 로컬 Docker는 공유 액세스를 제공하지 않습니다. 자동화된 파이프라인, CI/CD 시스템, 비기술 사용자들은 흩어진 컨테이너를 효과적으로 다룰 수 없습니다. 이로 인해 MCP 서버를 중앙화된 라이프사이클 관리를 갖춘 공유 인프라로 이전할 필요가 생깁니다.
Kubernetes에서의 오케스트레이션: 프록시 및 범용 배포
MCP 서버를 클러스터로 이전하려면 아키텍처 불일치를 연결해야 합니다. 대부분의 서버는 stdio를 사용하지만 Kubernetes 네트워킹은 HTTP/HTTPS에 의존합니다. MCP Gateway를 활용한 sidecar 패턴이 이 간극을 메웁니다. 프록시 컨테이너는 들어오는 HTTP 요청(Streamable HTTP 또는 SSE)을 처리해 대상 프로세스의 stdin으로 전달하고, 네트워크를 통해 응답을 중계합니다.
Streamable HTTP 모드의 MCP 서버는 상태 비저장 서비스이므로 HPA를 통한 수평 스케일링에 이상적입니다. 통합마다 매니페스트를 중복하지 않도록 두 가지 모드를 지원하는 범용 Helm 차트를 사용하세요:
- proxy — HTTP-to-stdio 변환을 위한 sidecar 컨테이너 실행.
- native — HTTP 전송을 이미 지원하는 서비스 직접 노출.
values.yaml을 통한 배포 설정으로 네트워킹, 비밀 주입, 라우팅을 유연하게 제어할 수 있습니다:
mode: proxy
proxy:
image:
repository: node
tag: "20-bookworm"
pullPolicy: IfNotPresent
gateway:
package: "@michlyn/mcpgateway"
stdioCommand: "npx -y @digitalocean/mcp --services apps,droplets,doks,networking"
outputTransport: streamable-http
port: 8080
httpPath: /mcp
vault:
enabled: true
role: "mcp"
path: "kubernetes_dev-fra1-01"
env:
- name: DIGITALOCEAN_API_TOKEN
value: vault:devops/data/ai/mcp/digitalocean#token
ingress:
enabled: true
className: "internal"
annotations:
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
HashiCorp Vault나 External Secrets Operator와의 통합으로 자격 증명을 버전 제어에서 제외합니다. Ingress 컨트롤러나 Gateway API가 라우팅을 관리하며, 버퍼링 비활성화와 타임아웃 연장으로 장기 연결과 스트리밍 데이터 지원을 보장합니다.
보안 및 인증: JWT, Envoy, 액세스 관리
MCP 프로토콜에는 내장 인증이 없으므로 인프라 게이트웨이에서 보호를 구현해야 합니다. 기본 인증은 기업 보안에 부족하며, Envoy Gateway를 통한 JWT 검증이 최선입니다. 게이트웨이는 요청이 MCP 서버 파드로 도달하기 전에 토큰 서명, 발행자, 청중을 확인합니다.
키와 토큰 생성은 표준 암호 도구를 사용합니다. 공개 키는 Envoy가 로드하고 검증할 수 있도록 ConfigMap에 JWKS로 패키징됩니다:
# Generate RSA keys and form JWT
openssl genrsa -out mcp-jwt-private.pem 4096
openssl rsa -in mcp-jwt-private.pem -pubout -out mcp-jwt-public.pem
KID=$(openssl rand -hex 16)
HEADER=$(echo -n '{"alg":"RS256","typ":"JWT","kid":"${KID}"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
PAYLOAD=$(echo -n '{"sub":"claude-desktop","aud":"mcp-servers","iss":"https://your-domain.com","iat":$(date +%s),"exp":$(( $(date +%s) + 31536000 ))}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
SIGNATURE=$(echo -n "${HEADER}.${PAYLOAD}" | openssl dgst -sha256 -sign mcp-jwt-private.pem | base64 -w0 | tr '+/' '-_' | tr -d '=')
echo "${HEADER}.${PAYLOAD}.${SIGNATURE}"
프로토콜 성숙도 이 단계에서 아키텍처 제한이 여전합니다. 대상 시스템 액세스는 공유 서비스 계정을 사용합니다—읽기에는 괜찮지만 쓰기에는 위험합니다. 최종 사용자 컨텍스트 전송 부재로 사용자별 권한 부여와 상세 도구 호출 감사가 불가능합니다. Envoy 로깅은 네트워크 메타데이터만 캡처하며 MCP 메서드 매개변수는 아닙니다.
주요 요점
- 로컬 MCP 서버 실행은 런타임 충돌과 자격 증명 유출 위험으로 팀 전체 확장이 어렵습니다.
- MCP Gateway를 활용한 sidecar 패턴이 stdio 전송과 Kubernetes 네트워킹 프로토콜을 연결합니다.
- 상태 비저장 Streamable HTTP 아키텍처가 표준 HPA를 통한 자동 수평 스케일링을 지원합니다.
- 프로토콜에 기본 인증이 없으므로 JWT 검증과 라우팅을 API Gateway로 위임하세요.
- MCP에 사용자 컨텍스트가 없어 세밀한 권한 부여와 종단 간 감사가 현재 제한됩니다.
— Editorial Team
아직 댓글이 없습니다.