我司在开发机器上部署最新版的代码需要用到一些陈年的脚本,经历以下3个步骤:
- 执行一个叫
mkview.sh
脚本,脚本运行之后会提示你输入 input 一个URL地址,就是你仓库分支的 gitlab 地址。然后这个脚本会去拉最新的代码分支; - 执行一个叫
build.sh
的脚本,等待 3min; - 执行一个脚
deploy.sh
的脚本,等待5min;
虽然说只有三步,但是太反人类了。首先必须 ssh 登陆执行,然后竟然是命令提示输入这种奇葩形式,而不是直接参数传入。另外这个竟然是传 URL 进去(然后脚本里面奇葩的再把 URL 解析成仓库名字,分支名字)。每次输入之间还要等待几分钟,烦的要死。
操作了几次就受不了了,所以就想办法简化这些步骤。
重写的尝试
首先尝试的是把这三个脚本合成一个,我来打开看看这里面都是什么妖魔鬼怪。结果一打开发现事情并不简单,这都是上千行的脚本(虽然我也不知道里面都写了些啥),然后中间还调用了一些 binary,里面掺杂着各种 xxx 已转岗,xxx 不再维护的注释。看了半天,我连哪里把 git 权限塞进去的都没找到,直接 clone 是不行的,这个脚本就有权限 clone。头大,我还是不去动他了。
上 Ansible
然后我就尝试用 Ansible 处理这三个操作。
处理 prompt
首先要解决的是那个蛋疼的 prompt 问题,毕竟我可不想每次都去拼 URL。搜索了一下,看起来只有这个 expect 模块能够解决终端提示输入的问题。看了一下,不出所料,实现其实是用的 pexpect 包,这个包我最近在开发终端工具 iredis 的时候用了很多。其实这个包坑也蛮多的,比如找不到预期输出的时候只能等待 Timeout。我猜大家都用这个是可能没有更好的选择吧。
因为这是 Ansible 在 remote 机器上的功能,所以需要给机器装上 pexpect。可我司机器 Python 版本是 2.6,没有自带pip……折腾一顿之后,总算是装上了 pexpect。
执行的时候,出现更加蛋疼的编码问题。好吧,看了一下,发现这个脚本把编码写死在脚本里面了。也太反人类了。
放弃这条路了。然后我想这个输入是从键盘输入进去的啊,也就意味着 stdin 输入进去就可以了。试了一下直接用下面这命令就可以:
1 |
printf 'user_input' | /bin/script |
假设 /bin/script
需要用户输入的话,user_input
就会输入进去。
其实这个问题之前遇到过的,像 apt
这种东西要你确认的Y/n?
可以这样: yes | apt install htop
,yes 会一直输出 y
。当然也可以直接用 -y
选项,正常的脚本都会有这种选项的。
处理 Daemon 进程问题
花了我时间最多的,是一个 deploy.sh
那个操作。很神奇的是,我直接 ssh 跳上去执行,部署成功。
1 |
ssh myhost "deploy.sh" |
但是放在 Ansible 里面,一模一样的命令,就不行了。
1 2 |
- name: Deploy branch. command: "deploy.sh" |
shell
command
不同的模块都试过了,换 bash deploy.sh
啥的来执行也试过,都不行。但是直接 ssh 去执行就可以。
Ansible 和 ssh 到底差在哪里呢?
想不出来,去问老师。
老师说:
-_-|| 看了一下,果然是 Ansible 退出的时候会清理一个 session group 的进程。
我试了下 Ansible 的 async 功能,好像还是没用,过段时间进程还是被杀掉的。最后直接暴力使用 setsid 重置进程组,父进程直接设置为1,就好了。命令是这么写的:
1 2 |
- name: Deploy branch. command: "setsid deploy.sh &" |
有关 setsid,nohup 和 disown 的区别,这篇文章写得很好,可以看下。
等等,这明明是 deploy.sh
脚本啊,部署的时候不应该把进程 id 啥的都给处理好吗?我都是在经历了些啥啊!
这种陈年老脚本真的会要了命的,维护起来没有好处还容易踩坑。。
是的,不敢动不敢动
手动点个赞
sa部署不是应该有devops吗,怎么会手动ssh上去搞什么build啥的
是有自动化的流程的。但是流程太慢,这是开发机器的环境,比如我更新的代码,想直接部署到开发机器上,这样跑脚本比走平台一步一步来要快一些。部署到生产环境还是走平台的。
没看懂你的需求是啥
想要一次性执行的话运行 cbd 就行了,想要 push 后自动部署 linke 上貌似有选项
我的需求文中说了啊,cbd不能部署特定分支。linke只能部署MR,还经常失败。