{{- range $name, $svc := .Values.services }} {{- $databaseUrl := $.Values.global.databaseUrl | default "" }} {{- $schemaManagementMode := $.Values.global.schemaManagementMode | default "legacy" }} {{- $isGateway := default false $svc.gateway }} apiVersion: apps/v1 kind: Deployment metadata: name: {{ $name }} namespace: {{ $.Values.namespace }} spec: replicas: {{ $svc.replicas }} selector: matchLabels: app: {{ $name }} template: metadata: labels: app: {{ $name }} spec: terminationGracePeriodSeconds: 30 {{- if $.Values.global.runtimeClass }} runtimeClassName: {{ $.Values.global.runtimeClass }} {{- end }} {{- if gt (int $svc.replicas) 1 }} affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app: {{ $name }} {{- end }} containers: - name: app image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}" imagePullPolicy: {{ $.Values.global.imagePullPolicy }} env: - name: APP_MODULE value: "{{ $svc.module }}" - name: CC_DATA_DIR value: /var/lib/mvp-cc/data - name: APP_TOKEN_SECRET value: "{{ $.Values.auth.appTokenSecret }}" - name: APP_TOKEN_TTL_SECONDS value: "{{ $.Values.auth.appTokenTtlSeconds }}" - name: ALLOW_LEGACY_HEADER_AUTH value: "{{ $.Values.auth.allowLegacyHeaderAuth }}" {{- if or $.Values.profiles.scale500.enabled $databaseUrl }} - name: DATABASE_URL value: "{{ if $.Values.profiles.scale500.enabled }}{{ required "global.databaseUrl is required when profiles.scale500.enabled=true" $.Values.global.databaseUrl }}{{ else }}{{ $databaseUrl }}{{ end }}" {{- end }} - name: SCHEMA_MANAGEMENT_MODE value: "{{ $schemaManagementMode }}" - name: DB_POOL_SIZE value: "{{ $.Values.db.poolSize }}" - name: DB_MAX_OVERFLOW value: "{{ $.Values.db.maxOverflow }}" - name: DB_POOL_TIMEOUT_SECONDS value: "{{ $.Values.db.poolTimeoutSeconds }}" - name: DB_POOL_RECYCLE_SECONDS value: "{{ $.Values.db.poolRecycleSeconds }}" - name: EVENT_BUS_ENABLED value: "{{ $.Values.eventBus.enabled }}" - name: EVENT_BUS_URL value: "{{ $.Values.eventBus.url }}" - name: EVENT_BUS_EXCHANGE value: "{{ $.Values.eventBus.exchange }}" - name: EVENT_BUS_DISPATCH_BATCH_SIZE value: "{{ $.Values.eventBus.dispatchBatchSize }}" - name: EVENT_BUS_MAX_ATTEMPTS value: "{{ $.Values.eventBus.maxAttempts }}" - name: EVENT_BUS_POLL_INTERVAL_SECONDS value: "{{ $.Values.eventBus.pollIntervalSeconds }}" - name: EVENT_BUS_CONSUMER_ENABLED value: "{{ $.Values.eventBus.consumerEnabled }}" - name: EVENT_BUS_AUDIT_QUEUE value: "{{ $.Values.eventBus.auditQueue }}" - name: EVENT_BUS_REPORTING_QUEUE value: "{{ $.Values.eventBus.reportingQueue }}" {{- if eq $name "asterisk-bridge-service" }} - name: ASTERISK_BRIDGE_ENABLED value: "{{ $.Values.asteriskBridge.enabled }}" - name: ASTERISK_AMI_HOST value: "{{ $.Values.asteriskBridge.amiHost }}" - name: ASTERISK_AMI_PORT value: "{{ $.Values.asteriskBridge.amiPort }}" - name: ASTERISK_AMI_USERNAME value: "{{ $.Values.asteriskBridge.amiUsername }}" - name: ASTERISK_AMI_SECRET value: "{{ $.Values.asteriskBridge.amiSecret }}" - name: ASTERISK_AMI_EVENT_PREFIX value: "{{ $.Values.asteriskBridge.amiEventPrefix }}" - name: ASTERISK_QUEUE_MAP_JSON value: '{{ $.Values.asteriskBridge.queueMapJson }}' - name: ASTERISK_SFTP_HOST value: "{{ $.Values.asteriskBridge.sftpHost }}" - name: ASTERISK_SFTP_PORT value: "{{ $.Values.asteriskBridge.sftpPort }}" - name: ASTERISK_SFTP_USERNAME value: "{{ $.Values.asteriskBridge.sftpUsername }}" - name: ASTERISK_SFTP_PASSWORD value: "{{ $.Values.asteriskBridge.sftpPassword }}" - name: ASTERISK_SFTP_BASE_PATH value: "{{ $.Values.asteriskBridge.sftpBasePath }}" - name: ASTERISK_BRIDGE_POLL_INTERVAL_SECONDS value: "{{ $.Values.asteriskBridge.pollIntervalSeconds }}" - name: ASTERISK_BRIDGE_AUTH_MODE value: "{{ $.Values.asteriskBridge.authMode }}" - name: ASTERISK_BRIDGE_AUTH_FALLBACK_LEGACY value: "{{ $.Values.asteriskBridge.authFallbackLegacy }}" - name: ASTERISK_BRIDGE_AUTH_SUBJECT value: "{{ $.Values.asteriskBridge.authSubject }}" - name: ASTERISK_BRIDGE_AUTH_USER value: "{{ $.Values.asteriskBridge.authUser }}" - name: ASTERISK_BRIDGE_AUTH_ROLE value: "{{ $.Values.asteriskBridge.authRole }}" - name: ASTERISK_BRIDGE_AUTH_TOKEN_TTL_SECONDS value: "{{ $.Values.asteriskBridge.authTokenTtlSeconds }}" - name: ASTERISK_IVR_FASTAGI_ENABLED value: "{{ $.Values.asteriskBridge.ivrFastagiEnabled }}" - name: ASTERISK_IVR_FASTAGI_HOST value: "{{ $.Values.asteriskBridge.ivrFastagiHost }}" - name: ASTERISK_IVR_FASTAGI_PORT value: "{{ $.Values.asteriskBridge.ivrFastagiPort }}" - name: ASTERISK_IVR_DTMF_TIMEOUT_SECONDS value: "{{ $.Values.asteriskBridge.ivrDtmfTimeoutSeconds }}" - name: ASTERISK_IVR_MAX_NO_INPUT_RETRIES value: "{{ $.Values.asteriskBridge.ivrMaxNoInputRetries }}" - name: ASTERISK_IVR_MAX_INVALID_RETRIES value: "{{ $.Values.asteriskBridge.ivrMaxInvalidRetries }}" - name: ASTERISK_IVR_CALL_LINK_WAIT_SECONDS value: "{{ $.Values.asteriskBridge.ivrCallLinkWaitSeconds }}" - name: ASTERISK_CALLCONTROL_ENABLED value: "{{ $.Values.asteriskBridge.callcontrolEnabled }}" - name: ASTERISK_CALLCONTROL_ACTION_TIMEOUT_SECONDS value: "{{ $.Values.asteriskBridge.callcontrolActionTimeoutSeconds }}" - name: ASTERISK_OPERATOR_EXTENSION_MAP_JSON value: '{{ $.Values.asteriskBridge.operatorExtensionMapJson }}' - name: ASTERISK_TRANSFER_TARGET_MAP_JSON value: '{{ $.Values.asteriskBridge.transferTargetMapJson }}' - name: ASTERISK_CALLCONTROL_CLAIM_CONTEXT value: "{{ $.Values.asteriskBridge.claimContext }}" - name: ASTERISK_CALLCONTROL_TRANSFER_CONTEXT value: "{{ $.Values.asteriskBridge.transferContext }}" - name: AI_VOICE_RUNTIME_SERVICE_URL value: http://ai-voice-runtime-service:8000 - name: AI_VOICE_ENABLED value: "{{ $.Values.voiceAI.enabled }}" - name: AI_VOICE_QUEUE_CONFIG_JSON value: '{{ $.Values.voiceAI.queueConfigJson }}' - name: AI_VOICE_RUNTIME_TRUSTED_SERVICE_SUBJECTS value: "{{ $.Values.voiceAI.runtimeTrustedServiceSubjects }}" - name: INTERACTION_SERVICE_URL value: http://interaction-service:8000 - name: VOICE_ADAPTER_SERVICE_URL value: http://voice-adapter-service:8000 - name: RECORDING_SERVICE_URL value: http://recording-service:8000 - name: IVR_SERVICE_URL value: http://ivr-service:8000 {{- end }} {{- if eq $name "ivr-service" }} - name: IVR_RUNTIME_TRUSTED_SERVICE_SUBJECTS value: "{{ $.Values.ivrRuntime.trustedServiceSubjects }}" {{- end }} {{- if eq $name "ai-orchestrator-service" }} - name: INTERACTION_SERVICE_URL value: http://interaction-service:8000 - name: TELEGRAM_ADAPTER_SERVICE_URL value: http://telegram-adapter-service:8000 - name: AI_VOICE_MAX_CONTEXT_SEGMENTS value: "{{ $.Values.voiceAI.maxContextSegments }}" {{- end }} {{- if eq $name "ai-voice-runtime-service" }} - name: AI_ORCHESTRATOR_SERVICE_URL value: http://ai-orchestrator-service:8000 - name: ASTERISK_BRIDGE_SERVICE_URL value: http://asterisk-bridge-service:8000 - name: AI_VOICE_ASR_PROVIDER value: "{{ $.Values.voiceAI.asrProvider }}" - name: AI_VOICE_TTS_PROVIDER value: "{{ $.Values.voiceAI.ttsProvider }}" - name: AI_VOICE_AUDIOSOCKET_ENABLED value: "{{ $.Values.voiceAI.audioSocketEnabled }}" - name: AI_VOICE_AUDIOSOCKET_HOST value: "{{ $.Values.voiceAI.audioSocketHost }}" - name: AI_VOICE_AUDIOSOCKET_PORT value: "{{ $.Values.voiceAI.audioSocketPort }}" - name: AI_VOICE_ASR_MODEL value: "{{ $.Values.voiceAI.asrModel }}" - name: AI_VOICE_TTS_MODEL value: "{{ $.Values.voiceAI.ttsModel }}" - name: AI_VOICE_TTS_VOICE value: "{{ $.Values.voiceAI.ttsVoice }}" - name: AI_VOICE_TTS_CACHE_ENABLED value: "{{ $.Values.voiceAI.ttsCacheEnabled }}" - name: AI_VOICE_TTS_CACHE_DIR value: "{{ $.Values.voiceAI.ttsCacheDir }}" - name: AI_VOICE_VAD_MIN_SPEECH_MS value: "{{ $.Values.voiceAI.vadMinSpeechMs }}" - name: AI_VOICE_VAD_TRAILING_SILENCE_MS value: "{{ $.Values.voiceAI.vadTrailingSilenceMs }}" - name: AI_VOICE_TURN_MAX_MS value: "{{ $.Values.voiceAI.turnMaxMs }}" - name: AI_VOICE_MEDIA_IDLE_TIMEOUT_SECONDS value: "{{ $.Values.voiceAI.mediaIdleTimeoutSeconds }}" - name: AI_VOICE_HANDOFF_TIMEOUT_SECONDS value: "{{ $.Values.voiceAI.handoffTimeoutSeconds }}" {{- end }} {{- if eq $name "recording-service" }} - name: CC_RECORDINGS_DIR value: /var/lib/mvp-cc/data/recordings - name: RECORDING_MAX_BYTES value: "26214400" - name: RECORDING_IMPORT_TRUSTED_SERVICE_SUBJECTS value: "{{ $.Values.recording.importTrustedServiceSubjects }}" - name: RECORDING_IMPORT_ALLOW_ADMIN value: "{{ $.Values.recording.importAllowAdmin }}" {{- end }} {{- if eq $name "voice-adapter-service" }} - name: VOICE_ADAPTER_TRUSTED_SERVICE_SUBJECTS value: "{{ $.Values.voiceAdapter.trustedServiceSubjects }}" {{- end }} {{- if eq $name "auth-service" }} - name: OIDC_ENABLED value: "{{ $.Values.auth.oidc.enabled }}" - name: OIDC_PROVIDER value: "{{ $.Values.auth.oidc.provider }}" - name: OIDC_ISSUER_URL value: "{{ $.Values.auth.oidc.issuerUrl }}" - name: OIDC_CLIENT_ID value: "{{ $.Values.auth.oidc.clientId }}" - name: OIDC_CLIENT_SECRET value: "{{ $.Values.auth.oidc.clientSecret }}" - name: OIDC_REDIRECT_URI value: "{{ $.Values.auth.oidc.redirectUri }}" - name: OIDC_SCOPES value: "{{ $.Values.auth.oidc.scopes }}" - name: OIDC_ROLE_CLAIM value: "{{ $.Values.auth.oidc.roleClaim }}" - name: OIDC_ROLE_MAP_JSON value: '{{ $.Values.auth.oidc.roleMapJson }}' {{- end }} {{- if $isGateway }} - name: AUTH_SERVICE_URL value: http://auth-service:8000 - name: AUDIT_SERVICE_URL value: http://audit-service:8000 - name: CUSTOMER_SERVICE_URL value: http://customer-service:8000 - name: INTERACTION_SERVICE_URL value: http://interaction-service:8000 - name: ROUTING_SERVICE_URL value: http://routing-service:8000 - name: VOICE_ADAPTER_SERVICE_URL value: http://voice-adapter-service:8000 - name: RECORDING_SERVICE_URL value: http://recording-service:8000 - name: IVR_SERVICE_URL value: http://ivr-service:8000 - name: EVENT_BUS_SERVICE_URL value: http://event-bus-service:8000 - name: ASTERISK_BRIDGE_SERVICE_URL value: http://asterisk-bridge-service:8000 - name: TELEGRAM_ADAPTER_SERVICE_URL value: http://telegram-adapter-service:8000 - name: AI_ORCHESTRATOR_SERVICE_URL value: http://ai-orchestrator-service:8000 - name: AI_VOICE_RUNTIME_SERVICE_URL value: http://ai-voice-runtime-service:8000 - name: WEBCHAT_ADAPTER_SERVICE_URL value: http://webchat-adapter-service:8000 - name: EMAIL_ADAPTER_SERVICE_URL value: http://email-adapter-service:8000 - name: KB_SERVICE_URL value: http://kb-service:8000 - name: REPORTING_SERVICE_URL value: http://reporting-service:8000 - name: SUPERVISOR_SERVICE_URL value: http://supervisor-service:8000 {{- end }} ports: - containerPort: 8000 {{- if eq $name "ai-voice-runtime-service" }} - containerPort: 9019 {{- end }} {{- if eq $name "asterisk-bridge-service" }} - containerPort: 4573 {{- end }} resources: requests: cpu: {{ $svc.resources.requests.cpu }} memory: {{ $svc.resources.requests.memory }} limits: cpu: {{ $svc.resources.limits.cpu }} memory: {{ $svc.resources.limits.memory }} startupProbe: httpGet: path: /health port: 8000 failureThreshold: 30 periodSeconds: 5 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 2 livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 20 periodSeconds: 15 timeoutSeconds: 2 {{- if $svc.persistence.enabled }} volumeMounts: - name: app-data mountPath: /var/lib/mvp-cc/data {{- end }} {{- if $svc.persistence.enabled }} volumes: - name: app-data persistentVolumeClaim: claimName: {{ $name }}-data {{- end }} --- apiVersion: v1 kind: Service metadata: name: {{ $name }} namespace: {{ $.Values.namespace }} spec: selector: app: {{ $name }} ports: - name: http port: 8000 targetPort: 8000 {{- if eq $name "ai-voice-runtime-service" }} - name: audiosocket port: 9019 targetPort: 9019 {{- end }} {{- if eq $name "asterisk-bridge-service" }} - name: fastagi port: 4573 targetPort: 4573 {{- end }} type: {{ if $isGateway }}LoadBalancer{{ else }}ClusterIP{{ end }} --- {{- if $svc.persistence.enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ $name }}-data namespace: {{ $.Values.namespace }} spec: accessModes: - ReadWriteOnce resources: requests: storage: {{ $svc.persistence.size }} --- {{- end }} {{- if and $svc.podDisruptionBudget.enabled (gt (int $svc.replicas) 1) }} apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: {{ $name }}-pdb namespace: {{ $.Values.namespace }} spec: minAvailable: {{ $svc.podDisruptionBudget.minAvailable }} selector: matchLabels: app: {{ $name }} --- {{- end }} {{- if $svc.autoscaling.enabled }} apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: {{ $name }}-hpa namespace: {{ $.Values.namespace }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: {{ $name }} minReplicas: {{ $svc.autoscaling.minReplicas }} maxReplicas: {{ $svc.autoscaling.maxReplicas }} metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: {{ $svc.autoscaling.targetCPUUtilizationPercentage }} --- {{- end }} {{- end }}