1. 介绍

文章主要介绍,EasySwoole使用双机热备思路实现代码不中断部署。

2. 学习案例

    1. 先部署9501服务
    1. 单起一个进程,定时轮询Git分支是否有新版本发布
    1. 如有新版本发布,clone一份
    1. composer update 更新库
    1. 启动9502服务
  • 6 更改nginx配置为9502并重启

只要有新版本发布,就轮询上面那几个步骤

整个过程的简单架构图 image.png

3. 提前需要了解的知识点

  1. Nginx负载均衡和反向代理 )
  2. EasySwoole自定义进程 )
  3. Nginx reload 和 restart的区别 )
  4. 双机热备

4. Nginx 配置

nginx.conf

当有新版本发布的时候EasySwoole自定义进程会将nginx.conf 的端口改为最新服务

  1. worker_processes 1;
  2. events {
  3. worker_connections 1024;
  4. }
  5. http {
  6. include mime.types;
  7. default_type application/octet-stream;
  8. log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  9. '$status $body_bytes_sent "$http_referer" '
  10. '"$http_user_agent" "$http_x_forwarded_for"';
  11. sendfile on;
  12. keepalive_timeout 65;
  13. // 轮询配置(这里是重点)
  14. upstream easyswoole.relase.com {
  15. server 127.0.0.1:9501;
  16. }
  17. server {
  18. listen 8080;
  19. server_name localhost;
  20. }
  21. include servers/*;
  22. }
es-release.conf
  1. server {
  2. listen 80;
  3. server_name easyswoole.relase.com;
  4. location / {
  5. root html;
  6. index index.html index.htm;
  7. proxy_pass http://easyswoole.relase.com; // 这里是重点
  8. }
  9. access_log /usr/local/etc/nginx/logs/es.access.log main;
  10. error_log /usr/local/etc/nginx/logs/es.error.log error;
  11. }%

5. EasySwoole 代码实现

代码只提供实现思路,并且这种脚本,最好单独去做,比如用shell脚本,防止服务down调无法正常部署代码

自定义进程文件
  1. <?php
  2. namespace App\Relase;
  3. use EasySwoole\Component\Process\AbstractProcess;
  4. use Swoole\Coroutine;
  5. class Relase extends AbstractProcess
  6. {
  7. protected function run($arg)
  8. {
  9. go(static function () {
  10. while (true)
  11. {
  12. $shellLog = ' 2>> /Users/xxx/sites/shell.log';
  13. error_log('开始检测代码是否更新5'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  14. // 检查Git是否有新代码发布
  15. $diffExec = 'cd ' .EASYSWOOLE_ROOT. '; git fetch; git diff --stat master origin/master;';
  16. $pullResult = exec($diffExec);
  17. error_log(json_encode($pullResult), 3, '/Users/xxx/sites/es-log.log');
  18. if ($pullResult !== '') {
  19. error_log('有新版本发布'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  20. // 新版本项目的目录
  21. $newVersionPath = '/Users/xxx/sites/relase-'.time();
  22. // 开始clone, 初始化代码
  23. $cloneExec = "git clone https://github.com/huizhang-Easyswoole/release.git {$newVersionPath} {$shellLog};cd {$newVersionPath} {$shellLog};composer update {$shellLog}; {$shellLog}";
  24. $res = exec($cloneExec, $a, $b);
  25. error_log('新版本代码clone'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  26. // 判断当前是哪个端口正在服务
  27. $lsofExec = "lsof -i:9501 {$shellLog}";
  28. $lsofResult = exec($lsofExec);
  29. $newPort = 9501;
  30. $oldPort = 9502;
  31. if ($lsofResult !== '') {
  32. $newPort = 9502;
  33. $oldPort = 9501;
  34. }
  35. // 将另一个闲置的端口,替换到新版本中
  36. error_log('开始替换端口'.$newPort.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  37. $devConfig = file_get_contents($newVersionPath.'/dev.php');
  38. $devConfig = str_replace($oldPort, $newPort, $devConfig);
  39. file_put_contents($newVersionPath.'/dev.php', $devConfig);
  40. // 启动新服务(这一刻新旧服务是同时存在的)
  41. error_log('新服务启动'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  42. $startExec = "cd {$newVersionPath}; php easyswoole start d {$shellLog}";
  43. exec($startExec);
  44. // 替换nginx配置
  45. error_log('开始替换ng端口'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  46. $ngConfigPath = '/usr/local/etc/nginx/nginx.conf';
  47. $ngConfig = file_get_contents($ngConfigPath);
  48. $ngConfig = str_replace($oldPort, $newPort, $ngConfig);
  49. file_put_contents($ngConfigPath, $ngConfig);
  50. // 重启Nginx
  51. error_log('重启ng'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  52. $reloadNgExec = "nginx -s reload {$shellLog}";
  53. exec($reloadNgExec);
  54. // 停掉旧服务
  55. error_log('旧服务停掉'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  56. $stopExec = "cd ".EASYSWOOLE_ROOT."; php easyswoole stop {$shellLog}";
  57. exec($stopExec);
  58. // 每30秒同步一次代码
  59. Coroutine::sleep(30);
  60. } else {
  61. error_log('无新版本'.PHP_EOL, 3, '/Users/xxx/sites/es-log.log');
  62. }
  63. }
  64. });
  65. }
  66. }
进程注册
  1. <?php
  2. namespace EasySwoole\EasySwoole;
  3. use EasySwoole\EasySwoole\Swoole\EventRegister;
  4. use EasySwoole\Http\Request;
  5. use EasySwoole\Http\Response;
  6. use App\Relase\Relase;
  7. class EasySwooleEvent implements Event
  8. {
  9. public static function initialize()
  10. {
  11. // TODO: Implement initialize() method.1
  12. date_default_timezone_set('Asia/Shanghai');
  13. }
  14. public static function mainServerCreate(EventRegister $register)
  15. {
  16. // TODO: Implement mainServerCreate() method.
  17. $process = new Relase('Es-relase');
  18. \EasySwoole\Component\Process\Manager::getInstance()->addProcess($process);
  19. }
  20. public static function onRequest(Request $request, Response $response): bool
  21. {
  22. // TODO: Implement onRequest() method.
  23. return true;
  24. }
  25. public static function afterRequest(Request $request, Response $response): void
  26. {
  27. // TODO: Implement afterAction() method.
  28. }
  29. }

6. 测试

绑定host
  1. 127.0.0.1 easyswoole.relase.com
访问easyswoole.relase.com

image.png

查看Nginx配置的端口
  1. nginx cat nginx.conf | grep 950
  2. server 127.0.0.1:9501;
发布新版本

重新clone一份代码,更改内容提交。

查看Nginx配置的端口
  1. nginx cat nginx.conf | grep 950
  2. server 127.0.0.1:9502;