文章目录
阅读本文前需要先了解consul的基础架构。
使用 docker 搭建consul集群
注意,
dockerhub-consul
提到:在正常的生产环境中,会在每个主机上运行一个Consul容器。consul在docker应该始终以
--network=host
模式运行,因为Consul 的共识和
Gossip
协议对延迟和数据包丢失很敏感,所以其他网络类型涉及的额外层通常是不可取的,也是不必要的。
使用host模式,Consul容器就和主机(服务器)共享同一个
Network Namespace
(网络命名空间)了,这可以减少额外的开销,而且不需要再配置那么多端口映射(很容易遗漏)。但是我没有这么多服务器,所以接下来并不会使用host模式(用和不用的区别并不大)。
目的
:在一个服务器上,用docker搭建consul集群。
方法分析
:利用docker的
network-bridge
网桥,同一个
network-bridge
上的容器位于同一网段,拥有独立的ip和端口范围。以此实现在一台机器上搭建集群。
-
server agent 节点:不必须启用UI 和 设置端口映射,因为它们通过
docker-network
进行内网通信。
但为了便于观察,最好还是启用UI。ui属于http-api,默认使用
8500
端口。
我们最好把client的
8500
映射到主机的
8500
(因为应用程序与client连接,而不是与server连接,不改变默认端口看起来会更简单),而把server的
8500
映射到其它端口,如
8501
、
8502
等。 -
client agent 节点:需要开放UI 和 设置端口映射,因为我们要通过连接client与consul集群交互。client与server也通过
docker-network
进行内网通信。 -
除了http-api端口,agent之间还至少会使用
8301
、
8300
端口进行内部通信,但因为它们都处于同一
docker-network
下,可以自由通信,因此并不需要我们特别关心这些端口。
Consul容器的
docker-entrypoint.sh
docker-entrypoint.sh
以下是一个简单的consul容器运行命令,容器的默认启动命令是
docker-entrypoint.sh agent -dev -client=0.0.0.0
docker run -d -p 8500:8500 consul
consul容器始终使用
docker-entrypoint.sh
脚本执行启动命令,无论是默认命令的还是我们指定的命令。这是通过dockerfile的
ENTRYPOINT
指令实现的。
docker-entrypoint.sh
脚本进行了一些初始封装,此脚本在容器内的路径:
/usr/local/bin/docker-entrypoint.sh
,可以查看其详细内容。
-
自定义启动命令部分可以直接写
agent
,等同于
consul agent
。docker run -d consul agent ...
-
-data-dir
被设置为
/consul/data
,
-config-dir
被设置为
/consul/config
,因此这两个选项不再需要我们手动配置,只需要按需进行挂载卷即可。(
dockerhub-consul
也提到了这两个可直接挂载的目录)
1. 创建 network
# 创建network
docker network create --subnet 172.10.0.0/16 --gateway 172.10.0.1 consul-network
# 这里指定了16位子网掩码,因此子网ip范围是 172.10.0.0 - 172.10.255.255
docker network 有两个
bug
(
issuse
):
2. 部署 Server-Agent
启动命令。创建
server-1
、
server-2
、
server-3
,一个高可用集群至少要有3个server节点。
# (不使用docker时的)基础格式是。
consul agent -server -node=<node_name> -bind=<listen_ip> [-advertise=<public_ip>] -data-dir=<data_dir> [-config-dir=<config_dir>] [-bootstrap-expect=<number_of_server_agents>] -client=0.0.0.0 -ui
# 刚刚讲过,`docker-entrypoint.sh`封装了`-data-dir`和`-config-dir`,因此直接按需挂载即可。
# 启动server-1。
docker run -d --network consul-network --ip 172.10.1.1 -p 8501:8500 -v consul_conf:/consul/config --name consul-server-1 \
consul agent -server -node=server-1 -bootstrap-expect=3 -bind=172.10.1.1 -client=0.0.0.0 -ui
# 启动server-2,并加入到server-1。
docker run -d --network consul-network --ip 172.10.1.2 -p 8502:8500 -v consul_conf:/consul/config --name consul-server-2 \
consul agent -server -node=server-2 -bootstrap-expect=3 -bind=172.10.1.2 -retry-join=172.10.1.1 -client=0.0.0.0 -ui
# 启动server-3,并加入到server-1。
docker run -d --network consul-network --ip 172.10.1.3 -p 8503:8500 -v consul_conf:/consul/config --name consul-server-3 \
consul agent -server -node=server-3 -bootstrap-expect=3 -bind=172.10.1.3 -retry-join=172.10.1.1 -client=0.0.0.0 -ui
主要选项说明
(包含命令中没用到的一些选项)
-
-server
:表示以server模式启动。 -
-node
:节点名称,在集群(一个数据中心)中必须是唯一的,不能包含空格或引号。默认值是主机名。 -
-ui
:启用web管控台功能。(dev模式默认启用,生产模式需要指定此选项启用) -
-config-dir
:consul读取配置文件的目录。 -
-data-dir
:consul运行时产生的数据的存储目录(必须提前创建好)。 -
-client
:允许访问的客户端ip,
0.0.0.0
表示不限制。 -
配置通信地址选项
-
-bind
:当前节点监听的本机ip,
集群内部通信的地址
。会被发送到集群中的其它节点,用作与本节点通信,因此需要能被其它节点访问到。
就是tcp/http的侦听地址
,必须是
本机的ip
(即本机某个网卡的ip),否则会报错
listen tcp xxx.xx.xxx.xx:8300: bind: can't assign requested address
。这不是consul专有的报错,而是tcp的报错,可以尝试自己动手写一个tcp/http,如果监听地址不写本机ip,就会报这个错误。 -
-advertise
:默认情况下,
-bind
选项的地址会被发送到集群中的其它节点,用作与本节点通信。但某些情况下,可能存在
无法
-bind
的可路由地址
,此时就可以使用
-advertise
选项,consul会把此选项指定的地址(而不再是
-bind
的地址)发送到集群中的其它节点,用作与本节点通信。解释”无法
-bind
的可路由地址”:例如一些云服务器的
公网ip
。有些云直接向服务器提供公网ip;而有些云则没有,并通过NAT转换提供公网ip的访问。对于后者,尽管可以通过公网ip访问到服务器,但无法将其设置为
-bind
的值,因为这种公网ip没有被直接分配到云服务器(即服务器上没有对应公网ip的本地网卡)。
-
-
“引导和加入集群”选项
。(详见
关于”引导和加入集群”
)-
-bootstrap-expect
:提供集群中预期的server节点数量。为了防止不一致和脑裂的情况,集群中所有server节点的此选项的
值必须一致
或者 不指定任何的值,只有指定了值的server才会尝试引导集群。
此选项需要
-server
。 -
-retry-join
:指定加入到集群(集群中的任意一个agent)的地址,重试直至加入成功。
-
-
-serf-lan-port
:Serf的
LAN Gossip
通信的端口,默认值8301。
可以通过
-serf-lan-bind
指定对应的ip,默认使用
-bind
选项的ip。 -
-serf-wan-port
:Serf的
WAN Gossip
通信的端口,默认值8302。跨数据中心使用。
可以通过
-serf-wan-bind
指定对应的ip,默认使用
-bind
选项的ip。 -
-datacenter
:控制Agent运行所属的数据中心,默认值”dc1″。
访问UI
观察集群状态:
ip:port/ui/
- 在全部成功启动之前,UI不会显示具体的内容,因为此时没有leader,无法获得可靠的信息。
- 在全部成功启动之后,访问任意一个UI,都能看到集群的信息,server-1是最初的leader(因为我们让2和3加入了它,这会让其成为初始leader),这表示集群启动成功。
3. 部署 Client-Agent
# (不使用docker时的)基础格式是。
consul agent -node=<node_name> -bind=<listen_ip> -retry-join=<server-ip> -data-dir=<data_dir> [-config-dir=<config_dir>] -client=0.0.0.0 -ui
# 启动client,并加入到server-1。
# 因为正常生产环境中会有很多client,都在集群中显示,所以我们给它的节点名编号为client-1。
docker run -d --network consul-network --ip 172.10.2.1 -p 8500:8500 -v consul_conf:/consul/config --name consul-client-1 \
consul agent -node=client-1 -bind=172.10.2.1 -retry-join=172.10.1.1 -client=0.0.0.0 -ui
访问UI
观察只因群状态:
ip:port/ui/
(是集群状态啦~🏀)
这就
完成了
,很简单吧~
接下来,用你的应用程序连接client节点,开始使用consul集群吧~
关于”引导和加入集群”
参考文档 –
Bootstrap a Datacenter
刚才我们使用
-retry-join
做了一件事:加入到
server-1
。如果不这么做,那么每个节点成功运行后,都还只是相互独立的,因此需要把它们关联起来,建立集群关系。
建立集群关系又可细分为两个部分:引导集群、加入集群(连接集群)。
① 引导集群
在 Consul 集群可以开始为请求提供服务之前,必须选举server节点的leader
。
引导
,是将这些”
初始server节点
“建立为可用群集的过程。
引导集群有两种不同的选项:(两个选项都需要
-server
,因为”引导集群”仅是server节点的功能)
选项一:
-bootstrap-expect
:提供集群中预期的server节点数量。为了防止不一致和脑裂的情况,集群中所有server节点的此选项的
值必须一致
或者 不指定任何的值,只有指定了值的server才会尝试引导集群。
Consul会等到有指定数量的server可用后,引导集群
,
自动选举
初始leader,在此之前会不断地打印错误日志:
No cluster leader
。
通常值设置为3或5,这是在可用性和效率之间的权衡。节点越多,数据在节点间的同步过程越长,效率越慢;节点越少,则越不能保证高可用。
选项二:
-bootstrap
:此选项控制server是否处于”引导”模式。处于引导模式的server可以
自选为leader
。
注意:
只能有一个
server节点处于此模式;否则,由于多个节点进行自选,会出现脑裂,无法保证一致性。
这两个选项通常单独使用,强烈不建议混用。
推荐使用
-bootstrap-expect
,因为
-bootstrap
更容易出错(由于配置时的不小心)。
② 加入集群(连接集群)
加入/连接集群:无论是加入到尚未引导的集群还是已经引导的集群,方式都一样。
- 当集群尚未达到引导所需的server数量时,需要将server连接到一起,达到引导条件才会引导集群,建立可用的集群。
- 新的agent也需要加入到已经可用的集群,才能成为集群的一员。
通过指定集群中任意一个或多个agent的ip地址加入集群
,具体也有两种不同的方式:
方式一:新的节点启动时,使用
-retry-join
选项加入集群,会不断重试直至加入成功。
v1.15
之前可以使用
-join
选项(
v1.15
已弃用)。
这种方式被称为自动加入。
consul agent -retry-join=172.10.1.1 [-retry-join=<ip> ...]
方式二:新的节点启动后,使用
consul join
命令加入集群。
这种方式被称为手动加入。
consul join 172.10.1.1 [...]
“加入集群”的
设计原则
是:
-
一旦加入集群,所有Agent(节点)将仅通过
Gossip
维持其成员资格,不再关心
join
指定的ip。可以
指定多个
要加入的节点ip,Agent会按照顺序尝试加入,直到出现第一个成功。 -
已经加入了集群的Agent还可以
join
另一个集群中的Agent,这会导致两个集群
合并
为单个集群。 -
因此可以看出来,
join
时
指定的ip不必须是相同的
,只要新的Agent能成功
join
到集群中的任何一个Agent,就能加入到集群,此后它们仅通过Gossip维持集群状态。
操作和使用
集群操作命令
consul members
:查询集群成员列表及其状态。
consul leave
:离开集群。
集群的使用
使用时,集群和dev模式没有太大的区别。
- 使用dev模式时,服务直接连接dev节点。
- 使用集群模式时,服务直接连接client节点。服务通过client和server间接通信,server节点的状态由consul内部维护。
使用 docker compose 一键搭建集群
docker compose 的优点就不必多说了,直接上配置!
编写
docker-compose.yml
文件:
(为了保证稳定性,可以指定镜像的版本。不然说不定哪次版本更新之后这个配置就不能用了呢~)
version: '1.0'
name: consul-cluster
services:
consul-server-1:
image: consul:1.15
ports:
- 8501:8500
volumes:
- consul_conf:/consul/config
networks:
consul-network:
ipv4_address: 172.10.1.1
container_name: compose-consul-server-1
command: agent -server -node=server-1 -bootstrap-expect=3 -bind=172.10.1.1 -client=0.0.0.0 -ui
consul-server-2:
image: consul:1.15
ports:
- 8502:8500
volumes:
- consul_conf:/consul/config
networks:
consul-network:
ipv4_address: 172.10.1.2
container_name: compose-consul-server-2
command: agent -server -node=server-2 -bootstrap-expect=3 -bind=172.10.1.2 -retry-join=172.10.1.1 -client=0.0.0.0 -ui
consul-server-3:
image: consul:1.15
ports:
- 8503:8500
volumes:
- consul_conf:/consul/config
networks:
consul-network:
ipv4_address: 172.10.1.3
container_name: compose-consul-server-3
command: agent -server -node=server-3 -bootstrap-expect=3 -bind=172.10.1.3 -retry-join=172.10.1.1 -client=0.0.0.0 -ui
consul-client-1:
image: consul:1.15
ports:
- 8500:8500
volumes:
- consul_conf:/consul/config
networks:
consul-network:
ipv4_address: 172.10.2.1
container_name: compose-consul-client-1
command: agent -node=client-1 -bind=172.10.2.1 -retry-join=172.10.1.1 -client=0.0.0.0 -ui
volumes:
consul_conf:
networks:
consul-network:
ipam:
config:
- subnet: 172.10.0.0/16
gateway: 172.10.0.1
启动
在
docker-compose.yml
文件所在目录指定启动命令:
docker compose up -d
ro~ 的一下就启动了🤗