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项配置健康检测。