这一节内容有点长,咱们将介绍如何基于docker搭建一client一server的consul测试环境,以及如何搭建多server consul测试集群.在基于docker搭建多server的consul集群时出碰到了一些坑,这对咱们是颇有益的提醒,不少时候咱们不能仅仅知足于最小化的环境搭建及简单使用,而是要朝着接近生产环境的方向努力.同时,咱们这里基于docker搭建集群其实和在宿主机上直接搭建并无太大区别,也就是咱们仅仅把docker看成相似虚拟机来使用,本系列咱们屡次强调新瓶装老酒,咱们要真正思考新的技术方案到底能为咱们的项目带来什么,如何充分利用新技术新方案来更好的服务于咱们的项目.后面咱们会基于k8s来搭建一个接近生产环境的集群,实现节点节点自动组成集群,某个节点挂掉后新增补的节点如何自动加入原有集群.后来咱们还会探索如何使用k8s的服务发现功能,实现consul节点的自动扩容.相比传统的方法手动启动宕掉的节点或者使用脚原本实现自动化,咱们彻底基于kubernetes的能力来实现自动化.闲言少叙.咱们进入正题,开始讲如何使用docker来搭建consul测试集群.后面的具体章节咱们再详细介绍这里讨论的内容.html
前面咱们介绍了在windows下部署dev环境的consul,咱们仅部署了一个节点,其实这个节点是一个client节点,不对数据作持久化存储,仅保存在内存中.生产环境须要持久化存储数据,所以须要server模式,本篇介绍如何使用consul docker镜像部署一个server和一个clientnode
使用docker pull consul
命令来拉取consul的docker镜像.linux
经过如下命令启动server端git
docker run -d -p 1234:8500 -h node1 --name node1 consul agent -server -bootstrap-expect=1 -node=node1 -client 0.0.0.0 -ui
执行命令后,docker返回容器idgithub
d107a4eda2f84bee09c0ae9044a22aa99249d144a1751e270ef6641fead79884
注意这个数字是随机的,读者要看本身的docker实际返回的idweb
而后咱们执行docker ps查看以上容器是否在运行docker
λ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d107a4eda2f8 consul "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 8300-8302/tcp, 8301-8302/udp, 8600/tcp, 8600/udp, 0.0.0.0:1234->8500/tcp node1
能够看到它已经在运行了.shell
此节点是server端,client须要加入它组成集群,client加入须要知道server的ip.咱们有两种方式获取server的ip,实际上就是server所在容器的ipjson
经过docker inspect -f '{{.NetworkSettings.IPAddress}}' node1
来查看查看server端的ip.bootstrap
经过docker exec -it node1 /bin/sh
进入到容器内部的交互shell,经过ip a
命令获取容器ip
我获取到的ip为172.17.0.2
.
经过如下命令
docker run -d -p 8600:8600 -p 8300:8500 -p 8600:53/udp --name client1 -h client1 consul agent -ui -node=client1 -join=172.17.0.2
启动client端,这里启动时自动加入node1组成集群,启动client和server的区别在于server启动的时候带有-server选项.
经过以上操做,咱们在宿主机访问localhost:1234
就能够访问到consul web管理界面了.
前面咱们使用docker部署了一server一client的集群.很是顺利,也很容易理解,本节部署多server集群,其实和前面也基本相似,只要知道了主节点的ip,新的节点即可以在运行时使用join ip
的形式加入到集群中.可是在实际部署中,包括后面的k8s部署,因为节点数增长,不少坑便暴露出来.这里和后面使用k8s部署都会讲到其中的坑.以供你们参考,方便你们在本身的部署中减小没必要要麻烦,快速上线产品.
坑一.
* Failed to join X.X.X.X: Member 'consul-deployment-2927201250-tlj1h' has conflicting node ID 'bd203bf1-2d59-42b0-901c-2a5dedf99c86' with this agent's ID) Failed to join any nodes.
经过以上内容能够看到是节点的id冲突.经过查询官方文档,官方文档里描述说 node id是一个随机生成的uuid.然而这个id并非每次建立都随机生成的,而是从宿主机获取到的一个随机字符串,这样同一台机器上启动多个consul容器实例就会出现冲突.k8s中部署也一样会有此问题.
须要注意的是,以上问题仅出如今同一个机器上启动多个consul节点,实际生产环境中,为了保证高可用,是要避免在同一台主机上部署多个server的.
以上问题请参看
解决方案有两种第一种是启动consul的时候指定node-id,并生成一个随机nodeid
docker run -d --name=node2 consul agent -server -bind=172.17.0.3 -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=node2
注意以上生成uuid和awk命令都是在执行命令的时候生成的,也就是在宿主机生成的,而不是在容器生成后执行的,所以须要容器宿主机支持
uuidgen
和awk
命令,在docker for windows下是没法执行经过的.
第二种解决办法是在启动consul时加上-disable-host-node-id
选项.
坑二. 没法访问ui
前面咱们在windows上部署时候,直接经过consul agent -dev
命令即可以启动consul,而且能够访问web管理界面.可是在集群部署时若是不指定-ui选项,则没法访问web管理界面(仅仅是web界面不能访问,其它路由仍是能够正常访问)
访问web管理界面还必须指定client绑定,不然也没法正常访问
下面咱们搭建一个3个server节点,一个client节点的集群.
docker run -d -p 8500:8500 -e --name=node1 consul agent -server -bootstrap-expect=3 -node=node1 -client=0.0.0.0 -ui
以上为了测试方便,防止暴露过多端口出现冲突(同一机器上展现),只暴露了http端口,实际上还须要暴露多个tcp和udp端口.下节在k8s集群中部署咱们将完整介绍整个部署方案.
docker run -d --name=node2 consul agent -server -join=172.17.0.2 -node=node2 -disable-host-node-id
启动节点和节点3都是使用上面的命令,唯一要修改的是--name=node2
和-node=node2
两处,节点3启动的时候以上两处都要改成node3
(固然也能够是其它名字)
注意,你们不要混淆,--name是docker为容器取的名字,-node是consul运行时给当前启动节点取的名字
以上的-join里的ip为第一个启动节点的ip,你们能够经过docker inspect -f '{{.NetworkSettings.IPAddress}}' node1
或者进入到第一个启动节点里面执行ip a
获取它的ip
咱们前面说过client和server的区别在于server启动的时候指定-server选项,若是不指定则启动的是client模式
docker run -d -p 8400:8500 --name=node4 consul agent -join=172.17.0.2 -node=node4 -disable-host-node-id -client=0.0.0.0 -ui
这里对client进行端口映射,以方便经过client进行http操做.
咱们经过localhost:8400或者localhost:8500
就能够看到整个集群的节点信息了
注 8500是leader映射出来的端口,而8400是client映射出来的端口
咱们任意进入一个节点内部,这里咱们以进入node4(也就是client)为例
docker exec -it node4 /bin/sh
/ # consul members Node Address Status Type Build Protocol DC Segment node1 172.17.0.2:8301 alive server 1.4.4 2 dc1 <all> node2 172.17.0.3:8301 alive server 1.4.4 2 dc1 <all> node3 172.17.0.4:8301 alive server 1.4.4 2 dc1 <all> node4 172.17.0.5:8301 alive client 1.4.4 2 dc1 <default> / #
/ # consul info agent: check_monitors = 0 check_ttls = 0 checks = 0 services = 0 build: prerelease = revision = ea5210a3 version = 1.4.4 consul: acl = disabled known_servers = 3 server = false runtime: arch = amd64 cpu_count = 2 goroutines = 49 max_procs = 2 os = linux version = go1.11.4 serf_lan: coordinate_resets = 0 encrypted = false event_queue = 0 event_time = 2 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 4 members = 4 query_queue = 0 query_time = 1 / #
以上信息量不小,咱们比较关心的是consul
部分的,server=false代表当前节点不是server,known_servers=3代表集群中共有3个server
若是当前执行命令的节点是server,还能够看到server 主(leader)信息
... consul: acl = disabled bootstrap = false known_datacenters = 1 leader = false leader_addr = 172.17.0.2:8300 server = true ...
当前节点从集群中离开
注,因为docker在启动容器时指定的要加入的ip,所以当前节点离开后经过
docker start
启动后会从新自动加入到集群.若是在实际生产中,不是以容器部署,当前节点挂掉后,须要再次执行前面咱们执行过的命令以加入节点
还有一点须要注意的是,主节点也可能会挂掉,这时候会产生新的节点,这时候就须要知道新的leader的ip,而后把
join
选项里的ip改成新的leader的ip.下节咱们使用k8s部署的时候咱们将介绍一种新的思路来自动解决易主后节点从新加入集群的问题.
关于命令的详细信息,能够查看官方文档
建立键值存储
consul除了能够用于服务注册外,还能够用做键值存储.下面咱们简单介绍一下键值存储用法
consul kv put user/config/connections 5
以上命令会在user目录下的config目录下存储一个键名为connections,值为5的键值对
咱们能够经过下图查看其层次
咱们能够经过如下命令获取刚存储的值
consul kv get -detailed user/config/connections
输出信息为
/ # consul kv get -detailed user/config/connections CreateIndex 407 Flags 0 Key user/config/connections LockIndex 0 ModifyIndex 407 Session - Value 5 / #
以上键值写入和读取能够在任意节点上进行操做
consul提供了丰富的api接口,因为本教程是偏管理部分的,所以仅对少数对管理有帮助的接口作简单介绍
目前,使用的版本都是v1,所以全部请求地址的固定部分都是
localhost:8500/v1
agent/members
[ ... { "Name": "node2", "Addr": "172.17.0.3", "Port": 8301, "Tags": { "acls": "0", "build": "1.4.4:ea5210a3", "dc": "dc1", "id": "1866ce4f-e219-78f9-2bee-64f567a1bf74", "port": "8300", "raft_vsn": "3", "role": "consul", "segment": "", "vsn": "2", "vsn_max": "3", "vsn_min": "2", "wan_join_port": "8302" } ... ]
经过以上返回信息,咱们能够看到节点的不少信息
/status/peers
[ "172.17.0.2:8300", "172.17.0.3:8300", "172.17.0.4:8300" ]
/status/leader
"172.17.0.2:8300"
经过执行命令查看主节点信息只能在server端执行,client没法获取到leader信息,而http api则能够在任意节点执行,都能获取到主节点信息
查询注意的服务 catalog/services
查询某一个服务 catalog/service/服务名
获取键值 kv/key的路径
好比咱们要获取咱们刚才添加的key,则请求路径为kv/user/config/connections
[ { "LockIndex": 0, "Key": "user/config/connections", "Flags": 0, "Value": "NQ==", "CreateIndex": 407, "ModifyIndex": 407 } ]
以上的值是base64编码过的字符串
kv/?keys