Реализация на отдельных двух машинах с протестированным взаимодействием по проверке сообщений

This commit is contained in:
mi
2026-08-19 18:24:00 +03:00
parent bbef7a30c9
commit c7a80e7256
103 changed files with 3457 additions and 3725 deletions
@@ -28,9 +28,7 @@ x-api-secrets: &api-secrets
- cursor_hmac_secret
x-api-runtime: &api-runtime
build:
context: ../../api-backend
image: ${API_BACKEND_IMAGE:-han-chat-api-backend:local}
image: ${API_BACKEND_IMAGE:?API_BACKEND_IMAGE must be pinned by digest}
environment:
<<: *api-secret-environment
APP_ENV: ${APP_ENV:-production-like}
@@ -40,8 +38,8 @@ x-api-runtime: &api-runtime
KEYCLOAK_INTERNAL_URL: ${KEYCLOAK_INTERNAL_URL:-http://keycloak:8080/auth}
KEYCLOAK_REALM: ${KEYCLOAK_REALM:-han-chat}
KEYCLOAK_AUDIENCE: ${KEYCLOAK_AUDIENCE:-han-chat-api}
MESSAGE_SAFETY_URL: ${MESSAGE_SAFETY_URL}
MESSAGE_SAFETY_API_PREFIX: /internal/safety/v2
MESSAGE_SAFETY_URL: ${MESSAGE_SAFETY_URL:-https://processing.internal:8443}
MESSAGE_SAFETY_API_PREFIX: ${MESSAGE_SAFETY_API_PREFIX:-/internal/safety/v2}
MESSAGE_SAFETY_CA_FILE: /run/config/message-safety-internal-ca.pem
MESSAGE_SAFETY_POST_TIMEOUT_SEC: ${MESSAGE_SAFETY_POST_TIMEOUT_SEC:-5}
MESSAGE_SAFETY_TASK_POLL_INTERVAL_SEC: ${MESSAGE_SAFETY_TASK_POLL_INTERVAL_SEC:-2}
@@ -65,8 +63,17 @@ x-api-runtime: &api-runtime
source: ${MESSAGE_SAFETY_CA_HOST_PATH}
target: /run/config/message-safety-internal-ca.pem
read_only: true
extra_hosts:
- "${MESSAGE_SAFETY_EXTRA_HOST:?MESSAGE_SAFETY_EXTRA_HOST must map VM2 private DNS to private IP}"
networks: [backend, observability, egress]
read_only: true
tmpfs:
- /tmp:size=128m,mode=1777
cap_drop: ["ALL"]
security_opt: ["no-new-privileges:true"]
pids_limit: 256
mem_limit: 1g
cpus: 1.0
ulimits:
core: {soft: 0, hard: 0}
logging:
@@ -96,9 +103,7 @@ x-sms-api-secrets: &sms-api-secrets
- idgtl_sms_callback_password
x-sms-runtime: &sms-runtime
build:
context: ../../sms-service
image: ${SMS_SERVICE_IMAGE:-han-chat-sms-service:local}
image: ${SMS_SERVICE_IMAGE:?SMS_SERVICE_IMAGE must be pinned by digest}
environment: *sms-api-environment
secrets: *sms-api-secrets
volumes:
@@ -106,7 +111,14 @@ x-sms-runtime: &sms-runtime
source: ${PG_CA_HOST_PATH}
target: /run/secrets/pg-ca.pem
read_only: true
read_only: true
tmpfs:
- /tmp:size=64m,mode=1777
cap_drop: ["ALL"]
security_opt: ["no-new-privileges:true"]
pids_limit: 128
mem_limit: 512m
cpus: 0.5
ulimits:
core: {soft: 0, hard: 0}
logging:
@@ -115,16 +127,7 @@ x-sms-runtime: &sms-runtime
services:
frontend-static:
build:
context: ../../frontend-test-site
target: static
args:
EXPO_PUBLIC_API_BASE_URL: ${PUBLIC_WEB_URL}
EXPO_PUBLIC_AUTH_BASE_URL: ${PUBLIC_AUTH_URL}
EXPO_PUBLIC_KEYCLOAK_REALM: ${KEYCLOAK_REALM:-han-chat}
EXPO_PUBLIC_KEYCLOAK_CLIENT_ID: han-chat-frontend
EXPO_PUBLIC_APP_ENV: ${APP_ENV:-production-like}
image: han-chat-frontend-static:${RELEASE_VERSION:-local}
image: ${FRONTEND_STATIC_IMAGE:?FRONTEND_STATIC_IMAGE must be pinned by digest}
volumes:
- frontend-static:/output
restart: "no"
@@ -133,13 +136,14 @@ services:
- /tmp:size=8m,mode=1777
cap_drop: ["ALL"]
security_opt: ["no-new-privileges:true"]
pids_limit: 64
mem_limit: 128m
cpus: 0.25
ulimits:
core: {soft: 0, hard: 0}
keycloak:
build:
context: ../../keycloak
image: ${KEYCLOAK_IMAGE:-han-chat-keycloak:local}
image: ${KEYCLOAK_IMAGE:?KEYCLOAK_IMAGE must be pinned by digest}
environment:
HAN_SECRET_VARS: >-
KC_DB_PASSWORD KC_BOOTSTRAP_ADMIN_PASSWORD
@@ -164,6 +168,7 @@ services:
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
KC_HOSTNAME: ${KEYCLOAK_PUBLIC_URL}
PUBLIC_WEB_URL: ${PUBLIC_WEB_URL:?PUBLIC_WEB_URL is required for realm import}
KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN}
KEYCLOAK_OTP_MOCK_ENABLED: ${KEYCLOAK_OTP_MOCK_ENABLED:-false}
KEYCLOAK_YANDEX_CAPTCHA_ENABLED: ${KEYCLOAK_YANDEX_CAPTCHA_ENABLED:-false}
@@ -194,7 +199,12 @@ services:
retries: 12
start_period: 60s
restart: unless-stopped
cap_drop: ["ALL"]
security_opt: ["no-new-privileges:true"]
# read_only is intentionally omitted until Keycloak runtime data/provider paths are externalized.
pids_limit: 512
mem_limit: 2g
cpus: 2.0
ulimits:
core: {soft: 0, hard: 0}
logging:
@@ -242,45 +252,12 @@ services:
start_period: 10s
restart: unless-stopped
message-safety:
build:
context: ../../message-safety
image: ${MESSAGE_SAFETY_IMAGE:-han-chat-message-safety:local}
environment:
HAN_SECRET_VARS: MESSAGE_SAFETY_REDIS_URL MESSAGE_SAFETY_SERVICE_TOKEN
MESSAGE_SAFETY_REDIS_URL_FILE: /run/secrets/message_safety_redis_url
MESSAGE_SAFETY_SERVICE_TOKEN_FILE: /run/secrets/message_safety_service_token
APP_ENV: ${APP_ENV:-production-like}
MESSAGE_SAFETY_RULES_VERSION: ${MESSAGE_SAFETY_RULES_VERSION:-2026-01-01}
MESSAGE_SAFETY_TASK_TTL_SEC: ${MESSAGE_SAFETY_TASK_TTL_SEC:-900}
secrets:
- message_safety_redis_url
- message_safety_service_token
expose: ["8080"]
networks: [backend, observability, egress]
depends_on:
redis: {condition: service_healthy}
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health/ready', timeout=3)"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30s
restart: unless-stopped
security_opt: ["no-new-privileges:true"]
ulimits:
core: {soft: 0, hard: 0}
logging:
driver: json-file
options: {max-size: "50m", max-file: "5"}
api-backend:
<<: *api-runtime
expose: ["8000"]
depends_on:
redis: {condition: service_healthy}
keycloak: {condition: service_healthy}
message-safety: {condition: service_healthy}
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health/ready', timeout=3)"]
interval: 10s
@@ -308,7 +285,6 @@ services:
command: ["han-safety-worker"]
depends_on:
api-backend: {condition: service_healthy}
message-safety: {condition: service_healthy}
healthcheck:
test: ["CMD", "python", "-c", "from pathlib import Path; assert b'han-safety-worker' in Path('/proc/1/cmdline').read_bytes()"]
interval: 30s
@@ -348,7 +324,6 @@ services:
command: ["han-notification-draft-cleanup-worker"]
depends_on:
api-backend: {condition: service_healthy}
message-safety: {condition: service_healthy}
healthcheck:
test: ["CMD", "python", "-c", "from pathlib import Path; assert b'han-notification-draft-cleanup-worker' in Path('/proc/1/cmdline').read_bytes()"]
interval: 30s
@@ -358,9 +333,7 @@ services:
restart: unless-stopped
bitrix-local-app:
build:
context: ../../bitrix-local-app
image: ${BITRIX_LOCAL_APP_IMAGE:-han-chat-bitrix-local-app:local}
image: ${BITRIX_LOCAL_APP_IMAGE:?BITRIX_LOCAL_APP_IMAGE must be pinned by digest}
environment:
HAN_SECRET_VARS: >-
BITRIX_DATABASE_URL BITRIX_CLIENT_SECRET
@@ -404,47 +377,20 @@ services:
retries: 12
start_period: 30s
restart: unless-stopped
read_only: true
tmpfs:
- /tmp:size=64m,mode=1777
cap_drop: ["ALL"]
security_opt: ["no-new-privileges:true"]
pids_limit: 128
mem_limit: 512m
cpus: 0.5
ulimits:
core: {soft: 0, hard: 0}
logging:
driver: json-file
options: {max-size: "50m", max-file: "5"}
bitrix-sync:
build:
context: ../../bitrix-sync
image: ${BITRIX_SYNC_IMAGE:-han-chat-bitrix-sync:local}
environment:
HAN_SECRET_VARS: BITRIX_SYNC_DATABASE_URL BITRIX_SYNC_SERVICE_TOKEN
BITRIX_SYNC_DATABASE_URL_FILE: /run/secrets/bitrix_sync_database_url
BITRIX_SYNC_SERVICE_TOKEN_FILE: /run/secrets/bitrix_sync_service_token
APP_ENV: ${APP_ENV:-production-like}
BITRIX_SYNC_ENABLED: ${BITRIX_SYNC_ENABLED:-false}
secrets:
- bitrix_sync_database_url
- bitrix_sync_service_token
expose: ["8080"]
volumes:
- type: bind
source: ${PG_CA_HOST_PATH}
target: /run/secrets/pg-ca.pem
read_only: true
networks: [backend, observability, egress]
depends_on:
redis: {condition: service_healthy}
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health/live', timeout=3)"]
interval: 15s
timeout: 5s
retries: 12
start_period: 30s
restart: unless-stopped
security_opt: ["no-new-privileges:true"]
logging:
driver: json-file
options: {max-size: "50m", max-file: "5"}
secrets:
api_database_url:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/DATABASE_URL
@@ -476,8 +422,6 @@ secrets:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/IDGTL_SMS_CALLBACK_USERNAME
idgtl_sms_callback_password:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/IDGTL_SMS_CALLBACK_PASSWORD
message_safety_redis_url:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/MESSAGE_SAFETY_REDIS_URL
bitrix_database_url:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/BITRIX_DATABASE_URL
bitrix_client_secret:
@@ -490,10 +434,6 @@ secrets:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/BITRIX_API_FORWARD_TOKEN
bitrix_token_encryption_key:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/BITRIX_TOKEN_ENCRYPTION_KEY
bitrix_sync_database_url:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/BITRIX_SYNC_DATABASE_URL
bitrix_sync_service_token:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/BITRIX_SYNC_SERVICE_TOKEN
keycloak_db_password:
file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_DB_PASSWORD
keycloak_admin_password: