首页 > 其他分享 >Laravel octane 使用蓝绿部署方案实现0停机部署

Laravel octane 使用蓝绿部署方案实现0停机部署

时间:2023-08-13 22:00:52浏览次数:38  
标签:Laravel set header 部署 server nginx proxy octane

最近在尝试使用 octane swoole 驱动的 Laravel 项目时出现了一个问题:在更新代码后使用 octane:reload 重新启动 workers 时新代码不生效。

我的项目是通过 deployer [1] 部署的,通过符号链接的形式将项目目录指向新的代码,但 octane:reload 后新代码并没有生效。

之后发现通过符号链接指向新目录、composer引入新的库、.env 在重启后都不生效,octane::reload 应该是从主进程映射的代码目录中重新启动 worker 进程, 因此新的代码并未生效。

之后我们部署代码后通过执行 octane::stop 和 octane::start  启动服务,这样代码是生效的,但这样并非热部署,每次执行上述命令服务都会中断几秒,导致此时进来的请求 502 报错。

解决方法

参考蓝绿部署形式

对于同一个项目(同一个代码目录)启动两套 octane swoole 服务,通过 nginx 指向新的服务的形式实现 0 downtime 部署。

启动 服务1、服务2 ,首次将 nginx 指向 服务1,在更新代码后通过stop&start重启服务2,将nginx指向服务2,reload nginx即实现热部署;在下次更新代码后重启服务1,将 nginx 指向 服务1 并 reload。

解决步骤

1.1、修改 octane 启动代码,使 octane 可以通过不同端口启动两套服务

当然你也可以在服务器上部署两套代码,这样就不需要该脚本了

新增 Artisan 命令行,自定义 octane 启动脚本

php artisan make:command Octane/StartOctane

修改脚本:

在原有 octane 服务启动脚本基础上修改不同端口对应不用的状态文件,这样就可以启动多个服务了

<?php

namespace App\Console\Commands\Octane;

use Laravel\Octane\Commands\StartCommand;
use Laravel\Octane\Swoole\ServerStateFile as SwooleServerStateFile;

class StartOctane extends StartCommand
{
    /**
     * The command's signature.
     *
     * @var string
     */
    public $signature = 'Octane:StartOctane
                    {--server= : The server that should be used to serve the application}
                    {--host=127.0.0.1 : The IP address the server should bind to}
                    {--port= : The port the server should be available on [default: "8000"]}
                    {--rpc-host= : The RPC IP address the server should bind to}
                    {--rpc-port= : The RPC port the server should be available on}
                    {--workers=auto : The number of workers that should be available to handle requests}
                    {--task-workers=auto : The number of task workers that should be available to handle tasks}
                    {--max-requests=500 : The number of requests to process before reloading the server}
                    {--rr-config= : The path to the RoadRunner .rr.yaml file}
                    {--watch : Automatically reload the server when the application is modified}
                    {--poll : Use file system polling while watching in order to watch files over a network}';


    /**
     * The command's description.
     *
     * @var string
     */
    public $description = '无停机部署 Octane server';


    /**
     * Handle the command.
     *
     * @return int
     */
    public function handle()
    {
        //  在原有octane 服务启动脚本基础上新增如下代码 start
        // 修改不同端口对应不用的状态文件,这样就可以启动多个服务了
        $port = $this->option('port') ?: 8012;

        app()->bind(SwooleServerStateFile::class, function($app) use ($port){
            return new SwooleServerStateFile($app['config']->get(
                'octane.state_file',
                storage_path('logs/octane-server-state' . $port . '.json')
            ));
        });
        // end

        $server = $this->option('server') ?: config('octane.server');

        return match ($server) {
            'swoole' => $this->startSwooleServer(),
            'roadrunner' => $this->startRoadRunnerServer(),
            default => $this->invalidServer($server),
        };
    }
}

1.2、服务启动脚本

若我们想启动两套服务,端口分别是 8012、8013

我们的服务使用 supervisorctl 管理:

将 octane:start 换为我们上一步创建的脚本 Octane:StartOctane

[program:server_8012]
command =   /bin/php -d variables_order=EGPCS /www/server/current/artisan Octane:StartOctane --max-requests=5000 --workers=4 --task-workers=4 --port=8012
user=www
process_name            = %(program_name)s_%(process_num)s
numprocs                = 1
autostart               = true
autorestart             = true
startretries            = 1000
stdout_logfile          = /log/supervisor/server.log
stdout_logfile_maxbytes = 1000MB
redirect_stderr=true

[program:server_8013]
command =   /bin/php -d variables_order=EGPCS /www/server/current/artisan Octane:StartOctane --max-requests=5000 --workers=4 --task-workers=4 --port=8013
user=www
process_name            = %(program_name)s_%(process_num)s
numprocs                = 1
autostart               = true
autorestart             = true
startretries            = 1000
stdout_logfile          = /log/supervisor/server.log
stdout_logfile_maxbytes = 1000MB
redirect_stderr=true

1.3、nginx 配置

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name test.net;
    server_tokens off;
    root /www/server/current/public;

    index index.html index.htm index.php default.html default.htm default.php;

    charset utf-8;

    error_page 404 /index.php;

    location /index.php {
        try_files /not_exists @octane;
    }

    location / {
        try_files $uri $uri/ @octane;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
        expires      30d;
    }

    location ~ .*\.(js|css)?$
    {
        expires      12h;
    }

    location ~ /.well-known {
        allow all;
    }

    location ~ /\.
    {
        deny all;
    }

    # 在此处引入配置文件,部署脚本通过修改配置文件设置 nginx 指向的服务
    include /www/server/current/nginx_octane.conf;
}

