使用 Consul + Docker + Registrator + Consul-template 搭建可伸缩服务发现平台

摘要:
Registrator简介Registrator通过Docker提供的API,监听Docker容器的启动、停止等状态变化,并且可以利用inspectAPI获取容器提供的服务,包括端口,IP地址等。Registrator发现服务之后,将服务相关的信息注册到Consul或者etcd等分布式数据库中。Registrator会判断这个参数的Schema来决定发送的数据协议。ConsulTemplate简介ConsulTemplate可以实时查询Consul分布式数据库中注册的服务,并根据这些服务的元信息按照模板格式更新Nginx的路由设置,如果有任何变化,则重新启动Nginx服务。
背景介绍

Docker 的出现,改变了软件的交付方式,使得开发、测试、运维都能在一个完全统一的环境中进行。在服务容器化的网络中,需要添加服务发现功能。每个服务可能对应多个示例以容器运行在多个机器上,并且提供自动注册和失败检测机制。
目前服务发现已经有很多成熟的解决方案,例如 Spring Cloud中的 Eureka 注册中心,Hystrix 断路器,zuul 服务网关等全家桶。但是需要依赖原生 Java 语言支持。另一个选择同样是 Spring 中的 Sidecar。我们这里介绍一个相比较轻量化的服务发现平台,可以通过一行代码不写,只需要配置就可以搭建服务发现集群。唯一的要求就是先将服务docker化。

总结需求如下:

  1. 先将服务使用 docker 部署。每个服务对应一个或多个容器。
  2. 多个机器上具有相同 name 启动参数的容器属于同一个服务。
  3. 容器的启停需要有统一的机制注册到存储并且在集群里同步。
  4. 为了实现外部的域名访问,申请一个前缀 FQDN。如只是内部访问,可以搭建 DNS Server 或者配置 resolve 也可以。
  5. 提供统一的 UI 界面对集群提供的服务进行查询。
一、Consul 简介

Consul 是一个开源的提供服务发现和KV键值存储的分布式框架,支持负载均衡,允许和 Kubernetes 集成,可以跨 物理机,虚拟机或是 Kubernetes 完成服务网格的部署。Consul下载地址在 https://www.consul.io/downloads.html。Consul 只是一个单可执行文件,类似 docker 提供了服务端和命令行工具二合一的使用方式。直接放在 /usr/local/bin 目录中或者任意可执行路径中就可以了。

参数说明

 -server - Serve模式,不带该参数时默认是Agent模式
 -bootstrap-expect - Server数量,加上这个参数时,服务器启动到指定数量集群才启动
 -data-dir - 数据目录
 -config-dir - 配置文件目录
 -node - Node名称
 -bind - 集群通讯地址,取本机IP地址
 -client:consul绑定在哪个client地址上,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1
 -ui - 启动web ui

常用命令

查看成员
consul members
加入到集群
consul join <集群节点IP>
退出集群
如果consul通过命令行启动,ctl+C就退出集群,如果是以服务的方式启动,则停止服务就退出了集群

consul-cli的用法说明

consul-cli是consul的HTTP接口的命令行版本,提供了一些便捷的命令行工具,用于对consul中注册的服务进行操作。详情参考 https://github.com/mantl/consul-cli

consul-cli agent force-leave skydns-100: 强制一个节点离线
consul-cli status leader:查看当前集群中的leader
consul-cli catalog service mongo-rs0:检查一个服务的状态
consul-cli service deregister consul-dc1-node3:mongo:27017:反注册一个服务

服务的注册

有几种注册服务的方式

  1. 通过配置文件
    echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' > /etc/consul.d/web.json
    可以通过这种方式注册一个测试服务。
    通过这种方式注册的服务,在consul启动的时候会自动获取 config-dir 目录的内容进行注册了。
  2. 直接通过HTTP请求
curl -XPUT 
127.0.0.1:8500/v1/agent/service/register 
-d '{
"ID": "simple_instance_1",
"Name":"simple",
"Port": 8000,
"tags": ["tag"]
}'

