initial commit of the converted role from helm charts for qubernetis to compose ansible role
304 lines
13 KiB
Django/Jinja
304 lines
13 KiB
Django/Jinja
# {{ ansible_managed }}
|
|
# ESS Pro v{{ ess_chart_version }} on docker compose — rendered by ess_pro_compose.
|
|
# Topology mirrors the Helm chart: HAProxy fronts all Synapse traffic,
|
|
# synapse-main is the Python homeserver, synapse-fed-reader is the Rust Pro
|
|
# worker handling federation reads, MAS handles all auth, LiveKit + lk-jwt
|
|
# serve Element Call.
|
|
|
|
name: {{ ess_compose_project_name }}
|
|
|
|
networks:
|
|
{{ ess_compose_traefik_network }}:
|
|
external: true
|
|
{{ ess_compose_internal_network }}:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
postgres_data:
|
|
synapse_media:
|
|
|
|
services:
|
|
|
|
# ===========================================================================
|
|
# Data plane
|
|
# ===========================================================================
|
|
|
|
postgres:
|
|
image: {{ ess_images.postgres }}
|
|
container_name: postgres
|
|
restart: unless-stopped
|
|
networks: [ {{ ess_compose_internal_network }} ]
|
|
environment:
|
|
LC_COLLATE: "C"
|
|
LC_CTYPE: "C"
|
|
PGDATA: /var/lib/postgresql/data/pgdata
|
|
POSTGRES_INITDB_ARGS: "-E UTF8"
|
|
POSTGRES_PASSWORD_FILE: /secrets/ess-generated/POSTGRES_ADMIN_PASSWORD
|
|
command:
|
|
- postgres
|
|
- "-c"
|
|
- "max_connections={{ ess_postgres_max_connections }}"
|
|
- "-c"
|
|
- "shared_buffers={{ ess_postgres_shared_buffers }}"
|
|
- "-c"
|
|
- "effective_cache_size={{ ess_postgres_effective_cache_size }}"
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
|
- {{ ess_compose_conf_dir }}/postgres/configure-dbs.sh:/docker-entrypoint-initdb.d/init-ess-dbs.sh:ro
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
redis:
|
|
image: {{ ess_images.redis }}
|
|
container_name: redis
|
|
restart: unless-stopped
|
|
networks: [ {{ ess_compose_internal_network }} ]
|
|
command: ["/usr/local/etc/redis/redis.conf"]
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 3s
|
|
retries: 5
|
|
|
|
# ===========================================================================
|
|
# Synapse (Python main + Rust federation-reader worker)
|
|
# ===========================================================================
|
|
|
|
synapse-main:
|
|
image: {{ ess_images.synapse }}
|
|
container_name: synapse-main
|
|
restart: unless-stopped
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
redis: { condition: service_healthy }
|
|
networks: [ {{ ess_compose_internal_network }} ]
|
|
command: ["python3", "-m", "synapse.app.homeserver", "-c", "/conf/homeserver.yaml"]
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/synapse/homeserver.yaml:/conf/homeserver.yaml:ro
|
|
- {{ ess_compose_conf_dir }}/synapse/log_config.yaml:/conf/log_config.yaml:ro
|
|
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
|
- synapse_media:/media
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 60s
|
|
|
|
{% for i in range(ess_synapse_fed_reader_replicas | int) %}
|
|
synapse-fed-reader-{{ i }}:
|
|
image: {{ ess_images.synapse_pro_worker }}
|
|
container_name: synapse-fed-reader-{{ i }}
|
|
restart: unless-stopped
|
|
depends_on:
|
|
synapse-main: { condition: service_healthy }
|
|
networks: [ {{ ess_compose_internal_network }} ]
|
|
environment:
|
|
APP_CONFIG_FILEPATH: /conf/federation-reader.yaml
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/synapse/federation-reader.yaml:/conf/federation-reader.yaml:ro
|
|
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
|
|
|
{% endfor %}
|
|
# ===========================================================================
|
|
# Matrix Authentication Service (4 listeners)
|
|
# ===========================================================================
|
|
|
|
mas:
|
|
image: {{ ess_images.mas }}
|
|
container_name: mas
|
|
restart: unless-stopped
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
networks:
|
|
- {{ ess_compose_internal_network }}
|
|
- {{ ess_compose_traefik_network }}
|
|
environment:
|
|
MAS_CONFIG: /conf/mas-config.yaml
|
|
command: ["server", "--no-migrate"]
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/mas/config.yaml:/conf/mas-config.yaml:ro
|
|
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-fsS", "http://localhost:8081/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 20
|
|
start_period: 30s
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
|
- "traefik.http.routers.ess-mas.rule=Host(`{{ ess_hostnames.mas }}`)"
|
|
- "traefik.http.routers.ess-mas.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-mas.tls=true"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-mas.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.services.ess-mas.loadbalancer.server.port=8080"
|
|
|
|
# MAS root listener (port 8082) is mounted as a separate Traefik router so
|
|
# /.well-known/openid-configuration on the apex of the mas host is reachable.
|
|
# We attach a second router on the same service via a path rule.
|
|
|
|
# ===========================================================================
|
|
# HAProxy — fronts all Synapse + well-known traffic
|
|
# ===========================================================================
|
|
|
|
haproxy:
|
|
image: {{ ess_images.haproxy }}
|
|
container_name: haproxy
|
|
restart: unless-stopped
|
|
depends_on:
|
|
synapse-main: { condition: service_healthy }
|
|
networks:
|
|
- {{ ess_compose_internal_network }}
|
|
- {{ ess_compose_traefik_network }}
|
|
command: ["-f", "/usr/local/etc/haproxy/haproxy.cfg", "-dW"]
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/path_map_file:/synapse/path_map_file:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/path_map_file_get:/synapse/path_map_file_get:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/429.http:/synapse/429.http:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/admin-allow-ips.lst:/synapse/admin-allow-ips.lst:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/well-known/server:/well-known/server:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/well-known/client:/well-known/client:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/well-known/support:/well-known/support:ro
|
|
- {{ ess_compose_conf_dir }}/haproxy/well-known/element.json:/well-known/element.json:ro
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8406/synapse_ready"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 20
|
|
start_period: 90s
|
|
labels:
|
|
# matrix.<server> -> HAProxy frontend synapse-http-in (port 8008)
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
|
- "traefik.http.routers.ess-synapse.rule=Host(`{{ ess_hostnames.synapse }}`)"
|
|
- "traefik.http.routers.ess-synapse.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-synapse.tls=true"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-synapse.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.routers.ess-synapse.service=ess-synapse"
|
|
- "traefik.http.services.ess-synapse.loadbalancer.server.port=8008"
|
|
# <server>/.well-known/matrix -> HAProxy well-known-in (port 8010)
|
|
- "traefik.http.routers.ess-wellknown.rule=Host(`{{ ess_server_name }}`) && PathPrefix(`/.well-known/matrix`)"
|
|
- "traefik.http.routers.ess-wellknown.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-wellknown.tls=true"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-wellknown.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.routers.ess-wellknown.service=ess-wellknown"
|
|
- "traefik.http.services.ess-wellknown.loadbalancer.server.port=8010"
|
|
|
|
# ===========================================================================
|
|
# Element Web (browser client)
|
|
# ===========================================================================
|
|
|
|
element-web:
|
|
image: {{ ess_images.element_web }}
|
|
container_name: element-web
|
|
restart: unless-stopped
|
|
networks: [ {{ ess_compose_traefik_network }} ]
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/element-web/config.json:/app/config.json:ro
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
|
- "traefik.http.routers.ess-element-web.rule=Host(`{{ ess_hostnames.element_web }}`)"
|
|
- "traefik.http.routers.ess-element-web.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-element-web.tls=true"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-element-web.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.services.ess-element-web.loadbalancer.server.port=8080"
|
|
|
|
# ===========================================================================
|
|
# Element Admin (admin panel)
|
|
# ===========================================================================
|
|
|
|
element-admin:
|
|
image: {{ ess_images.element_admin }}
|
|
container_name: element-admin
|
|
restart: unless-stopped
|
|
networks: [ {{ ess_compose_traefik_network }} ]
|
|
environment:
|
|
SERVER_NAME: "{{ ess_server_name }}"
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
|
- "traefik.http.routers.ess-element-admin.rule=Host(`{{ ess_hostnames.element_admin }}`)"
|
|
- "traefik.http.routers.ess-element-admin.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-element-admin.tls=true"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-element-admin.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.services.ess-element-admin.loadbalancer.server.port=8080"
|
|
|
|
# ===========================================================================
|
|
# Matrix RTC / Element Call (LiveKit SFU + lk-jwt)
|
|
# ===========================================================================
|
|
|
|
matrix-rtc-sfu:
|
|
image: {{ ess_images.livekit }}
|
|
container_name: matrix-rtc-sfu
|
|
restart: unless-stopped
|
|
networks:
|
|
- {{ ess_compose_internal_network }}
|
|
- {{ ess_compose_traefik_network }}
|
|
command: ["--config", "/conf/sfu-config.yaml"]
|
|
volumes:
|
|
- {{ ess_compose_conf_dir }}/sfu/config.yaml:/conf/sfu-config.yaml:ro
|
|
# WebRTC media ports — DMZ firewall must NAT-forward these to this host.
|
|
ports:
|
|
- "{{ ess_rtc_tcp_port }}:{{ ess_rtc_tcp_port }}/tcp"
|
|
- "{{ ess_rtc_udp_port }}:{{ ess_rtc_udp_port }}/udp"
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
|
- "traefik.http.routers.ess-matrix-rtc.rule=Host(`{{ ess_hostnames.matrix_rtc }}`)"
|
|
- "traefik.http.routers.ess-matrix-rtc.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-matrix-rtc.tls=true"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-matrix-rtc.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.routers.ess-matrix-rtc.service=ess-matrix-rtc"
|
|
- "traefik.http.services.ess-matrix-rtc.loadbalancer.server.port=7880"
|
|
|
|
matrix-rtc-authorisation:
|
|
image: {{ ess_images.lk_jwt }}
|
|
container_name: matrix-rtc-authorisation
|
|
restart: unless-stopped
|
|
depends_on:
|
|
matrix-rtc-sfu: { condition: service_started }
|
|
networks:
|
|
- {{ ess_compose_internal_network }}
|
|
- {{ ess_compose_traefik_network }}
|
|
environment:
|
|
LIVEKIT_URL: "wss://{{ ess_hostnames.matrix_rtc }}"
|
|
LIVEKIT_KEY: "{{ ess_livekit_key }}"
|
|
LIVEKIT_SECRET_FROM_FILE: /secrets/ess-generated/ELEMENT_CALL_LIVEKIT_SECRET
|
|
LIVEKIT_FULL_ACCESS_HOMESERVERS: "{{ ess_server_name }}"
|
|
volumes:
|
|
- {{ ess_compose_secrets_dir }}:/secrets/ess-generated:ro
|
|
labels:
|
|
# /sfu/get is the JWT token endpoint Element Call hits to join calls.
|
|
# It lives on the same host as the SFU but on a different backend.
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ ess_compose_traefik_network }}"
|
|
- "traefik.http.routers.ess-matrix-rtc-auth.rule=Host(`{{ ess_hostnames.matrix_rtc }}`) && PathPrefix(`/sfu/get`)"
|
|
- "traefik.http.routers.ess-matrix-rtc-auth.entrypoints={{ ess_compose_traefik_entrypoint }}"
|
|
- "traefik.http.routers.ess-matrix-rtc-auth.tls=true"
|
|
- "traefik.http.routers.ess-matrix-rtc-auth.priority=200"
|
|
{% if ess_compose_traefik_certresolver | length > 0 %}
|
|
- "traefik.http.routers.ess-matrix-rtc-auth.tls.certresolver={{ ess_compose_traefik_certresolver }}"
|
|
{% endif %}
|
|
- "traefik.http.routers.ess-matrix-rtc-auth.service=ess-matrix-rtc-auth"
|
|
- "traefik.http.services.ess-matrix-rtc-auth.loadbalancer.server.port=8080"
|