安全的代码部署
最后更新于:2022-04-02 04:32:03
## 安全的代码部署
![](http://cdn.aipin100.cn/18-4-10/98820547.jpg)
安全,优雅的线上代码部署。
非常非常重要却又极其容易被忽视的问题:**原子发布**
* * * * *
#### 如果不能完全避免错误,那就努力把出错的概率降到最低。
~~~
`switch` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT '应用开关:1-开,0-关。应用升级、安装、维护时需要暂时关闭,使其不能访问,否则会出现意外(即使这样也还是不能完全避免极端时候的并发问题,不过还是将故障降到最低概率了)',
来自家校 s_app表
~~~
* * * * *
### 安全的实现服务部署的思考
上面这个问题可引申到怎么实现安全,平滑的代码部署的问题上去了。
要想实现安全的代码迁移、热替换、部署,光从应用层,用文件锁,做开关的形式去做还是不行的,必须从内核的角度去做。
比如实现php服务的线上运行环境的代码部署,如果直接替换文件可能会出现不可预料的问题,以及错误,所以做一个开关,暂停网站,但是已有的代码还在内存中跑怎么办,那就做一个程序生命检测的机制,只要程序有活着的,那就锁文件,知道文件没锁了就说明整个系统停了,但是这样还不够,很难保证所有程序都遵循这个约定,活着时都去摸一摸这个问题。
那么就要使出最后的绝招了,从内核去控制程序的生命,首先使用传统的方式暂停所有程序,关闭队列服务,关闭常驻程序,关闭访问开关,此时也还不能够确定是不是都停止了,那我们就等(正常的服务正在运行的可能此时还在内存中运行着呢),只要常驻和队列服务关闭了,那么内核一会也会停止的,只要从php内核那里检测到彻底没有生命活动了,就表示当前没有任何活动程序了,那么此时就说明绝对安全了,此时就可以放心的开始部署工作了。
对于线上的服务部署,针对不同的平台。业界肯定早已经有成熟的技术方案了,以后有时间在研究。
>[danger] 如果直接采用替换文件的方式,那么是很危险的,可能会出现难以预料的错误,这在生产环境中是致命的,因为文件的替换可能不是原子性的同时都能够替换(这是由PHP的运行机制决定的),这样的话,如果旧文件引入新文件的,那么逻辑可能就会出现难以预料的问题。所以安全的替换必须是原子性的,即要么同时都替换,要么都不替换,不能出现交叉的情况。
> 这种部署方式需要停服,对于一个线上的使用量很大的生产系统来说,停服代价太大了。
>
> 应该使用平稳的部署方案,比如A服务是旧服务,最新的提交时B服务,那么开启一个B服务,让新的请求全部使用B服务,这样就平滑过渡过来了,对原有的A服务完全没有影响,两者可以同时运行。等A服务逐渐没有人访问时,再停止就可以。
* * * * *
#### 热迁移
热迁移,可以想象的例子,蜂巢迁移,想把A蜂巢的蜜蜂迁移到B蜂巢,但是当前A蜂巢已经在使用中了,要使得迁移过程中不影响采蜜的蜜蜂只能这样,做个和A一样性质的蜂巢B,将B放在A旁边,关闭A的入口,只保留出口,这样蜜蜂会慢慢到B蜂巢中去,而此时A蜂巢中还有工作的蜜蜂,所以不能直接关闭,但是我们关闭入口只保留出口,这样A里面的蜜蜂会逐渐减少,一段时间后完全没有蜜蜂了,此时我们已经完成了热迁移了,蜜蜂都转移到B中了,现在可以放心的停用A了。
----
[SSH隧道技术----端口转发,socket代理 - 登高行远 - 博客园](https://www.cnblogs.com/fbwfbi/p/3702896.html)
[字节和腾讯都在使用,DevOps工具Zadig究竟有何魔力 - 知乎](https://zhuanlan.zhihu.com/p/381238540)
[Zadig | Cloud native CI/CD for large scale software development. 面向大规模微服务软件开发的云原生 CI/CD | KodeRover](https://www.koderover.com/)
[又一篇 Deployer 的使用攻略 | Laravel China 社区](https://learnku.com/articles/13242/another-introduction-to-the-use-of-deployer)
[Deployer让部署变得更加的简单_The Hard Way To Code-CSDN博客_deployer](https://blog.csdn.net/seven_2016/article/details/83628778)
[deployer 实战经验分享 | Laravel China 社区](https://learnku.com/articles/10985/deployer-real-experience-sharing)
[又一篇 Deployer 的使用攻略 - overtrue](https://overtrue.me/articles/2018/06/deployer-guide.html)
[PHP如何正确发布 PHP 代码 - 李培刚的博客 - CSDN博客](https://blog.csdn.net/lipeigang1109/article/details/79495324)
> 先通过`ln`创建一个临时的软链接,再通过`mv`实现原子操作,此时如果使用`strace`监控,会发现`mv`的`「T」`选项实际上仅仅执行了一个`rename`操作,所以是原子的。
[如何正确发布PHP代码 | 火丁笔记](https://blog.huoding.com/2016/05/27/515#comment-398297)
[php + Laravel 实现部署自动化](http://mp.weixin.qq.com/s/qZGVdNtCJOycR_sye9az6w)
[Facebook 如何实现大规模快速发布?](http://mp.weixin.qq.com/s/0GHf5_zfsqPuFYa4k-Um0A)
[Facebook 是如何做大规模代码部署的?](http://mp.weixin.qq.com/s/BbfRQ3tHQqmAIzoQ7Sj_hA)
[容器技术演化史](http://mp.weixin.qq.com/s/wwwB8OHQmbwqmKKE8Lyv-w)
[少年,是时候换种更优雅的方式部署你的php代码了 - 码王信息 - 博客园](https://www.cnblogs.com/mawang/p/6749396.html)
[一般如何将开发测试服务器上的代码部署到生产环境? - 知乎](https://www.zhihu.com/question/33411671)
[利用WebHook实现PHP自动部署Git代码-萧晔离](https://m.aoh.cc/149.html)
> `git pull` 能实现原子性替换吗?
[php - 使用git在服务器上更新代码,经常导致权限变了,日志没有写进去,怎么解决? - SegmentFault 思否](https://segmentfault.com/q/1010000019110432)
[Deployer — Deployment Tool for PHP](https://deployer.org/)
[在 2016 年做 PHP 开发是一种什么样的体验?(一) - SegmentFault 思否](https://segmentfault.com/p/1210000007170414?from=timeline&isappinstalled=1)
[简单轻松部署你的项目 - Deployer - PHP 那些事 - SegmentFault 思否](https://segmentfault.com/a/1190000009000278)
[使用php部署工具deployer实现自动部署 - 二次元の技术宅](https://www.maoxuner.cn/2017/05/04/php-deployer.html)
[如何正确发布PHP代码 - CSDN博客](https://blog.csdn.net/ivan820819/article/details/51719230)
>[danger] **一个正确实现的发布系统至少应该支持原子发布。如果说每一个版本都表示一个独立的状态的话,那么在发布期间,任何一次请求只能在单一状态下被执行。如此称之为支持原子发布**;反之如果在发布期间,一次请求跨越不同的状态,那么就不能称之为原子发布。我们不妨举个例子来说明一下:**假设一次请求需要 include 两个 PHP 文件,分别是 a.php 和 b.php,当 include a.php 完成后,发布代码,接着 include b.php,如果处理不当的话,那么就可能会导致旧版本的 a.php 和新版本的 b.php 同时存在于同一个请求之中,换句话说就是没有实现原子发布。** **(重要:非常非常重要却又极其容易被忽视的问题)**
[PHP执行系统外部命令函数:exec()、passthru()、system()、shell_exec() - gaohj - 博客园](http://www.cnblogs.com/gaohj/p/3267692.html)
* * * * *
### 从nginx看 线上环境的热部署和热更新替换
[【开源组件】深入浅出Nginx](https://mp.weixin.qq.com/s/31DGDYpDHcYg-4qM4OczxA)
~~~
思考1:Nginx如何做到热部署?
所谓热部署,就是配置文件nginx.conf修改后,不需要stop Nginx,不需要中断请求,就能让配置文件生效!(nginx -s reload 重新加载/nginx -t检查配置/nginx -s stop)
通过上文我们已经知道worker进程负责处理具体的请求,那么如果想达到热部署的效果,可以想象:
方案一:修改配置文件nginx.conf后,主进程master负责推送给worker进程更新配置信息,worker进程收到信息后,更新进程内部的线程信息。
方案二:修改配置文件nginx.conf后,重新生成新的worker进程,当然会以新的配置进行处理,而且新的请求都必须交给新的worker进程,至于老worker进程,等把那些以前的请求处理完毕,kill掉即可。
Nginx采用的就是方案二来达到热部署的!
~~~
[深入NGINX:nginx高性能的实现原理 - panda521 - 博客园](https://www.cnblogs.com/chenjfblog/p/8715580.html)
> …… **通知旧的工作进程安静地退出。** 这些旧进程不会再接受新的连接了。只要它们处理的HTTP请求结束了,它们就会干净地关闭连接。一旦所有的连接都被关闭,工作进程也就退出了。
> (优雅的退出,优雅的在不中断服务的情况下更新配置,php-fpm也是这样的哦,修改php.ini后,只需要 `service php-fpm reload` 也不需要重启进程,直接就 再装 应用新配置和加载新扩展了,原理也同理,新启动的cli就更不用说了,但是注意已经运行的进程,已经在内存中的进程则无法获得新配置)
*****
[代码部署规范 - 个人文章 - SegmentFault 思否](https://segmentfault.com/a/1190000012042692#articleHeader1)
[为啥总在凌晨上线,如何无损发布](https://mp.weixin.qq.com/s/OirX0Q1ilXKqlQL8sI2utQ)
* * * * *
### 无服务器环境的安全部署
没有服务器的网站怎么安全部署呢(只能FTP上传文件的那种虚拟主机),网站需要增加一个站点开关,能够关闭入口(用户访问时就显示网站关闭升级中,多多返利程序升级时就是这样的,需要在后台关闭站点),并保证没有后台程序在运行时(开关关闭后等一会,检查没有队列等后台任务),再上传新文件覆盖就可以,等新文件上传完毕后在打开站点开关,这样才能确保安全。否则直接上传文件覆盖就不满足原子发布。
* * * * *
### 如何制作升级补丁包
老版本升级时,怎么制作老版本的升级包呢,拉出两个版本的commit,difference出所有变化/新增/删除文件,建立更新文件包(变化文件直接替换,新增文件直接新增),然后还要生成diff文件(处理旧文件的删除)。这就好了好?但这只是文件上的更新,如果涉及到数据库上的更新,那么需要一个update.sql作为一个数据库的升级文件。
所以升级补丁包至少包含:`更新文件包`,`update.diff`,`update.sql`
程序文件的升级,数据库的升级。完成了这两部分的处理,就可以在线拉取升级补丁包直接升级了。**不过升级时还是要以安全的原子升级为前提。**
>[danger] 有表结构变化的升级部署,升级时必须增加开关,停止服务才行。
* * * * *
原子发布,前端也有这个问题。
[大公司里怎样开发和部署前端代码? - 知乎](https://www.zhihu.com/question/20790576/answer/32602154)
[45分钟搞垮一家上市公司,只因一次失败的部署?](https://mp.weixin.qq.com/s/ylMi_ShSnmbE1DRJcGLiMg)
* * * * *
last update:2018-6-2 19:33:09
';