使用deployer来部署你的项目

2017/07/14 Linux PHP

起因

之前部署项目都是使用git 来拉取代码到生产机器上,同时会忽略掉某些文件

的方式来部署生产代码,之前也是很OK 的。没啥问题。可是有次特别奇

怪,使用git来拉取代码一直提示lock文件存在的问题,特别恼火!然后,想

到有没有一种方式来自动化部署代码,诚然,githook是一种方式,但是对于

上线来说,有点太草率了。

方案

git拉取一份干净代码 -> 导出到一个目录1 -> 将配置文件替换上传到->目录1 -> 将生产项目目录备份以便回滚 -> 把生产环境目录整体替换 -> OK !

参考

Deployer 中文网:http://www.deployercn.com/docs

脚本

在目录中创建deploy.php文件,代码如下:

<?php
namespace Deployer;

date_default_timezone_set("PRC");
require 'recipe/common.php';

define("LOCALPATH","/home/minsongtao");
define("PATH",'/home/minsongtao');//todo需要修改 远端主目录
// Configuration

set('ssh_type', 'native');      //phpseclib: (default) 使用 phpseclib 作为 SSH 客户端, ext-ssh2: 使用 php ssh2 拓展, native: 使用原生 ssh 客户端
set('ssh_multiplexing', true);  // 使用 ssh multiplexing 来加速 SSH 执行

set('repository', 'ssh://[email protected]/tao.git');    // 代码仓库地址

set('keep_releases', 5);
set('shared_files', []);    // 共享文件列表
set('shared_dirs', []);     // 共享目录列表
set('writable_dirs', []);   // 指定 web server 可写的目录
set('http_user', 'www');

// Servers
// server 里面可以传递三个参数,第一个是名称,第二个服务器地址,可以是 ip,也可以是域名,第三个参数是端口,可选,默认为 22
// username 登录服务器使用的用户名
// password 登录服务器使用的密码
server('production', '192.168.X.X', 22)
    ->user('minsongtao')  // 用户名
    ->password('')
    ->set('deploy_path', '/home/minsongtao') // 远程服务器上的部署目录
    ->set('keep_releases', 5);


// Tasks

desc('Restart PHP-FPM service');    // 任务的描述信息.
task('php-fpm:restart', function () {
    // The user must have rights for restart service
    // /etc/sudoers: username ALL=NOPASSWD:/bin/systemctl restart php-fpm.service
    run('sudo systemctl restart php-fpm.service');
});
after('deploy:symlink', 'php-fpm:restart');     // 在 deploy:symlink 任务执行后, php-fpm:restart 将会执行。


task('play', function() {
    writeln('<info>开始...</info>');
    $path = PATH;
    $path = $path.'/step';
    if(run("test -e $path && echo \"exist\" || echo \"Not exist\"") == 'Not exist'){
        run("mkdir $path");
    }
    $product_name = "shop";
    $repository = 'ssh://[email protected]/pro/songtao.git';
    cd($path);
    if(run("test -e $product_name && echo \"exist\" || echo \"Not exist\"") == 'Not exist'){
        run("git clone $repository");
    }
    cd($path.'/'.$product_name);
    run('git checkout dev');
    run('git pull origin dev');
    run("git archive --format zip --output '$path/output.zip' dev -0");
    writeln('<info>完成.</info>');
});

task('uploadconfig',function() {
    writeln('<info>开始...</info>');
    $path = PATH;
    $path = $path.'/step1';
    $play_path = PATH.'/step/output.zip';
    if(run("test -e $path && echo \"exist\" || echo \"Not exist\"") == 'Not exist'){
        run("mkdir $path");
    }
    run("unzip -o $play_path -d $path ");

    $config_array = array(
        "Common" => "
       		XXXXXX
    ",
        "Home" => "
        	XXXXXXX
	",
        "User" => "
        	XXXXXXXX
        ",

        "Indexphp" => "
        define ( 'APP_DEBUG', false );
        ",

    );

    $content = shell_exec("cat ".LOCALPATH.'/shop/Application/Common/Conf/config.php');
    $content = (array)$content;
    $content = array_values($content);
    $rel_content = $content[0];
    $res = getNeedBetween($rel_content,'//mark','//mark');
    $rel_content = str_replace($res,$config_array['Common'],$rel_content);

    //在建一个本地switch 目录用来生成新的conifg 文件
    file_put_contents("./switch.php",$rel_content);
    upload("./switch.php",$path.'/Application/Common/Conf/config.php');

    $content = shell_exec("cat ".LOCALPATH.'/shop/Application/Home/Conf/config.php');
    $content = (array)$content;
    $content = array_values($content);
    $rel_content = $content[0];
    $res = getNeedBetween($rel_content,'//mark','//mark');
    $rel_content = str_replace($res,$config_array['Home'],$rel_content);
    //在建一个本地switch 目录用来生成新的conifg 文件
    file_put_contents("./switch.php",$rel_content);
    upload("./switch.php",$path.'/Application/Home/Conf/config.php');

    $content = shell_exec("cat ".LOCALPATH.'/shop/Application/User/Conf/config.php');
    $content = (array)$content;
    $content = array_values($content);
    $rel_content = $content[0];
    $res = getNeedBetween($rel_content,'//mark','//mark');
    $rel_content = str_replace($res,$config_array['User'],$rel_content);
    //在建一个本地switch 目录用来生成新的conifg 文件
    file_put_contents("./switch.php",$rel_content);
    upload("./switch.php",$path.'/Application/User/Conf/config.php');

    $content = shell_exec("cat ".LOCALPATH.'/shop/index.php');
    $content = (array)$content;
    $content = array_values($content);
    $rel_content = $content[0];
    $res = getNeedBetween($rel_content,'//mark','//mark');
    $rel_content = str_replace($res,$config_array['Indexphp'],$rel_content);
    //在建一个本地switch 目录用来生成新的conifg 文件
    file_put_contents("./switch.php",$rel_content);
    upload("./switch.php",$path.'/index.php');

    writeln('<info>完成.</info>');
});

