# ================================================ # Level 1: 基础设施服务 # Nacos, MinIO, Nginx, Jitsi Meet # ================================================ services: # ====================== Nginx 反向代理 ====================== nginx: image: nginx:alpine container_name: urban-lifeline-nginx restart: unless-stopped profiles: ["infra", "all"] networks: - urban-lifeline ports: - "80:80" - "443:443" environment: TZ: Asia/Shanghai volumes: - ${DATA_ROOT:-../volumes}/nginx/logs:/var/log/nginx - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/conf.d:/etc/nginx/conf.d:ro # SSL 证书(可选) # - ./nginx/ssl:/etc/nginx/ssl:ro depends_on: - urban-lifeline-serv - urban-lifeline-web healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 start_period: 30s # ====================== 后端服务 All-in-One ====================== urban-lifeline-serv: image: urban-lifeline-serv:${IMAGE_VERSION:-latest} container_name: urban-lifeline-serv restart: unless-stopped profiles: ["infra", "serv", "all"] networks: - urban-lifeline expose: - "8080" - "8081" - "8082" - "8083" - "8084" - "8085" - "8086" - "8087" - "8088" - "8089" - "8090" environment: TZ: Asia/Shanghai SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod} NACOS_SERVER_ADDR: nacos:8848 NACOS_NAMESPACE: ${NACOS_NAMESPACE:-} volumes: - ${DATA_ROOT:-../volumes}/logs/serv:/app/logs depends_on: nacos: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 30s timeout: 10s retries: 3 start_period: 180s # ====================== 前端服务 All-in-One ====================== urban-lifeline-web: image: urban-lifeline-web:${IMAGE_VERSION:-latest} container_name: urban-lifeline-web restart: unless-stopped profiles: ["infra", "web", "all"] networks: - urban-lifeline expose: - "8000" - "8001" - "8002" - "8003" - "8004" environment: TZ: Asia/Shanghai SHARED_PORT: 8000 PLATFORM_PORT: 8001 WORKCASE_PORT: 8002 BIDDING_PORT: 8003 WORKCASE_WECHAT_PORT: 8004 volumes: - ${DATA_ROOT:-../volumes}/logs/web:/app/logs healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/"] interval: 30s timeout: 10s retries: 3 start_period: 30s # ====================== Nacos 注册中心 ====================== nacos: image: nacos/nacos-server:v3.1.0 container_name: urban-lifeline-nacos restart: unless-stopped profiles: ["infra", "all"] networks: - urban-lifeline ports: - "8081:8080" - "8848:8848" - "9848:9848" - "9849:9849" environment: MODE: standalone SPRING_DATASOURCE_PLATFORM: mysql MYSQL_SERVICE_HOST: ${MYSQL_HOST:-host.docker.internal} MYSQL_SERVICE_PORT: ${MYSQL_PORT:-3306} MYSQL_SERVICE_DB_NAME: nacos_config MYSQL_SERVICE_USER: ${MYSQL_USER:-root} MYSQL_SERVICE_PASSWORD: ${MYSQL_PASSWORD:-123456} MYSQL_SERVICE_DB_PARAM: allowPublicKeyRetrieval=true&useSSL=false JVM_XMS: 512m JVM_XMX: 512m JVM_XMN: 256m NACOS_AUTH_ENABLE: "false" NACOS_AUTH_TOKEN: ${NACOS_AUTH_TOKEN:-ZlRkR2ZxR3BvZ1F0a3JxY2V6RUx2cUh1Rkx6V1ZQbE9kUVd1R1VOcWFFS2t3dG5hS0E9PQ==} NACOS_AUTH_IDENTITY_KEY: ${NACOS_AUTH_TOKEN:-ZlRkR2ZxR3BvZ1F0a3JxY2V6RUx2cUh1Rkx6V1ZQbE9kUVd1R1VOcWFFS2t3dG5hS0E9PQ==} NACOS_AUTH_IDENTITY_VALUE: ${NACOS_AUTH_TOKEN:-ZlRkR2ZxR3BvZ1F0a3JxY2V6RUx2cUh1Rkx6V1ZQbE9kUVd1R1VOcWFFS2t3dG5hS0E9PQ==} volumes: - ${DATA_ROOT:-../volumes}/nacos/data:/home/nacos/data - ${DATA_ROOT:-../volumes}/nacos/logs:/home/nacos/logs healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/"] interval: 30s timeout: 10s retries: 5 start_period: 60s extra_hosts: - "host.docker.internal:host-gateway" # ====================== MinIO 对象存储 ====================== minio: image: minio/minio:latest container_name: urban-lifeline-minio restart: unless-stopped profiles: ["infra", "all"] networks: - urban-lifeline ports: - "9000:9000" - "9001:9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin123} MINIO_CONSOLE_ADDRESS: ":9001" MINIO_ADDRESS: ":9000" TZ: Asia/Shanghai volumes: - ${DATA_ROOT:-../volumes}/minio/data:/data - ${DATA_ROOT:-../volumes}/minio/config:/root/.minio command: server /data --console-address ":9001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 start_period: 30s # ====================== Jitsi Meet 视频会议 ====================== jitsi-web: image: jitsi/web:stable-9584 container_name: urban-lifeline-jitsi-web restart: unless-stopped profiles: ["infra", "jitsi", "all"] networks: - urban-lifeline ports: - "8280:80" - "8443:443" environment: TZ: Asia/Shanghai PUBLIC_URL: ${JITSI_PUBLIC_URL:-https://org.xyzh.yslg.jitsi} ENABLE_HTTPS: 0 ENABLE_HTTP_REDIRECT: 0 DISABLE_HTTPS: 1 XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_BOSH_URL_BASE: http://jitsi-prosody:5280 XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi XMPP_GUEST_DOMAIN: guest.meet.jitsi JICOFO_COMPONENT_SECRET: jicofo-secret JICOFO_AUTH_USER: focus JVB_AUTH_USER: jvb JVB_AUTH_PASSWORD: jvb-password ENABLE_AUTH: 1 ENABLE_GUESTS: 0 AUTH_TYPE: jwt JWT_APP_ID: ${JWT_APP_ID:-urbanLifeline} JWT_APP_SECRET: ${JWT_APP_SECRET:-urbanLifeline-jitsi-secret-key-2025-production-safe-hs256} JWT_ACCEPTED_ISSUERS: ${JWT_APP_ID:-urbanLifeline} JWT_ACCEPTED_AUDIENCES: jitsi JWT_ALLOW_EMPTY: 0 JWT_AUTH_TYPE: token JWT_TOKEN_AUTH_MODULE: token_verification ENABLE_RECORDING: 0 ENABLE_TRANSCRIPTIONS: 0 ENABLE_SUBDOMAINS: 0 ENABLE_XMPP_WEBSOCKET: 1 ENABLE_SCTP: 1 volumes: - ${DATA_ROOT:-../volumes}/jitsi/web:/config - ${DATA_ROOT:-../volumes}/jitsi/transcripts:/usr/share/jitsi-meet/transcripts depends_on: - jitsi-prosody healthcheck: test: ["CMD", "curl", "-f", "http://localhost:80/"] interval: 30s timeout: 10s retries: 3 start_period: 60s jitsi-prosody: image: jitsi/prosody:stable-9584 container_name: urban-lifeline-jitsi-prosody restart: unless-stopped profiles: ["infra", "jitsi", "all"] networks: - urban-lifeline expose: - "5222" - "5347" - "5280" environment: TZ: Asia/Shanghai XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi XMPP_GUEST_DOMAIN: guest.meet.jitsi JICOFO_COMPONENT_SECRET: jicofo-secret JICOFO_AUTH_USER: focus JICOFO_AUTH_PASSWORD: focus-password JVB_AUTH_USER: jvb JVB_AUTH_PASSWORD: jvb-password ENABLE_AUTH: 1 ENABLE_GUESTS: 0 AUTH_TYPE: jwt JWT_APP_ID: ${JWT_APP_ID:-urbanLifeline} JWT_APP_SECRET: ${JWT_APP_SECRET:-urbanLifeline-jitsi-secret-key-2025-production-safe-hs256} JWT_ACCEPTED_ISSUERS: ${JWT_APP_ID:-urbanLifeline} JWT_ACCEPTED_AUDIENCES: jitsi JWT_ALLOW_EMPTY: 0 JWT_AUTH_TYPE: token JWT_TOKEN_AUTH_MODULE: token_verification LOG_LEVEL: info PUBLIC_URL: ${JITSI_PUBLIC_URL:-https://org.xyzh.yslg.jitsi} JWT_DISABLE_AUTO_MODERATOR: true volumes: - ${DATA_ROOT:-../volumes}/jitsi/prosody/config:/config - ${DATA_ROOT:-../volumes}/jitsi/prosody/prosody-plugins-custom:/prosody-plugins-custom healthcheck: test: ["CMD", "prosodyctl", "status"] interval: 30s timeout: 10s retries: 3 start_period: 90s jitsi-jicofo: image: jitsi/jicofo:stable-9584 container_name: urban-lifeline-jitsi-jicofo restart: unless-stopped profiles: ["infra", "jitsi", "all"] networks: - urban-lifeline environment: TZ: Asia/Shanghai XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_MUC_DOMAIN: muc.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi XMPP_SERVER: jitsi-prosody JICOFO_COMPONENT_SECRET: jicofo-secret JICOFO_AUTH_USER: focus JICOFO_AUTH_PASSWORD: focus-password AUTH_TYPE: jwt JVB_BREWERY_MUC: jvbbrewery JICOFO_ENABLE_HEALTH_CHECKS: true JICOFO_ENABLE_AUTO_OWNER: false JICOFO_ENABLE_AUTO_LOGIN: false JICOFO_CONFERENCE_INITIAL_OWNER: "" volumes: - ${DATA_ROOT:-../volumes}/jitsi/jicofo:/config depends_on: - jitsi-prosody healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8888/about/health"] interval: 30s timeout: 10s retries: 3 start_period: 90s jitsi-jvb: image: jitsi/jvb:stable-9584 container_name: urban-lifeline-jitsi-jvb restart: unless-stopped profiles: ["infra", "jitsi", "all"] networks: - urban-lifeline ports: - "10000:10000/udp" - "4443:4443/tcp" environment: TZ: Asia/Shanghai XMPP_DOMAIN: meet.jitsi XMPP_AUTH_DOMAIN: auth.meet.jitsi XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi XMPP_SERVER: jitsi-prosody JVB_AUTH_USER: jvb JVB_AUTH_PASSWORD: jvb-password JVB_BREWERY_MUC: jvbbrewery JVB_PORT: 10000 JVB_STUN_SERVERS: stun.l.google.com:19302,stun1.l.google.com:19302 DOCKER_HOST_ADDRESS: ${JVB_HOST_ADDRESS:-192.168.0.253} JVB_ADVERTISE_IPS: ${JVB_HOST_ADDRESS:-192.168.0.253} JVB_ENABLE_APIS: rest,colibri JVB_TCP_HARVESTER_DISABLED: "false" JVB_TCP_PORT: 4443 JVB_TCP_MAPPED_PORT: 4443 volumes: - ${DATA_ROOT:-../volumes}/jitsi/jvb:/config depends_on: - jitsi-prosody healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/about/health"] interval: 30s timeout: 10s retries: 3 start_period: 90s networks: urban-lifeline: external: true