kafka在私有云DNAT环境中集群的典型应用

今天配置的是一个2.5.0的一个kafka集群,新的版本将废弃zookeeper,今天不讨论新版本有一个私有的云环境,业务需求希望通过公网向kafka发送数据,使用SCRAM-SHA-256加密,内网仍然需要能够正常访问, 而其中,需要通过DNAT的方式来映射内网端口暴漏给互联网。而在做映射的时候,必然是一个端口对一个端口的,于是,大致的示意拓扑如下

如果你不是这种方式,可以尝试Kafka 实现内外网访问流量分离来解决问题

image-20220311232204412.png

而在实际的生产中,你会发现,内网采用内网IP进行访问的时候,kafka是可以正常协商进行处理请求

而在公网通过6.78.5.32的9092,9093,9094端口访问的时候会出现出现一个问题,客户端当请求A通过6.78.5.32:9092发送,经过防火墙DNAT层后,发给后端kafka,而此时kafka收到消息后回复给发送者,而回复的时候是使用的172.16.100.7:9092端口,你的客户端根本就不认识172.16.100.7,因此发送失败

image-20220311233012743.png

而这个现象在你只是向kafka发送消息,而不在乎他是否返回的时候,代码层面显示是成功的,但是数据并未成功插入。于是,就有了另外一种方式

image-20220311234318947.png

消息发送后需要返回,服务端和客户端都分别写ip和hostname,通过域名和本地hosts的方式解析出ip,分别发送到代理服务器和客户端,而不是某一个固定的ip。无论来自公网的访问还是内网的访问,最终在本地的hosts各自指向一个可以被访问到的一个ip,从而完成响应。

这种形式在官网的某些字段中被解读为“防止中间人攻击”

如下

image-20220311234535042.png

  • version: kafka_2.12-2.5.0
  • jdk: 1.8.0_211

先决条件:

  • 同步时间
10 * * * * ntpdate ntp.aliyun.com
  • 修改hosts并本地hosts
#172.16.100.7
hostnamectl set-hostname   kafka1
#172.16.100.8
hostnamectl set-hostname   kafka2
#172.16.100.9
hostnamectl set-hostname   kafka3
172.16.100.7 kafka1
172.16.100.8 kafka2
172.16.100.9 kafka3

准备工作

二进制安装java,或者rpm安装即可

tar xf jdk-8u211-linux-x64.tar.gz -C /usr/local/
cd /usr/local && ln -s jdk1.8.0_211 java
cat > /etc/profile.d/java.sh  /etc/systemd/system/zookeeper.service  /usr/local/kafka/config/server-scram.properties  /usr/local/kafka/config/server-scram.properties  /etc/systemd/system/kafka.service  /u01/data/zookeeper/myid

172.16.100.9

echo "2" > /u01/data/zookeeper/myid