环境说明

主要技术以及版本

  • vagrant

    • vagrant是一个对虚拟环境管理的工具。
  • virtualbox

    • VirtualBox 是一款开源虚拟机软件。
  • docker

    • version 20.10.7
    • docker是一个开源的应用容器引擎。
    • 安装docker
    • 具体安装细节以及权限问题解决请参考Ubuntu安装docker
  • consul

    • version 1.11.3
    • consul是一个用来实现分布式系统的服务发现与配置的开源工具。
    • 官网下载地址
  • consul-template

  • nginx

    • version 1.21.6
    • 地球人都知道的嘛!!!
  • 额外说明

    • virtualboxvagrant版本不兼容会出现很多未知问题(坑),官方网站也没有介绍哪个版本对应兼容,我这里分享一个兼容性不错的版本下载连接放下面,供大家参考。
    • 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/

consul ui界面

编写直播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集群

  • consul api 文档

    //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;

    4.jpg

搭建nginx转发服务,安装consul-template并关联订阅服务consul集群更新nginx转发配置,重启nginx。

  • 目录结构

dockerfile所在目录结构

  • 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  

    8.jpg

9.jpg

10.jpg

Last modification:July 4, 2022
如果觉得我的文章对你有用,请随意赞赏