Contents

Windows使用docker部署中间件


背景

受限于现有设备的硬件性能(一台 M1/8G Mac 和一台 i3-9100f/8G Windows),在开发应用时我遇到了明显的瓶颈。尤其是当需要同时运行 MySQL、Redis、Kafka、Elasticsearch 等多个中间件,再启动 Web 应用时,单台设备的 CPU 和内存资源均难以独立支撑

因此,我计划将 Windows 台式机作为专用的中间件服务器,通过 Docker 部署所有依赖服务,而 Mac 仅专注于代码编写与应用运行,以此分担负载,实现流畅开发。

总览

client可以ping通server -> client正常访问server的某些端口 -> server正常部署、本机访问正常 -> client访问server中间件

保证连通性

内网穿透

选择一个内网穿透工具,我使用的Tailscale,官方服务器帮助打洞,无需涉及网络底层,只需要在需要互相访问的电脑上登陆Tailscale即可获得一个互相访问的IP。

使用ping IP检测是否联通,如果出现问题,应是内网穿透工具的问题,请先解决该问题再继续。

防火墙(windows版)

开启防火墙

通过内网穿透工具我们可以从其他设备访问到自己的服务器,本次使用的是windows作为服务器。

按下面的图示从控制面板找到防火墙设置,然后新增入站规则

图1 图2

测试防火墙

写一个简单的go测试脚本

package main

import (
	"fmt"
	"net"
)

func main() {
	ln, err := net.Listen("tcp", "0.0.0.0:3303")
	if err != nil {
		panic(err)
	}
	fmt.Println("Listening on 0.0.0.0:3303")
	for {
		conn, err := ln.Accept()
		if err != nil {
			continue
			fmt.Println("[Error]", err)
		}
		fmt.Println("[Success] Connected from %s\n", conn.RemoteAddr())
		conn.Write([]byte("hello from mac\n"))
		conn.Close()
	}
}

Ps

  1. 通过测试应用测试时,如果弹出允许程序接受传入网络连接选了接受,那么不用开启防火墙也能访问到该程序。反之,如果拒绝了就需要防火墙有其他准入的规则。为了测试防火墙规则是否正常,选择拒绝

windows使用docker部署中间件

我使用docker-compose部署多个中间件。经过上面的联通,只要docker部署正常就可以访问到(但是windows docker似乎有点bug,我一开始连通正常但一直访问不到mysql等的端口,后面重启后过了一天就好了)。

ps:

  1. docker-compose up -d --force-recreate重启并使修改后的配置生效。
  2. windows的docker有个bug,使用netstat -an | findStr "3306"找不到docker接受的端口。

测试+遇到的bug

mysql

直接使用mysql -h 100.82.159.69 -P 3309 -uroot -p进行连接测试。

ps:

  1. mysql可能有些奇怪的问题,可以删除挂载卷对应的本机文件进行完全重制。
ERROR 1130

ERROR 1130 (HY000): Host '172.18.0.1' is not allowed to connect to this MySQL server

这个是因为我在docker里使用mysql_native_password认证,但是mac中的mysql是9点几,不支持这个插件。只需要在docker里修改使用更新的,例如mysql8默认的caching_sha2_password。

Kafka

我是直接启动web应用测试的。

advertised.listeners里不能出现0.0.0.0

如果出现,客户端拿到这个“不可路由”地址后就不知道该连那一台机器。

KAFKA_ADVERTISED_LISTENERS: PLAINTEXT_INTERNAL://video_kafka:9092,PLAINTEXT_EXTERNAL://100.82.159.69:9094

PLAINTEXT_EXTERNAL不能为0.0.0.0,我直接改成Windows 的IP(内网穿透的),然后就可以正常使用。

因为KAFKA_ADVERTISED_LISTENERS就是告诉客户端去哪找本机的kafka。

ps:

KAFKA_LISTENERS的PLAINTEXT_EXTERNAL一定要是0.0.0.0不能是127.0.0.1,否则就无法接收到其他主机的访问。

docker-compose.yaml
video_kafka:
    # 使用 Apache 官方镜像,3.9.0 版本默认使用 KRaft 模式(不再依赖 Zookeeper)
     image: apache/kafka:3.9.0
    # 指定容器的主机名和容器名,方便 Docker 内部的其他容器(如 kafka-ui)通过名字访问它
     hostname: video_kafka
	 	 container_name: video_kafka

    ports:
      # 【外部访问端口】
      # 将宿主机(Windows)的 9094 映射到容器的 9094
      # 这是你的 Mac 通过 Tailscale IP 访问 Kafka 的入口
      - "9094:9094"
      
    environment:
      # 【基础集群配置】
      # 节点 ID,集群中每个节点必须唯一,单机版设为 1 即可
      KAFKA_NODE_ID: 1
      # 角色配置:同时作为 broker (存数据) 和 controller (管集群),因为是单机 KRaft 模式
      KAFKA_PROCESS_ROLES: broker,controller
      # 定义参与投票的节点列表,格式为 id@host:port
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@video_kafka:9093
      
      # 【监听器名称定义】
      # 指定哪一个监听器是用作控制器内部通信的
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      # 指定哪一个监听器是用作 Broker 之间内部通信的
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT_INTERNAL
      
      # 【安全协议映射】
      # 定义三个通道的协议,开发环境全部使用 PLAINTEXT (明文不加密)
      # 1. CONTROLLER: 管理通道
      # 2. PLAINTEXT_EXTERNAL: 外部连接通道 (Mac 用)
      # 3. PLAINTEXT_INTERNAL: 内部连接通道 (Docker 内部用)
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT_EXTERNAL:PLAINTEXT,PLAINTEXT_INTERNAL:PLAINTEXT
      
      # 【关键配置:监听地址 (Listeners)】
      # Kafka 进程在容器内部实际监听的网卡和端口
      # 1. 9092: 给 Docker 内部用的(绑定 0.0.0.0 代表监听所有网卡)
      # 2. 9093: 给 Controller 管理用的
      # 3. 9094: 给外部用的(建议绑定 0.0.0.0,确保能接收来自 Windows 端口映射的流量)
      KAFKA_LISTENERS: PLAINTEXT_INTERNAL://0.0.0.0:9092,CONTROLLER://video_kafka:9093,PLAINTEXT_EXTERNAL://0.0.0.0:9094
      
      # 【关键配置:广告地址 (Advertised Listeners)】
      # Kafka 告诉客户端“你应该访问哪个地址来找我”
      # 1. 内部客户端(如 kafka-ui): 告诉它访问 video_kafka:9092
      # 2. 外部客户端(你的 Mac): 告诉它访问 Windows 的 Tailscale IP + 9094
      # ★★★ 请确保 100.82.159.69 是你 Windows 的 Tailscale IP ★★★
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT_INTERNAL://video_kafka:9092,PLAINTEXT_EXTERNAL://100.82.159.69:9094
      
      # 【单机版防报错优化】
      # 生产环境通常为 3,单机环境必须强行设为 1,否则会因为节点数不够而一直报错或无法启动
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1         # 消费位移主题副本数
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 # 事务日志副本数
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1            # 最小同步副本数
      
      # 【其他优化】
      # 消费者组初始化延迟,设为 0 加快开发环境启动速度
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      # 默认创建 Topic 时的分区数
      KAFKA_NUM_PARTITIONS: 3
      # 数据存储路径
      KAFKA_LOG_DIRS: /var/lib/kafka/data
      
    volumes:
      # 数据持久化挂载:防止容器删除后数据丢失
      - ./deploy/data/kafka/data:/var/lib/kafka/data