nginx_octane_8012.conf

location @octane {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://127.0.0.1:8012$suffix;
    }

nginx_octane_8013.conf

location @octane {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://127.0.0.1:8013$suffix;
    }

1.4、服务部署流程

我们是通过 deployer 脚本部署的代码,如上次部署用的 8012 端口的服务,本次部署用 8013 端口服务,服务重启脚本如下:

这样在 8013 端口重启后,在将 nginx 指向8013 即可实现0停机部署

task('supervisor:reload', function(){
    $env = get('labels')['env'];
    if ($env == 'pre8012’) {
        # 重启8012端口服务
        run('sudo /usr/bin/supervisorctl restart server_8012:');
        # 将 nginx 指向 8012 端口
        run('cd {{release_path}} && /usr/bin/cp ./nginx_octane_8012.conf ../../shared/nginx_octane.conf');
    }
    if ($env == 'pre8013') {
        # 重启8013端口服务
        run('sudo /usr/bin/supervisorctl restart server_8013:');
        # 将 nginx 指向 8013 端口
        run('cd {{release_path}} && /usr/bin/cp ./nginx_octane_8013.conf ../../shared/nginx_octane.conf');
    }
    # 热重启 nginx
    run('sudo /usr/bin/lnmp nginx reload');
});

本次执行命令:

dep deploy pre8013 -vvv

引用链接

[1] deployer : https://deployer.org/

标签:Laravel,set,header,部署,server,nginx,proxy,octane
From: https://blog.51cto.com/sdwml/7069950

相关文章

  • gitlab-runner配合k8s完成代码自动打包部署上线
    前期搭建了云服务器私有的gitlab和k8s环境,但是都是独立运行的,每次代码更新需要手动去打包好镜像,推送到镜像仓库,然后在deployment里面更新image,这样平时不太有问题,但是会给运维我这边产生很多琐事(反正就是想偷懒,能自动化的为什么要手动,懒惰才是提高生产力的动力!)。在这种情况下我就考......
  • laravel 面试题
    laravel框架面试题1.什么是Laravel框架?它的主要特点是什么?Laravel框架是一个用于构建Web应用程序的开源PHP框架,它提供了许多工具和功能来简化开发流程。其特点包括优雅的语法、强大的路由系统、EloquentORM、Blade模板引擎等2.如何通过Composer安装Laravel?使用Composer......
  • 使用 Docker 部署 Mongodb
    Mongodb是最像关系型数据库的NoSql数据库,其数据类型非常丰富,数据结构松散,采用类似Json的Bson二进制格式存储数据,还支持对索引功能。主要应用在数据量大、读多写少或者读写都比较频繁、数据价值较低的场景中,如果社交平台的点赞和评论、游戏、物流信息和轨迹存储等。由于在......
  • vue项目部署到gitee
    1、首先本地项目生成静态网页npmrunbuild使用本命令将vue项目打包成静态网页存放到dist文件夹里2、将静态资源推到gitee仓库前提条件:新建了git仓库,然后 gitclone +仓库地址,拉到本地,将dist整个文件夹放到刚才拉下来的项目文件夹中。gitadddistgitcommit-m"部署......
  • 支持本地部署,完全免费的 ABAP 来了 - ABAP Platform Trial 1909 发布
    我曾经编写过一套零基础的ABAP编程学习教程,截至2023年8月2日,总共包含114篇文章:零基础快速学习ABAP有零基础自学ABAP的朋友咨询,如果手头没有ABAP开发环境该怎么办?我在2019年时写过一篇文章,提到了SAP云平台上免费的ABAP编程环境:ABAP开发者上云的时候到了-......
  • SVN服务器部署
    SVN服务器安装与配置[SVN安装](SVN安装|菜鸟教程(runoob.com))SVN创建版本库linux下搭建SVN服务器完全手册官方文档一、安装详见教程:https://www.runoob.com/svn/svn-install.html二、创建版本库新建一个目录用于存储SVN所有文件#mkdir/home/svn新建一个......
  • 读发布!设计与部署稳定的分布式系统(第2版)笔记30_为部署而设计
    1. 部署行为是系统生命的重要组成部分1.1. 只编写代码是不够的,只要没有在生产环境中运行,一切都不算完成1.2. 要想取得成功,需要早早地频繁部署软件1.3. 设计易于部署的软件非常有必要1.4. 零停机部署就是目标2. 机器与服务2.1. 机器是可配置的操作系统实例2.1.1. ......
  • 活字格-Linux部署
    活字格-Linux部署什么是活字格?活字格是一个企业级低代码开发平台,旨在显著提升企业或者软件公司应用系统的开发效率,同时提供前所未有的灵活性和扩展性,开发人员可以使用涵盖整个开发生命周期的集成开发环境(活字格设计器,服务管理器)进行开发、质量检测、部署、监控和管理。什么需......
  • CentOS 批量部署用户免密服务器
    一、前言在Linux系统中,SSH(SecureShell)是一种常用的远程登录和文件传输协议。传统的SSH登录需要输入用户密码,既不方便也不安全。为了解决这个问题,我们可以部署SSH的公钥认证,即免密登录。本文将详细介绍如何在CentOS上批量部署用户免密服务器。二、准备环境1台CentOS7.x的服务器(本......
  • CentOS系统上部署PXE服务器步骤
    安装Apache首先,需要安装Apache服务器。可以使用以下命令安装:yuminstallhttpd配置Apache接下来,需要配置Apache服务器,使其能够正确响应PXE请求。在httpd.conf文件中,找到以下行:<Directory"/var/www/html">将该行的AllowOverride选项设置为All,以便能够使用.htaccess文件进行配置。然......