services: zookeeper: image: registry.cn-qingdao.aliyuncs.com/jisheyun/pulsar:4.1.1 container_name: zookeeper hostname: zookeeper restart: unless-stopped deploy: resources: limits: cpus: "2" memory: 2g command: > /bin/bash -c "bin/apply-config-from-env.py conf/zookeeper.conf && bin/pulsar zookeeper" environment: - PULSAR_MEM=-Xms512m -Xmx512m -Dcom.sun.management.jmxremote -Djute.maxbuffer=10485760 ports: - "${PULSAR_ZOOKEEPER_PORT}:${PULSAR_ZOOKEEPER_PORT}" networks: - pulsar-net volumes: - pulsar-zookeeper-data:/pulsar/data/zookeeper healthcheck: test: ["CMD", "bin/pulsar-zookeeper-ruok.sh"] interval: 30s timeout: 10s retries: 5 start_period: 60s pulsar-cluster-init: image: registry.cn-qingdao.aliyuncs.com/jisheyun/pulsar:4.1.1 container_name: pulsar-cluster-init hostname: pulsar-cluster-init command: > /bin/bash -c "bin/pulsar initialize-cluster-metadata --cluster pulsar-cluster-1 --zookeeper zookeeper:${PULSAR_ZOOKEEPER_PORT} --configuration-store zookeeper:${PULSAR_ZOOKEEPER_PORT} --web-service-url http://${SERVER_IP}:${PULSAR_ADMIN_PORT} --broker-service-url pulsar://${SERVER_IP}:${PULSAR_BROKER_PORT} || echo 'Cluster metadata already exists'" depends_on: zookeeper: condition: service_healthy networks: - pulsar-net bookie: image: registry.cn-qingdao.aliyuncs.com/jisheyun/pulsar:4.1.1 container_name: pulsar-bookie hostname: pulsar-bookie restart: unless-stopped deploy: resources: limits: cpus: "2" memory: 4g command: > /bin/bash -c "bin/apply-config-from-env.py conf/bookkeeper.conf && (bin/bookkeeper shell metaformat -n --force || echo 'Bookie already formatted') && bin/pulsar bookie" environment: - PULSAR_MEM=-Xms1g -Xmx1g -XX:MaxDirectMemorySize=1g - BOOKIE_MEM=-Xms1g -Xmx1g -XX:MaxDirectMemorySize=1g - PULSAR_PREFIX_zkServers=zookeeper:${PULSAR_ZOOKEEPER_PORT} # Bookie 使用容器名作为 advertisedAddress,确保 broker 通过内网连接 - PULSAR_PREFIX_advertisedAddress=pulsar-bookie depends_on: zookeeper: condition: service_healthy pulsar-cluster-init: condition: service_completed_successfully networks: - pulsar-net volumes: - pulsar-bookkeeper-data:/pulsar/data/bookkeeper broker: image: registry.cn-qingdao.aliyuncs.com/jisheyun/pulsar:4.1.1 container_name: pulsar-broker hostname: pulsar-broker restart: unless-stopped deploy: resources: limits: cpus: "2" memory: 4g command: > /bin/bash -c "bin/apply-config-from-env.py conf/broker.conf && bin/pulsar broker" environment: - PULSAR_MEM=-Xms1g -Xmx1g -XX:MaxDirectMemorySize=1g - PULSAR_PREFIX_clusterName=pulsar-cluster-1 - PULSAR_PREFIX_zookeeperServers=zookeeper:${PULSAR_ZOOKEEPER_PORT} - PULSAR_PREFIX_configurationStoreServers=zookeeper:${PULSAR_ZOOKEEPER_PORT} - PULSAR_PREFIX_bookkeeperClientPort=3181 - PULSAR_PREFIX_webServicePort=${PULSAR_ADMIN_PORT} # 多监听器配置:internal=容器内网(9093),external=公网(单独端口) # bindAddresses: 为不同监听器绑定不同端口,便于根据端口识别 listenerName - PULSAR_PREFIX_bindAddresses=internal:pulsar://0.0.0.0:${PULSAR_BROKER_PORT},external:pulsar://0.0.0.0:${PULSAR_BROKER_EXTERNAL_PORT} # 兼容旧的客户端链接方式 - PULSAR_PREFIX_advertisedAddress=${SERVER_IP} # advertisedListeners: internal 通告容器名与内网端口;external 通告公网 IP 与外网端口 - PULSAR_PREFIX_advertisedListeners=internal:pulsar://pulsar-broker:${PULSAR_BROKER_PORT},external:pulsar://${SERVER_IP}:${PULSAR_BROKER_EXTERNAL_PORT} # internalListenerName: 指定内部通信使用的监听器名称 - PULSAR_PREFIX_internalListenerName=internal - PULSAR_PREFIX_managedLedgerDefaultEnsembleSize=1 - PULSAR_PREFIX_managedLedgerDefaultWriteQuorum=1 - PULSAR_PREFIX_managedLedgerDefaultAckQuorum=1 - PULSAR_PREFIX_allowAutoTopicCreation=true # 启用非持久化主题 - PULSAR_PREFIX_enableNonPersistentTopics=true # 基本认证配置 - PULSAR_PREFIX_authenticationEnabled=true - PULSAR_PREFIX_authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderBasic - PULSAR_PREFIX_basicAuthConf=file:///pulsar/auth/.htpasswd # Broker自身的认证配置 - PULSAR_PREFIX_brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationBasic - PULSAR_PREFIX_brokerClientAuthenticationParameters={"userId":"${PULSAR_ADMIN_USER}","password":"${PULSAR_ADMIN_PASSWORD}"} # 授权配置 - PULSAR_PREFIX_authorizationEnabled=false - PULSAR_PREFIX_allowAutoTopicCreationType=partitioned - PULSAR_PREFIX_allowAnonymousAccess=false # 非持久化主题特殊配置 - PULSAR_PREFIX_allowNonPersistentTopics=true - PULSAR_PREFIX_nonPersistentTopicsEnabled=true ports: - "${PULSAR_BROKER_PORT}:${PULSAR_BROKER_PORT}" - "${PULSAR_BROKER_EXTERNAL_PORT}:${PULSAR_BROKER_EXTERNAL_PORT}" - "${PULSAR_ADMIN_PORT}:${PULSAR_ADMIN_PORT}" depends_on: zookeeper: condition: service_healthy bookie: condition: service_started pulsar-cluster-init: condition: service_completed_successfully networks: - pulsar-net volumes: - pulsar-broker-data:/pulsar/data - ./pulsar/auth:/pulsar/auth healthcheck: test: ["CMD", "bin/pulsar-admin", "--admin-url", "http://localhost:${PULSAR_ADMIN_PORT}", "--auth-plugin", "org.apache.pulsar.client.impl.auth.AuthenticationBasic", "--auth-params", '{"userId":"${PULSAR_ADMIN_USER}","password":"${PULSAR_ADMIN_PASSWORD}"}', "clusters", "list"] interval: 30s timeout: 10s retries: 5 start_period: 60s pulsar-init: image: registry.cn-qingdao.aliyuncs.com/jisheyun/pulsar:4.1.1 container_name: pulsar-init hostname: pulsar-init command: > /bin/bash -c " # 等待broker就绪 until bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' clusters list; do echo 'Waiting for Pulsar broker to be ready...' sleep 5 done; # 创建租户和命名空间 bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' tenants create public --allowed-clusters pulsar-cluster-1 -r admin || echo 'Tenant public already exists'; bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' namespaces create public/default || echo 'Namespace public/default already exists'; # 创建非持久化主题 bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' topics create non-persistent://public/default/default-topic || echo 'Topic non-persistent://public/default/default-topic already exists'; # 设置命名空间策略 echo 'Setting namespace policies...'; bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' namespaces set-subscription-types-enabled public/default --types NonDurable; bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' namespaces set-message-ttl public/default --messageTTL 0; bin/pulsar-admin --admin-url http://pulsar-broker:${PULSAR_ADMIN_PORT} --auth-plugin org.apache.pulsar.client.impl.auth.AuthenticationBasic --auth-params '{\"userId\":\"${PULSAR_ADMIN_USER}\",\"password\":\"${PULSAR_ADMIN_PASSWORD}\"}' namespaces set-retention public/default --sizeLimit -1 --timeLimit -1; echo 'Pulsar initialization completed with Basic Authentication!'; " depends_on: broker: condition: service_healthy networks: - pulsar-net iotdb-standalone-service: image: registry.cn-qingdao.aliyuncs.com/jisheyun/iotdb:2.0.5-standalone hostname: iotdb-standalone container_name: iotdb-standalone restart: always deploy: resources: limits: cpus: "8" memory: 16g ports: - "${IOTDB_PORT}:6667" environment: - cn_internal_address=iotdb-standalone - cn_internal_port=10710 - cn_consensus_port=10720 - cn_seed_config_node=iotdb-standalone:10710 - dn_rpc_address=iotdb-standalone - dn_internal_address=iotdb-standalone - dn_rpc_port=6667 - dn_internal_port=10730 - dn_mpp_data_exchange_port=10740 - dn_schema_region_consensus_port=10750 - dn_data_region_consensus_port=10760 - dn_seed_config_node=iotdb-standalone:10710 privileged: true volumes: - ./iotdb/conf:/iotdb/conf - ./iotdb/data:/iotdb/data - ./iotdb/logs:/iotdb/logs networks: - pulsar-net redis-service: image: registry.cn-qingdao.aliyuncs.com/jisheyun/redis:8.0.2-alpine3.21 container_name: redis restart: always hostname: redis deploy: resources: limits: cpus: "1.0" memory: 1g ports: - "${REDIS_PORT}:6379" volumes: - ./redis/outdata:/data - ./redis/conf:/etc/redis/conf command: redis-server /etc/redis/conf/redis.conf stdin_open: true tty: true networks: - pulsar-net mysql-service: image: registry.cn-qingdao.aliyuncs.com/jisheyun/mysql:8.4.6 container_name: mysql hostname: mysql restart: always privileged: true user: "1000:1000" # 使用宿主机用户ID ports: - "${MYSQL_PORT}:3306" environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} TZ: Asia/Shanghai volumes: - ./mysql/log:/var/log/mysql - ./mysql/data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci - --user=mysql # 确保MySQL以mysql用户运行 deploy: resources: limits: cpus: "2.0" memory: 2g stdin_open: true tty: true networks: - pulsar-net admin-api-service: image: registry.cn-qingdao.aliyuncs.com/jisheyun/jishe.iot.admin:2025.1103.1615 container_name: admin-api hostname: admin-api restart: always deploy: resources: limits: cpus: "2.0" memory: 4g ports: - "${ADMIN_API_PORT}:10500" volumes: - ./adminapi/conf:/app/configs - ./adminapi/logs:/app/logs stdin_open: true tty: true depends_on: mysql-service: condition: service_started redis-service: condition: service_started iotdb-standalone-service: condition: service_started zookeeper: condition: service_healthy broker: condition: service_healthy networks: - pulsar-net admin-web-service: image: registry.cn-qingdao.aliyuncs.com/jisheyun/jishe.iot.ui:2025.1030.0949 container_name: admin-web hostname: admin-web restart: always deploy: resources: limits: cpus: "1.0" memory: 200mb ports: - "${ADMIN_WEB_PORT}:8080" stdin_open: true tty: true depends_on: admin-api-service: condition: service_started networks: - pulsar-net networks: pulsar-net: driver: bridge ipam: driver: default config: - subnet: 172.23.0.0/16 gateway: 172.23.0.1 volumes: pulsar-zookeeper-data: driver: local driver_opts: type: none o: bind device: ./pulsar/zookeeper-data pulsar-bookkeeper-data: driver: local driver_opts: type: none o: bind device: ./pulsar/bookkeeper-data pulsar-broker-data: driver: local driver_opts: type: none o: bind device: ./pulsar/pulsar-data