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

  • Post author:
  • Post category:其他



阅读本文前需要先了解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



以下是一个简单的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-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~ 的一下就启动了🤗



版权声明:本文为qq_43413788原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。