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>
This commit is contained in:
277
deploy/examples/axhub-mcp-dev-manual.template.yaml
Normal file
277
deploy/examples/axhub-mcp-dev-manual.template.yaml
Normal file
@@ -0,0 +1,277 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user