无论是哪种注册方式,随后可以通过 UI 来查看服务的状态http://127.0.0.1:8500/

上面两种方式并没有真正自动发现一个服务,而只是一个注册中心应该有的功能。要做到真正意义上的服务自动发现,就需要有一个机制可以监听服务的生命周期并且自动完成注册动作。而我们知道, dockerd 提供了 http API 来可以让外部程序获取或者管理容器,这就使得自动化服务发现成为可能。

Registrator简介

Registrator 通过 Docker 提供的API,监听Docker 容器的启动、停止等状态变化,并且可以利用 inspect API 获取容器提供的服务,包括端口,IP地址等。在本文描述中,可以把服务看做任何监听一个端口的东西。Registrator 发现服务之后,将服务相关的信息注册到 Consul 或者 etcd 等分布式数据库中。官网地址在http://gliderlabs.github.io/registrator/latest/user/quickstart/

更可喜的是 Registrator 可以以 docker 方式启动, 以注册到 Consul 为例,下面的例子启动一个 Registrator 服务, net 参数为 host 表示使用本机的网络配置,以监听本机的端口。使用 volume 参数获取 dockerd 工作的端口。同时将注册的目标地址这里是 Consul 集群的地址,作为启动参数传入。Registrator 会判断这个参数的 Schema 来决定发送的数据协议。

docker run -d --name=registrator --net=host --volume=/var/run/docker.sock:/tmp/docker.sock --restart always --log-opt max-size=50m gliderlabs/registrator:latest consul://localhost:8500

到此已经解决了服务注册的问题,而且随着容器的启动,在 Consul 的 Web-UI 界面上可以看到新添加的服务地址。但是对于服务使用方来说,需要每次查询服务列表才能知道对应服务的地址。如果将每个服务在每个机器上都部署在相同端口上,则就失去了 Consul 的意义。是否有方法可以让容器的 IP 和端口可以自由变化,在 Registrator 发现并注册后,当我们访问 Consul 集群中任何一台机器时,可以重定向到真正的服务地址上。
当然有啊,就是使用 Nginx 转发。因此就需要解决每次服务发生变化时,对 nginx 自动进行配置。

Consul Template简介

Consul Template 可以实时查询 Consul 分布式数据库中注册的服务,并根据这些服务的元信息按照模板格式更新 Nginx 的路由设置,如果有任何变化,则重新启动Nginx服务。当然 Consul Template 可以更新的模板、重新加载的服务不仅仅包括Nginx,还可以是任何其他的服务。
在启动 Consul 的时候加上如下参数指定 consul template 使用的配置文件

-config=/opt/consul/consul-template.conf 

这个配置文件中需要指定Consule Template所更新的模板(源),模板更新之后的目标路径,模板更新之后执行的命令

模板的格式请参考 consul template 主页了解关于配置文件的格式以及模板语言的语法
https://github.com/hashicorp/consul-template
https://www.hashicorp.com/blog/introducing-consul-template/

结论:

以上内容连在一起,

  1. Consul提供了个高可用强一致性的分布式key-value数据库,并提供健康检查、DNS等功能。
  2. Registrator自动发现本机上通过Docker容器提供的服务,注册到Consul数据库中
  3. Consul template则自动根据 Consul 数据库注册的内容更新Nginx的配置文件、路由设置并自动重启Nginx
  4. enable、start consul服务,组建集群
  5. consul集群的每个节点上启动registrator container
  6. consul集群的每个节点上enable、start consule template服务
  7. 接下来就是启动任意docker容器提供web service了。整个过程不需要任何其他手工配置,服务动态扩容,水平扩展
操作步骤笔记

将consul 和 consul 和 consul-template 服务文件,分别放置到位置 /usr/lib/systemd/system/
注意修改下面参数的填写
consul.service 文件(需要先改主机名,先用 hostname 命令,再改 /etc/hostname 文件)

[Unit]
Description=consul

