Initial import with GitLab CI/CD and registry deploy flow
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
APP_IMAGE=registry.example.com/group/project/app:latest
|
||||
ASTERISK_IMAGE=registry.example.com/group/project/asterisk:latest
|
||||
@@ -0,0 +1,21 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
asterisk \
|
||||
ca-certificates \
|
||||
curl \
|
||||
openssl \
|
||||
python3 \
|
||||
procps \
|
||||
uuid-runtime \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY deployment/asterisk/entrypoint.sh /usr/local/bin/mvpcc-asterisk-entrypoint.sh
|
||||
|
||||
RUN chmod +x /usr/local/bin/mvpcc-asterisk-entrypoint.sh \
|
||||
&& mkdir -p /config-template /assets /etc/asterisk/keys /var/spool/asterisk/monitor/mvpcc
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/mvpcc-asterisk-entrypoint.sh"]
|
||||
@@ -0,0 +1,74 @@
|
||||
# Asterisk Lab Config
|
||||
|
||||
This folder contains the lab-grade configuration set for Track 9, Track 11, and Track 14:
|
||||
|
||||
- `pjsip.conf`
|
||||
- `extensions.conf`
|
||||
- `manager.conf`
|
||||
- `http.conf`
|
||||
- `rtp.conf`
|
||||
|
||||
These files are templates for a dedicated Linux VM running Asterisk 20 LTS.
|
||||
|
||||
Before using them:
|
||||
|
||||
1. Replace default passwords and secrets.
|
||||
2. Confirm the softphone source network.
|
||||
3. Create the recording directory:
|
||||
- `/var/spool/asterisk/monitor/mvpcc`
|
||||
4. Point `ASTERISK_QUEUE_MAP_JSON` in the platform to the matching queue code:
|
||||
- `voice_lab`
|
||||
- `voice_lab_ai` for the dedicated AI-first staging entrypoint
|
||||
- `voice_lab_ivr` for the dedicated IVR staging entrypoint
|
||||
5. Configure operator extension mapping in bridge env for Track 11 call control:
|
||||
- `ASTERISK_OPERATOR_EXTENSION_MAP_JSON={"operator_a":"2001","operator_b":"2002"}`
|
||||
6. Optional transfer map for queue-code based blind transfer:
|
||||
- `ASTERISK_TRANSFER_TARGET_MAP_JSON={"voice_lab":"2001","voice_lab_ai":"2001","voice_lab_ivr":"7200"}`
|
||||
7. For IVR-over-Asterisk staging:
|
||||
- enable `ASTERISK_IVR_FASTAGI_ENABLED=1`
|
||||
- set `ASTERISK_IVR_FASTAGI_HOST=<bridge-host>`
|
||||
- set `ASTERISK_IVR_FASTAGI_PORT=4573`
|
||||
- set `IVR_RUNTIME_TRUSTED_SERVICE_SUBJECTS=svc:asterisk-bridge`
|
||||
- provision the referenced `prompt_audio_key` files under the Asterisk sounds directory
|
||||
- if you want a higher-quality prompt from OpenAI TTS, generate it once and keep it on the server:
|
||||
- `python scripts/materialize_tts_prompt.py --text "Здравствуйте! Добро пожаловать в контакт-центр. Для русского языка нажмите 1. Қазақ тілі үшін 2 басыңыз." --output /usr/share/asterisk/sounds/en/mvpcc_ivr_language.wav --language ru`
|
||||
- `python scripts/materialize_tts_prompt.py --text "Для отдела продаж нажмите 1. Для службы поддержки нажмите 2." --output /usr/share/asterisk/sounds/en/mvpcc_ivr_menu_ru.wav --language ru`
|
||||
- `python scripts/materialize_tts_prompt.py --text "Сату бөлімі үшін 1 басыңыз. Қолдау қызметі үшін 2 басыңыз." --output /usr/share/asterisk/sounds/en/mvpcc_ivr_menu_kz.wav --language kk`
|
||||
- repeated runs reuse the server cache from `AI_VOICE_TTS_CACHE_DIR` instead of calling OpenAI again for the same text
|
||||
8. For Track 14 browser softphone QA:
|
||||
- enable `ASTERISK_WEBRTC_ENABLED=1`
|
||||
- set `ASTERISK_WEBRTC_WS_URL=wss://<asterisk-host>:8089/ws`
|
||||
- configure `ASTERISK_BROWSER_SIP_MAP_JSON`
|
||||
- replace TLS placeholders in `http.conf` with a trusted cert/key pair
|
||||
9. For Voice AI V1 lab wiring:
|
||||
- enable `AI_VOICE_ENABLED=1`
|
||||
- set `AI_VOICE_QUEUE_CONFIG_JSON={"voice_lab_ai":{"mode":"ai_first","agent_profile":"voice_support","handoff_queue_code":"voice_lab","language":"ru"}}`
|
||||
- set `AI_VOICE_RUNTIME_SERVICE_URL=http://ai-voice-runtime-service:8000`
|
||||
- keep `AI_VOICE_RUNTIME_TRUSTED_SERVICE_SUBJECTS=svc:ai-voice-runtime`
|
||||
- load `app_audiosocket.so` on the Asterisk VM before enabling the AI media path
|
||||
- set `MVPCC_AI_AUDIOSOCKET_SERVICE=<media-host>:<port>` in `extensions.conf` only after the AudioSocket listener is reachable
|
||||
|
||||
Entrypoints in `extensions.conf`:
|
||||
|
||||
- `7000`: human-only baseline. This path preserves the original Track 9/11 behavior.
|
||||
- `7100`: AI-first staging path. It emits the normal `MVPCCCallStarted` event with `QueueCode=voice_lab_ai`, then:
|
||||
- falls back to human dialing immediately if `MVPCC_AI_AUDIOSOCKET_SERVICE` is blank
|
||||
- otherwise starts `AudioSocket(<uuid>,<host>:<port>)` for the media bridge
|
||||
- `7200`: IVR staging path. It emits the normal `MVPCCCallStarted` event with `QueueCode=voice_lab_ivr`, then:
|
||||
- hands control to FastAGI at `MVPCC_IVR_FASTAGI_HOSTPORT`
|
||||
- routes completed IVR sessions through `mvpcc-transfer`
|
||||
- falls back to the human baseline if FastAGI does not return a transfer target
|
||||
|
||||
Important Voice AI note:
|
||||
|
||||
- `AI_VOICE_RUNTIME_SERVICE_URL` is the HTTP control-plane endpoint for platform services.
|
||||
- `MVPCC_AI_AUDIOSOCKET_SERVICE` is a separate raw AudioSocket address for Asterisk media.
|
||||
- Do not point `MVPCC_AI_AUDIOSOCKET_SERVICE` at the runtime HTTP port.
|
||||
|
||||
Default lab SIP accounts from `pjsip.conf`:
|
||||
- `1001` (caller)
|
||||
- `2001` (operator A)
|
||||
- `2002` (operator B)
|
||||
|
||||
Track 14 note:
|
||||
- `2001` and `2002` are allowed to keep multiple contacts so browser registration can coexist with `MicroSIP/Zoiper` in QA.
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
template_dir="/config-template"
|
||||
monitor_dir="/var/spool/asterisk/monitor/mvpcc"
|
||||
primary_sounds_dir="/usr/share/asterisk/sounds"
|
||||
legacy_sounds_dir="/var/lib/asterisk/sounds"
|
||||
keys_dir="/etc/asterisk/keys"
|
||||
|
||||
password_1001="${ASTERISK_ENDPOINT_1001_PASSWORD:-${ASTERISK_AMI_SECRET:-ChangeMe-1001}}"
|
||||
password_2001="${ASTERISK_ENDPOINT_2001_PASSWORD:-${ASTERISK_AMI_SECRET:-ChangeMe-2001}}"
|
||||
password_2002="${ASTERISK_ENDPOINT_2002_PASSWORD:-${ASTERISK_AMI_SECRET:-ChangeMe-2002}}"
|
||||
ami_secret="${ASTERISK_AMI_SECRET:-ChangeMe-AmiSecret}"
|
||||
external_address="${ASTERISK_EXTERNAL_ADDRESS:-92.38.48.166}"
|
||||
|
||||
mkdir -p /etc/asterisk "$monitor_dir" "$primary_sounds_dir" "$legacy_sounds_dir" "$keys_dir"
|
||||
|
||||
for file in extensions.conf pjsip.conf manager.conf http.conf rtp.conf; do
|
||||
cp "${template_dir}/${file}" "/etc/asterisk/${file}"
|
||||
done
|
||||
|
||||
export ASTERISK_PASSWORD_1001="$password_1001"
|
||||
export ASTERISK_PASSWORD_2001="$password_2001"
|
||||
export ASTERISK_PASSWORD_2002="$password_2002"
|
||||
export ASTERISK_MANAGER_SECRET="$ami_secret"
|
||||
export ASTERISK_EXTERNAL_ADDRESS_VALUE="$external_address"
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
replacements = {
|
||||
"ChangeMe-1001": os.environ["ASTERISK_PASSWORD_1001"],
|
||||
"ChangeMe-2001": os.environ["ASTERISK_PASSWORD_2001"],
|
||||
"ChangeMe-2002": os.environ["ASTERISK_PASSWORD_2002"],
|
||||
"ChangeMe-AmiSecret": os.environ["ASTERISK_MANAGER_SECRET"],
|
||||
"92.38.48.166": os.environ["ASTERISK_EXTERNAL_ADDRESS_VALUE"],
|
||||
}
|
||||
|
||||
for path in (
|
||||
Path("/etc/asterisk/pjsip.conf"),
|
||||
Path("/etc/asterisk/manager.conf"),
|
||||
):
|
||||
text = path.read_text(encoding="utf-8")
|
||||
for old, new in replacements.items():
|
||||
text = text.replace(old, new)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
|
||||
modules_path = Path("/etc/asterisk/modules.conf")
|
||||
if modules_path.exists():
|
||||
text = modules_path.read_text(encoding="utf-8")
|
||||
if "noload => chan_sip.so" not in text:
|
||||
stanza = (
|
||||
"; MVPCC uses PJSIP/WebRTC for browser softphones.\n"
|
||||
"noload => chan_sip.so\n\n"
|
||||
)
|
||||
if "[global]" in text:
|
||||
text = text.replace("[global]", f"{stanza}[global]", 1)
|
||||
elif "[modules]" in text:
|
||||
text = text.rstrip() + "\n\n" + stanza
|
||||
else:
|
||||
text = "[modules]\nautoload=yes\n\n" + stanza + text
|
||||
modules_path.write_text(text, encoding="utf-8")
|
||||
PY
|
||||
|
||||
if [ ! -f "${keys_dir}/asterisk.pem" ] || [ ! -f "${keys_dir}/asterisk.key" ]; then
|
||||
openssl req \
|
||||
-x509 \
|
||||
-nodes \
|
||||
-newkey rsa:2048 \
|
||||
-keyout "${keys_dir}/asterisk.key" \
|
||||
-out "${keys_dir}/asterisk.pem" \
|
||||
-days 3650 \
|
||||
-subj "/CN=${external_address}"
|
||||
fi
|
||||
|
||||
if [ -f /assets/mvpcc_ivr_prompt.wav ]; then
|
||||
for sounds_dir in "$primary_sounds_dir" "$legacy_sounds_dir"; do
|
||||
cp /assets/mvpcc_ivr_prompt.wav "${sounds_dir}/mvpcc_ivr_prompt.wav"
|
||||
mkdir -p "${sounds_dir}/en" "${sounds_dir}/ru" "${sounds_dir}/ru_RU"
|
||||
cp /assets/mvpcc_ivr_prompt.wav "${sounds_dir}/en/mvpcc_ivr_prompt.wav"
|
||||
cp /assets/mvpcc_ivr_prompt.wav "${sounds_dir}/ru/mvpcc_ivr_prompt.wav"
|
||||
cp /assets/mvpcc_ivr_prompt.wav "${sounds_dir}/ru_RU/mvpcc_ivr_prompt.wav"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -d /assets/ivr ]; then
|
||||
for sounds_dir in "$primary_sounds_dir" "$legacy_sounds_dir"; do
|
||||
mkdir -p "${sounds_dir}/ivr"
|
||||
cp -a /assets/ivr/. "${sounds_dir}/ivr/"
|
||||
done
|
||||
fi
|
||||
|
||||
chown -R asterisk:asterisk /etc/asterisk "$keys_dir" /var/spool/asterisk/monitor
|
||||
|
||||
for sounds_dir in "$primary_sounds_dir" "$legacy_sounds_dir"; do
|
||||
if [ -w "$sounds_dir" ]; then
|
||||
chown -R asterisk:asterisk "$sounds_dir"
|
||||
fi
|
||||
done
|
||||
|
||||
chmod 0755 /var/spool/asterisk /var/spool/asterisk/monitor "$monitor_dir"
|
||||
|
||||
exec /usr/sbin/asterisk -f -U asterisk -G asterisk -vvv
|
||||
@@ -0,0 +1,119 @@
|
||||
[globals]
|
||||
MVPCC_QUEUE_CODE=voice_lab
|
||||
MVPCC_AI_QUEUE_CODE=voice_lab_ai
|
||||
MVPCC_IVR_QUEUE_CODE=voice_lab_ivr
|
||||
MVPCC_IVR_FALLBACK_QUEUE_CODE=voice_lab
|
||||
MVPCC_MONITOR_DIR=/var/spool/asterisk/monitor/mvpcc
|
||||
MVPCC_HUMAN_DIAL_TARGETS=PJSIP/2001&PJSIP/2002
|
||||
MVPCC_AI_AUDIOSOCKET_SERVICE=127.0.0.1:9019
|
||||
MVPCC_IVR_FASTAGI_HOSTPORT=127.0.0.1:4573
|
||||
|
||||
[from-softphones]
|
||||
exten => 7000,1,NoOp(MVPCC human baseline entrypoint)
|
||||
same => n,Answer()
|
||||
same => n,Set(MVPCC_QUEUE=${MVPCC_QUEUE_CODE})
|
||||
same => n,Gosub(mvpcc-call-init,s,1(${EXTEN}))
|
||||
same => n,Dial(${MVPCC_HUMAN_DIAL_TARGETS},40,U(mvpcc-connected^${MVPCC_CALL_ID}^${MVPCC_LINKED_ID}))
|
||||
same => n,Hangup()
|
||||
|
||||
exten => 7100,1,NoOp(MVPCC AI-first voice lab entrypoint)
|
||||
same => n,Set(MVPCC_QUEUE=${IF($["${MVPCC_AI_QUEUE_OVERRIDE}" != ""]?${MVPCC_AI_QUEUE_OVERRIDE}:${MVPCC_AI_QUEUE_CODE})})
|
||||
same => n,GotoIf($["${MVPCC_AI_REUSE_CALL}" = "1"]?ai-reuse,1)
|
||||
same => n,Answer()
|
||||
same => n,Gosub(mvpcc-call-init,s,1(${EXTEN}))
|
||||
same => n,Goto(ai-audiosocket,1)
|
||||
|
||||
exten => ai-reuse,1,NoOp(MVPCC AI handoff reusing active IVR call)
|
||||
same => n,Goto(ai-audiosocket,1)
|
||||
|
||||
exten => ai-audiosocket,1,NoOp(MVPCC AI audio bridge start)
|
||||
same => n,GotoIf($["${MVPCC_AI_AUDIOSOCKET_SERVICE}" = ""]?ai-human-fallback,1)
|
||||
same => n,Set(MVPCC_MEDIA_UUID=${SHELL(uuidgen | tr -d '\r\n')})
|
||||
same => n,UserEvent(MVPCCAIAudioBridgeRequested,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},MediaUUID:${MVPCC_MEDIA_UUID},UuidLen:${LEN(${MVPCC_MEDIA_UUID})},AudioSocketService:${MVPCC_AI_AUDIOSOCKET_SERVICE},Channel:${CHANNEL})
|
||||
same => n,UserEvent(MVPCCAIAudioSocketAttempt,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},MediaUUID:${MVPCC_MEDIA_UUID},UuidLen:${LEN(${MVPCC_MEDIA_UUID})},AudioSocketService:${MVPCC_AI_AUDIOSOCKET_SERVICE},Channel:${CHANNEL})
|
||||
same => n,TryExec(AudioSocket(${MVPCC_MEDIA_UUID},${MVPCC_AI_AUDIOSOCKET_SERVICE}))
|
||||
same => n,UserEvent(MVPCCAIAudioSocketResult,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},MediaUUID:${MVPCC_MEDIA_UUID},UuidLen:${LEN(${MVPCC_MEDIA_UUID})},AudioSocketService:${MVPCC_AI_AUDIOSOCKET_SERVICE},TryExecStatus:${TRYSTATUS},Channel:${CHANNEL})
|
||||
same => n,GotoIf($["${TRYSTATUS}" = "SUCCESS"]?ai-bridge-ended,1)
|
||||
same => n,UserEvent(MVPCCAIFallbackToHuman,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},Reason:audiosocket_failed,TryExecStatus:${TRYSTATUS},Channel:${CHANNEL})
|
||||
same => n,Dial(${MVPCC_HUMAN_DIAL_TARGETS},40,U(mvpcc-connected^${MVPCC_CALL_ID}^${MVPCC_LINKED_ID}))
|
||||
same => n,Hangup()
|
||||
|
||||
exten => ai-bridge-ended,1,UserEvent(MVPCCAIAudioBridgeEnded,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},MediaUUID:${MVPCC_MEDIA_UUID},AudioSocketService:${MVPCC_AI_AUDIOSOCKET_SERVICE},Channel:${CHANNEL})
|
||||
same => n,Hangup()
|
||||
|
||||
exten => ai-human-fallback,1,UserEvent(MVPCCAIFallbackToHuman,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},Reason:audiosocket_service_missing,Channel:${CHANNEL})
|
||||
same => n,Dial(${MVPCC_HUMAN_DIAL_TARGETS},40,U(mvpcc-connected^${MVPCC_CALL_ID}^${MVPCC_LINKED_ID}))
|
||||
same => n,Hangup()
|
||||
|
||||
exten => 7200,1,NoOp(MVPCC IVR staging entrypoint)
|
||||
same => n,Answer()
|
||||
same => n,Set(MVPCC_QUEUE=${MVPCC_IVR_QUEUE_CODE})
|
||||
same => n,Set(MVPCC_IVR_FALLBACK_QUEUE_CODE=${GLOBAL(MVPCC_IVR_FALLBACK_QUEUE_CODE)})
|
||||
same => n,Gosub(mvpcc-call-init,s,1(${EXTEN}))
|
||||
same => n,Set(MVPCC_IVR_RESULT=started)
|
||||
same => n,Set(MVPCC_IVR_TARGET_QUEUE_CODE=)
|
||||
same => n,Set(MVPCC_IVR_TARGET_EXTENSION=)
|
||||
same => n,Set(MVPCC_IVR_SESSION_ID=)
|
||||
same => n,GotoIf($["${MVPCC_IVR_FASTAGI_HOSTPORT}" = ""]?ivr-human-fallback,1)
|
||||
same => n,AGI(agi://${MVPCC_IVR_FASTAGI_HOSTPORT}/ivr,${MVPCC_CALL_ID},${MVPCC_LINKED_ID},${MVPCC_QUEUE},${MVPCC_IVR_FALLBACK_QUEUE_CODE},${EXTEN})
|
||||
same => n,GotoIf($["${MVPCC_IVR_TARGET_EXTENSION}" = ""]?ivr-human-fallback,1)
|
||||
same => n,Goto(mvpcc-transfer,${MVPCC_IVR_TARGET_EXTENSION},1)
|
||||
|
||||
exten => ivr-human-fallback,1,UserEvent(MVPCCIVRFallbackToHuman,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},QueueCode:${MVPCC_QUEUE},FallbackQueueCode:${MVPCC_IVR_FALLBACK_QUEUE_CODE},Extension:${MVPCC_ENTRY_EXTENSION},Result:${MVPCC_IVR_RESULT},TargetQueueCode:${MVPCC_IVR_TARGET_QUEUE_CODE},TargetExtension:${MVPCC_IVR_TARGET_EXTENSION},Channel:${CHANNEL})
|
||||
same => n,Dial(${MVPCC_HUMAN_DIAL_TARGETS},40,U(mvpcc-connected^${MVPCC_CALL_ID}^${MVPCC_LINKED_ID}))
|
||||
same => n,Hangup()
|
||||
|
||||
exten => h,1,StopMixMonitor()
|
||||
same => n,UserEvent(MVPCCCallEnded,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},HangupCause:${HANGUPCAUSE},DurationSeconds:${CDR(duration)})
|
||||
same => n,UserEvent(MVPCCRecordingReady,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},RemotePath:${MONITOR_FILENAME},FileName:${MVPCC_RECORD_FILE},MimeType:audio/wav,DurationSeconds:${CDR(duration)})
|
||||
|
||||
[mvpcc-call-init]
|
||||
exten => s,1,Set(MVPCC_ENTRY_EXTENSION=${ARG1})
|
||||
same => n,Set(MVPCC_CALL_ID=${UNIQUEID})
|
||||
same => n,Set(MVPCC_LINKED_ID=${CHANNEL(linkedid)})
|
||||
same => n,Set(MVPCC_RECORD_FILE=${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}.wav)
|
||||
same => n,Set(MONITOR_FILENAME=${MVPCC_MONITOR_DIR}/${MVPCC_RECORD_FILE})
|
||||
same => n,UserEvent(MVPCCCallStarted,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},CallerNumber:${CALLERID(num)},CallerName:${CALLERID(name)},QueueCode:${MVPCC_QUEUE},Extension:${MVPCC_ENTRY_EXTENSION},Context:${CONTEXT},Direction:inbound,Channel:${CHANNEL})
|
||||
same => n,MixMonitor(${MONITOR_FILENAME},a)
|
||||
same => n,Return()
|
||||
|
||||
[mvpcc-connected]
|
||||
exten => s,1,Set(MVPCC_OPERATOR=${IF($["${ARG3}" != ""]?${ARG3}:${CHANNEL(peername)})})
|
||||
same => n,Set(MVPCC_OPERATOR=${IF($["${MVPCC_OPERATOR}" = ""]?${EXTEN}:${MVPCC_OPERATOR})})
|
||||
same => n,UserEvent(MVPCCOperatorConnected,CallID:${ARG1},LinkedID:${ARG2},OperatorExtension:${MVPCC_OPERATOR},Context:${CONTEXT},Channel:${CHANNEL},ClaimedByUser:${MVPCC_OPERATOR})
|
||||
same => n,Return()
|
||||
|
||||
[mvpcc-claim]
|
||||
exten => _X.,1,NoOp(Claimed call routed to operator ${EXTEN})
|
||||
same => n,Set(MVPCC_CALL_ID=${CHANNEL(linkedid)})
|
||||
same => n,Set(MVPCC_LINKED_ID=${CHANNEL(linkedid)})
|
||||
same => n,Dial(PJSIP/${EXTEN},40,U(mvpcc-connected^${MVPCC_CALL_ID}^${MVPCC_LINKED_ID}^${EXTEN}))
|
||||
same => n,Hangup()
|
||||
|
||||
[mvpcc-transfer]
|
||||
exten => 7000,1,NoOp(Queue transfer target ${EXTEN})
|
||||
same => n,Dial(${MVPCC_HUMAN_DIAL_TARGETS},40)
|
||||
same => n,Hangup()
|
||||
|
||||
exten => 7100,1,NoOp(Queue transfer target ${EXTEN})
|
||||
same => n,Goto(from-softphones,7100,1)
|
||||
|
||||
exten => 7200,1,NoOp(Queue transfer target ${EXTEN})
|
||||
same => n,Goto(from-softphones,7200,1)
|
||||
|
||||
exten => _X.,1,NoOp(Blind transfer target ${EXTEN})
|
||||
same => n,Dial(PJSIP/${EXTEN},40,U(mvpcc-connected^${MVPCC_CALL_ID}^${MVPCC_LINKED_ID}^${EXTEN}))
|
||||
same => n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?transfer-finished,1)
|
||||
same => n,GotoIf($["${MVPCC_IVR_FALLBACK_QUEUE_CODE}" = ""]?transfer-finished,1)
|
||||
same => n,Set(MVPCC_IVR_RESULT=fallback_transfer_unavailable)
|
||||
same => n,Goto(from-softphones,ivr-human-fallback,1)
|
||||
|
||||
exten => transfer-finished,1,Hangup()
|
||||
|
||||
exten => h,1,StopMixMonitor()
|
||||
same => n,UserEvent(MVPCCCallEnded,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},HangupCause:${HANGUPCAUSE},DurationSeconds:${CDR(duration)})
|
||||
same => n,UserEvent(MVPCCRecordingReady,CallID:${MVPCC_CALL_ID},LinkedID:${MVPCC_LINKED_ID},RemotePath:${MONITOR_FILENAME},FileName:${MVPCC_RECORD_FILE},MimeType:audio/wav,DurationSeconds:${CDR(duration)})
|
||||
|
||||
[mvpcc-operators]
|
||||
exten => _X.,1,Dial(PJSIP/${EXTEN},30)
|
||||
same => n,Hangup()
|
||||
@@ -0,0 +1,12 @@
|
||||
[general]
|
||||
enabled=yes
|
||||
enablestatic=yes
|
||||
bindaddr=0.0.0.0
|
||||
bindport=8088
|
||||
|
||||
; QA-only TLS placeholders for direct browser SIP over WebSocket.
|
||||
; Replace with your actual trusted certificate and key paths before enabling WSS.
|
||||
tlsenable=yes
|
||||
tlsbindaddr=0.0.0.0:8089
|
||||
tlscertfile=/etc/asterisk/keys/asterisk.pem
|
||||
tlsprivatekey=/etc/asterisk/keys/asterisk.key
|
||||
@@ -0,0 +1,11 @@
|
||||
[general]
|
||||
enabled = yes
|
||||
port = 5038
|
||||
bindaddr = 0.0.0.0
|
||||
|
||||
[mvpcc]
|
||||
secret = ChangeMe-AmiSecret
|
||||
deny = 0.0.0.0/0.0.0.0
|
||||
permit = 0.0.0.0/0.0.0.0
|
||||
read = system,call,log,verbose,command,agent,user,dtmf,reporting,cdr,dialplan
|
||||
write = command,call,originate,agent,user
|
||||
@@ -0,0 +1,84 @@
|
||||
[transport-udp]
|
||||
type=transport
|
||||
protocol=udp
|
||||
bind=0.0.0.0
|
||||
external_signaling_address=92.38.48.166
|
||||
external_media_address=92.38.48.166
|
||||
|
||||
[transport-wss]
|
||||
type=transport
|
||||
protocol=wss
|
||||
bind=0.0.0.0
|
||||
external_signaling_address=92.38.48.166
|
||||
external_media_address=92.38.48.166
|
||||
|
||||
[softphone-endpoint](!)
|
||||
type=endpoint
|
||||
disallow=all
|
||||
allow=opus,ulaw,alaw
|
||||
dtmf_mode=auto_info
|
||||
direct_media=no
|
||||
rtp_symmetric=yes
|
||||
force_rport=yes
|
||||
rewrite_contact=yes
|
||||
webrtc=yes
|
||||
ice_support=yes
|
||||
rtcp_mux=yes
|
||||
use_avpf=yes
|
||||
media_encryption=dtls
|
||||
dtls_auto_generate_cert=yes
|
||||
dtls_setup=actpass
|
||||
media_use_received_transport=yes
|
||||
media_address=92.38.48.166
|
||||
|
||||
[caller-endpoint](!,softphone-endpoint)
|
||||
context=from-softphones
|
||||
|
||||
[operator-endpoint](!,softphone-endpoint)
|
||||
context=mvpcc-operators
|
||||
|
||||
[1001](caller-endpoint)
|
||||
auth=1001-auth
|
||||
aors=1001
|
||||
|
||||
[1001-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=1001
|
||||
password=ChangeMe-1001
|
||||
|
||||
[1001]
|
||||
type=aor
|
||||
max_contacts=2
|
||||
|
||||
[2001](operator-endpoint)
|
||||
auth=2001-auth
|
||||
aors=2001
|
||||
|
||||
[2001-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=2001
|
||||
password=ChangeMe-2001
|
||||
|
||||
[2001]
|
||||
type=aor
|
||||
max_contacts=1
|
||||
remove_existing=yes
|
||||
support_path=yes
|
||||
|
||||
[2002](operator-endpoint)
|
||||
auth=2002-auth
|
||||
aors=2002
|
||||
|
||||
[2002-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=2002
|
||||
password=ChangeMe-2002
|
||||
|
||||
[2002]
|
||||
type=aor
|
||||
max_contacts=1
|
||||
remove_existing=yes
|
||||
support_path=yes
|
||||
@@ -0,0 +1,5 @@
|
||||
[general]
|
||||
rtpstart=10000
|
||||
rtpend=20000
|
||||
icesupport=true
|
||||
stunaddr=stun.l.google.com:19302
|
||||
@@ -0,0 +1,24 @@
|
||||
services:
|
||||
asterisk:
|
||||
image: ${ASTERISK_IMAGE:?Set ASTERISK_IMAGE in deployment/.env.images or shell env}
|
||||
container_name: call-center-asterisk
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ../.env.production
|
||||
environment:
|
||||
ASTERISK_EXTERNAL_ADDRESS: 92.38.48.166
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./asterisk:/config-template:ro
|
||||
- ../.asterisk_assets:/assets
|
||||
- ../.data_local/generated_ivr_yandex/ivr:/usr/share/asterisk/sounds/ivr
|
||||
- ../.data_local/generated_ivr_yandex/ivr:/var/lib/asterisk/sounds/ivr
|
||||
- /var/spool/asterisk/monitor:/var/spool/asterisk/monitor
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- asterisk -rx "core show version" >/dev/null 2>&1
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
@@ -0,0 +1,27 @@
|
||||
services:
|
||||
asterisk:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deployment/asterisk/Dockerfile
|
||||
image: call-center-asterisk:local
|
||||
container_name: call-center-asterisk
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ../.env.production
|
||||
environment:
|
||||
ASTERISK_EXTERNAL_ADDRESS: 92.38.48.166
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./asterisk:/config-template:ro
|
||||
- ../.codex_tmp:/assets
|
||||
- ../.data_local/generated_ivr_yandex/ivr:/usr/share/asterisk/sounds/ivr
|
||||
- ../.data_local/generated_ivr_yandex/ivr:/var/lib/asterisk/sounds/ivr
|
||||
- /var/spool/asterisk/monitor:/var/spool/asterisk/monitor
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- asterisk -rx "core show version" >/dev/null 2>&1
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
@@ -0,0 +1,207 @@
|
||||
name: call-center-pg
|
||||
|
||||
x-app-env: &app_env
|
||||
CC_DATA_DIR: /app/.data_pg_parallel
|
||||
SCHEMA_MANAGEMENT_MODE: migrations
|
||||
AUTH_SERVICE_URL: http://auth-service:8000
|
||||
AUDIT_SERVICE_URL: http://audit-service:8000
|
||||
CUSTOMER_SERVICE_URL: http://customer-service:8000
|
||||
INTERACTION_SERVICE_URL: http://interaction-service:8000
|
||||
ROUTING_SERVICE_URL: http://routing-service:8000
|
||||
VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000
|
||||
RECORDING_SERVICE_URL: http://recording-service:8000
|
||||
IVR_SERVICE_URL: http://ivr-service:8000
|
||||
EVENT_BUS_SERVICE_URL: http://event-bus-service:8000
|
||||
ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000
|
||||
TELEGRAM_ADAPTER_SERVICE_URL: http://telegram-adapter-service:8000
|
||||
WHATSAPP_ADAPTER_SERVICE_URL: http://whatsapp-adapter-service:8000
|
||||
AI_ORCHESTRATOR_SERVICE_URL: http://ai-orchestrator-service:8000
|
||||
AI_VOICE_RUNTIME_SERVICE_URL: http://ai-voice-runtime-service:8000
|
||||
WEBCHAT_ADAPTER_SERVICE_URL: http://webchat-adapter-service:8000
|
||||
EMAIL_ADAPTER_SERVICE_URL: http://email-adapter-service:8000
|
||||
KB_SERVICE_URL: http://kb-service:8000
|
||||
REPORTING_SERVICE_URL: http://reporting-service:8000
|
||||
SUPERVISOR_SERVICE_URL: http://supervisor-service:8000
|
||||
|
||||
x-service-defaults: &service_defaults
|
||||
build:
|
||||
context: ..
|
||||
image: call-center-app:pg-parallel
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ../.env.production
|
||||
- ../.env.postgres.parallel.server
|
||||
environment:
|
||||
<<: *app_env
|
||||
volumes:
|
||||
- ../.data_pg_parallel:/app/.data_pg_parallel
|
||||
networks:
|
||||
- default
|
||||
- postgres
|
||||
extra_hosts:
|
||||
- host.docker.internal:host-gateway
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- python
|
||||
- -c
|
||||
- |
|
||||
from urllib.request import urlopen
|
||||
import sys
|
||||
sys.exit(0 if urlopen("http://127.0.0.1:8000/health", timeout=2).getcode() == 200 else 1)
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
|
||||
services:
|
||||
auth-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.auth_service.app:app
|
||||
|
||||
audit-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.audit_service.app:app
|
||||
|
||||
customer-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.customer_service.app:app
|
||||
|
||||
interaction-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.interaction_service.app:app
|
||||
|
||||
routing-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.routing_service.app:app
|
||||
|
||||
voice-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.voice_adapter_service.app:app
|
||||
|
||||
recording-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.recording_service.app:app
|
||||
CC_RECORDINGS_DIR: /app/.data_pg_parallel/recordings
|
||||
RECORDING_MAX_BYTES: 26214400
|
||||
|
||||
ivr-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ivr_service.app:app
|
||||
|
||||
telegram-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.telegram_adapter_service.app:app
|
||||
|
||||
whatsapp-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.whatsapp_adapter_service.app:app
|
||||
|
||||
ai-orchestrator-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_orchestrator_service.app:app
|
||||
|
||||
ai-voice-runtime-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_voice_runtime_service.app:app
|
||||
|
||||
webchat-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.webchat_adapter_service.app:app
|
||||
|
||||
email-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.email_adapter_service.app:app
|
||||
|
||||
kb-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.kb_service.app:app
|
||||
|
||||
reporting-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.reporting_service.app:app
|
||||
|
||||
supervisor-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.supervisor_service.app:app
|
||||
|
||||
event-bus-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.event_bus_service.app:app
|
||||
|
||||
asterisk-bridge-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.asterisk_bridge_service.app:app
|
||||
ASTERISK_IVR_FASTAGI_HOST: 0.0.0.0
|
||||
ASTERISK_IVR_FASTAGI_PORT: 4573
|
||||
|
||||
api-gateway:
|
||||
<<: *service_defaults
|
||||
depends_on:
|
||||
- auth-service
|
||||
- audit-service
|
||||
- customer-service
|
||||
- interaction-service
|
||||
- routing-service
|
||||
- voice-adapter-service
|
||||
- recording-service
|
||||
- ivr-service
|
||||
- telegram-adapter-service
|
||||
- whatsapp-adapter-service
|
||||
- ai-orchestrator-service
|
||||
- ai-voice-runtime-service
|
||||
- webchat-adapter-service
|
||||
- email-adapter-service
|
||||
- kb-service
|
||||
- reporting-service
|
||||
- supervisor-service
|
||||
- event-bus-service
|
||||
- asterisk-bridge-service
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: gateway.app:app
|
||||
ports:
|
||||
- "18080:8000"
|
||||
|
||||
networks:
|
||||
postgres:
|
||||
external: true
|
||||
name: call-center-postgres_default
|
||||
@@ -0,0 +1,21 @@
|
||||
name: call-center-postgres
|
||||
|
||||
services:
|
||||
postgres:
|
||||
container_name: call-center-postgres
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ../.env.postgres.server
|
||||
ports:
|
||||
- "127.0.0.1:5434:5432"
|
||||
volumes:
|
||||
- ../.data_pg:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 15s
|
||||
@@ -0,0 +1,201 @@
|
||||
name: call-center
|
||||
|
||||
x-app-env: &app_env
|
||||
CC_DATA_DIR: /app/.data_local
|
||||
DATABASE_URL: sqlite:////app/.data_local/mvp_cc.db
|
||||
AUTH_SERVICE_URL: http://auth-service:8000
|
||||
AUDIT_SERVICE_URL: http://audit-service:8000
|
||||
CUSTOMER_SERVICE_URL: http://customer-service:8000
|
||||
INTERACTION_SERVICE_URL: http://interaction-service:8000
|
||||
ROUTING_SERVICE_URL: http://routing-service:8000
|
||||
VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000
|
||||
RECORDING_SERVICE_URL: http://recording-service:8000
|
||||
IVR_SERVICE_URL: http://ivr-service:8000
|
||||
EVENT_BUS_SERVICE_URL: http://event-bus-service:8000
|
||||
ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000
|
||||
TELEGRAM_ADAPTER_SERVICE_URL: http://telegram-adapter-service:8000
|
||||
WHATSAPP_ADAPTER_SERVICE_URL: http://whatsapp-adapter-service:8000
|
||||
AI_ORCHESTRATOR_SERVICE_URL: http://ai-orchestrator-service:8000
|
||||
AI_VOICE_RUNTIME_SERVICE_URL: http://ai-voice-runtime-service:8000
|
||||
WEBCHAT_ADAPTER_SERVICE_URL: http://webchat-adapter-service:8000
|
||||
EMAIL_ADAPTER_SERVICE_URL: http://email-adapter-service:8000
|
||||
KB_SERVICE_URL: http://kb-service:8000
|
||||
REPORTING_SERVICE_URL: http://reporting-service:8000
|
||||
SUPERVISOR_SERVICE_URL: http://supervisor-service:8000
|
||||
|
||||
x-service-defaults: &service_defaults
|
||||
image: ${APP_IMAGE:?Set APP_IMAGE in deployment/.env.images or shell env}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ../.env.production
|
||||
environment:
|
||||
<<: *app_env
|
||||
volumes:
|
||||
- ../.data_local:/app/.data_local
|
||||
extra_hosts:
|
||||
- host.docker.internal:host-gateway
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- python
|
||||
- -c
|
||||
- |
|
||||
from urllib.request import urlopen
|
||||
import sys
|
||||
sys.exit(0 if urlopen("http://127.0.0.1:8000/health", timeout=2).getcode() == 200 else 1)
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
|
||||
services:
|
||||
auth-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.auth_service.app:app
|
||||
|
||||
audit-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.audit_service.app:app
|
||||
|
||||
customer-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.customer_service.app:app
|
||||
|
||||
interaction-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.interaction_service.app:app
|
||||
|
||||
routing-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.routing_service.app:app
|
||||
|
||||
voice-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.voice_adapter_service.app:app
|
||||
|
||||
recording-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.recording_service.app:app
|
||||
CC_RECORDINGS_DIR: /app/.data_local/recordings
|
||||
RECORDING_MAX_BYTES: 26214400
|
||||
|
||||
ivr-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ivr_service.app:app
|
||||
|
||||
telegram-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.telegram_adapter_service.app:app
|
||||
|
||||
whatsapp-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.whatsapp_adapter_service.app:app
|
||||
|
||||
ai-orchestrator-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_orchestrator_service.app:app
|
||||
|
||||
ai-voice-runtime-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_voice_runtime_service.app:app
|
||||
ports:
|
||||
- "9019:9019"
|
||||
|
||||
webchat-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.webchat_adapter_service.app:app
|
||||
|
||||
email-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.email_adapter_service.app:app
|
||||
|
||||
kb-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.kb_service.app:app
|
||||
|
||||
reporting-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.reporting_service.app:app
|
||||
|
||||
supervisor-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.supervisor_service.app:app
|
||||
|
||||
event-bus-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.event_bus_service.app:app
|
||||
|
||||
asterisk-bridge-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.asterisk_bridge_service.app:app
|
||||
ASTERISK_IVR_FASTAGI_HOST: 0.0.0.0
|
||||
ASTERISK_IVR_FASTAGI_PORT: 4573
|
||||
ports:
|
||||
- "4573:4573"
|
||||
|
||||
api-gateway:
|
||||
<<: *service_defaults
|
||||
container_name: call-center-api-gateway
|
||||
depends_on:
|
||||
- auth-service
|
||||
- audit-service
|
||||
- customer-service
|
||||
- interaction-service
|
||||
- routing-service
|
||||
- voice-adapter-service
|
||||
- recording-service
|
||||
- ivr-service
|
||||
- telegram-adapter-service
|
||||
- whatsapp-adapter-service
|
||||
- ai-orchestrator-service
|
||||
- ai-voice-runtime-service
|
||||
- webchat-adapter-service
|
||||
- email-adapter-service
|
||||
- kb-service
|
||||
- reporting-service
|
||||
- supervisor-service
|
||||
- event-bus-service
|
||||
- asterisk-bridge-service
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: gateway.app:app
|
||||
ports:
|
||||
- "8080:8000"
|
||||
@@ -0,0 +1,203 @@
|
||||
name: call-center
|
||||
|
||||
x-app-env: &app_env
|
||||
CC_DATA_DIR: /app/.data_local
|
||||
DATABASE_URL: sqlite:////app/.data_local/mvp_cc.db
|
||||
AUTH_SERVICE_URL: http://auth-service:8000
|
||||
AUDIT_SERVICE_URL: http://audit-service:8000
|
||||
CUSTOMER_SERVICE_URL: http://customer-service:8000
|
||||
INTERACTION_SERVICE_URL: http://interaction-service:8000
|
||||
ROUTING_SERVICE_URL: http://routing-service:8000
|
||||
VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000
|
||||
RECORDING_SERVICE_URL: http://recording-service:8000
|
||||
IVR_SERVICE_URL: http://ivr-service:8000
|
||||
EVENT_BUS_SERVICE_URL: http://event-bus-service:8000
|
||||
ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000
|
||||
TELEGRAM_ADAPTER_SERVICE_URL: http://telegram-adapter-service:8000
|
||||
WHATSAPP_ADAPTER_SERVICE_URL: http://whatsapp-adapter-service:8000
|
||||
AI_ORCHESTRATOR_SERVICE_URL: http://ai-orchestrator-service:8000
|
||||
AI_VOICE_RUNTIME_SERVICE_URL: http://ai-voice-runtime-service:8000
|
||||
WEBCHAT_ADAPTER_SERVICE_URL: http://webchat-adapter-service:8000
|
||||
EMAIL_ADAPTER_SERVICE_URL: http://email-adapter-service:8000
|
||||
KB_SERVICE_URL: http://kb-service:8000
|
||||
REPORTING_SERVICE_URL: http://reporting-service:8000
|
||||
SUPERVISOR_SERVICE_URL: http://supervisor-service:8000
|
||||
|
||||
x-service-defaults: &service_defaults
|
||||
build:
|
||||
context: ..
|
||||
image: call-center-app:local
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ../.env.production
|
||||
environment:
|
||||
<<: *app_env
|
||||
volumes:
|
||||
- ../.data_local:/app/.data_local
|
||||
extra_hosts:
|
||||
- host.docker.internal:host-gateway
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- python
|
||||
- -c
|
||||
- |
|
||||
from urllib.request import urlopen
|
||||
import sys
|
||||
sys.exit(0 if urlopen("http://127.0.0.1:8000/health", timeout=2).getcode() == 200 else 1)
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
|
||||
services:
|
||||
auth-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.auth_service.app:app
|
||||
|
||||
audit-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.audit_service.app:app
|
||||
|
||||
customer-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.customer_service.app:app
|
||||
|
||||
interaction-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.interaction_service.app:app
|
||||
|
||||
routing-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.routing_service.app:app
|
||||
|
||||
voice-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.voice_adapter_service.app:app
|
||||
|
||||
recording-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.recording_service.app:app
|
||||
CC_RECORDINGS_DIR: /app/.data_local/recordings
|
||||
RECORDING_MAX_BYTES: 26214400
|
||||
|
||||
ivr-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ivr_service.app:app
|
||||
|
||||
telegram-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.telegram_adapter_service.app:app
|
||||
|
||||
whatsapp-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.whatsapp_adapter_service.app:app
|
||||
|
||||
ai-orchestrator-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_orchestrator_service.app:app
|
||||
|
||||
ai-voice-runtime-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_voice_runtime_service.app:app
|
||||
ports:
|
||||
- "9019:9019"
|
||||
|
||||
webchat-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.webchat_adapter_service.app:app
|
||||
|
||||
email-adapter-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.email_adapter_service.app:app
|
||||
|
||||
kb-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.kb_service.app:app
|
||||
|
||||
reporting-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.reporting_service.app:app
|
||||
|
||||
supervisor-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.supervisor_service.app:app
|
||||
|
||||
event-bus-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.event_bus_service.app:app
|
||||
|
||||
asterisk-bridge-service:
|
||||
<<: *service_defaults
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.asterisk_bridge_service.app:app
|
||||
ASTERISK_IVR_FASTAGI_HOST: 0.0.0.0
|
||||
ASTERISK_IVR_FASTAGI_PORT: 4573
|
||||
ports:
|
||||
- "4573:4573"
|
||||
|
||||
api-gateway:
|
||||
<<: *service_defaults
|
||||
container_name: call-center-api-gateway
|
||||
depends_on:
|
||||
- auth-service
|
||||
- audit-service
|
||||
- customer-service
|
||||
- interaction-service
|
||||
- routing-service
|
||||
- voice-adapter-service
|
||||
- recording-service
|
||||
- ivr-service
|
||||
- telegram-adapter-service
|
||||
- whatsapp-adapter-service
|
||||
- ai-orchestrator-service
|
||||
- ai-voice-runtime-service
|
||||
- webchat-adapter-service
|
||||
- email-adapter-service
|
||||
- kb-service
|
||||
- reporting-service
|
||||
- supervisor-service
|
||||
- event-bus-service
|
||||
- asterisk-bridge-service
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: gateway.app:app
|
||||
ports:
|
||||
- "8080:8000"
|
||||
@@ -0,0 +1,325 @@
|
||||
|
||||
x-app-env: &app_env
|
||||
CC_DATA_DIR: /app/.data
|
||||
DATABASE_URL: postgresql://mvp:mvp@postgres:5432/mvpcc
|
||||
SCHEMA_MANAGEMENT_MODE: migrations
|
||||
EVENT_BUS_ENABLED: "1"
|
||||
EVENT_BUS_URL: amqp://guest:guest@rabbitmq:5672/
|
||||
EVENT_BUS_EXCHANGE: mvpcc.domain.events
|
||||
EVENT_BUS_DISPATCH_BATCH_SIZE: "50"
|
||||
EVENT_BUS_MAX_ATTEMPTS: "5"
|
||||
EVENT_BUS_POLL_INTERVAL_SECONDS: "2"
|
||||
EVENT_BUS_CONSUMER_ENABLED: "1"
|
||||
EVENT_BUS_AUDIT_QUEUE: mvpcc.audit.events
|
||||
EVENT_BUS_REPORTING_QUEUE: mvpcc.reporting.events
|
||||
ASTERISK_BRIDGE_ENABLED: "0"
|
||||
ASTERISK_AMI_EVENT_PREFIX: MVPCC
|
||||
ASTERISK_QUEUE_MAP_JSON: "{}"
|
||||
AI_VOICE_RUNTIME_SERVICE_URL: http://ai-voice-runtime-service:8000
|
||||
AI_VOICE_ENABLED: "0"
|
||||
AI_VOICE_QUEUE_CONFIG_JSON: "{}"
|
||||
AI_VOICE_ASR_PROVIDER: openai
|
||||
AI_VOICE_TTS_PROVIDER: openai
|
||||
AI_VOICE_AUDIOSOCKET_ENABLED: "1"
|
||||
AI_VOICE_AUDIOSOCKET_HOST: 0.0.0.0
|
||||
AI_VOICE_AUDIOSOCKET_PORT: "9019"
|
||||
AI_VOICE_ASR_MODEL: gpt-4o-mini-transcribe
|
||||
AI_VOICE_TTS_MODEL: gpt-4o-mini-tts
|
||||
AI_VOICE_TTS_VOICE: alloy
|
||||
AI_VOICE_TTS_CACHE_ENABLED: "1"
|
||||
AI_VOICE_TTS_CACHE_DIR: /app/.data/ai_voice_tts_cache
|
||||
AI_VOICE_VAD_MIN_SPEECH_MS: "300"
|
||||
AI_VOICE_VAD_TRAILING_SILENCE_MS: "700"
|
||||
AI_VOICE_TURN_MAX_MS: "10000"
|
||||
AI_VOICE_MEDIA_IDLE_TIMEOUT_SECONDS: "15"
|
||||
AI_VOICE_MAX_CONTEXT_SEGMENTS: "8"
|
||||
AI_VOICE_HANDOFF_TIMEOUT_SECONDS: "8"
|
||||
AI_VOICE_RUNTIME_TRUSTED_SERVICE_SUBJECTS: svc:ai-voice-runtime
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_DB: mvpcc
|
||||
POSTGRES_USER: mvp
|
||||
POSTGRES_PASSWORD: mvp
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
rabbitmq:
|
||||
image: rabbitmq:3-management
|
||||
ports:
|
||||
- "5672:5672"
|
||||
- "15672:15672"
|
||||
|
||||
auth-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.auth_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8001:8000"
|
||||
|
||||
audit-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.audit_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8002:8000"
|
||||
|
||||
customer-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.customer_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8003:8000"
|
||||
|
||||
interaction-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.interaction_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8004:8000"
|
||||
|
||||
routing-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.routing_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8005:8000"
|
||||
|
||||
voice-adapter-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.voice_adapter_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8006:8000"
|
||||
|
||||
recording-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.recording_service.app:app
|
||||
CC_RECORDINGS_DIR: /app/.data/recordings
|
||||
RECORDING_MAX_BYTES: 26214400
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8013:8000"
|
||||
|
||||
ivr-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ivr_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8014:8000"
|
||||
|
||||
telegram-adapter-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.telegram_adapter_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8007:8000"
|
||||
|
||||
whatsapp-adapter-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.whatsapp_adapter_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8019:8000"
|
||||
|
||||
ai-orchestrator-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_orchestrator_service.app:app
|
||||
TELEGRAM_ADAPTER_SERVICE_URL: http://telegram-adapter-service:8000
|
||||
WHATSAPP_ADAPTER_SERVICE_URL: http://whatsapp-adapter-service:8000
|
||||
INTERACTION_SERVICE_URL: http://interaction-service:8000
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8017:8000"
|
||||
|
||||
ai-voice-runtime-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.ai_voice_runtime_service.app:app
|
||||
AI_ORCHESTRATOR_SERVICE_URL: http://ai-orchestrator-service:8000
|
||||
ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8018:8000"
|
||||
- "9019:9019"
|
||||
|
||||
webchat-adapter-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.webchat_adapter_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8011:8000"
|
||||
|
||||
email-adapter-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.email_adapter_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8012:8000"
|
||||
|
||||
kb-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.kb_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8008:8000"
|
||||
|
||||
reporting-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.reporting_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8009:8000"
|
||||
|
||||
supervisor-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.supervisor_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8010:8000"
|
||||
|
||||
event-bus-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.event_bus_service.app:app
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8015:8000"
|
||||
|
||||
asterisk-bridge-service:
|
||||
build: ..
|
||||
depends_on: [postgres, rabbitmq]
|
||||
environment:
|
||||
<<: *app_env
|
||||
APP_MODULE: services.asterisk_bridge_service.app:app
|
||||
INTERACTION_SERVICE_URL: http://interaction-service:8000
|
||||
VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000
|
||||
RECORDING_SERVICE_URL: http://recording-service:8000
|
||||
IVR_SERVICE_URL: http://ivr-service:8000
|
||||
volumes:
|
||||
- ../.data:/app/.data
|
||||
ports:
|
||||
- "8016:8000"
|
||||
- "4573:4573"
|
||||
|
||||
api-gateway:
|
||||
build: ..
|
||||
depends_on:
|
||||
- auth-service
|
||||
- audit-service
|
||||
- customer-service
|
||||
- interaction-service
|
||||
- routing-service
|
||||
- voice-adapter-service
|
||||
- recording-service
|
||||
- ivr-service
|
||||
- telegram-adapter-service
|
||||
- whatsapp-adapter-service
|
||||
- ai-orchestrator-service
|
||||
- ai-voice-runtime-service
|
||||
- webchat-adapter-service
|
||||
- email-adapter-service
|
||||
- kb-service
|
||||
- reporting-service
|
||||
- supervisor-service
|
||||
- event-bus-service
|
||||
- asterisk-bridge-service
|
||||
environment:
|
||||
APP_MODULE: gateway.app:app
|
||||
AUTH_SERVICE_URL: http://auth-service:8000
|
||||
AUDIT_SERVICE_URL: http://audit-service:8000
|
||||
CUSTOMER_SERVICE_URL: http://customer-service:8000
|
||||
INTERACTION_SERVICE_URL: http://interaction-service:8000
|
||||
ROUTING_SERVICE_URL: http://routing-service:8000
|
||||
VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000
|
||||
RECORDING_SERVICE_URL: http://recording-service:8000
|
||||
IVR_SERVICE_URL: http://ivr-service:8000
|
||||
EVENT_BUS_SERVICE_URL: http://event-bus-service:8000
|
||||
ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000
|
||||
TELEGRAM_ADAPTER_SERVICE_URL: http://telegram-adapter-service:8000
|
||||
WHATSAPP_ADAPTER_SERVICE_URL: http://whatsapp-adapter-service:8000
|
||||
AI_ORCHESTRATOR_SERVICE_URL: http://ai-orchestrator-service:8000
|
||||
WEBCHAT_ADAPTER_SERVICE_URL: http://webchat-adapter-service:8000
|
||||
EMAIL_ADAPTER_SERVICE_URL: http://email-adapter-service:8000
|
||||
KB_SERVICE_URL: http://kb-service:8000
|
||||
REPORTING_SERVICE_URL: http://reporting-service:8000
|
||||
SUPERVISOR_SERVICE_URL: http://supervisor-service:8000
|
||||
ports:
|
||||
- "8080:8000"
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: mvp-cc-platform
|
||||
description: Helm chart for MVP Contact Center microservices
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
||||
@@ -0,0 +1,48 @@
|
||||
{{- $databaseUrl := $.Values.global.databaseUrl | default "" }}
|
||||
{{- $schemaManagementMode := $.Values.global.schemaManagementMode | default "legacy" }}
|
||||
{{- $runMigrations := and $.Values.migrations.enabled (eq $schemaManagementMode "migrations") (or $.Values.profiles.scale500.enabled $databaseUrl) }}
|
||||
{{- if $runMigrations }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-db-migrate
|
||||
namespace: {{ $.Values.namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade
|
||||
"helm.sh/hook-weight": "-10"
|
||||
"helm.sh/hook-delete-policy": "{{ $.Values.migrations.hookDeletePolicy }}"
|
||||
spec:
|
||||
backoffLimit: {{ $.Values.migrations.backoffLimit }}
|
||||
activeDeadlineSeconds: {{ $.Values.migrations.activeDeadlineSeconds }}
|
||||
ttlSecondsAfterFinished: {{ $.Values.migrations.ttlSecondsAfterFinished }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ .Release.Name }}-db-migrate
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
{{- if $.Values.global.runtimeClass }}
|
||||
runtimeClassName: {{ $.Values.global.runtimeClass }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: migrate
|
||||
image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}"
|
||||
imagePullPolicy: {{ $.Values.global.imagePullPolicy }}
|
||||
command:
|
||||
- python
|
||||
- scripts/migrate_core_db.py
|
||||
env:
|
||||
- name: CC_DATA_DIR
|
||||
value: /var/lib/mvp-cc/data
|
||||
- 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 }}"
|
||||
- name: SCHEMA_MANAGEMENT_MODE
|
||||
value: "{{ $schemaManagementMode }}"
|
||||
resources:
|
||||
requests:
|
||||
cpu: {{ $.Values.migrations.resources.requests.cpu }}
|
||||
memory: {{ $.Values.migrations.resources.requests.memory }}
|
||||
limits:
|
||||
cpu: {{ $.Values.migrations.resources.limits.cpu }}
|
||||
memory: {{ $.Values.migrations.resources.limits.memory }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .Values.namespace }}
|
||||
@@ -0,0 +1,46 @@
|
||||
{{- if .Values.rabbitmq.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
replicas: {{ .Values.rabbitmq.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rabbitmq
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rabbitmq
|
||||
spec:
|
||||
containers:
|
||||
- name: rabbitmq
|
||||
image: {{ .Values.rabbitmq.image }}
|
||||
env:
|
||||
- name: RABBITMQ_DEFAULT_USER
|
||||
value: "{{ .Values.rabbitmq.user }}"
|
||||
- name: RABBITMQ_DEFAULT_PASS
|
||||
value: "{{ .Values.rabbitmq.password }}"
|
||||
ports:
|
||||
- name: amqp
|
||||
containerPort: {{ .Values.rabbitmq.servicePort }}
|
||||
- name: management
|
||||
containerPort: {{ .Values.rabbitmq.managementPort }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
namespace: {{ .Values.namespace }}
|
||||
spec:
|
||||
selector:
|
||||
app: rabbitmq
|
||||
ports:
|
||||
- name: amqp
|
||||
port: {{ .Values.rabbitmq.servicePort }}
|
||||
targetPort: {{ .Values.rabbitmq.servicePort }}
|
||||
- name: management
|
||||
port: {{ .Values.rabbitmq.managementPort }}
|
||||
targetPort: {{ .Values.rabbitmq.managementPort }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,404 @@
|
||||
{{- 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 }}
|
||||
@@ -0,0 +1,12 @@
|
||||
profiles:
|
||||
scale500:
|
||||
enabled: true
|
||||
|
||||
auth:
|
||||
allowLegacyHeaderAuth: "0"
|
||||
|
||||
db:
|
||||
poolSize: "15"
|
||||
maxOverflow: "30"
|
||||
poolTimeoutSeconds: "30"
|
||||
poolRecycleSeconds: "1800"
|
||||
@@ -0,0 +1,77 @@
|
||||
auth:
|
||||
allowLegacyHeaderAuth: "0"
|
||||
|
||||
eventBus:
|
||||
enabled: "0"
|
||||
url: amqp://guest:guest@rabbitmq:5672/
|
||||
exchange: mvpcc.domain.events
|
||||
dispatchBatchSize: "50"
|
||||
maxAttempts: "5"
|
||||
pollIntervalSeconds: "2"
|
||||
consumerEnabled: "1"
|
||||
auditQueue: mvpcc.audit.events
|
||||
reportingQueue: mvpcc.reporting.events
|
||||
|
||||
rabbitmq:
|
||||
enabled: false
|
||||
image: rabbitmq:3-management
|
||||
replicas: 1
|
||||
user: guest
|
||||
password: guest
|
||||
servicePort: 5672
|
||||
managementPort: 15672
|
||||
|
||||
asteriskBridge:
|
||||
enabled: "1"
|
||||
amiEventPrefix: MVPCC
|
||||
queueMapJson: '{"voice_lab":"<queue_id>"}'
|
||||
authMode: bearer
|
||||
authFallbackLegacy: "0"
|
||||
authSubject: svc:asterisk-bridge
|
||||
authUser: asterisk-bridge
|
||||
authRole: admin
|
||||
authTokenTtlSeconds: "300"
|
||||
callcontrolEnabled: "0"
|
||||
callcontrolActionTimeoutSeconds: "10"
|
||||
operatorExtensionMapJson: "{}"
|
||||
transferTargetMapJson: "{}"
|
||||
claimContext: mvpcc-claim
|
||||
transferContext: mvpcc-transfer
|
||||
pollIntervalSeconds: "1"
|
||||
|
||||
voiceAdapter:
|
||||
trustedServiceSubjects: svc:asterisk-bridge,svc:ivr-service
|
||||
|
||||
recording:
|
||||
importTrustedServiceSubjects: svc:asterisk-bridge
|
||||
importAllowAdmin: "0"
|
||||
|
||||
services:
|
||||
auth-service:
|
||||
replicas: 1
|
||||
voice-adapter-service:
|
||||
replicas: 1
|
||||
recording-service:
|
||||
replicas: 1
|
||||
asterisk-bridge-service:
|
||||
module: services.asterisk_bridge_service.app:app
|
||||
# Must stay singleton: background AMI consumption and retry/reconcile loops are not multi-replica safe.
|
||||
replicas: 1
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
@@ -0,0 +1,18 @@
|
||||
auth:
|
||||
allowLegacyHeaderAuth: "0"
|
||||
|
||||
asteriskBridge:
|
||||
enabled: "1"
|
||||
authMode: bearer
|
||||
authFallbackLegacy: "0"
|
||||
authSubject: svc:asterisk-bridge
|
||||
authUser: asterisk-bridge
|
||||
authRole: admin
|
||||
authTokenTtlSeconds: "300"
|
||||
|
||||
voiceAdapter:
|
||||
trustedServiceSubjects: svc:asterisk-bridge,svc:ivr-service
|
||||
|
||||
recording:
|
||||
importTrustedServiceSubjects: svc:asterisk-bridge
|
||||
importAllowAdmin: "0"
|
||||
@@ -0,0 +1,538 @@
|
||||
namespace: mvp-cc
|
||||
|
||||
image:
|
||||
repository: mvp-cc-platform
|
||||
tag: latest
|
||||
|
||||
global:
|
||||
databaseUrl: postgresql://mvp:mvp@postgresql.mvp-cc.svc.cluster.local:5432/mvpcc
|
||||
schemaManagementMode: migrations
|
||||
runtimeClass: ""
|
||||
imagePullPolicy: IfNotPresent
|
||||
|
||||
migrations:
|
||||
enabled: true
|
||||
backoffLimit: 1
|
||||
activeDeadlineSeconds: 300
|
||||
ttlSecondsAfterFinished: 600
|
||||
hookDeletePolicy: before-hook-creation,hook-succeeded
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
|
||||
profiles:
|
||||
scale500:
|
||||
enabled: false
|
||||
|
||||
db:
|
||||
poolSize: "15"
|
||||
maxOverflow: "30"
|
||||
poolTimeoutSeconds: "30"
|
||||
poolRecycleSeconds: "1800"
|
||||
|
||||
voiceAdapter:
|
||||
trustedServiceSubjects: svc:asterisk-bridge,svc:ivr-service
|
||||
|
||||
ivrRuntime:
|
||||
trustedServiceSubjects: svc:asterisk-bridge
|
||||
|
||||
recording:
|
||||
importTrustedServiceSubjects: svc:asterisk-bridge
|
||||
importAllowAdmin: "1"
|
||||
|
||||
voiceAI:
|
||||
enabled: "0"
|
||||
queueConfigJson: "{}"
|
||||
asrProvider: openai
|
||||
ttsProvider: openai
|
||||
audioSocketEnabled: "1"
|
||||
audioSocketHost: 0.0.0.0
|
||||
audioSocketPort: "9019"
|
||||
asrModel: gpt-4o-mini-transcribe
|
||||
ttsModel: gpt-4o-mini-tts
|
||||
ttsVoice: alloy
|
||||
ttsCacheEnabled: "1"
|
||||
ttsCacheDir: /var/lib/mvp-cc/data/ai_voice_tts_cache
|
||||
vadMinSpeechMs: "300"
|
||||
vadTrailingSilenceMs: "700"
|
||||
turnMaxMs: "10000"
|
||||
mediaIdleTimeoutSeconds: "15"
|
||||
maxContextSegments: "8"
|
||||
handoffTimeoutSeconds: "8"
|
||||
runtimeTrustedServiceSubjects: svc:ai-voice-runtime
|
||||
|
||||
eventBus:
|
||||
enabled: "0"
|
||||
url: amqp://guest:guest@rabbitmq:5672/
|
||||
exchange: mvpcc.domain.events
|
||||
dispatchBatchSize: "50"
|
||||
maxAttempts: "5"
|
||||
pollIntervalSeconds: "2"
|
||||
consumerEnabled: "1"
|
||||
auditQueue: mvpcc.audit.events
|
||||
reportingQueue: mvpcc.reporting.events
|
||||
|
||||
asteriskBridge:
|
||||
enabled: "0"
|
||||
amiHost: ""
|
||||
amiPort: "5038"
|
||||
amiUsername: ""
|
||||
amiSecret: ""
|
||||
amiEventPrefix: MVPCC
|
||||
queueMapJson: "{}"
|
||||
authMode: legacy_headers
|
||||
authFallbackLegacy: "1"
|
||||
authSubject: svc:asterisk-bridge
|
||||
authUser: asterisk-bridge
|
||||
authRole: admin
|
||||
authTokenTtlSeconds: "300"
|
||||
ivrFastagiEnabled: "0"
|
||||
ivrFastagiHost: 0.0.0.0
|
||||
ivrFastagiPort: "4573"
|
||||
ivrDtmfTimeoutSeconds: "5"
|
||||
ivrMaxNoInputRetries: "2"
|
||||
ivrMaxInvalidRetries: "2"
|
||||
ivrCallLinkWaitSeconds: "5"
|
||||
callcontrolEnabled: "0"
|
||||
callcontrolActionTimeoutSeconds: "10"
|
||||
operatorExtensionMapJson: "{}"
|
||||
transferTargetMapJson: "{}"
|
||||
claimContext: mvpcc-claim
|
||||
transferContext: mvpcc-transfer
|
||||
sftpHost: ""
|
||||
sftpPort: "22"
|
||||
sftpUsername: ""
|
||||
sftpPassword: ""
|
||||
sftpBasePath: /var/spool/asterisk/monitor
|
||||
pollIntervalSeconds: "1"
|
||||
|
||||
rabbitmq:
|
||||
enabled: false
|
||||
image: rabbitmq:3-management
|
||||
replicas: 1
|
||||
user: guest
|
||||
password: guest
|
||||
servicePort: 5672
|
||||
managementPort: 15672
|
||||
|
||||
auth:
|
||||
appTokenSecret: change-me-app-token-secret
|
||||
appTokenTtlSeconds: "3600"
|
||||
allowLegacyHeaderAuth: "1"
|
||||
oidc:
|
||||
enabled: "0"
|
||||
provider: keycloak
|
||||
issuerUrl: https://keycloak.example.local/realms/mvp-cc
|
||||
clientId: mvp-cc
|
||||
clientSecret: change-me-keycloak-client-secret
|
||||
redirectUri: https://cc.example.local/proxy/auth/auth/oidc/callback
|
||||
scopes: openid profile email
|
||||
roleClaim: groups
|
||||
roleMapJson: '{"kc_admin":"admin","kc_supervisor":"supervisor","kc_operator":"operator","kc_analyst":"analyst"}'
|
||||
|
||||
services:
|
||||
auth-service:
|
||||
module: services.auth_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
audit-service:
|
||||
module: services.audit_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
customer-service:
|
||||
module: services.customer_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
interaction-service:
|
||||
module: services.interaction_service.app:app
|
||||
replicas: 4
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 1Gi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 4
|
||||
maxReplicas: 8
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
routing-service:
|
||||
module: services.routing_service.app:app
|
||||
replicas: 3
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 1Gi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 3
|
||||
maxReplicas: 6
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
voice-adapter-service:
|
||||
module: services.voice_adapter_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
recording-service:
|
||||
module: services.recording_service.app:app
|
||||
replicas: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 10Gi
|
||||
ivr-service:
|
||||
module: services.ivr_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
event-bus-service:
|
||||
module: services.event_bus_service.app:app
|
||||
replicas: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
asterisk-bridge-service:
|
||||
module: services.asterisk_bridge_service.app:app
|
||||
# Must stay singleton: background AMI consumption and retry/reconcile loops are not multi-replica safe.
|
||||
replicas: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
telegram-adapter-service:
|
||||
module: services.telegram_adapter_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
ai-orchestrator-service:
|
||||
module: services.ai_orchestrator_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
ai-voice-runtime-service:
|
||||
module: services.ai_voice_runtime_service.app:app
|
||||
replicas: 1
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
webchat-adapter-service:
|
||||
module: services.webchat_adapter_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
email-adapter-service:
|
||||
module: services.email_adapter_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
kb-service:
|
||||
module: services.kb_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
reporting-service:
|
||||
module: services.reporting_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
supervisor-service:
|
||||
module: services.supervisor_service.app:app
|
||||
replicas: 2
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 2
|
||||
maxReplicas: 2
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
api-gateway:
|
||||
module: gateway.app:app
|
||||
gateway: true
|
||||
replicas: 4
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 1Gi
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 4
|
||||
maxReplicas: 8
|
||||
targetCPUUtilizationPercentage: 70
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
persistence:
|
||||
enabled: false
|
||||
size: 1Gi
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: prometheus-config
|
||||
namespace: mvp-cc
|
||||
data:
|
||||
prometheus.yml: |
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
scrape_configs:
|
||||
- job_name: 'mvp-services'
|
||||
metrics_path: /health
|
||||
static_configs:
|
||||
- targets:
|
||||
- auth-service:8000
|
||||
- audit-service:8000
|
||||
- customer-service:8000
|
||||
- interaction-service:8000
|
||||
- routing-service:8000
|
||||
- voice-adapter-service:8000
|
||||
- telegram-adapter-service:8000
|
||||
- kb-service:8000
|
||||
- reporting-service:8000
|
||||
- supervisor-service:8000
|
||||
- api-gateway:8000
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: mvp-cc
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: prometheus
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: prometheus
|
||||
spec:
|
||||
containers:
|
||||
- name: prometheus
|
||||
image: prom/prometheus:v2.55.1
|
||||
args:
|
||||
- --config.file=/etc/prometheus/prometheus.yml
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/prometheus
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: prometheus-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: prometheus
|
||||
namespace: mvp-cc
|
||||
spec:
|
||||
selector:
|
||||
app: prometheus
|
||||
ports:
|
||||
- name: http
|
||||
port: 9090
|
||||
targetPort: 9090
|
||||
type: ClusterIP
|
||||
Reference in New Issue
Block a user