name: edu-full services: mysql: # 镜像加速:通过 daocloud 镜像源绕过 docker.io 被墙问题 image: docker.m.daocloud.io/library/mysql:8.0 container_name: edu-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-changeme} MYSQL_DATABASE: ${MYSQL_DATABASE:-next_edu_cloud} MYSQL_USER: ${MYSQL_USER:-edu} MYSQL_PASSWORD: ${MYSQL_PASSWORD:-changeme} ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql - ./init-sql:/docker-entrypoint-initdb.d:ro healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 redis: image: docker.m.daocloud.io/library/redis:7-alpine container_name: edu-redis restart: unless-stopped ports: - "6379:6379" volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 5 kafka: image: docker.m.daocloud.io/confluentinc/cp-kafka:7.6.0 container_name: edu-kafka profiles: ["p3", "p4", "p5", "p6"] restart: unless-stopped depends_on: zookeeper: condition: service_healthy environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 # 双 listener:INSIDE 容器间互访(kafka:29092),OUTSIDE 主机访问(localhost:9092) # 必须用 INSIDE 作为 inter.broker.listener.name,否则 Debezium Connect 拿到 metadata # 后会切回 advertised.listeners 中的 localhost,导致连接失败 KAFKA_LISTENERS: INSIDE://:29092,OUTSIDE://:9092 KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:29092,OUTSIDE://localhost:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" ports: - "9092:9092" healthcheck: test: ["CMD", "kafka-topics", "--bootstrap-server", "localhost:9092", "--list"] interval: 15s timeout: 10s retries: 5 zookeeper: image: docker.m.daocloud.io/confluentinc/cp-zookeeper:7.6.0 container_name: edu-zookeeper profiles: ["p3", "p4", "p5", "p6"] restart: unless-stopped environment: ZOOKEEPER_CLIENT_PORT: 2181 healthcheck: test: ["CMD", "nc", "-z", "localhost", "2181"] interval: 10s timeout: 5s retries: 5 clickhouse: image: docker.m.daocloud.io/clickhouse/clickhouse-server:24.3 container_name: edu-clickhouse profiles: ["p4", "p5", "p6"] restart: unless-stopped ports: - "8123:8123" - "9000:9000" volumes: - clickhouse_data:/var/lib/clickhouse # 覆盖默认 default-user.xml 限制(默认仅允许 127.0.0.1/::1 无密码访问) - ./clickhouse/users.d/custom-users.xml:/etc/clickhouse-server/users.d/custom-users.xml:ro healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:8123/ping"] interval: 10s timeout: 5s retries: 5 neo4j: image: docker.m.daocloud.io/library/neo4j:5.20 container_name: edu-neo4j profiles: ["p4", "p5", "p6"] restart: unless-stopped environment: NEO4J_AUTH: neo4j/${NEO4J_PASSWORD:-changeme} ports: - "7474:7474" - "7687:7687" volumes: - neo4j_data:/data healthcheck: test: ["CMD", "cypher-shell", "-u", "neo4j", "-p", "${NEO4J_PASSWORD:-changeme}", "RETURN 1"] interval: 15s timeout: 10s retries: 5 elasticsearch: # Elastic 官方镜像在 docker.elastic.co,非 Docker Hub,通常不被墙 image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0 container_name: edu-es profiles: ["p5", "p6"] restart: unless-stopped environment: discovery.type: single-node xpack.security.enabled: "false" ES_JAVA_OPTS: "-Xms512m -Xmx512m" ports: - "9200:9200" volumes: - es_data:/usr/share/elasticsearch/data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"] interval: 15s timeout: 10s retries: 5 jaeger: image: docker.m.daocloud.io/jaegertracing/all-in-one:1.57 container_name: edu-jaeger profiles: ["observability"] restart: unless-stopped environment: COLLECTOR_OTLP_ENABLED: "true" ports: - "16686:16686" - "4318:4318" # ============================================================ # Debezium Connect - CDC 链路核心 # 监听 MySQL binlog → 写入 Kafka topic # topic 命名约定:..(如 edu-cdc.next_edu_cloud.grades) # ============================================================ debezium-connect: image: quay.io/debezium/connect:2.7 container_name: edu-debezium profiles: ["p4", "p5", "p6"] restart: unless-stopped depends_on: kafka: condition: service_healthy environment: # Kafka Connect 基础配置(Debezium 2.x 容器映射规则:环境变量名大写 → connect 配置项) # 必须用 INSIDE listener (kafka:29092),否则会拿到 OUTSIDE 的 localhost metadata 导致连不上 BOOTSTRAP_SERVERS: kafka:29092 GROUP_ID: edu-debezium CONFIG_STORAGE_TOPIC: edu-connect-configs OFFSET_STORAGE_TOPIC: edu-connect-offsets STATUS_STORAGE_TOPIC: edu-connect-status # 内部 converter 配置(必须与 Debezium 事件格式一致) CONFIG_STORAGE_REPLICATION_FACTOR: "1" OFFSET_STORAGE_REPLICATION_FACTOR: "1" STATUS_STORAGE_REPLICATION_FACTOR: "1" KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter KEY_CONVERTER_SCHEMAS_ENABLE: "false" VALUE_CONVERTER_SCHEMAS_ENABLE: "false" # 监听端口 REST_PORT: 8083 REST_ADVERTISED_HOST_NAME: debezium-connect # 日志级别 LOG_LEVEL: INFO ports: - "8083:8083" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8083/connectors"] interval: 15s timeout: 5s start_period: 30s retries: 10 networks: - default prometheus: image: docker.m.daocloud.io/prom/prometheus:v2.51.0 container_name: edu-prometheus profiles: ["observability"] restart: unless-stopped command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention.time=15d" - "--web.enable-lifecycle" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus ports: - "9090:9090" grafana: image: docker.m.daocloud.io/grafana/grafana:10.4.0 container_name: edu-grafana profiles: ["observability"] restart: unless-stopped environment: GF_SECURITY_ADMIN_PASSWORD: admin ports: - "3030:3000" volumes: - grafana_data:/var/lib/grafana # ============================================================ # Alertmanager - 告警路由与抑制(observability profile) # ============================================================ alertmanager: image: docker.m.daocloud.io/prom/alertmanager:v0.27.0 container_name: edu-alertmanager profiles: ["observability"] restart: unless-stopped command: - "--config.file=/etc/alertmanager/alertmanager.yml" - "--storage.path=/alertmanager" ports: - "9093:9093" volumes: - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro - alertmanager_data:/alertmanager # ============================================================ # Loki - 日志聚合(observability profile) # ============================================================ loki: image: docker.m.daocloud.io/grafana/loki:3.2.1 container_name: edu-loki profiles: ["observability"] restart: unless-stopped command: -config.file=/etc/loki/local-config.yaml ports: - "3100:3100" volumes: - loki_data:/loki # ============================================================ # Promtail - 日志采集(observability profile) # ============================================================ promtail: image: docker.m.daocloud.io/grafana/promtail:3.2.1 container_name: edu-promtail profiles: ["observability"] restart: unless-stopped command: -config.file=/etc/promtail/config.yml volumes: - ./promtail/config.yml:/etc/promtail/config.yml:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/run/docker.sock:/var/run/docker.sock:ro depends_on: - loki # ============================================================ # Exporters(observability profile,与 Prometheus 同网络) # ============================================================ node-exporter: image: docker.m.daocloud.io/prom/node-exporter:v1.8.2 container_name: edu-node-exporter profiles: ["observability"] restart: unless-stopped command: - "--path.rootfs=/host" ports: - "9100:9100" volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/host:ro mysql-exporter: image: docker.m.daocloud.io/prom/mysqld-exporter:v0.15.1 container_name: edu-mysql-exporter profiles: ["observability"] restart: unless-stopped command: - "--mysqld.address=edu-mysql:3306" - "--mysqld.username=edu:changeme" environment: MYSQLD_EXPORTER_PASSWORD: "changeme" ports: - "9104:9104" depends_on: mysql: condition: service_healthy redis-exporter: image: docker.m.daocloud.io/oliver006/redis_exporter:v1.67.0 container_name: edu-redis-exporter profiles: ["observability"] restart: unless-stopped environment: REDIS_ADDR: "redis://edu-redis:6379" ports: - "9121:9121" depends_on: redis: condition: service_started volumes: mysql_data: redis_data: clickhouse_data: neo4j_data: es_data: grafana_data: prometheus_data: alertmanager_data: loki_data: