# AX HUB MCP 서버 개발계 수동 배포 샘플 # # 주의: # - 이 파일은 Helm template이 아니라, AA와 값을 협의한 뒤 수동으로 적용할 Raw OpenShift YAML 샘플이다. # - "{{대문자_이름}}"은 확정되지 않은 값이다. 모든 자리표시자를 실제 값으로 교체한 뒤 적용한다. # - 비밀번호와 API Key를 담는 Secret 및 그 참조는 현재 사용하지 않으므로 포함하지 않았다. # - Harbor 인증이 필요하면 AA가 별도로 ServiceAccount에 image pull secret을 연결해야 한다. # - 이 파일은 임시 수동 배포용 예제이며, 배포 정의의 정본은 deploy/helm/mcp-server Chart다. # # AA와 협의할 값: # - {{DEV_NAMESPACE}}: MCP 서버를 배포할 개발계 namespace # - {{HARBOR_IMAGE_REPOSITORY}}: Harbor project를 포함한 이미지 경로. 예: harbor.example/axhub/axhub-mcp # - {{IMAGE_TAG}}: AA가 Podman으로 만들어 Push한 이미지 tag # - {{DEV_MCP_HOST}}: 개발계 OpenShift Route host # - {{AGENT_BUILDER_EGRESS_CIDR}}: Route 접근을 허용할 Agent Builder의 고정 egress CIDR # - {{AGENT_BUILDER_NAMESPACE}}: Agent Builder Pod이 있는 namespace # - {{DEV_PORTAL_REGISTRY_URL}}: 개발계 Portal registry API 주소 # - {{REDIS_SERVICE_HOST}}: 개발계 Redis Service host 또는 FQDN # - {{CONFIG_VERSION}}: ConfigMap을 바꿀 때마다 증가시키는 값. 예: 1, 2, 3 # # 적용 전 자리표시자 확인 예시(PowerShell): # Get-Content .\deploy\examples\axhub-mcp-dev-manual.template.yaml | # Where-Object { $_ -notmatch '^\s*#' } | # Select-String -Pattern '\{\{[A-Z0-9_]+\}\}' # # 적용 예시: # oc apply -f .\deploy\examples\axhub-mcp-dev-manual.template.yaml apiVersion: v1 kind: ConfigMap metadata: name: axhub-mcp-config namespace: "{{DEV_NAMESPACE}}" labels: app: axhub-mcp app.kubernetes.io/name: axhub-mcp app.kubernetes.io/instance: axhub-mcp-dev app.kubernetes.io/component: mcp-server app.kubernetes.io/part-of: ax-hub ax-hub/mode: portal ax-hub/tier: critical data: # SPRING_PROFILES_ACTIVE=dev이므로 파일명도 application-dev.yml이어야 한다. application-dev.yml: | management: server: port: 9090 health: redis: enabled: false mcp: # 환경별 Redis key가 서로 겹치지 않도록 개발계 identity를 고정한다. identity: axhub-mcp-dev # Route가 경로를 변경하지 않고 그대로 전달하므로 Route path와 같아야 한다. endpoint-path: "/mcp" registry: refresh-interval-seconds: 30 refresh-jitter-seconds: 5 discovery: enabled: true redis: enabled: true # Portal 조회 실패 시 사용하는 Redis fallback key다. Portal과 같은 key인지 확인한다. portal-registry-key: "axhub:mcp:portal-registry" portal: enabled: true registry-url: "{{DEV_PORTAL_REGISTRY_URL}}" refresh-interval-seconds: 60 # Portal이 route와 Tool Server 주소를 제공하므로 정적 bundle은 두지 않는다. bundles: [] --- apiVersion: apps/v1 kind: Deployment metadata: name: axhub-mcp namespace: "{{DEV_NAMESPACE}}" labels: app: axhub-mcp app.kubernetes.io/name: axhub-mcp app.kubernetes.io/instance: axhub-mcp-dev app.kubernetes.io/component: mcp-server app.kubernetes.io/part-of: ax-hub ax-hub/mode: portal ax-hub/tier: critical spec: # 개발계 임시 테스트이므로 Pod 한 개로 구성한다. replicas: 1 selector: matchLabels: app: axhub-mcp template: metadata: labels: app: axhub-mcp app.kubernetes.io/name: axhub-mcp app.kubernetes.io/instance: axhub-mcp-dev app.kubernetes.io/component: mcp-server app.kubernetes.io/part-of: ax-hub ax-hub/mode: portal ax-hub/tier: critical annotations: # Raw YAML은 Helm checksum을 자동 생성하지 못한다. ConfigMap 변경 시 이 값을 올리면 Pod이 재기동된다. ax-hub/config-version: "{{CONFIG_VERSION}}" spec: terminationGracePeriodSeconds: 45 containers: - name: mcp-server image: "{{HARBOR_IMAGE_REPOSITORY}}:{{IMAGE_TAG}}" imagePullPolicy: IfNotPresent ports: - name: http containerPort: 8080 protocol: TCP - name: management containerPort: 9090 protocol: TCP env: - name: SPRING_PROFILES_ACTIVE value: dev # ConfigMap의 application-dev.yml을 JAR 내부 설정보다 우선 적용한다. - name: SPRING_CONFIG_ADDITIONAL_LOCATION value: file:/opt/app/config/ - name: REDIS_HOST value: "{{REDIS_SERVICE_HOST}}" - name: REDIS_PORT value: "16379" - name: MANAGEMENT_SERVER_PORT value: "9090" volumeMounts: - name: config mountPath: /opt/app/config readOnly: true readinessProbe: httpGet: path: /actuator/health/readiness port: management initialDelaySeconds: 10 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health/liveness port: management initialDelaySeconds: 20 periodSeconds: 20 resources: requests: cpu: 250m memory: 512Mi limits: cpu: "1" memory: 1Gi securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL runAsNonRoot: true seccompProfile: type: RuntimeDefault volumes: - name: config configMap: name: axhub-mcp-config --- apiVersion: v1 kind: Service metadata: name: axhub-mcp namespace: "{{DEV_NAMESPACE}}" labels: app: axhub-mcp app.kubernetes.io/name: axhub-mcp app.kubernetes.io/instance: axhub-mcp-dev app.kubernetes.io/component: mcp-server app.kubernetes.io/part-of: ax-hub ax-hub/mode: portal ax-hub/tier: critical spec: type: ClusterIP selector: app: axhub-mcp ports: - name: http port: 8080 targetPort: http protocol: TCP --- apiVersion: route.openshift.io/v1 kind: Route metadata: name: axhub-mcp namespace: "{{DEV_NAMESPACE}}" labels: app: axhub-mcp app.kubernetes.io/name: axhub-mcp app.kubernetes.io/instance: axhub-mcp-dev app.kubernetes.io/component: mcp-server app.kubernetes.io/part-of: ax-hub ax-hub/mode: portal ax-hub/tier: critical annotations: haproxy.router.openshift.io/timeout: 300s # 이 서버는 자체 인증을 하지 않으므로 반드시 실제 Agent Builder 고정 egress CIDR로 제한한다. haproxy.router.openshift.io/ip_allowlist: "{{AGENT_BUILDER_EGRESS_CIDR}}" spec: host: "{{DEV_MCP_HOST}}" # /mcp/{routeKey} 요청도 prefix match로 이 Route에 들어온다. rewrite는 사용하지 않는다. path: /mcp to: kind: Service name: axhub-mcp weight: 100 port: targetPort: http tls: termination: edge insecureEdgeTerminationPolicy: Redirect wildcardPolicy: None --- # MCP 서버는 자체 인증·인가를 하지 않으므로 NetworkPolicy를 제거하면 안 된다. apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: axhub-mcp-ingress namespace: "{{DEV_NAMESPACE}}" labels: app: axhub-mcp app.kubernetes.io/name: axhub-mcp app.kubernetes.io/instance: axhub-mcp-dev app.kubernetes.io/component: mcp-server app.kubernetes.io/part-of: ax-hub ax-hub/mode: portal ax-hub/tier: critical spec: podSelector: matchLabels: app: axhub-mcp policyTypes: - Ingress ingress: # OpenShift Route를 통과한 요청을 8080 포트로 허용한다. - from: - namespaceSelector: matchLabels: policy-group.network.openshift.io/ingress: "" ports: - protocol: TCP port: 8080 # 같은 클러스터 안에서 Agent Builder가 직접 호출하는 경우만 8080 포트로 허용한다. - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: "{{AGENT_BUILDER_NAMESPACE}}" ports: - protocol: TCP port: 8080 # Actuator management 포트는 OpenShift 관제 namespace에서만 접근하도록 제한한다. - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: openshift-monitoring ports: - protocol: TCP port: 9090