Swoft与Consul(三) - 服务动态自动注册

服务动态自动注册

当学习了 Consul理解与使用(二) - 商品服务注册与注销 之后,
如果需要多个服务架构的时候,怎么实现各服务的动态自动注册?
以下通过sh脚本生成.env文件配置的方式来演示过程:

1. Dockerfile配置

FROM swoft/alphp:fpm
EXPOSE 18306 18307 18308 18309
COPY ./init.sh /var/www/init.sh
RUN chmod +x /var/www/init.sh

目录下运行命令生成新镜像
docker build -t swoft-auto .

2. init.sh脚本

#!/bin/sh
location=`ip addr | grep /24 | awk '{print $2}' | awk -F '/' '{print $1}'`

host="HOST="$location
context=$host"\n"

while getopts "t:i:p:" opt;
do
   case    $opt in
    t) 
        # t=${OPTARG}
        context=$context"CONSUL_CHECK_TYPE="$OPTARG"\n"
    ;;
    i) 
        # i=${OPTARG}        
        context=$context"CONSUL_CHECK_IP="$OPTARG"\n"
    ;;
    p) 
        # p=${OPTARG}        
        context=$context"CONSUL_CHECK_PORT="$OPTARG"\n"
    ;;
   esac
done
echo -e $context > /var/www/.env

自动获取容器ip,健康检测配置参数

3. docker-compose.yml配置

# 定义容器
version: "3.3" # 确定docker-composer文件的版本
services: # 代表就是一组服务 - 简单来说一组容器
  swoft_goods_server_172_110: # 这个表示服务的名称,可自定义; 注意不是容器名称
    image: swoft-auto  # 指定容器的镜像文件
    container_name: swoft_goods_server_172_110 # 这是容器的名称
    ports:
      - "18316:18306"
    networks: ## 引入外部预先定义的网段
       app_swoft:
         ipv4_address: 172.200.7.110   #设置ip地址
    privileged: true # 执行特殊权限的命令
    volumes: # 配置数据挂载
        - /mnt/share/goods/app/server/swoft:/var/www/swoft
    working_dir: /var/www/swoft #工作目录
    #command:/var/www/init.sh
    command: php /var/www/swoft/bin/swoft http:start ext_init=-t:http?-i:192.168.3.66?-p:18316
  swoft_goods_server_172_120: # 这个表示服务的名称,可自定义; 注意不是容器名称
    image: swoft-auto  # 指定容器的镜像文件
    container_name: swoft_goods_server_172_120 # 这是容器的名称
    ports:
      - "18326:18306"
    networks: ## 引入外部预先定义的网段
       app_swoft:
         ipv4_address: 172.200.7.120   #设置ip地址
    privileged: true # 执行特殊权限的命令
    volumes: # 配置数据挂载
        - /mnt/share/goods/app/server/swoft:/var/www/swoft
    working_dir: /var/www/swoft #工作目录
    #command:/var/www/init.sh
    command: php /var/www/swoft/bin/swoft http:start ext_init=-t:http?-i:192.168.3.66?-p:18326
  swoft_goods_server_172_130: # 这个表示服务的名称,可自定义; 注意不是容器名称
    image: swoft-auto  # 指定容器的镜像文件
    container_name: swoft_goods_server_172_130 # 这是容器的名称
    ports:
      - "18336:18306"
    networks: ## 引入外部预先定义的网段
       app_swoft:
         ipv4_address: 172.200.7.130   #设置ip地址
    privileged: true # 执行特殊权限的命令
    volumes: # 配置数据挂载
        - /mnt/share/goods/app/server/swoft:/var/www/swoft
    working_dir: /var/www/swoft #工作目录
    #command:/var/www/init.sh
    command: php /var/www/swoft/bin/swoft http:start ext_init=-t:http?-i:192.168.3.66?-p:18336
# 设置网络模块
networks:
  # 自定义网络
  app_swoft:
    driver: bridge
    ipam: #定义网段
      config:
        - subnet: "172.200.7.0/24"

swoft代码调整

1. 读取.env

/mnt/share/goods/app/server/swoft/bin/swoft文件读取.env

//(new \App\Application())->run();
$app = new \App\Application();
$app->setEnvFile('/var/www/.env');
$app->run();

2. 执行init.sh脚本

/mnt/share/goods/app/server/swoft/bin/bootstrap.php启动文件添加执行init.sh脚本

// php swoft/bin/swoft http:start ext_init=-t:http?-i:192.168.3.66?-p:18316
//echo "获取的命令".$argv[$argc - 1]."\n";
$retCall = " ";
if ($extInitCalls = strstr($argv[$argc - 1], 'ext_init')) {
    $initCalls = (explode('=', $extInitCalls))[1];
    if ($calls = strstr($initCalls, '?')) {
        $calls = explode('?', $initCalls);
        foreach ($calls as $key => $call) {
            $retCall .= str_replace(":"," ", $call)." ";
        }
    } else {
        $retCall .= str_replace(":"," ", $initCalls)." ";
    }
}
//var_dump($argv);
//echo $retCall;//-t http -i 192.168.3.66 -p 18336
// exit;
exec('/var/www/init.sh '.$retCall,$out,$status);

3. 添加Config文件

添加Config文件/mnt/share/goods/app/server/swoft/config/consul.php

return [
    'consul_service_name' => 'swoft-goods-server',
];

4. 自定义方法

/mnt/share/goods/app/server/swoft/app/Helper/Functions.php添加自定义方法

if (!function_exists('getConsulServiceId')) {
    /**
     * @param string $ConsulServiceName
     * $ConsulServiceName swoft_goods_server
     * @return string
     */
    function getConsulServiceId(string $ConsulServiceName): string
    {
        $HOST = explode(".",env("HOST"));
        return $ConsulServiceName."-".$HOST[0]."-".$HOST[3];//swoft_goods_server_172_110
    }
}

5. 读取配置

/mnt/share/goods/app/server/swoft/app/Listener/RegisterServiceListener.php读取配置

/**
     * @Config("consul.consul_service_name")
     */
    private $consul_service_name;

    /**
     * @param EventInterface $event
     */
    public function handle(EventInterface $event): void{
        $httpServer = $event->getTarget();

        $service = [
            'ID'                => getConsulServiceId($this->consul_service_name),
            'Name'              => $this->consul_service_name,
            'Tags'              => [
                'http'
            ],
            'Address'           => env("HOST"),
            //'Address'           => '192.168.3.66',
            'Port'              => $httpServer->getPort(),
            'Meta'              => [
                'version' => '1.0'
            ],
            // 健康检查
            "Check" => [
                "name"     => "swoft.goods.server",
                env("CONSUL_CHECK_TYPE") => "http://".env("CONSUL_CHECK_IP").":".env("CONSUL_CHECK_PORT"),
                //"http"      => "http://192.168.3.66:18316",//swoft 的服务宿主机地址
                //"tcp"      => "192.168.3.66:18317",//swoft 的服务宿主机地址
                "interval" => '10s',
                "timeout"  => '2s'
            ],
            ...

以上是在swoft中执行sh脚本命令。
疑问:
在sh脚本内执行php /var/www/swoft/bin/swoft http:start,
然后在docker-compose.yml内执行command:/var/www/init.sh这样的方式可行吗?
答:
不行,虽然没有错误,但是当docker-compose down(模拟服务容器出问题)时,Consul内还是一直保留有着服务存在,显然不合理,这是因为容器停止时停止执行sh脚本,而没有取消执行php bin/swoft http:start

服务健康检测

在上面docker-compose.yml配置了容器对外端口,服务注册时添加的Check项配置健康检测。

标签: .env

添加新评论