Powrót do strony głównej

Wdrożenie serwerów MCP w Kubernetes: architektura i JWT

Artykuł opisuje migrację serwerów MCP od lokalnego uruchamiania do scentralizowanej infrastruktury w Kubernetes. Omawiane są wzorce proxywania sidecar, konfiguracja uwierzytelniania JWT przez Envoy i zarządzanie sekretami za pomocą Vault.

Jak wdrożyć serwery MCP w Kubernetes dla całego zespołu
Advertisement 728x90

# Centralizowane wdrażanie serwerów MCP w Kubernetes: architektura, uwierzytelnianie i zarządzanie sekretami

Lokalne uruchamianie serwerów MCP za pomocą menedżerów pakietów lub kontenerów szybko staje się wąskim gardłem przy skalowaniu infrastruktury AI na cały zespół. Rozproszone środowiska uruchomieniowe, niekontrolowane rozprzestrzenianie danych logowania i brak jednolitego punktu dostępu blokują bezpieczną integrację modeli językowych w środowisku firmowym. W artykule przedstawiono praktyczną ścieżkę migracji od izolowanych instancji do scentralizowanej architektury w Kubernetes z wykorzystaniem wzorca sidecar-proxy, walidacji JWT i orkiestracji sekretów.

Ewolucja architektury: od lokalnych procesów do konteneryzacji

Na początkowym etapie wdrożenia Model Context Protocol wystarczy korzystać z gotowych zdalnych endpointów od dostawców. Konfiguracja sprowadza się do podania URL w aplikacji klienckiej, a kwestie uwierzytelniania i skalowania przejmuje dostawca. Jednak przy podłączaniu wewnętrznych systemów (Kubernetes, Grafana, bazy danych) pojawia się potrzeba samodzielnego uruchamiania serwerów.

Standardowe podejście z lokalnym wywołaniem npx, uvx lub skompilowanych plików binarnych powoduje problemy z zarządzaniem zależnościami. Każda integracja wymaga osobnego środowiska uruchomieniowego, co prowadzi do konfliktów wersji i komplikuje onboarding nowych pracowników. Ponadto przechowywanie tokenów dostępu do środowisk produkcyjnych w lokalnych plikach konfiguracyjnych narusza podstawowe zasady bezpieczeństwa informacji.

Google AdInline article slot

Konteneryzacja rozwiązuje problem izolacji środowiska. Uruchamianie każdego serwera MCP w osobnym kontenerze z przekazywaniem zmiennych środowiskowych pozwala na standaryzację wdrożeń na poziomie jednej stacji roboczej. Przykładowa konfiguracja dla izolowanego uruchomienia:

{
  "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>"
      }
    }
  }
}

Mimo poprawy izolacji lokalny Docker nie rozwiązuje problemu współdzielonego dostępu. Zautomatyzowane potoki, systemy CI/CD i specjaliści nietechniczni nie mogą efektywnie współpracować z rozproszonymi kontenerami. Pojawia się potrzeba przeniesienia serwerów MCP do wspólnej infrastruktury ze scentralizowanym zarządzaniem cyklem życia.

Orkiestracja w Kubernetes: proxy i uniwersalne wdrażanie

Przeniesienie serwerów MCP do klastra wymaga rozwiązania niezgodności architektonicznej: większość serwerów działa przez stdio, podczas gdy interakcje sieciowe w Kubernetes opierają się na HTTP i HTTPS. Aby zniwelować tę lukę, stosuje się wzorzec sidecar z MCP Gateway. Kontener proxy odbiera przychodzące żądania HTTP (Streamable HTTP lub SSE), przekłada je na standardowy strumień wejściowy docelowego procesu i zwraca odpowiedź z powrotem do sieci.

Google AdInline article slot

Ponieważ serwery MCP w trybie Streamable HTTP są usługami stateless, idealnie nadają się do poziomego skalowania za pomocą HPA. Aby uniknąć dublowania manifestów dla każdej integracji, warto użyć uniwersalnego Helm charta obsługującego dwa tryby pracy:

  • proxy — uruchomienie kontenera sidecar do translacji HTTP na stdio.
  • native — bezpośrednie eksponowanie usług już obsługujących transport HTTP.

Konfiguracja wdrożenia przez values.yaml pozwala elastycznie zarządzać ustawieniami sieciowymi, przekazywaniem sekretów i routingiem:

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"

Integracja z HashiCorp Vault lub External Secrets Operator zapewnia, że dane logowania nie trafiają do systemu kontroli wersji. Kontroler Ingress lub Gateway API obsługuje routing, a wyłączenie buforowania oraz zwiększenie timeoutów jest niezbędne dla poprawnego działania długotrwałych połączeń i transmisji strumieniowej danych.

Google AdInline article slot

Bezpieczeństwo i uwierzytelnianie: JWT, Envoy i zarządzanie dostępem

Brak wbudowanych mechanizmów uwierzytelniania w samym protokole MCP wymaga wdrożenia ochrony na poziomie infrastrukturalnej bramy. Podstawowe uwierzytelnianie nie zapewnia wystarczającego poziomu bezpieczeństwa w środowisku korporacyjnym, dlatego optymalnym rozwiązaniem jest walidacja JWT przez Envoy Gateway. Brama weryfikuje podpis tokena, wydawcę i odbiorcę, zanim żądanie dotrze do poda z serwerem MCP.

Generowanie kluczy i tokenów odbywa się za pomocą standardowych narzędzi kryptograficznych. Klucz publiczny jest pakowany w format JWKS i umieszczany w ConfigMap, skąd Envoy pobiera go do weryfikacji:

# Generate RSA keys and create a 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}"

Na obecnym etapie rozwoju protokołu pozostaje kilka ograniczeń architektonicznych. Dostęp do systemów docelowych odbywa się za pośrednictwem jednolitych kont serwisowych, co jest akceptowalne dla operacji odczytu, ale stwarza ryzyka przy operacjach zapisu. Protokół nie przekazuje kontekstu użytkownika końcowego, co uniemożliwia wdrożenie autoryzacji użytkownika i szczegółowego audytu wywołań narzędzi. Logowanie na poziomie Envoy rejestruje tylko metadane sieciowe, ale nie parametry wywołań konkretnych metod MCP.

Co ważne

  • Lokalne uruchamianie serwerów MCP nie skaluje się na zespół z powodu konfliktów środowisk uruchomieniowych i ryzyka wycieku danych logowania.
  • Wzorzec sidecar z MCP Gateway rozwiązuje problem niezgodności transportu stdio i protokołów sieciowych Kubernetes.
  • Architektura stateless Streamable HTTP pozwala na użycie standardowego HPA do automatycznego poziomego skalowania.
  • Walidację JWT i routing należy przenosić na poziom API Gateway, ponieważ sam protokół nie zawiera mechanizmów uwierzytelniania.
  • Brak przekazywania kontekstu użytkownika w MCP na razie ogranicza możliwości granularnej autoryzacji i audytu end-to-end.

— Editorial Team

Advertisement 728x90

Czytaj dalej