[Service]
Type=simple
ExecStartPre=/bin/mkdir -p /opt/consul/data /opt/consul/config /opt/consul/log
ExecStart=/bin/bash -c 'exec /opt/consul/consul agent -bootstrap -server -ui -node=$(hostname) -bind=$(hostname -i) -data-dir=/opt/consul/data/ -config-dir=/opt/consul/config/ -advertise=$(hostname -i) -recursor=10.64.1.54 -recursor=10.64.1.55 -dns-port=53 -client=0.0.0.0 &>> /opt/consul/log/consul.log'
WorkingDirectory=/opt/consul
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

consul-template.template 文件

[Unit]
Description=consul-template

[Service]
Type=simple
ExecStart=/bin/bash -c 'exec /opt/consul/consul-template -config=/opt/consul/consul-template.conf &>> /opt/consul/log/consul-template.log'
WorkingDirectory=/opt/consul
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

然后分别启动服务

systemctl start consul
systemctl start consul-template

使用下面的命令查询是否成功,然后尝试启动

systemctl status consul
journalctl -f -xn | grep consul         // 跟踪显示 consul 这个服务的信息 , x 选项是添加 category 错误信息提示。

如果没有错误了,加入自启动列表

systemctl  enable consul
systemctl enable consul-template

consul-template 这个服务的功能是用来使用 /var/lib/consul/sock 这个 docker 启动的监听通道监控是否有新的服务变动(包含启动和停止),
如果有变动机会 1. 渲染源模板文件. 2.替换目标文件. 3. 执行指定的命令(常常是更新系统配置的命令)
上面例子中的nginx模板文件 nginx.ctmpl 内容如下

server_names_hash_bucket_size 128;
client_max_body_size 10G;