task('coverdirectory',function(){
    writeln('<info>开始...</info>');
    $path = PATH;
    $origin_path = $path.'/step1';
    $product_path = $path.'/step2';//todo 后面改成shop
    if(run("test -e $product_path && echo \"exist\" || echo \"Not exist\"") == 'Not exist'){
        run("mkdir $product_path");
    }
    run("cp -R $origin_path"."/*  $product_path");
    writeln('<info>完成.</info>');
});

task('copyproduct',function(){
    writeln('<info>开始...</info>');
    $path = PATH;
    $product_path = $path.'/step2';//todo 后面改成shop
    $back_path = $path.'/back';
    if(run("test -e $back_path && echo \"exist\" || echo \"Not exist\"") == 'Not exist'){
        run("mkdir $back_path");
    }
    run("cp -R $product_path"."/*  $back_path");
    writeln('<info>完成.</info>');
});

//回滚代码
task('rollbackpro',function(){
    writeln('<info>开始...</info>');
    $path = PATH;
    $product_path = $path.'/step2';//todo 后面改成shop
    $back_path = $path.'/back';
    run("cp -R -a $back_path"."/*  $product_path");
    writeln('<info>完成.</info>');
});


task('pro',[
    //第一步拉取dev代码
    'play',
    //导出一份干净代码
    'uploadconfig',
    //备份一份代码以便回滚
    'copyproduct',
    //覆盖到生产目录
    'coverdirectory',
]);


/**
 * 返回两个字符串之间的内容
 * @param $kw
 * @param $mark1
 * @param $mark2
 * @return array|void
 */
function getNeedBetween($kw, $mark1, $mark2)
{

    static $result;
    if (!strpos($kw, $mark1)) {
        return array();
    } else {
        $kw = substr($kw, (strpos($kw, $mark1) + strlen($mark1)));
    }
    if (!strpos($kw, $mark2)) {
        return array();
    } else {
        $res = substr($kw, 0, (strpos($kw, $mark2) - strlen($kw)));
        $result[] = $res;
    }

    if (!$res) {
        return;
    } else {
        getNeedBetween($kw, $mark1, $mark2);
    }

    return $result;
}


desc('Deploy your project');    // 任务描述信息.

// 任务列表
task('deploy', [
    // 前期准备工作
    'deploy:prepare',
    // 打开锁定状态
    'deploy:lock',
    // 创建 release 文件夹结构
    'deploy:release',
    // 从 git repo 拉代码
    'deploy:update_code',
    // 设置共享目录
    'deploy:shared',
    // 设置可写入文件夹, 如 storage, bootstrap/cache 等
    'deploy:writable',
    // 执行 composer install 操作
    'deploy:vendors',
    // 清理目录
    'deploy:clear_paths',
    // 将共享目录 link 至部署文件夹中
    'deploy:symlink',
    // 解除锁定状态
    'deploy:unlock',
    // 清理收尾
    'cleanup',
    // 成功
    'success'
]);

// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');


测试

dep pro -vvv

  • -v 一般信息,
  • -vv 更详细的输出,
  • -vvv 输出调试信息.
➤ Executing task copyproduct
开始...
[production] > test -e /home/minsongtao/back && echo "exist" || echo "Not exist"
[production] < exist
[production] > cp -R /home/minsongtao/step2/*  /home/minsongtao/back
完成.
• done on [production]
✔ Ok [168ms]
➤ Executing task coverdirectory
开始...
[production] > test -e /home/minsongtao/step2 && echo "exist" || echo "Not exist"
[production] < exist
[production] > cp -R /home/minsongtao/step1/*  /home/minsongtao/step2
完成.

总结

代码生产上线还是交给脚本来实现,这样的确会比人自己做这种复杂,重

复劳动来的更加快捷,安全。一个小例子,希望对你有所帮助。

Search

    Post Directory