使用 docker 基于 Hyperf 搭建微服务 consul 服务发现 - 基础搭建

384 阅读5分钟

1.安装docker

2.拉取consul

docker pull consul:1.12.2

3.创建consul镜像

docker run -d --name=consul -v F:\www\consul:/data/project/consul -p 8500:8500 consul:1.12.2 agent -server -bootstrap -ui -node=1 -client='0.0.0.0'
  • agent: 表示启动 Agent 进程。
  • server:表示启动 Consul Server 模式
  • client:表示启动 Consul Cilent 模式。
  • bootstrap:表示这个节点是 Server-Leader ,每个数据中心只能运行一台服务器。技术角度上讲 Leader 是通过 Raft 算法选举的,但是集群第一次启动时需要一个引导 Leader,在引导群集后,建议不要使用此标志。
  • ui:表示启动 Web UI 管理器,默认开放端口 8500,所以上面使用 Docker 命令把 8500 端口对外开放。
  • node:节点的名称,集群中必须是唯一的,默认是该节点的主机名。
  • client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
  • join:表示加入到某一个集群中去。 如:-json=192.168.0.11。

4.浏览器访问 http://127.0.0.1:8500/ 查看是否启动成功

5.docker 创建3个服务容器(也配置消费者) 1个消费者容器

docker run --name consumer -v F:\www\consumer:/data/project/consumer -p 9501:9501 -p 9502:9502 -p 9503:9503 -p 9504:9505 -p 9505:9505 -it --privileged -u root --entrypoint /bin/sh hyperf/hyperf:7.4-alpine-v3.15-swoole
docker run --name service1 -v F:\www\service1:/data/project/service1 -p 9101:9501 -p 9102:9502 -p 9103:9503 -p 9104:9505 -p 9105:9505 -it --privileged -u root --entrypoint /bin/sh hyperf/hyperf:7.4-alpine-v3.15-swoole
docker run --name service2 -v F:\www\service1:/data/project/service2 -p 9201:9501 -p 9202:9502 -p 9203:9503 -p 9204:9505 -p 9205:9505  -it --privileged -u root --entrypoint /bin/sh hyperf/hyperf:7.4-alpine-v3.15-swoole
docker run --name service3 -v F:\www\service1:/data/project/service3 -p 9301:9501 -p 9302:9502 -p 9303:9503 -p 9304:9505 -p 9305:9505 -it --privileged -u root --entrypoint /bin/sh hyperf/hyperf:7.4-alpine-v3.15-swoole

6.为了方便容器间进行通讯,新开一个cmd终端,创建自定义bridge

docker network create --driver bridge my-bridge

7.把所有容器加入到my-bridge中

docker network connect my-bridge service1
docker network connect my-bridge service2
docker network connect my-bridge service3
docker network connect my-bridge consumer
docker network connect my-bridge consul

8.进入容器搭建Hyperf(新建容器后会根据指令进入),或者手动进入

docker exec -i -t  service1 /bin/sh

先ping一下其他容器看看是否成功

ping consul

然后创建Hyperf项目到当前目录

cd /data/project/xxx
composer create-project hyperf/hyperf-skeleton ./

9.服务注册目前 Hyperf 仅适配了 JSON RPC 协议,先配置JSON RPC服务 安装

composer require hyperf/json-rpc

要使用 JSON RPC 服务端:

composer require hyperf/rpc-server

要使用 JSON RPC 客户端:

composer require hyperf/rpc-client

ps:服务端客户端都安装好,方便模拟实际场景,每个服务都可能是服务端和客户端

10.在config/autoload/server.php内配置jsonrpc-http

'servers' => [
    [
        'name' => 'http',//留着http,后续做消费者可用
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9501,//这个端口改了就访问不了,原因不了解
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
        ],
    ],
    [
        'name' => 'jsonrpc-http',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9502,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
        ],
    ],
],

11.配置服务注册 直接安装consul适配器组件

composer require hyperf/service-governance-consul

12.在config/autoload/servers.php内配置服务注册(servers.php需要新建)

return [
    'enable' => [
        // 开启服务发现
        'discovery' => true,
        // 开启服务注册
        'register' => true,
    ],
    // 服务消费者相关配置
    'consumers' => [],
    // 服务提供者相关配置
    'providers' => [],
    // 服务驱动相关配置
    'drivers' => [
        'consul' => [
            'uri' => 'consul:8500',
            'token' => '',
            'check' => [
                'deregister_critical_service_after' => '90m',
                'interval' => '1s',
            ],
        ],
    ],
];

13.app下新建JsonRpc目录,编写TestService.php和TestServiceInterface.php文件。

TestServiceInterface 对外提供两个接口,一个用于接收参数并输出,一个用于输出简单文本。

