🧱(mcp) add server deployment

Provide the helm chart declaration to deploy the MCP server.
This commit is contained in:
Quentin BEY
2025-05-28 11:29:38 +02:00
parent 83d8478b5d
commit c1a591fb4f
7 changed files with 419 additions and 3 deletions
+10 -1
View File
@@ -39,10 +39,19 @@ docker_build(
]
)
docker_build(
'localhost:5001/impress-mcp-server:latest',
context='../src/mcp_server',
dockerfile='../src/mcp_server/Dockerfile',
)
k8s_resource('impress-docs-backend-migrate', resource_deps=['postgres-postgresql'])
k8s_resource('impress-docs-backend-createsuperuser', resource_deps=['impress-docs-backend-migrate'])
k8s_resource('impress-docs-backend', resource_deps=['impress-docs-backend-migrate'])
k8s_yaml(local('cd ../src/helm && helmfile -n impress -e dev template .'))
# helmfile in docker mount the current working directory and the helmfile.yaml
# requires the keycloak config in another directory
k8s_yaml(local('cd .. && helmfile -n impress -e ${DEV_ENV:-dev} template --file ./src/helm/helmfile.yaml'))
migration = '''
set -eu
+25 -2
View File
@@ -29,19 +29,25 @@ backend:
DJANGO_EMAIL_PORT: 1025
DJANGO_EMAIL_USE_SSL: False
LOGGING_LEVEL_HANDLERS_CONSOLE: ERROR
LOGGING_LEVEL_LOGGERS_ROOT: INFO
LOGGING_LEVEL_LOGGERS_APP: INFO
LOGGING_LEVEL_LOGGERS_ROOT: DEBUG
LOGGING_LEVEL_LOGGERS_APP: DEBUG
OIDC_USERINFO_SHORTNAME_FIELD: "given_name"
OIDC_USERINFO_FULLNAME_FIELDS: "given_name,usual_name"
OIDC_OP_URL: https://keycloak.127.0.0.1.nip.io/realms/people
OIDC_OP_JWKS_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/certs
OIDC_OP_AUTHORIZATION_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/auth
OIDC_OP_TOKEN_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/token
OIDC_OP_USER_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/userinfo
OIDC_OP_LOGOUT_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/logout
OIDC_OP_INTROSPECTION_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/token/introspect
OIDC_RP_CLIENT_ID: impress
OIDC_RP_CLIENT_SECRET: ThisIsAnExampleKeyForDevPurposeOnly
OIDC_RP_SIGN_ALGO: RS256
OIDC_RP_SCOPES: "openid email"
OIDC_RS_CLIENT_ID: impress
OIDC_RS_CLIENT_SECRET: ThisIsAnExampleKeyForDevPurposeOnly
OIDC_RS_SIGNING_ALGO: RS256
OIDC_RS_SCOPES: "openid,profile,email"
LOGIN_REDIRECT_URL: https://impress.127.0.0.1.nip.io
LOGIN_REDIRECT_URL_FAILURE: https://impress.127.0.0.1.nip.io
LOGOUT_REDIRECT_URL: https://impress.127.0.0.1.nip.io
@@ -171,3 +177,20 @@ ingressMedia:
serviceMedia:
host: minio.impress.svc.cluster.local
port: 9000
mcpServer:
replicas: 1
image:
repository: localhost:5001/impress-mcp-server
pullPolicy: Always
tag: "latest"
envVars:
DOCS_API_URL: https://impress.127.0.0.1.nip.io/
SERVER_TRANSPORT: STREAMABLE_HTTP
ingressMcpServer:
enabled: true
host: impress.127.0.0.1.nip.io
+9
View File
@@ -178,6 +178,15 @@ Requires top level scope
{{ include "impress.fullname" . }}-celery-worker
{{- end }}
{{/*
Full name for the MCP server
Requires top level scope
*/}}
{{- define "impress.mcpServer.fullname" -}}
{{ include "impress.fullname" . }}-mcp-server
{{- end }}
{{/*
Usage : {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" .Values.path.to.the.image1) }}
*/}}
@@ -0,0 +1,89 @@
{{- if .Values.ingressMcpServer.enabled -}}
{{- $fullName := include "impress.fullname" . -}}
{{- if and .Values.ingressMcpServer.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingressMcpServer.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingressMcpServer.annotations "kubernetes.io/ingress.class" .Values.ingressMcpServer.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}-mcp-server
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.labels" . | nindent 4 }}
{{- with .Values.ingressMcpServer.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingressMcpServer.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingressMcpServer.className }}
{{- end }}
{{- if .Values.ingressMcpServer.tls.enabled }}
tls:
{{- if .Values.ingressMcpServer.host }}
- secretName: {{ .Values.ingressMcpServer.tls.secretName | default (printf "%s-tls" $fullName) | quote }}
hosts:
- {{ .Values.ingressMcpServer.host | quote }}
{{- end }}
{{- range .Values.ingressMcpServer.tls.additional }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- if .Values.ingressMcpServer.host }}
- host: {{ .Values.ingressMcpServer.host | quote }}
http:
paths:
- path: {{ .Values.ingressMcpServer.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.mcpServer.fullname" . }}
port:
number: {{ .Values.mcpServer.service.port }}
{{- else }}
serviceName: {{ include "impress.mcpServer.fullname" . }}
servicePort: {{ .Values.mcpServer.service.port }}
{{- end }}
{{- with .Values.ingressMcpServer.customBackends }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}
{{- range .Values.ingressMcpServer.hosts }}
- host: {{ . | quote }}
http:
paths:
- path: {{ $.Values.ingressMcpServer.path | quote }}
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: Prefix
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ include "impress.mcpServer.fullname" $ }}
port:
number: {{ $.Values.mcpServer.service.port }}
{{- else }}
serviceName: {{ include "impress.mcpServer.fullname" $ }}
servicePort: {{ $.Values.mcpServer.service.port }}
{{- end }}
{{- with $.Values.ingressMcpServer.customBackends }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}
{{- end }}
@@ -0,0 +1,153 @@
{{- $envVars := include "impress.common.env" (list . .Values.mcpServer) -}}
{{- $fullName := include "impress.mcpServer.fullname" . -}}
{{- $component := "mcp-server" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
annotations:
{{- with .Values.mcpServer.dpAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
replicas: {{ .Values.backend.replicas }}
selector:
matchLabels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
template:
metadata:
annotations:
{{- with .Values.backend.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
spec:
{{- if $.Values.image.credentials }}
imagePullSecrets:
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
{{- end}}
shareProcessNamespace: {{ .Values.backend.shareProcessNamespace }}
containers:
{{- with .Values.mcpServer.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ (.Values.mcpServer.image | default dict).repository }}:{{ (.Values.mcpServer.image | default dict).tag }}"
imagePullPolicy: {{ (.Values.mcpServer.image | default dict).pullPolicy }}
{{- with .Values.mcpServer.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.mcpServer.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
{{- if $envVars}}
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.mcpServer.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.mcpServer.service.targetPort }}
protocol: TCP
{{- if .Values.mcpServer.probes.liveness }}
livenessProbe:
{{- include "impress.probes.abstract" (merge .Values.mcpServer.probes.liveness (dict "targetPort" .Values.mcpServer.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.mcpServer.probes.readiness }}
readinessProbe:
{{- include "impress.probes.abstract" (merge .Values.mcpServer.probes.readiness (dict "targetPort" .Values.mcpServer.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.mcpServer.probes.startup }}
startupProbe:
{{- include "impress.probes.abstract" (merge .Values.mcpServer.probes.startup (dict "targetPort" .Values.mcpServer.service.targetPort )) | nindent 12 }}
{{- end }}
{{- with .Values.mcpServer.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
mountPath: {{ $value.path }}
subPath: content
{{- end }}
{{- range $name, $volume := .Values.mcpServer.persistence }}
- name: "{{ $name }}"
mountPath: "{{ $volume.mountPath }}"
{{- end }}
{{- range .Values.mcpServer.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- with .Values.mcpServer.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.mcpServer.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.mcpServer.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- range $index, $value := .Values.mountFiles }}
- name: "files-{{ $index }}"
configMap:
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
{{- end }}
{{- range $name, $volume := .Values.mcpServer.persistence }}
- name: "{{ $name }}"
{{- if eq $volume.type "emptyDir" }}
emptyDir: {}
{{- else }}
persistentVolumeClaim:
claimName: "{{ $fullName }}-{{ $name }}"
{{- end }}
{{- end }}
{{- range .Values.mcpServer.extraVolumes }}
- name: {{ .name }}
{{- if .existingClaim }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- else if .hostPath }}
hostPath:
{{ toYaml .hostPath | nindent 12 }}
{{- else if .csi }}
csi:
{{- toYaml .csi | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
---
{{ if .Values.mcpServer.pdb.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
spec:
maxUnavailable: 1
selector:
matchLabels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
{{ end }}
@@ -0,0 +1,21 @@
{{- $envVars := include "impress.common.env" (list . .Values.mcpServer) -}}
{{- $fullName := include "impress.mcpServer.fullname" . -}}
{{- $component := "mcp-server" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
annotations:
{{- toYaml $.Values.mcpServer.service.annotations | nindent 4 }}
spec:
type: {{ .Values.mcpServer.service.type }}
ports:
- port: {{ .Values.mcpServer.service.port }}
targetPort: {{ .Values.mcpServer.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}
+112
View File
@@ -50,6 +50,31 @@ ingress:
## @param ingress.customBackends Add custom backends to ingress
customBackends: []
## @param ingressMcpServer.enabled whether to enable the Ingress or not
## @param ingressMcpServer.className IngressClass to use for the Ingress
## @param ingressMcpServer.host Host for the Ingress
## @param ingressMcpServer.path Path to use for the Ingress
ingressMcpServer:
enabled: false
className: null
host: impress.example.com
path: /mcp/docs/
## @param ingressMcpServer.hosts Additional host to configure for the Ingress
hosts: []
# - chart-example.local
## @param ingressMcpServer.tls.enabled Weather to enable TLS for the Ingress
## @param ingressMcpServer.tls.secretName Secret name for TLS config
## @skip ingressMcpServer.tls.additional
## @extra ingressMcpServer.tls.additional[].secretName Secret name for additional TLS config
## @extra ingressMcpServer.tls.additional[].hosts[] Hosts for additional TLS config
tls:
enabled: true
secretName: null
additional: []
## @param ingressMcpServer.customBackends Add custom backends to ingress
customBackends: []
## @param ingressCollaborationWS.enabled whether to enable the Ingress or not
## @param ingressCollaborationWS.className IngressClass to use for the Ingress
## @param ingressCollaborationWS.host Host for the Ingress
@@ -348,6 +373,93 @@ backend:
timeoutSeconds: 5
## @section mcpServer
mcpServer:
## @param mcpServer.image.repository Repository to use to pull impress's MCP server container image
## @param mcpServer.image.tag impress's MCP server container tag
## @param mcpServer.image.pullPolicy MCP server container image pull policy
image:
repository: lasuite/impress-mcp-server
pullPolicy: IfNotPresent
tag: "latest"
## @param mcpServer.command Override the MCP server container command
command: []
## @param mcpServer.args Override the backend container args
args: []
## @param mcpServer.envVars Configure MCP server container environment variables
envVars: []
## @param mcpServer.replicas Amount of backend replicas
replicas: 3
## @param mcpServer.podAnnotations Annotations to add to the MCP server Pod
podAnnotations: {}
## @param mcpServer.dpAnnotations Annotations to add to the MCP server Deployment
dpAnnotations: {}
## @param mcpServer.sidecars Add sidecars containers to MCP server deployment
sidecars: []
## @param mcpServer.securityContext Configure MCP server Pod security context
securityContext: null
## @param mcpServer.service.type frontend Service type
## @param mcpServer.service.port frontend Service listening port
## @param mcpServer.service.targetPort frontend container listening port
## @param mcpServer.service.annotations Annotations to add to the frontend Service
service:
type: ClusterIP
port: 80
targetPort: 4200
annotations: {}
## @param mcpServer.probes Configure probe for frontend
## @extra mcpServer.probes.liveness.path Configure path for frontend HTTP liveness probe
## @extra mcpServer.probes.liveness.targetPort Configure port for frontend HTTP liveness probe
## @extra mcpServer.probes.liveness.initialDelaySeconds Configure initial delay for frontend liveness probe
## @extra mcpServer.probes.liveness.initialDelaySeconds Configure timeout for frontend liveness probe
## @extra mcpServer.probes.startup.path Configure path for frontend HTTP startup probe
## @extra mcpServer.probes.startup.targetPort Configure port for frontend HTTP startup probe
## @extra mcpServer.probes.startup.initialDelaySeconds Configure initial delay for frontend startup probe
## @extra mcpServer.probes.startup.initialDelaySeconds Configure timeout for frontend startup probe
## @extra mcpServer.probes.readiness.path Configure path for frontend HTTP readiness probe
## @extra mcpServer.probes.readiness.targetPort Configure port for frontend HTTP readiness probe
## @extra mcpServer.probes.readiness.initialDelaySeconds Configure initial delay for frontend readiness probe
## @extra mcpServer.probes.readiness.initialDelaySeconds Configure timeout for frontend readiness probe
probes: {}
## @param mcpServer.resources Resource requirements for the frontend container
resources: {}
## @param mcpServer.persistence Additional volumes to create and mount on the backend. Used for debugging purposes
## @extra mcpServer.persistence.volume-name.size Size of the additional volume
## @extra mcpServer.persistence.volume-name.type Type of the additional volume, persistentVolumeClaim or emptyDir
## @extra mcpServer.persistence.volume-name.mountPath Path where the volume should be mounted to
persistence: {}
## @param mcpServer.extraVolumeMounts Additional volumes to mount on the backend.
extraVolumeMounts: [ ]
## @param mcpServer.extraVolumes Additional volumes to mount on the backend.
extraVolumes: []
## @param mcpServer.nodeSelector Node selector for the backend Pod
nodeSelector: {}
## @param mcpServer.affinity Affinity for the backend Pod
affinity: {}
## @param mcpServer.tolerations Tolerations for the backend Pod
tolerations: []
## @param mcpServer.pdb.enabled Enable pdb on backend
pdb:
enabled: true
## @section frontend