Files
han-app/VM2_services/codebase/services/docker-compose.yml
T

463 lines
15 KiB
YAML

name: han-processing
x-hardening: &hardening
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
restart: unless-stopped
x-postgres-ca-volume: &postgres-ca-volume
type: bind
source: ${PG_CA_HOST_PATH:?set PostgreSQL CA host path}
target: /run/config/postgresql-ca.pem
read_only: true
x-message-safety-environment: &message-safety-environment
APP_ENV: ${APP_ENV:?set APP_ENV}
RELEASE_VERSION: ${RELEASE_VERSION:?set RELEASE_VERSION}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
MESSAGE_SAFETY_HOST: ${MESSAGE_SAFETY_HOST:-0.0.0.0}
MESSAGE_SAFETY_PORT: ${MESSAGE_SAFETY_PORT:-8080}
MESSAGE_SAFETY_WORKER_CONCURRENCY: ${MESSAGE_SAFETY_WORKER_CONCURRENCY:-5}
MESSAGE_SAFETY_DNS_RESOLVERS: ${MESSAGE_SAFETY_DNS_RESOLVERS:?set trusted DNS resolvers}
MESSAGE_SAFETY_ANTIVIRUS_SOCKET: /run/han-kesl/scan.sock
MESSAGE_SAFETY_ARTIFACTS_DIR: ${MESSAGE_SAFETY_ARTIFACTS_DIR:-/app/app/artifacts}
MESSAGE_SAFETY_MODE_FILE: /etc/han-chat/message-safety-mode.env
PG_CA_FILE: /run/config/postgresql-ca.pem
SELECTEL_S3_ENDPOINT_URL: ${SELECTEL_S3_ENDPOINT_URL:?set S3 endpoint}
SELECTEL_S3_BUCKET_QUARANTINE: ${SELECTEL_S3_BUCKET_QUARANTINE:?set quarantine bucket}
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4317}
MESSAGE_SAFETY_DATABASE_URL_FILE: /run/secrets/message_safety_database_url
MESSAGE_SAFETY_REDIS_URL_FILE: /run/secrets/message_safety_redis_url
MESSAGE_SAFETY_SERVICE_TOKEN_FILE: /run/secrets/message_safety_service_token
SELECTEL_S3_QUARANTINE_READ_ACCESS_KEY_FILE: /run/secrets/s3_quarantine_read_access_key
SELECTEL_S3_QUARANTINE_READ_SECRET_KEY_FILE: /run/secrets/s3_quarantine_read_secret_key
x-bitrix-sync-environment: &bitrix-sync-environment
APP_ENV: ${APP_ENV:?set APP_ENV}
RELEASE_VERSION: ${RELEASE_VERSION:?set RELEASE_VERSION}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
BITRIX_SYNC_ENABLED: ${BITRIX_SYNC_ENABLED:-false}
BITRIX_SYNC_MODE: ${BITRIX_SYNC_MODE:-disabled}
BITRIX_SYNC_PORTAL_HOST: ${BITRIX_SYNC_PORTAL_HOST:?set approved portal}
BITRIX_SYNC_PORTAL_MEMBER_ID: ${BITRIX_SYNC_PORTAL_MEMBER_ID:?set member id}
BITRIX_SYNC_PUBLIC_BASE_URL: ${BITRIX_SYNC_PUBLIC_BASE_URL:?set public base URL}
BITRIX_SYNC_CONTACT_USER_ID_FIELD: ${BITRIX_SYNC_CONTACT_USER_ID_FIELD:?set contact field}
BITRIX_SYNC_CONTACT_REGISTERED_FIELD: ${BITRIX_SYNC_CONTACT_REGISTERED_FIELD:?set registration field}
BITRIX_SYNC_CONTACT_CITIZENSHIP_FIELD: ${BITRIX_SYNC_CONTACT_CITIZENSHIP_FIELD:?set citizenship field}
BITRIX_SYNC_CONTACT_SOURCE: ${BITRIX_SYNC_CONTACT_SOURCE:?set contact source}
BITRIX_SYNC_WEBHOOK_ALLOWED_CIDRS: ${BITRIX_WEBHOOK_ALLOWED_CIDRS:-}
BITRIX_SYNC_HTTP_TIMEOUT_SEC: ${BITRIX_SYNC_HTTP_TIMEOUT_SEC:-10}
BITRIX_SYNC_DB_POOL_SIZE: ${BITRIX_SYNC_DB_POOL_SIZE:-5}
PG_CA_FILE: /run/config/postgresql-ca.pem
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4317}
BITRIX_SYNC_DATABASE_URL_FILE: /run/secrets/bitrix_sync_database_url
BITRIX_SYNC_CRM_REST_WEBHOOK_URL_FILE: /run/secrets/bitrix_sync_crm_rest_webhook_url
BITRIX_SYNC_CONTACT_RECEIVER_TOKEN_FILE: /run/secrets/bitrix_sync_contact_receiver_token
BITRIX_SYNC_ALERT_RECEIVER_TOKEN_FILE: /run/secrets/bitrix_sync_alert_receiver_token
BITRIX_SYNC_SERVICE_TOKEN_FILE: /run/secrets/bitrix_sync_service_token
services:
nginx:
<<: *hardening
image: ${NGINX_IMAGE:?set immutable nginx image digest}
user: "101:11001"
environment:
PROCESSING_PUBLIC_HOST: ${PROCESSING_PUBLIC_HOST:?set PROCESSING_PUBLIC_HOST}
MESSAGE_SAFETY_UPSTREAM_HOST: message-safety-api
BITRIX_SYNC_UPSTREAM_HOST: bitrix-sync
ports:
- "80:8080"
- "443:8444"
- "${PROCESSING_PRIVATE_BIND_ADDRESS:?set private bind IP}:8443:8443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/templates:/etc/nginx/templates:ro
- ./nginx/allowlists:/etc/nginx/allowlists:ro
- /var/lib/han-chat/public-tls:/run/public-tls:ro
- /var/lib/han-chat/acme:/var/www/certbot:ro
secrets:
- source: internal_tls_certificate
target: internal_tls_certificate
mode: 0444
- source: internal_tls_private_key
target: internal_tls_private_key
mode: 0444
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=64m
- /var/cache/nginx:rw,noexec,nosuid,nodev,size=64m,uid=101,gid=11001,mode=0750
- /var/run:rw,noexec,nosuid,nodev,size=8m,uid=101,gid=11001,mode=0750
- /etc/nginx/conf.d:rw,noexec,nosuid,nodev,size=8m,uid=101,gid=11001,mode=0750
ulimits:
nofile:
soft: 4096
hard: 4096
networks: [public, backend, observability]
expose: ["8081"]
depends_on:
message-safety-api:
condition: service_started
bitrix-sync:
condition: service_started
healthcheck:
test: ["CMD", "nginx", "-t", "-q", "-c", "/etc/nginx/nginx.conf"]
interval: 15s
timeout: 3s
retries: 3
start_period: 10s
pids_limit: 200
mem_limit: 256m
cpus: 1.0
redis-safety:
<<: *hardening
image: ${REDIS_IMAGE:?set immutable Redis image digest}
user: "999:999"
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
- redis-safety-data:/data
secrets:
- source: redis_safety_acl
target: redis-safety.acl
mode: 0444
networks: [backend]
expose: ["6379"]
healthcheck:
test: ["CMD", "redis-cli", "--no-auth-warning", "PING"]
interval: 15s
timeout: 3s
retries: 3
pids_limit: 100
mem_limit: 640m
cpus: 1.0
redis-exporter:
<<: *hardening
image: ${REDIS_EXPORTER_IMAGE:?set immutable Redis exporter image digest}
environment:
REDIS_ADDR: redis://redis-safety:6379
REDIS_USER: exporter
REDIS_PASSWORD_FILE: /run/secrets/redis_exporter_password
secrets:
- redis_exporter_password
networks: [backend, observability]
expose: ["9121"]
depends_on:
redis-safety:
condition: service_healthy
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=16m
pids_limit: 50
mem_limit: 64m
cpus: 0.25
nginx-exporter:
<<: *hardening
image: ${NGINX_EXPORTER_IMAGE:?set immutable nginx exporter image digest}
command:
- --nginx.scrape-uri=http://nginx:8081/stub_status
networks: [observability]
expose: ["9113"]
depends_on:
nginx:
condition: service_healthy
pids_limit: 50
mem_limit: 64m
cpus: 0.25
otel-queue-init:
<<: *hardening
image: ${REDIS_IMAGE:?set immutable Redis image digest}
entrypoint: ["sh", "-c"]
command: ["chown 10001:10001 /queue && chmod 0700 /queue"]
user: "0:0"
restart: "no"
network_mode: none
volumes:
- otel-queue:/queue
cap_add:
- CHOWN
- FOWNER
pids_limit: 20
mem_limit: 32m
cpus: 0.1
otel-collector:
<<: *hardening
image: ${OTEL_COLLECTOR_IMAGE:?set immutable Collector image digest}
user: "10001:10001"
command: ["--config=/etc/otelcol-contrib/config.yaml"]
environment:
APP_ENV: ${APP_ENV:?set APP_ENV}
RELEASE_VERSION: ${RELEASE_VERSION:?set RELEASE_VERSION}
OTEL_REMOTE_ENDPOINT: ${OTEL_REMOTE_ENDPOINT:?set private OTLP endpoint}
OTEL_REMOTE_TLS_INSECURE: ${OTEL_REMOTE_TLS_INSECURE:?set OTLP TLS mode}
volumes:
- ./observability/otel-collector.yaml:/etc/otelcol-contrib/config.yaml:ro
- otel-queue:/var/lib/otelcol/queue
- /:/hostfs:ro
networks:
observability: {}
telemetry-egress:
gw_priority: 1
depends_on:
otel-queue-init:
condition: service_completed_successfully
expose: ["4317", "4318", "13133", "8888"]
healthcheck:
test: ["CMD", "/otelcol-contrib", "validate", "--config=/etc/otelcol-contrib/config.yaml"]
interval: 30s
timeout: 5s
retries: 3
pids_limit: 200
mem_limit: 512m
cpus: 1.0
message-safety-api:
<<: *hardening
image: ${MESSAGE_SAFETY_IMAGE:?set immutable message-safety image digest}
command: ["message-safety"]
user: "10001:10001"
environment:
<<: *message-safety-environment
MESSAGE_SAFETY_PROCESS_ROLE: api
volumes:
- /etc/han-chat/message-safety-mode.env:/etc/han-chat/message-safety-mode.env:ro
- /run/han-kesl:/run/han-kesl:ro
- *postgres-ca-volume
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=64m
networks:
backend: {}
observability: {}
safety-egress:
gw_priority: 1
expose: ["8080"]
secrets:
- message_safety_database_url
- message_safety_redis_url
- message_safety_service_token
depends_on:
redis-safety:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health/live',timeout=2)"]
interval: 15s
timeout: 3s
retries: 3
start_period: 20s
pids_limit: 200
mem_limit: 512m
cpus: 1.0
message-safety-worker:
<<: *hardening
image: ${MESSAGE_SAFETY_IMAGE:?set immutable message-safety image digest}
command: ["message-safety-worker"]
user: "10001:10001"
environment:
<<: *message-safety-environment
MESSAGE_SAFETY_PROCESS_ROLE: worker
volumes:
- /etc/han-chat/message-safety-mode.env:/etc/han-chat/message-safety-mode.env:ro
- /run/han-kesl:/run/han-kesl:ro
- *postgres-ca-volume
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=256m
networks:
backend: {}
observability: {}
safety-egress:
gw_priority: 1
secrets:
- message_safety_database_url
- message_safety_redis_url
- s3_quarantine_read_access_key
- s3_quarantine_read_secret_key
depends_on:
redis-safety:
condition: service_healthy
pids_limit: 400
mem_limit: 2g
cpus: 2.0
message-safety-migrate:
<<: *hardening
image: ${MESSAGE_SAFETY_IMAGE:?set immutable message-safety image digest}
entrypoint: ["alembic"]
command: ["upgrade", "head"]
user: "10001:10001"
restart: "no"
profiles: ["ops"]
environment:
MESSAGE_SAFETY_CONFIG_ADMIN_DATABASE_URL_FILE: /run/secrets/message_safety_config_admin_database_url
PG_CA_FILE: /run/config/postgresql-ca.pem
volumes:
- *postgres-ca-volume
networks:
safety-egress:
gw_priority: 1
secrets:
- message_safety_config_admin_database_url
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=32m
pids_limit: 100
mem_limit: 256m
cpus: 0.5
bitrix-sync:
<<: *hardening
image: ${BITRIX_SYNC_IMAGE:?set immutable bitrix-sync image digest}
command: ["han-bitrix-sync-api"]
user: "10001:10001"
environment: *bitrix-sync-environment
volumes:
- *postgres-ca-volume
networks:
backend: {}
observability: {}
bitrix-egress:
gw_priority: 1
expose: ["8080"]
secrets:
- bitrix_sync_database_url
- bitrix_sync_crm_rest_webhook_url
- bitrix_sync_contact_receiver_token
- bitrix_sync_alert_receiver_token
- bitrix_sync_service_token
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=32m
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/health/live',timeout=2)"]
interval: 15s
timeout: 3s
retries: 3
start_period: 20s
pids_limit: 200
mem_limit: 384m
cpus: 1.0
bitrix-sync-worker:
<<: *hardening
image: ${BITRIX_SYNC_IMAGE:?set immutable bitrix-sync image digest}
command: ["han-bitrix-sync-worker"]
user: "10001:10001"
environment: *bitrix-sync-environment
volumes:
- *postgres-ca-volume
networks:
observability: {}
bitrix-egress:
gw_priority: 1
secrets:
- bitrix_sync_database_url
- bitrix_sync_crm_rest_webhook_url
- bitrix_sync_contact_receiver_token
- bitrix_sync_alert_receiver_token
- bitrix_sync_service_token
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=32m
pids_limit: 200
mem_limit: 512m
cpus: 1.0
bitrix-sync-reconciliation:
<<: *hardening
image: ${BITRIX_SYNC_IMAGE:?set immutable bitrix-sync image digest}
command: ["han-bitrix-sync-reconciliation"]
user: "10001:10001"
restart: "no"
environment: *bitrix-sync-environment
volumes:
- *postgres-ca-volume
networks:
observability: {}
bitrix-egress:
gw_priority: 1
secrets:
- bitrix_sync_database_url
- bitrix_sync_crm_rest_webhook_url
- bitrix_sync_contact_receiver_token
- bitrix_sync_alert_receiver_token
- bitrix_sync_service_token
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=32m
pids_limit: 150
mem_limit: 384m
cpus: 0.75
bitrix-sync-migrate:
<<: *hardening
image: ${BITRIX_SYNC_IMAGE:?set immutable bitrix-sync image digest}
entrypoint: ["alembic"]
command: ["upgrade", "head"]
user: "10001:10001"
restart: "no"
profiles: ["ops"]
environment:
BITRIX_SYNC_MIGRATION_DATABASE_URL_FILE: /run/secrets/bitrix_sync_migration_database_url
PG_CA_FILE: /run/config/postgresql-ca.pem
volumes:
- *postgres-ca-volume
networks:
bitrix-egress:
gw_priority: 1
secrets:
- bitrix_sync_migration_database_url
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=32m
pids_limit: 100
mem_limit: 256m
cpus: 0.5
networks:
public:
backend:
internal: true
observability:
internal: true
safety-egress:
bitrix-egress:
telemetry-egress:
volumes:
redis-safety-data:
otel-queue:
secrets:
message_safety_database_url:
file: /run/han-chat/secrets/MESSAGE_SAFETY_DATABASE_URL
message_safety_config_admin_database_url:
file: /run/han-chat/secrets/MESSAGE_SAFETY_CONFIG_ADMIN_DATABASE_URL
message_safety_redis_url:
file: /run/han-chat/secrets/MESSAGE_SAFETY_REDIS_URL
message_safety_service_token:
file: /run/han-chat/secrets/MESSAGE_SAFETY_SERVICE_TOKEN
s3_quarantine_read_access_key:
file: /run/han-chat/secrets/SELECTEL_S3_QUARANTINE_READ_ACCESS_KEY
s3_quarantine_read_secret_key:
file: /run/han-chat/secrets/SELECTEL_S3_QUARANTINE_READ_SECRET_KEY
internal_tls_certificate:
file: /run/han-chat/secrets/VM2_INTERNAL_TLS_CERTIFICATE
internal_tls_private_key:
file: /run/han-chat/secrets/VM2_INTERNAL_TLS_PRIVATE_KEY
bitrix_sync_database_url:
file: /run/han-chat/secrets/BITRIX_SYNC_DATABASE_URL
bitrix_sync_migration_database_url:
file: /run/han-chat/secrets/BITRIX_SYNC_MIGRATION_DATABASE_URL
bitrix_sync_crm_rest_webhook_url:
file: /run/han-chat/secrets/BITRIX_SYNC_CRM_REST_WEBHOOK_URL
bitrix_sync_contact_receiver_token:
file: /run/han-chat/secrets/BITRIX_SYNC_CONTACT_RECEIVER_TOKEN
bitrix_sync_alert_receiver_token:
file: /run/han-chat/secrets/BITRIX_SYNC_ALERT_RECEIVER_TOKEN
bitrix_sync_service_token:
file: /run/han-chat/secrets/BITRIX_SYNC_SERVICE_TOKEN
redis_safety_acl:
file: /run/han-chat/secrets/REDIS_SAFETY_ACL
redis_exporter_password:
file: /run/han-chat/secrets/REDIS_EXPORTER_PASSWORD