最近在学docker,随着微服务的发展,服务直接部署到云主机上似乎有点浪费,于是容器化部署就被提出,并且发展迅速。学了docker总要练练,于是就学习了zookeeper和kafka,来用它们来搭建集群,在网上看了许多其他大神的博客,有多机器搭建集群,也有单节点搭建的伪集群,做了参考,我这里计划单节点搭建集群。话不多说,直接开始。
CPU: 1核
内存: 2 GiB
操作系统: CentOS 7.4 64位
配置属实有点垃圾,租的便宜云主机,不过没关系,勉强够用。docker不是说启动容器占用的资源小吗,单个机器能起上千个吗。(当然不是我这个配置)
因为只有一台机器,集群中的服务要映射到宿主机的不同端口。
zookeeper
zookeeper | ip | 宿主机端口->容器端口 |
---|---|---|
zoo1 | 172.21.0.11 | 2184->2181 |
zoo2 | 172.21.0.12 | 2185->2181 |
zoo3 | 172.21.0.13 | 2186->2181 |
kafka
kafka | ip | 宿主机端口->容器端口 |
---|---|---|
kafka1 | 172.21.0.14 | 9092->9092 |
kafka2 | 172.21.0.15 | 9093->9093 |
kafka3 | 172.21.0.16 | 9094->9094 |
kafka的默认端口是9092,容器端口都可以映射到9092,不过我在参考(搬运?)别人配置时,修改了kafka的环境变量,指定了kafka的端口,所以这里就这样配了。
安装docker,和docker-compose;拉取zookeeper,kafka镜像。
//安装前的配置
yum install -y yum-utils device-mapper-persistent-data lvm2 //安装前的配置
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
//安装
yum install docker-ce
//安装docker-compose
sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
//拉取镜像
docker pull zookeeper
docker pull wurstmeister/kafka
创建名为zk的network
docker network create --driver bridge --subnet=172.21.0.0/16 --gateway 172.21.0.1 zk
使用docker-compose快速搭建zookeeper集群
zk-compose.yml
version: '3.4'
services:
zoo1:
image: zookeeper
restart: always
hostname: zoo1
container_name: zoo1
ports:
- 2184:2181
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
networks:
zk:
ipv4_address: 172.21.0.11
zoo2:
image: zookeeper
restart: always
hostname: zoo2
container_name: zoo2
ports:
- 2185:2181
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=0.0.0.0:2888:3888 server.3=zoo3:2888:3888
networks:
zk:
ipv4_address: 172.21.0.12
zoo3:
image: zookeeper
restart: always
hostname: zoo3
container_name: zoo3
ports:
- 2186:2181
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=0.0.0.0:2888:3888
networks:
zk:
ipv4_address: 172.21.0.13
networks:
zk:
external:
name: zk
//在zk-compoe.yml文件目录下执行
docker-compose -f ./zk-compose.yml up -d
查看启动的集群 docker ps
进入容器查看集群状态
docker exec -it 952ec71dbd5f bash
docker exec -it 952ec71dbd5f bash //进入zoo1
zkServer.sh status //查看节点状态
可以看到zoo1启动成功,并且是follower。
踩坑一:这里如果没有启动成功,提示找不到zoo.cfg文件,需要自己添加。我是
直接自己复制一个到容器中的/conf目录下。
zoo.cfg
dataDir=/data
dataLogDir=/datalog
tickTime=2000
initLimit=5
syncLimit=2
clientPort=2181
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
admin.enableServer=true
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
宿主机与容器间可以复制文件
docker cp ./zoo.cfg 952ec71dbd5f:/conf/
三个节点都复制后重启就行了。
也可以使用nc在宿主机上查看节点:
2184端口对应的是zoo1,可以看到是follower节点。这里我的kafka也搭好了,可以看到连上了zookeeper。
踩坑二:这里使用nc可能会提示连接被拒绝,因为没有加入白名单。
解决:修改zkServer.sh脚本文件。添加一行。
ZOOMAIN="-Dzookeeper.4lw.commands.whitelist=* ${ZOOMAIN}"
添加在77行
72 fi
73 else
74 echo "JMX disabled by user request" >&2
75 ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
76 fi
77 ZOOMAIN="-Dzookeeper.4lw.commands.whitelist=* ${ZOOMAIN}"
78 if [ "x$SERVER_JVMFLAGS" != "x" ]
可以用sed命令添加,容器里没有vi,vim;也可以复制到宿主机上,改完在复制回去。
zkCli.sh是自带的命令行客户端。使用我就不说了,可以自己看。
搭建完zookeeper后就可以搭建kafka集群了。
同样使用docker-compose
kafka-compose.yml
version: '2'
services:
kafka1:
image: wurstmeister/kafka
restart: always
hostname: kafka1
container_name: kafka1
ports:
- 9092:9092
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka1
KAFKA_ADVERTISED_PORT: 9092
KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
volumes:
- /kafka/k1/logs:/kafka
external_links:
- zoo1
- zoo2
- zoo3
networks:
zk:
ipv4_address: 172.21.0.14
kafka2:
image: wurstmeister/kafka
restart: always
hostname: kafka2
container_name: kafka2
ports:
- 9093:9093
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka2
KAFKA_ADVERTISED_PORT: 9093
KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
volumes:
- /kafka/k2/logs:/kafka
external_links:
- zoo1
- zoo2
- zoo3
networks:
zk:
ipv4_address: 172.21.0.15
kafka3:
image: wurstmeister/kafka
restart: always
hostname: kafka3
container_name: kafka3
ports:
- 9094:9094
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka3
KAFKA_ADVERTISED_PORT: 9094
KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
volumes:
- /kafka/k3/logs:/kafka
external_links:
- zoo1
- zoo2
- zoo3
networks:
zk:
ipv4_address: 172.21.0.16
networks:
zk:
external:
name: zk
可以看到kafka2,与kafka3,修改了端口
ports:
- 9093:9093
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka2
KAFKA_ADVERTISED_PORT: 9093
KAFKA_ZOOKEEPER_CONNECT: zoo1:2181,zoo2:2181,zoo3:2181
这里加黑的是容器自己的端口,我认为可以不用修改保持9092就可以了。我没有验证过,感兴趣可以自己验证。
同样使用docker-compose启动
//启动
docker-compose -f kafka.yml up -d
//查看
docker ps
发现启动成功了,就这么简单?当然不是,这个是我调整过的。
实际上,刚开是是显示up,但过一会所有的kafka都变成了restarting,也无法进入容器。
踩坑三:看容器的启动日志,docker logs [容器id],发现了一大堆日志,找到了几条:
Out of Memory Error (os_linux.cpp:2773), pid=1, tid=0x00007fd89ee21b10
heap address: 0x00000000c0000000, size: 1024 MB, Compressed Oops mode: Non-zero based:0x00000000bffff000
说的是内存不够了,我一看一个kafka的jvm堆大小就占1024M,三个就3G,我总内存就2G,这怎么能启动起来。这让我有点怀疑docker在云主机上到底能不能启动几百上千个容器,是不是虚假宣传(手动滑稽)。
没办法,那就修改启动是的jvm参数吧。
在kafka的容器/opt/kafka_2.12-2.3.0/bin/目录下的kafka-server-start.sh文件
27
28 if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
29 export KAFKA_HEAP_OPTS="-Xmx256m -Xms256m"
30 fi
修改第29行,我把1G改成了256m,如果你的内存也是2G的话,我建议及改成128m,应为我的机器改成这个已经很卡了。看看我的内存:
[root@developer bin]# free -m
total used free shared buff/cache available
Mem: 1838 1689 57 0 91 19
Swap: 0 0 0
//可用的只剩19m了,而我仅仅启动了zookeeper和kafka集群。
你要问我怎么找到自己容器上的kafka-server-start.sh的文件在哪?因为容器根本进不去,我直接把容器根目录拷贝到宿主机上找的,没办法,刚开始了解,这能用这种办法,有好办法记得告诉我。
容器虽然没有启动成功,但也可以在宿主机上复制文件,改完在复制过去就行了。
搭建成功后,就可以测试了。进入任意一个kafka容器/opt/kafka/bin/。
建立一个topic
#创建Topic
./kafka-topics.sh --create --zookeeper 172.21.0.11:2181,172.21.0.12:12181,172.21.0.13:2181 --replication-factor 2 --partitions 1 --topic test
#解释--replication-factor 2 #复制两份--partitions 1 #创建1个分区--topic #主题为test
`
查看创建的topic
./kafka-topics.sh --describe --zookeeper 172.21.0.11:2181 --topic test
//zookeeper也可以是任一节点
Topic:test PartitionCount:1 ReplicationFactor:2 Configs:
Topic: test Partition: 0 Leader: 1 Replicas: 1,3 Isr: 1,3
#分区为为1 复制因子为2 他的 test的分区为0
#Replicas: 1,3 复制的为1,3#
创建发布者
./kafka-console-producer.sh --broker-list 172.21.0.14:9092,172.21.0.15:9093,172.21.0.16:9094 --topic test
这里的端口就是构建时的端口。
kafka-console-consumer.sh --bootstrap-server 172.21.0.14:9092 --from-beginning --topic test
创建发布者和消费者这里也会失败:
[2019-10-05 02:54:47,156] WARN [Producer clientId=console-producer] Connection to node -1 (localhost/127.0.0.1:9093) could not be established. Broker may not be available. (org.apache.kafka.clients.NetworkClient)
要修改容器/opt/kafka/config/ 下的server.properties文件,添加
#listeners=PLAINTEXT://your_hosts:9092
listeners=PLAINTEXT://172.21.0.14:9092
这个14机器对应的是9092,那么15,16,对应的是是9093,9094,和之前配置的一致。总之这个改好后集群就能正常运行了。
kafka中文官方文档