环境说明
- ubuntu16.04.7 LTS xenial
- boxes 下载地址
- 我这里用的ubuntu/xenial64下载地址
- 具体安装细节请参考Ubuntu安装docker准备篇
主要技术以及版本
vagrant
- vagrant是一个对虚拟环境管理的工具。
virtualbox
- VirtualBox 是一款开源虚拟机软件。
docker
- version 20.10.7
- docker是一个开源的应用容器引擎。
- 安装docker
- 具体安装细节以及权限问题解决请参考Ubuntu安装docker
consul
- version 1.11.3
- consul是一个用来实现分布式系统的服务发现与配置的开源工具。
- 官网下载地址
consul-template
- version 0.19.0
- consul-template基于consul的自动替换配置文件的应用。
- consul-template 下载地址
nginx
- version 1.21.6
- 地球人都知道的嘛!!!
额外说明
virtualbox
和vagrant
版本不兼容会出现很多未知问题(坑),官方网站也没有介绍哪个版本对应兼容,我这里分享一个兼容性不错的版本下载连接放下面,供大家参考。- virtualbox5.2.8
- vagrant2.1.1
简要说明
传统负载均衡架构图
- 假如目前服务需要扩容,增加了一台Web Server5,你需要手动修改Nginx配置并且重启Nginx。
- 假如目前Web Server1、Web Server4服务大半夜突然挂了,你岂不是需要爬起来修改Nginx配置,这种情况重复来几次,这可不是什么好的体验,会让人崩溃的呢!!!
我们要实现什么呢?下面我们附上图来说明!!
- 因需要或者意外情况而造成增加/减少机器及或者某个服务而动态实现nginx配置自动更新并实现更新重载。
- web server 通过 registrator 注册到consul服务里,然后consul-template订阅consul实现nginx配置更新重载,达到动态扩容(增加/减少),保证服务稳定可靠运行的目的。
实现
- 假设你已经安装好虚拟机(以ubuntu为例)和docker应用容器引擎。
- 这里可以先完整安装一台机器的软件和应用,然后使用vagrant打包剩下的两个机器。
机器说明
- 服务器1: IP: 192.168.56.2
- 服务器2: IP: 192.168.56.3
- 服务器3: IP: 192.168.56.4
consul集群角色分配(我这里电脑配置有限,搞太多虚拟机测试主机windows机器容易卡死,所以我的consul集群和webserver以及nginx转发服务器都用这三个机器实现啦)
- 服务器1: IP: 192.168.56.2 leader
- 服务器2: IP: 192.168.56.3 service
- 服务器3: IP: 192.168.56.4 client nginx转发服务器
应用程序角色分配
- 服务器1: IP: 192.168.56.2 直播服务API1
- 服务器2: IP: 192.168.56.3 直播服务API2
- 服务器3: IP: 192.168.56.4 直播服务API3
部署consul集群
consul常用命令
- server : 定义agent运行在server模式
- bootstrap-expect :在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap共用
- bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0
- node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
- ui-dir: 提供存放web ui资源的路径,该目录必须是可读的
- rejoin:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。
- config-dir:配置文件目录,里面所有以.json结尾的文件都会被加载
- client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
# 拉取镜像 docker pull consul # 192.168.56.2 (leader server) docker run --net=host --name consul1 -d consul agent -server -bootstrap-expect 1 -ui -node=s0 -bind=192.168.56.2 -client=0.0.0.0 # 192.168.56.3 (server) docker run --net=host --name consul3 -d consul agent -server -ui -node=s3 -bind=192.168.56.3 -client=0.0.0.0 -join=192.168.56.2 # 192.168.56.4 (client) docker run --net=host --name consul4 -d consul agent -ui -node=s4 -bind=192.168.56.4 -client=0.0.0.0 -join 192.168.56.2 # 查看consul cluster中consul节点的信息 docker exec -it consul1 consul members #查看consul集群已经启动以及选举的leader docker exec -it consul1 consul operator raft list-peers
- 浏览器访问UI界面 http://192.168.56.2:8500/
编写直播API服务
我这里直接使用swoole简单模拟搭建一个直播的HTTP服务,前提是你的php安装了swoole扩展(server.php)
<?php #192.168.56.2 $http = new Swoole\Http\Server('0.0.0.0', 8080); $http->on('Request', function ($request, $response) { $response->header('Content-Type', 'text/html; charset=utf-8'); $response->end('<h1>直播服务API1 #IP:192.168.56.2</h1>'); }); $http->start();
<?php #192.168.56.3 $http = new Swoole\Http\Server('0.0.0.0', 8080); $http->on('Request', function ($request, $response) { $response->header('Content-Type', 'text/html; charset=utf-8'); $response->end('<h1>直播服务API2 #IP:192.168.56.3</h1>'); }); $http->start();
<?php #192.168.56.4 $http = new Swoole\Http\Server('0.0.0.0', 8080); $http->on('Request', function ($request, $response) { $response->header('Content-Type', 'text/html; charset=utf-8'); $response->end('<h1>直播服务API3 #IP:192.168.56.4</h1>'); }); $http->start();
注册直播服务API到consul集群
//composer require php-curl-class/php-curl-class require __DIR__ . '/vendor/autoload.php'; use Curl\Curl; function _curl($u = '',$method = 'get', $data = null) { $curl = new Curl(); $baseUrl = 'http://192.168.56.4:8500/v1'; $url = $baseUrl. $u; if (in_array(strtolower($method), ['put','post']) && !empty($data)) { return $curl->$method($url,$data); } else { return $curl->$method($url); } } $res = 'init'; //注册开始 $servers = [ ['ip' => '192.168.56.2','port' => 8080,'id' => 'zhibo-1','Name' => 'zhibo_service'], ['ip' => '192.168.56.3','port' => 8080,'id' => 'zhibo-2','Name' => 'zhibo_service'], ['ip' => '192.168.56.4','port' => 8080,'id' => 'zhibo-3','Name' => 'zhibo_service'] ]; foreach ($servers as $serve) { //注意同一个服务Name必须一样ID可以不同 $data = array( 'ID' => $serve['id'], 'Name' => $serve['Name'], 'Tags' => ["primary", "v2"], 'Address' => $serve['ip'], 'Port' => $serve['port'], 'EnableTagOverride' => false, 'check' => array( 'DeregisterCriticalServiceAfter' => '90m', 'HTTP' => "http://{$serve['ip']}:{$serve['port']}", 'Interval' => '10s', "Timeout" => "5s" ) ); $data = json_encode($data,JSON_UNESCAPED_SLASHES); $res = _curl('/agent/service/register','put',$data); //$res = _curl('/agent/service/register?replace-existing-checks=true','put',$data); echo "<pre>"; print_r($res); } ##其他API大概描述 //注销直播-3服务 //$res = _curl('/agent/service/deregister/zhibo-3','put'); //启用维护模式(enable=true/false) //$res = _curl('/agent/service/maintenance/zhibo-3?enable=false&reason=维护原因','put'); //检查是否健康 status 为passing的为通过 //$res = _curl('/health/checks/zhibo_service'); //列出服务 //$res = _curl('/agent/services'); //获取服务配置 //$res = _curl('/agent/service/zhibo-3'); //获取本地服务运行状况 //json //$res = _curl('/agent/health/service/name/zhibo_service'); //text //$res = _curl('/agent/health/service/name/zhibo_service?format=text'); //通过 ID 获取本地服务运行状况 //$res = _curl('/agent/health/service/id/zhibo-3'); //$res = _curl('/agent/health/service/id/zhibo-3?format=text'); echo '<pre>'; print_r($res); die;
搭建nginx转发服务,安装consul-template并关联订阅服务consul集群更新nginx转发配置,重启nginx。
- 目录结构
- consul-template文档地址
模板文件
{{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 zhibo_service.com; location / { root /usr/share/nginx/html/; index index.html; } location /stub_status { stub_status; } {{range services}} {{$name := .Name}} location /{{$name}} { proxy_pass http://{{$name}}; } {{end}} }
Dockerfile 文件
#指定基础镜像 FROM nginx:latest #指定维护人 #MAINTAINER zhengniu LABEL authors="zhengniu <771036148@qq.com>" #https://releases.hashicorp.com/consul-template ARG CONSUL_TMEPLATE_VERSION="0.19.0" RUN rm -rf /etc/nginx/sites-available/ ENV CONSUL_URL 127.0.0.1:8500 #ADD https://releases.hashicorp.com/consul-template/${CONSUL_TMEPLATE_VERSION}/consul-template_${CONSUL_TMEPLATE_VERSION}_linux_amd64.zip /usr/local/bin/ ADD consul-template_0.19.0_linux_amd64.tgz /usr/local/bin/ VOLUME /templates ADD service.ctmpl /templates/ EXPOSE 80 RUN mkdir -p /etc/service/nginx && rm -rf /etc/service/nginx/* ADD start.sh /etc/service/nginx/run CMD ["/etc/service/nginx/run"]
start.sh
#!/bin/bash service nginx start & consul-template -consul-addr=$CONSUL_URL -template="/templates/service.ctmpl:/etc/nginx/conf.d/service.conf:service nginx reload"
构建镜像以及启动镜像
docker build -t nginx:consuleTemplate . docker run --net=host -d --name nginx nginx:consuleTemplate
验证
查看是否生成配置文件
#查看 docker exec -it nginx sh -c "cat /etc/nginx/conf.d/service.conf" #结果 upstream consul { zone upstream-consul 64k; server 192.168.56.2:8300 max_fails=3 fail_timeout=60 weight=1; server 192.168.56.3:8300 max_fails=3 fail_timeout=60 weight=1; } upstream zhibo_service { zone upstream-zhibo_service 64k; server 127.0.0.1:65535; # force a 502 } server { listen 80 zhibo_service.com; location / { root /usr/share/nginx/html/; index index.html; } location /stub_status { stub_status; } location /consul { proxy_pass http://consul; } location /zhibo_service { proxy_pass http://zhibo_service; } }
分别启动直播-1、直播-2、直播-3服务
#192.168.56.2 php server.php #192.168.56.3 php server.php #192.168.56.4 php server.php #查看 docker exec -it nginx sh -c "cat /etc/nginx/conf.d/service.conf" #查看结果动态增加了 upstream consul { zone upstream-consul 64k; server 192.168.56.2:8300 max_fails=3 fail_timeout=60 weight=1; server 192.168.56.3:8300 max_fails=3 fail_timeout=60 weight=1; } upstream zhibo_service { zone upstream-zhibo_service 64k; server 192.168.56.2:8080 max_fails=3 fail_timeout=60 weight=1; server 192.168.56.3:8080 max_fails=3 fail_timeout=60 weight=1; server 192.168.56.4:8080 max_fails=3 fail_timeout=60 weight=1; } server { listen 80 zhibo_service.com; location / { root /usr/share/nginx/html/; index index.html; } location /stub_status { stub_status; } location /consul { proxy_pass http://consul; } location /zhibo_service { proxy_pass http://zhibo_service; } } # 浏览器访问 http://zhibo.com/zhibo_service
Comment here is closed