Files
dap-was-dapms/deploy/examples/axhub-mcp-dev-manual.template.yaml
koseokmin d1d93f7dc9 GitOps 이전까지 쓸 배포 파이프라인과 Portal 모드 Chart를 추가한다
GitOps 저장소도 ArgoCD Application도 아직 없어, 그때까지 이 저장소가
push 방식 파이프라인(.gitea/workflows/)을 임시로 소유한다. 무엇을
포기하는지와 넘길 때 할 일은 deploy/README.md에 적었다.

Chart는 portal과 bundles 두 배포 모델을 모두 렌더링한다. ADR-0013이
ADR-0007을 대체했으므로 운영은 portal이 기준이지만, bundles 경로를
언제 삭제할지는 아직 정하지 않았다.

- .gitea/workflows/ci.yaml, deploy-openshift.yaml
- deploy/ci/render-manifests.sh, deploy/examples/
- Chart: mode 분기, selectedDeployment/tier helper, imagePullSecrets,
  toolService.apiKeySecret 참조
- extension-points.md에 미결 항목 9~12 추가

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 11:02:36 +09:00

278 lines
8.6 KiB
YAML

# 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