起因
之前部署项目都是使用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
完成.
总结
代码生产上线还是交给脚本来实现,这样的确会比人自己做这种复杂,重
复劳动来的更加快捷,安全。一个小例子,希望对你有所帮助。