[TestServiceInterface]

<?php
namespace App\JsonRpc;
interface TestServiceInterface
{
    public function say();
    public function add(int $a, int $b);
}
[TestService]

<?php
namespace App\JsonRpc;
use Hyperf\RpcServer\Annotation\RpcService;
/**
 * @RpcService(name="TestService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="consul")
 */
class TestService implements TestServiceInterface
{
    /**
     * @param int $a
     * @param int $b
     * @return int
     */
    public function add(int $a, int $b)
    {
        return $a + $b;
    }
    /**
     * @return string
     */
    public function say()
    {
        return '这是service1';//这里区分每个service
    }
}

14.服务端配置完成启动Hyperf(可能会报错,报错的话先走下面步骤,配置好服务消费者再回来启动,原因我也不知道)

php bin/hyperf.php start

15.配置服务消费者,安装Hyperf/JSON RPC/consul适配器组件等,全部同服务端

16.在config/autoload/servers.php内设置服务提供方地址,注册中心的地址(servers.php需要新建)

<?php
return [
    // 此处省略了其它同层级的配置
    'consumers' => [
        [
            // name 需与服务提供者的 name 属性相同
            'name' => 'TestService',
            // 服务接口名,可选,默认值等于 name 配置的值,如果 name 直接定义为接口类则可忽略此行配置,如 name 为字符串则需要配置 service 对应到接口类
            'service' => \App\JsonRpc\TestServiceInterface::class,
            // 对应容器对象 ID,可选,默认值等于 service 配置的值,用来定义依赖注入的 key
            'id' => \App\JsonRpc\TestServiceInterface::class,
            // 服务提供者的服务协议,可选,默认值为 jsonrpc-http
            // 可选 jsonrpc-http jsonrpc jsonrpc-tcp-length-check
            'protocol' => 'jsonrpc-http',
            // 负载均衡算法,可选,默认值为 random
            'load_balancer' => 'random',
            // 这个消费者要从哪个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
            'registry' => [
                'protocol' => 'consul',
                'address' => 'consul:8500',
            ],
            // 如果没有指定上面的 registry 配置,即为直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
            'nodes' => [
                ['host' => '172.17.0.3', 'port' => 9501],
            ],
            // 配置项,会影响到 Packer 和 Transporter
            'options' => [
                'connect_timeout' => 5.0,
                'recv_timeout' => 5.0,
                'settings' => [
                    // 根据协议不同,区分配置
                    'open_eof_split' => true,
                    'package_eof' => "\r\n",
                    // 'open_length_check' => true,
                    // 'package_length_type' => 'N',
                    // 'package_length_offset' => 0,
                    // 'package_body_offset' => 4,
                ],
                // 重试次数,默认值为 2,收包超时不进行重试。暂只支持 JsonRpcPoolTransporter
                'retry_count' => 2,
                // 重试间隔,毫秒
                'retry_interval' => 100,
                // 使用多路复用 RPC 时的心跳间隔,null 为不触发心跳
                'heartbeat' => 30,
                // 当使用 JsonRpcPoolTransporter 时会用到以下配置
                'pool' => [
                    'min_connections' => 1,
                    'max_connections' => 32,
                    'connect_timeout' => 10.0,
                    'wait_timeout' => 3.0,
                    'heartbeat' => -1,
                    'max_idle_time' => 60.0,
                ],
            ],
        ]
    ],
];

17.定义接口,同服务端保持一致,新建JsonRpc目录,目录下新建TestServiceInterface.php,简单试用时这样自己创建,实际开发中接口应该发布到composer包,被多个服务所依赖

<?php
namespace App\JsonRpc;
interface TestServiceInterface
{
    public function say();
    public function add(int $a, int $b);
}

18.在config目录下的routes.php下定义测试路由

Router::addRoute(['GET'], '/say', 'App\Controller\IndexController@say');

19.在app/Controller/IndexController.php内写调用方法

//省略部分代码
use App\JsonRpc\TestServiceInterface;
use Hyperf\Utils\ApplicationContext;

public function say()
{
    $client = ApplicationContext::getContainer()->get(TestServiceInterface::class);
    $res = $client->say();

    return ['say' => $res];
}

20.消费端配置完成启动Hyperf,如服务端启动报错现在可以去启动服务端,同时打开http://127.0.0.1:8500/ 查看服务端是否注册成功

php bin/hyperf.php start

21.都启动成功的话调用http://127.0.0.1:9504/say (具体端口自行查看)看看是否有返回值

22.继续配置另外两个service

23.消费端调用 http://127.0.0.1:9501/say 看看是否有输出

目前按照完整流程下来,可以经过服务中心注册,并调用成功