(docker) add docspec deployment and service to kubernetes configuration

Added Helm templates for docspec deployment and service to enable
document specification conversion in the Kubernetes environment.
Updated Tiltfile, compose.yml, and Helm values to
configure docspec integration alongside the
backend converter service for document import functionality.
This commit is contained in:
Stephan Meijer
2026-01-12 19:16:40 +01:00
committed by Anthony LC
parent f0cc29e779
commit 9345d8deab
9 changed files with 263 additions and 9 deletions

View File

@@ -8,6 +8,7 @@ docker_build(
dockerfile='../Dockerfile',
only=['./src/backend', './src/mail', './docker'],
target = 'backend-production',
build_args={'DOCKER_USER': '1000:1000'},
live_update=[
sync('../src/backend', '/app'),
run(
@@ -23,6 +24,7 @@ docker_build(
dockerfile='../src/frontend/servers/y-provider/Dockerfile',
only=['./src/frontend/', './docker/', './.dockerignore'],
target = 'y-provider',
build_args={'DOCKER_USER': '1000:1000'},
live_update=[
sync('../src/frontend/servers/y-provider/src', '/home/frontend/servers/y-provider/src'),
]
@@ -34,6 +36,7 @@ docker_build(
dockerfile='../src/frontend/Dockerfile',
only=['./src/frontend', './docker', './.dockerignore'],
target = 'impress',
build_args={'DOCKER_USER': '1000:1000'},
live_update=[
sync('../src/frontend', '/home/frontend'),
]

View File

@@ -232,7 +232,7 @@ services:
restart: true
docspec:
image: ghcr.io/docspecio/api:2.4.4
image: ghcr.io/docspecio/api:2.6.3
ports:
- "4000:4000"

View File

@@ -1,5 +1,6 @@
"""Y-Provider API services."""
import logging
import typing
from base64 import b64encode
@@ -9,6 +10,8 @@ import requests
from core.services import mime_types
logger = logging.getLogger(__name__)
class ConversionError(Exception):
"""Base exception for conversion-related errors."""
@@ -66,6 +69,13 @@ class DocSpecConverter:
timeout=settings.CONVERSION_API_TIMEOUT,
verify=settings.CONVERSION_API_SECURE,
)
if not response.ok:
logger.error(
"DocSpec API error: url=%s, status=%d, response=%s",
url,
response.status_code,
response.text[:200] if response.text else "empty",
)
response.raise_for_status()
return response
@@ -82,6 +92,7 @@ class DocSpecConverter:
try:
return self._request(settings.DOCSPEC_API_URL, data, content_type).content
except requests.RequestException as err:
logger.exception("DocSpec service error: url=%s", settings.DOCSPEC_API_URL)
raise ServiceUnavailableError(
"Failed to connect to DocSpec conversion service",
) from err
@@ -109,6 +120,13 @@ class YdocConverter:
timeout=settings.CONVERSION_API_TIMEOUT,
verify=settings.CONVERSION_API_SECURE,
)
if not response.ok:
logger.error(
"Y-Provider API error: url=%s, status=%d, response=%s",
url,
response.status_code,
response.text[:200] if response.text else "empty",
)
response.raise_for_status()
return response
@@ -118,13 +136,9 @@ class YdocConverter:
if not data:
raise ValidationError("Input data cannot be empty")
url = f"{settings.Y_PROVIDER_API_BASE_URL}{settings.CONVERSION_API_ENDPOINT}/"
try:
response = self._request(
f"{settings.Y_PROVIDER_API_BASE_URL}{settings.CONVERSION_API_ENDPOINT}/",
data,
content_type,
accept,
)
response = self._request(url, data, content_type, accept)
if accept == mime_types.YJS:
return b64encode(response.content).decode("utf-8")
if accept in {mime_types.MARKDOWN, "text/html"}:
@@ -133,6 +147,7 @@ class YdocConverter:
return response.json()
raise ValidationError("Unsupported format")
except requests.RequestException as err:
logger.exception("Y-Provider service error: url=%s", url)
raise ServiceUnavailableError(
f"Failed to connect to YDoc conversion service {content_type}, {accept}",
) from err

View File

@@ -67,7 +67,8 @@ backend:
AWS_S3_SECRET_ACCESS_KEY: password
AWS_STORAGE_BUCKET_NAME: docs-media-storage
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
Y_PROVIDER_API_BASE_URL: http://impress-y-provider:443/api/
DOCSPEC_API_URL: http://impress-docs-docspec:4000/conversion
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
Y_PROVIDER_API_KEY: my-secret
CACHES_KEY_PREFIX: "{{ now | unixEpoch }}"
migrate:
@@ -156,6 +157,21 @@ yProvider:
COLLABORATION_SERVER_SECRET: my-secret
Y_PROVIDER_API_KEY: my-secret
docSpec:
enabled: true
replicas: 1
image:
repository: ghcr.io/docspecio/api
pullPolicy: IfNotPresent
tag: "2.6.3"
probes:
liveness:
path: /health
readiness:
path: /health
ingress:
enabled: true
host: docs.127.0.0.1.nip.io

View File

@@ -68,7 +68,8 @@ backend:
AWS_S3_SECRET_ACCESS_KEY: password
AWS_STORAGE_BUCKET_NAME: docs-media-storage
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
Y_PROVIDER_API_BASE_URL: http://impress-y-provider:443/api/
DOCSPEC_API_URL: http://impress-docs-docspec:4000/conversion
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
Y_PROVIDER_API_KEY: my-secret
CACHES_KEY_PREFIX: "{{ now | unixEpoch }}"
migrate:
@@ -142,6 +143,21 @@ yProvider:
COLLABORATION_SERVER_SECRET: my-secret
Y_PROVIDER_API_KEY: my-secret
docSpec:
enabled: true
replicas: 1
image:
repository: ghcr.io/docspecio/api
pullPolicy: IfNotPresent
tag: "2.6.3"
probes:
liveness:
path: /health
readiness:
path: /health
ingress:
enabled: true
host: {{ .Values.feature }}-docs.{{ .Values.domain }}

View File

@@ -167,6 +167,16 @@ Requires top level scope
{{- end }}
{{/*
Full name for the docSpec
Requires top level scope
*/}}
{{- define "impress.docSpec.fullname" -}}
{{ include "impress.fullname" . }}-docspec
{{- end }}
{{/*
Full name for the Celery Worker

View File

@@ -0,0 +1,108 @@
{{- if .Values.docSpec.enabled -}}
{{- $envVars := include "impress.common.env" (list . .Values.docSpec) -}}
{{- $fullName := include "impress.docSpec.fullname" . -}}
{{- $component := "docspec" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
replicas: {{ .Values.docSpec.replicas }}
selector:
matchLabels:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
template:
metadata:
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}}
containers:
- name: {{ .Chart.Name }}-docspec
image: "{{ .Values.docSpec.image.repository }}:{{ .Values.docSpec.image.tag }}"
imagePullPolicy: {{ .Values.docSpec.image.pullPolicy }}
{{- with .Values.docSpec.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.docSpec.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if $envVars }}
env:
{{- $envVars | indent 12 }}
{{- end }}
{{- with .Values.docSpec.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.docSpec.service.targetPort }}
protocol: TCP
{{- if .Values.docSpec.probes.liveness }}
livenessProbe:
{{- include "impress.probes.abstract" (merge .Values.docSpec.probes.liveness (dict "targetPort" .Values.docSpec.service.targetPort )) | nindent 12 }}
{{- end }}
{{- if .Values.docSpec.probes.readiness }}
readinessProbe:
{{- include "impress.probes.abstract" (merge .Values.docSpec.probes.readiness (dict "targetPort" .Values.docSpec.service.targetPort )) | nindent 12 }}
{{- end }}
{{- with .Values.docSpec.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.docSpec.extraVolumeMounts }}
volumeMounts:
{{- range .Values.docSpec.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- if .subPath }}
subPath: {{ .subPath }}
{{- end }}
{{- if .readOnly }}
readOnly: {{ .readOnly }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.docSpec.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.docSpec.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.docSpec.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.docSpec.extraVolumes }}
volumes:
{{- range .Values.docSpec.extraVolumes }}
- name: {{ .name }}
{{- if .persistentVolumeClaim }}
persistentVolumeClaim:
{{- toYaml .persistentVolumeClaim | nindent 12 }}
{{- else if .emptyDir }}
emptyDir:
{{- toYaml .emptyDir | nindent 12 }}
{{- else if .configMap }}
configMap:
{{- toYaml .configMap | nindent 12 }}
{{- else if .secret }}
secret:
{{- toYaml .secret | nindent 12 }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,20 @@
{{- if .Values.docSpec.enabled -}}
{{- $fullName := include "impress.docSpec.fullname" . -}}
{{- $component := "docspec" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace | quote }}
labels:
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
spec:
type: {{ .Values.docSpec.service.type }}
ports:
- port: {{ .Values.docSpec.service.port }}
targetPort: {{ .Values.docSpec.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}
{{- end }}

View File

@@ -701,3 +701,69 @@ yProvider:
## @param yProvider.serviceAccountName Optional service account name to use for yProvider pods
serviceAccountName: null
## @section docSpec
docSpec:
## @param docSpec.enabled Enable docSpec deployment
enabled: false
## @param docSpec.image.repository Repository to use to pull docSpec container image
## @param docSpec.image.tag docSpec container tag
## @param docSpec.image.pullPolicy docSpec container image pull policy
image:
repository: ghcr.io/docspecio/api
pullPolicy: IfNotPresent
tag: "2.6.3"
## @param docSpec.command Override the docSpec container command
command: []
## @param docSpec.args Override the docSpec container args
args: []
## @param docSpec.replicas Amount of docSpec replicas
replicas: 1
## @param docSpec.securityContext Configure docSpec Pod security context
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
## @param docSpec.envVars Configure docSpec container environment variables
envVars: {}
## @param docSpec.service Configure docSpec service
service:
type: ClusterIP
port: 4000
targetPort: 4000
## @param docSpec.probes Configure docSpec probes
probes:
liveness:
path: /health
readiness:
path: /health
## @param docSpec.resources docSpec resources
resources: {}
## @param docSpec.nodeSelector Node selector for the docSpec Pod
nodeSelector: {}
## @param docSpec.tolerations Tolerations for the docSpec Pod
tolerations: []
## @param docSpec.affinity Affinity for the docSpec Pod
affinity: {}
## @param docSpec.extraVolumeMounts Additional volumes to mount on docSpec
extraVolumeMounts: []
## @param docSpec.extraVolumes Additional volumes to mount on docSpec
extraVolumes: []