{{range services}} {{$name := .Name}} {{$service := service .Name}}
upstream {{$name}} {
  zone upstream-{{$name}} 64k;
  {{range $service}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
  {{else}}server 127.0.0.1:65535; # force a 502{{end}}
} {{end}}

server {
  listen 80 default_server;

  location / {
    return 404;
  }

  location /health {
    return 200;
  }
}

{{range services}} {{$name := .Name}}
server {
  listen 80;
  server_name {{$name}}.service.test.org {{$name}}.service.org;

  location / {
    proxy_pass http://{{$name}};
    proxy_http_version 1.1;

    proxy_set_header Host {{$name}}.service.test.org;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Real-IP $remote_addr;

    # upgrade connection for websocket
    set $proxy_upgrade "";
    set $proxy_connection "";
    if ($http_upgrade != ''){
        set $proxy_upgrade $http_upgrade;
        set $proxy_connection "upgrade";
    }
    proxy_set_header Upgrade $proxy_upgrade;
    proxy_set_header Connection $proxy_connection;

  }
}
{{end}}

server {
  listen 80;
  server_name consul-ui.service.test.org;

  location / {
    proxy_pass http://127.0.0.1:8500;
  }
}

当第一个consul 节点启动成功之后,就可以在其他节点上面使用下面的命令加入到consul集群中

consul  join  第一台节点 ip 地址

每台机器需要使用 nginx 服务做端口转发。最终的效果是访问 Consul 集群中任何一个机器的 8500 看到的 web 界面是一样的。

/opt/consul/consul-template.conf 文件

# see https://github.com/hashicorp/consul-template#configuration-file-format
consul {
  auth {
    enabled  = true
    username = "test"
    password = "test"
  }
  address = "127.0.0.1:8500"
  token = "111111"
  retry {
    enabled = true
    attempts = 5
    backoff = "250ms"
  }
}

reload_signal = "SIGHUP"
#dump_signal = "SIGQUIT"
kill_signal = "SIGINT"
max_stale = "10m"
log_level = "warn"
pid_file = "/opt/consul/run/consul-template.pid"

wait {
  min = "5s"
  max = "10s"
}

syslog {
  enabled = true
  facility = "LOCAL5"
}

deduplicate {
  enabled = true
  prefix = "consul-template/dedup/"
}

template {
  source = "/opt/consul/nginx.ctmpl"
  destination = "/etc/nginx/sites-enabled/default"
  command = "service nginx reload"
  command_timeout = "60s"
  perms = 0644
  #backup = true
  left_delimiter  = "{{"
  right_delimiter = "}}"
  wait {
    min = "2s"
    max = "10s"
  }
}

常见问题:

  1. 在 consul-ui 网页上面看到,显示的服务在实际的机器上面不存在。这是因为缓存没有更新造成的。删除掉 consul/data 文件夹,重启 consul, consul-template 服务。
  2. 使用的consul, consul-template, registrator 版本要一致,否则会出现莫名其妙的问题。
  3. registrator 一定要注册到 localhost:8500, 否则这台机器上启动的容器会显示到 注册的机器 上面。
  4. 重新修复的 consul 集群,启动 registrator 之后,consul-ui 会找不到现有的 docker 容器。需要手动触发一次 registrator 的reload
docker exec -it registrator sh
/bin/registrator  -resync=0 consul://localhost:8500

其中,consul://localhost:8500 就是 docker run 启动 registrator 的参数。

  1. 启动单节点的Consul时往往会报错
2016/11/25 21:06:10 [ERR] agent: failed to sync remote state: No cluster leader
2016/11/25 21:06:35 [ERR] agent: coordinate update error: No cluster leader

这是因为 Consul 集群启动数量太少无法进行选举。可以在 consul 启动命令中加上参数 -bootsrapt, 就可以让单节点启动。

  1. 节点加入到集群中之后,又修改了hostname导致以旧hostname注册的节点一直存在集群中
    通过 force-leave 命令强制离线

  2. Mongo节点出现故障,恢复之后service registry中注册的mongo服务的节点仍然处于不正确的状态,
    通过 deregister 注销然后再重新注册服务

免责声明:文章转载自《使用 Consul + Docker + Registrator + Consul-template 搭建可伸缩服务发现平台》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Ubuntu apt-cache命令查找可用软件包Mysql源码学习——词法分析MYSQLlex下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

微服务的接入层设计与动静资源隔离

本文由  网易云 发布。 作者:刘超,网易云解决方案架构师 这个系列是微服务高并发设计,所以我们先从最外层的接入层入手,看都有什么样的策略保证高并发。 接入层的架构如下图所示: 接下来我们依次解析各个部分以及可以做的优化。   一、数据中心之外:DNS,HttpDNS,GSLB 当我们要访问一个网站的服务的时候,首先访问的肯定是一个域名,然后由DNS,将...

Docker学习のWindows下安装Docker

一、docker最初只支持linux的,因此在windows下运行需要虚拟机。 利用VirtualBox建立linux虚拟机,在linux虚拟机中安装docker服务端和客户端 利用Windows的Hyper-v虚拟化技术,直接在Windows上安装docker服务端和客户端。(在windows10和windows server2016) WIndow...

linux下安装nginx(编译安装)及反向代理及负载均衡

首先卸载掉之前用yum命令下载的nginx yum remove nginx 安装nginx需要的依赖库 yum install -y gcc patch libffi-devel python-devel zlib-devel bzip2-devel openssl openssl-devel ncurses-devel sqlite-devel re...

Docker容器利用weave实现跨主机互联

Docker容器利用weave实现跨主机互联 环境: 实现目的:实现主机A中容器1与主机B中容器1的网络互联 主机A步骤: ①下载复制weave二进制执行文件(需要internet)[root@192 ~]#git clone https://github.com/weaveworks... #如没有git,yum install git[root@19...

docker 配置 mysql

docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7.30 ## 一个是数据文件夹,一个是配置文件夹 ## mysql 容器中 my.cnf incloud 了 conf.d 文件夹下所有的 cnf 配置文件,所以这里我们只要将 conf.d...

Docker最全教程——从理论到实战(六)

Docker最全教程——从理论到实战(六) 托管到腾讯云容器服务托管到腾讯云容器服务,我们的公众号“magiccodes”已经发布了相关的录屏教程,大家可以结合本篇教程一起查阅。   自建还是托管? 在开始之前,我们先来讨论一个问题——是自建容器服务还是托管到云容器服务? 这里笔者建议大家托管到云容器服务。对于中小团队来说,很多情况下,团队中的运维人员是缺...