使用docker和docker-compose搭建consul集群 -- 详细教程


阅读本文前需要先了解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映射到其它端口,如85018502等。
  • client agent 节点:需要开放UI 和 设置端口映射,因为我们要通过连接client与consul集群交互。client与server也通过docker-network进行内网通信。
  • 除了http-api端口,agent之间还至少会使用83018300端口进行内部通信,但因为它们都处于同一docker-network下,可以自由通信,因此并不需要我们特别关心这些端口。

Consul容器的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):

  • 不用--subnet创建的网络,启动容器时无法使用--ip指定静态ip,但这篇文档写的可以。
  • 使用--subnet创建的网络,不会自动设置网关(但这篇文档写的会自动设置),需要用--gateway指定。
    之所以说"不会自动设置",根据是:用docker inspect命令查看network的信息看不到gateway。不过,尽管如此,但如果把容器加入到网络,容器内执行route -n命令又能看到网关地址,默认是subnet.1,如172.10.0.1

2. 部署 Server-Agent

启动命令。创建server-1server-2server-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~ 的一下就启动了🤗

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值