前面的文章部署zk服务,直接在裸机上部署,较为不便,现在很多服务如果不做docker化,无论在故障恢复、运维都增加很大困难,无法做到自动化部署,这种低效率的IT运营模式是比较难接受的,对于我们开发而已,必须是一键式优雅部署,所以本篇文章采用docker方式部署zk集群,可以从中对比裸机部署过程的不同以及优势
1、部署docker和docker-compose 参考本博客文章:链接
2、部署zookeeper集群 拉取zk镜像,可以dockerhub上面看下目前的zk官方镜像的tag有什么版本,默认是latest,接着是3.5.5以及3.4.14,这里用的stable版本3.4.14
1 2 [root@dn2 opt]# docker pull zookeeper:3.4.14
在宿主机上新建一个存放docker集群zk服务器目录(仅为了方便管理),并在该目录下新建一个compose配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 [root@dn2 zk_docker_cluster]# pwd /opt/zk_docker_cluster [root@dn2 zk_docker_cluster]# vi docker-compose.yml version: '3.3' services: zoo1: # 使用zookeeper:3.4.14镜像,加上tag标签 image: zookeeper:3.4.14 restart: always hostname: zoo1 container_name: zk1 ports: - 2181:2181 volumes: # 宿主机目录路径无需手工创建,docker-compose有权限进行自行创建挂载的目录路径 - /opt/zk_docker_cluster/zoo1/data:/data - /opt/zk_docker_cluster/zoo1/datalog:/datalog - /opt/zk_docker_cluster/zoo1/logs:/logs environment: ZOO_MY_ID: 1 ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888 zoo2: image: zookeeper restart: always hostname: zoo2 container_name: zk2 ports: - 2182:2181 volumes: - /opt/zk_docker_cluster/zoo2/data:/data - /opt/zk_docker_cluster/zoo2/datalog:/datalog - /opt/zk_docker_cluster/zoo2/logs:/logs environment: ZOO_MY_ID: 2 ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888 zoo3: image: zookeeper restart: always hostname: zoo3 container_name: zk3 ports: - 2183:2181 volumes: - /opt/zk_docker_cluster/zoo3/data:/data - /opt/zk_docker_cluster/zoo3/datalog:/datalog - /opt/zk_docker_cluster/zoo3/logs:/logs environment: ZOO_MY_ID: 3 ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
配置文件需要注意的地方
在运行前,可以用docker-compose -f docker-compose.yml config
检查配置文件是否正确
1)version 版本号不能随便改,例如这里改为1.0,提示不支持
1 2 [root@dn2 zk_docker_cluster]# docker-compose -f docker-compose.yml config ERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a supported version (e.g "2.2" or "3.3") and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.
2)注意yaml语法的层次表达
例如在这里,故意把zoo1放置在service同层次上,引起解析出错,所以在编排zk的配置时,要注意这些细节
1 2 3 4 ERROR: yaml.parser.ParserError: while parsing a block mapping in "./docker-compose .yml", line 1, column 1 expected <block end>, but found '<block mapping start>' in "./docker-compose .yml", line 17, column 3
==3) 注意到docker-compose yml跟裸机部署集群的不同==
在docker中,无需要指明具体的ip地址,因为docker使用其内部私网为zk服务自动分配私网ip,而且自动DNS解析主机名,因此配置文件可以直接用zoo1这样的主机名
而在裸机部署中,裸机自己的网络设置需要指定具体IP地址,如果zoo.cfg配置用了主机名代替服务器IP,那么要求裸机网卡设定的DNS需支持zk网段的主机名解析
在docker-compose里,直接主机名,server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 ,前面已经提过,docker内部其实已经对三个zk容器都分配相应的私网地址,通过以下命令查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # 列出所有docker容器IP [root@dn2 zk_docker_cluster]# docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq) /zk1 - 172.18.0.4 /zk3 - 172.18.0.2 /zk2 - 172.18.0.3 # 也可以用docker inspect zk2 查看容器内部具体的信息,这里截取一部分 [root@dn2 zk_docker_cluster]# docker inspect zk2 "HostConfig": { "Binds": [ # datalog:rw,说明docker对宿挂载的宿主机有读写权限 "/opt/zk_docker_cluster/zoo2/datalog:/datalog:rw", "/opt/zk_docker_cluster/zoo2/data:/data:rw" ], "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "zk_docker_cluster_default", "PortBindings": { # 绑定宿主机的端口号 "2181/tcp": [ { "HostIp": "", # zoo2容器内部的zk服务监听端口号 "HostPort": "2182" } ] }, ....... "Networks": { "zk_docker_cluster_default": { "IPAMConfig": null, "Links": null, "Aliases": [ "0595457ea13d", # hostname主机名 "zoo2" ], "NetworkID": "46f7dbb34f0eefb1181729aeaaf6a1080d64a46fdba935b21d5e37a3b1aea34e", "EndpointID": "9dd1d2726ba6850ab851f0227fb04aa1a027c35e84d36cd308208a4d4fb42f7d", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.3", "IPPrefixLen": 16,
docker内部的私网段可以在宿主机上ip a
命令查看到,这是个docker的网桥网络,
地址池:172.18.0.1/16
1 2 3 4 5 6 8: br-46f7dbb34f0e: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:82:51:27:a6 brd ff:ff:ff:ff:ff:ff inet 172.18.0.1/16 brd 172.18.255.255 scope global br-46f7dbb34f0e valid_lft forever preferred_lft forever inet6 fe80::42:82ff:fe51:27a6/64 scope link valid_lft forever preferred_lft forever
三个zk容器服务分别从这个地址池获取三个ip,网关为172.18.0.1,相当于三台独立服务器,因此在server.n设置端口都可以指定为2888:3888相同端口,也即
zoo1:2888:3888等于172.18.0.4:2888:3888 zoo2:2888:3888等于172.18.0.3:2888:3888
zoo3:2888:3888等于172.18.0.2:2888:3888
总之,docker内部出色的网络结构设计,使得管理员从相对繁琐的网络配置解放出来。
而在单台裸机部署集群的配置中,则要指明ip(若有dns或者配置主机名解析,可无须指定IP地址)以及不同的管理端口号(使用不同端口是防止在同一服务器上端口冲突):
1 2 3 server.1=192.168.4.100:42182:42183 server.2=192.168.4.100:42184:42185 server.3=192.168.4.100:42186:42187
启动docker-compose
注意:所有的操作都应该在对应的docker-compse项目下进行,这是因为命令docker-compose自动读取本目录下的docker-compose.yml配置,注意这里仅当配置文件名为默认值docker-compose.yml
,运行docker-compose命令才无需传入配置文件,否则如果项目目录下,yml配置文件为其它名字,例如
zk_docker_cluster.yml,每次执行docker-compose命令都需要指定配置文件:
docker-compose -f zk_docker_cluster.yml up -d
改了默认文件名的配置文件,在执行命令没传人配置文件,docker-compose提示:
1 2 3 4 5 6 7 8 9 10 [root@dn2 zk_docker_cluster]# ls zk_docker_cluster.yml zoo1 zoo2 zoo3 [root@dn2 zk_docker_cluster]# docker-compose ps ERROR: Can't find a suitable configuration file in this directory or any parent. Are you in the right directory? Supported filenames: docker-compose.yml, docker-compose.yaml # 它这里提示在当前目录或者docker-compose的默认目录,都没有砸到配合文件, # 支持两种使用默认值命名的文件:docker-compose.yml, docker-compose.yaml
执行相关命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 [root@dn2 zk_docker_cluster]# docker-compose up -d Starting zk2 ... done Creating zk1 ... done Creating zk3 ... done [root@dn2 zk_docker_cluster]# docker-compose stop Stopping zk1 ... done Stopping zk3 ... done Stopping zk2 ... done # 查看zk_docker_cluster目录结构,目录路径由docker根据compose配置自动创建,无需手工预先创建 [root@dn2 zk_docker_cluster]# tree . ├── docker-compose.yml ├── zoo1 │ ├── data │ │ ├── myid │ │ └── version-2 │ │ ├── acceptedEpoch │ │ ├── currentEpoch │ │ ├── snapshot.0 │ │ └── snapshot.400000000 │ ├── datalog │ │ └── version-2 │ └── logs ├── zoo2 │ ├── data │ │ ├── myid │ │ └── version-2 │ │ ├── acceptedEpoch │ │ ├── currentEpoch │ │ ├── snapshot.0 │ │ └── snapshot.400000000 │ ├── datalog │ │ └── version-2 │ └── logs └── zoo3 ├── data │ ├── myid │ └── version-2 │ ├── acceptedEpoch │ ├── currentEpoch │ ├── snapshot.0 │ └── snapshot.400000000 ├── datalog │ └── version-2 └── logs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 可以直接进入容器内部查看 [root@dn2 ~]# docker exec -it zk1 /bin/bash root@zoo1:/zookeeper-3.4.14# ./bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /conf/zoo.cfg Mode: follower # 在zk容器内部使用Cli登录并创建节点 [zk: localhost:2181(CONNECTED) 3] create /foo 1 Created /foo [zk: localhost:2181(CONNECTED) 3] create /app_conf 1 Created /app_conf [zk: localhost:2181(CONNECTED) 5] ls / [zookeeper,app_conf,foo] # 创建临时顺序节点 [zk: localhost:2181(CONNECTED) 6] create -e -s /foo 1 Created /foo0000000001 [zk: localhost:2181(CONNECTED) 7] create -e -s /foo 1 Created /foo0000000002 [zk: localhost:2181(CONNECTED) 8] create -e -s /foo 1 Created /foo0000000003
在zk的docker容器内部,指定zk容器ip进入相应的服务
在前面已经给出三个zk服务在docker内部分配的私网IP,若想进入指定的zk容器,则需要用到这些私网网IP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # 三个zk服务器在docker内部分配到的IP (docker ps -aq) /zk3 - 172.18.0.3 /zk1 - 172.18.0.4 /zk2 - 172.18.0.2 # 先选一个容器进入其内部,例如其内部zk client环境连接到其他zk服务实例, [root@dn2 bin]# docker exec -it zk1 /bin/bash root@zoo1:/zookeeper-3.4.14# # 连接zk1服务 root@zoo1:/zookeeper-3.4.14# ./bin/zkCli.sh -server 172.18.0.4 [zk: 172.18.0.4:2181(CONNECTED) 1] ls / [zookeeper, app_conf, foo] # 连接zk2服务 root@zoo1:/zookeeper-3.4.14# ./bin/zkCli.sh -server 172.18.0.2 [zk: 172.18.0.2:2181(CONNECTED) 1] ls / [zookeeper, app_conf, foo] # 连接zk1服务 root@zoo1:/zookeeper-3.4.14# ./bin/zkCli.sh -server 172.18.0.3 [zk: 172.18.0.3:2181(CONNECTED) 1] ls / [zookeeper, app_conf, foo]
3、用zk的四字命令查看zk集群状态 通过进入容器查看zk状态显然不优雅,zk中有快捷的命令可以查看服务器的运行状态,它们的长度为4个英文字母缩写,又叫“四字命令”,需要结合nc命令,服务器安装nmap-ncat.x86_64(可通过yum install nc)
state stat命令用于获取zk的运行时状态信息,包括基本的zk版本、打包信息、运行时角色、集群数据节点个数等信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # 详细信息 [root@dn2 zk_docker_cluster]# echo stat | nc 127.0.0.1 2181 Zookeeper version: 3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT Clients: /172.18.0.1:38660[0](queued=0,recved=1,sent=0) Latency min/avg/max: 2/18/49 Received: 7 Sent: 6 Connections: 1 Outstanding: 0 Zxid: 0x300000002 Mode: follower Node count: 4 # 每个zk实例的角色 [root@dn2 zk_docker_cluster]# echo stat | nc 127.0.0.1 2181|grep Mode Mode: follower [root@dn2 zk_docker_cluster]# echo stat | nc 127.0.0.1 2182|grep Mode Mode: follower [root@dn2 zk_docker_cluster]# echo stat | nc 127.0.0.1 2183|grep Mode Mode: leader
conf conf命令用于输出ZooKeeper服务器运行时使用的基本配置信息,包括clientPort、dataDir和tickTime等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@dn2 zk_docker_cluster]# echo conf | nc 127.0.0.1 2181 clientPort=2181 dataDir=/data/version-2 dataLogDir=/datalog/version-2 tickTime=2000 maxClientCnxns=60 minSessionTimeout=4000 maxSessionTimeout=40000 serverId=1 initLimit=5 syncLimit=2 electionAlg=3 electionPort=3888 quorumPort=2888 peerType=0
mntr mntr命令用于输出比stat命令更为详尽的服务器统计信息,包括请求处理的延迟情况、服务器内存数据库大小和集群的数据同步情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@dn2 zk_docker_cluster]# echo mntr | nc 127.0.0.1 2181 zk_version 3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT zk_avg_latency 18 zk_max_latency 49 zk_min_latency 2 zk_packets_received 8 zk_packets_sent 7 zk_num_alive_connections 1 zk_outstanding_requests 0 zk_server_state follower zk_znode_count 4 zk_watch_count 0 zk_ephemerals_count 0 zk_approximate_data_size 27 zk_open_file_descriptor_count 31 zk_max_file_descriptor_count 1048576 zk_fsync_threshold_exceed_count 0
crst crst命令是一个功能性命令(client reset),用于重置所有的客户端连接统计信息
1 2 [root@dn2 zk_docker_cluster]# echo crst | nc 127.0.0.1 2181 Connection stats reset.
srvr srvr命令和stat命令的功能一致,唯一的区别是srvr不会将客户端的连接情况输出,仅仅输出服务器的自身信息
1 2 3 4 5 6 7 8 9 10 imok[root@dn2 zk_docker_cluster]# echo srvr | nc 127.0.0.1 2181 Zookeeper version: 3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT Latency min/avg/max: 0/0/49 Received: 327 Sent: 326 Connections: 2 Outstanding: 0 Zxid: 0x300000004 Mode: follower Node count: 5
dump dump命令用于输出当前集群的所有会话信息,包括这些会话的会话ID,以及每个会话创建的临时节点等信息。
1 2 3 4 5 [root@dn2 zk_docker_cluster]# echo dump | nc 127.0.0.1 2181 SessionTracker dump: org.apache.zookeeper.server.quorum.LearnerSessionTracker@77315813 ephemeral nodes dump: Sessions with Ephemerals (0):
envi envi命令用于输出ZooKeeper所在服务器环境以及一些runtime环境,包括os.version、java.version和user.home等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@dn2 zk_docker_cluster]# echo envi | nc 127.0.0.1 2181 Environment: zookeeper.version=3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT host.name=zoo1 java.version=1.8.0_222 java.vendor=Oracle Corporation java.home=/usr/local/openjdk-8 java.class.path=/zookeeper-3.4.14/bin/../zookeeper-server/target/classes:/zookeeper-3.4.14/bin/../build/classes:/zookeeper-3.4.14/bin/../zookeeper-server/target/lib/*.jar:/zookeeper-3.4.14/bin/../build/lib/*.jar:/zookeeper-3.4.14/bin/../lib/slf4j-log4j12-1.7.25.jar:/zookeeper-3.4.14/bin/../lib/slf4j-api-1.7.25.jar:/zookeeper-3.4.14/bin/../lib/netty-3.10.6.Final.jar:/zookeeper-3.4.14/bin/../lib/log4j-1.2.17.jar:/zookeeper-3.4.14/bin/../lib/jline-0.9.94.jar:/zookeeper-3.4.14/bin/../lib/audience-annotations-0.5.0.jar:/zookeeper-3.4.14/bin/../zookeeper-3.4.14.jar:/zookeeper-3.4.14/bin/../zookeeper-server/src/main/resources/lib/*.jar:/conf: java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib java.io.tmpdir=/tmp java.compiler=<NA> os.name=Linux os.arch=amd64 os.version=3.10.0-957.27.2.el7.x86_64 user.name=zookeeper user.home=/home/zookeeper user.dir=/zookeeper-3.4.14
ruok ruok命令用于输出当前ZooKeeper服务器是否正在运行,“Are you ok”的缩写?如果当前ZooKeeper服务器正在运行,那么返回“imok”(I am ok),否则没有任何响应输出。
1 2 [root@dn2 zk_docker_cluster]# echo ruok | nc 127.0.0.1 2181 imok
wchs wchs命令用于输出当前服务器上管理的Watcher的概要信息
1 2 3 [root@dn2 zk_docker_cluster]# echo wchs | nc 127.0.0.1 2181 connections watching 0 paths Total watches:0
wchc wchc命令用于输出当前服务器上管理的Watcher的详细信息,以会话为单位进行归组,同时列出被该会话注册了Watcher的节点路径
wchp wchp命令和wchc命令非常类似,也是用于输出当前服务器上管理的Watcher的详细信息,不同点在于wchp命令的输出信息以节点路径为单位进行归组。