PPT:
swoft.pdf
演讲文稿:
大家好,我来自平台开发,都是多年的老同事了,就不再做自我介绍了~我本次分享的主题是swoft with docker。
部门原有的后端老项目运行时间长,体量大,特别是我们原有的项目的经过四五年的n个版本迭代,也就导致了大量的冗余代码,作为一线的技术开发人员,删繁就简肯定是大家的共同追求,但在系统的稳定性的要求下,对于祖传的老代码进行调整成了一件费力不讨好的事。
相信大家多少次对着屏幕上,熟悉或陌生的代码,都想把后悔打在公屏上,某个功能明明能能有更好的写法,为什么当时没有想到?!如果一切可以重来,我要做李白,啊不,我要把代码质量写得更好!
可不,趁着公司项目两个技术项目组合并的春风,经过长时间的相互融合相互学习,经过多次的开会沟通探讨,后端技术人员一起对后端技术重新选型,因地制宜结合公司实际,最后选定的开发语言还是php,框架选用基于swoole的swoft,从新出发,从零开始,大家同舟共济勠力同心把新项目做到功能能实现,质量有保证,响应能快速,项目能稳定!
回归到本次的主题,这次主要是分享主要是如何用docker部署swoft项目以及swoft项目中需要注意到的点,鉴于大家已经对swoft文档已经看过,也已经在本地环境实践过了,所以这次分享的的重点还是在docker部署swoft项目上上。
传统的php项目的话,使用的lnmp/lamp架构,以lnmp举例,nginx转发php请求到实现了fastcgi协议的php-fpm上,php-fpm的worker进程进行实际的php的处理,项目代码没有没有常驻进程,好处是节省资源,但是每次请求都要初始化,特别像laravel这种大型工程化的框架,框架自己本身初始化可能比业务本身代码更耗时间,严重拖慢了我们现有项目的api的响应速度,边际效应递减,我们既要php开发的便捷又要常驻进程语言的优点,所以选定了swoft作为本次开发的框架。
既然说到了swof能常驻内存,那么势必它的更新与发布就和我们之前的git pull一把梭会有不同,这就是为什么会需要docker的原因。
言归正传,说起docker,我们主要弄明白两个问题:
- docker是什么
- docker怎么用在我们项目里
docker是一个开源的容器应用,那么什么是容器呢?容器的定义是「通过对应用的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行(Runtime)生命周期进行管理,达到应用组件级别的“一次封装,到处运行”。这里的应用组件,既可以是一个Web应用、一个编译环境,也可以是一套数据库平台服务,甚至是一个操作系统或集群」,看看docker的slogn: Build, Ship and Run Any App, Anywhere
,简而言之就是一次编译到处运行,能让应用脱离对环境的依赖,做到千人一面。docker具有轻量、开销低、可移植性好的特点,它本身对资源的占用可以忽略不计,同时它的出现简化了交付流程,当然它也得到了目前主流的linux系统的支持。
下面问题来了,物理机与虚拟机还有docker的区别是什么呢?ppt中的三张图分别代表了物理机,虚拟机和docker,从house->apartment->胶囊旅馆,很形象的说明了它们三者对资源的占用与消耗,如果对于人来说,当然读大house更舒服,但是对于程序来说,尽可能的去压榨服务器才是真正做到物尽其用。
这次分享主要是抛砖引玉的作用,对于安装那块就不再做具体说明。
关于学习docker的材料,推荐几个:
- docker官网
- docker的菜鸟教程
- 书籍《docker技术入门与实践》,这个微信读书上有,可以在那上面看。
当然最重要最应该牢记的,要善用docker [command] --help
帮助命令。
回到我们的项目本身,既然我们选择的语言是php这种脚本语言,为什么我们还要使用docker跑swoft?我想我们目前面临以下几个问题:
- 服务器内本身有多个php版本共存。从php5到php7,目前也没有强约定必须使用哪个版本。
- 编译swoole过程麻烦且不可控。在测试服务器做编译就出现了一些编译扩展不成功的问题,我要编译一个swoole,却又要因为其他编译依赖版本问题导致编译不成功的例子,同时swoole扩展与某些php其他扩展有冲突,这也是问题的原因,这也意味着要专门为swoole编译一个php版本,当然还有头事可能自己电脑的开发环境编译也是失败的。
- 横向扩展复杂。如果项目再需要开新服务器,那么意味着又要重新编译一遍,即使有云服务器的镜像,如果要变更php的版本,麻烦程度可想而知。
接下来我再说说到底docker怎么与swoft结合到一起?
首先要有两个前提:
- 开发环境有安装好的docker
- 对docker有个基本的认识,它的基础命令如
docker run、docker stop
之类的命令知道是什么。
而在我们项目内也有两种使用方式,一种是直接使用Dockfile
,另外一种是升级版。使用docker三剑客之一的docker-compose
,项目内的Dockfile
与docker-compose.yml
都已经经过调整,可以直接使用。
- Dockerfile。Dockerfile
,那么在第一次使用时需要先编译:docker build -t swoft:v1 .
,因为第一次需要构建基础所需的php环境镜像,所以第一次使用需要等待一段时间,以后再编译就挺快了。
- 项目里的dockerfile
已经经过调整,拉下代码后执行build -t swoft:v1 .
,等待镜像编译完成。镜像编译完成后执行:docker run --name "swoft-v1-dev" -v $(pwd):/var/www/swoft -p 18306:18306 -d swoft:v1.1
开启一个名字为swoft-v1-dev
的容器,特别需要注意的是,需要-v
将本地数据卷绑定到容器里的swoft的对应目录里面,没有绑定的话即使git拉了代码也不会更新,特别是对于开发与测试环境,为了避免频繁编译造成时间浪费,最好是用-v
参数进行挂载,特别注意的是,当然如果依赖有更新,那么我们可以通过docker exec
命令进入容器内进行依赖的更新,而不是直接在本地项目进行更新,如果本地项目与容器内的php版本不一致,可能会有莫名其妙的问题出现,我们项目容器内的php版本是7.2。
我再稍微讲一下使用dockerfile的流程,首先我们cd到swoft项目内,执行docker build –t swoft:v1.1 .
进行镜像的编译,特别注意不要漏掉最后的点,那个代表是指当前目录,-t
是给镜像命名和打标签,这一步在第一次运行时会比较耗时,跟我们在原生环境编译一样,扩展的编译,依赖的更新等。在镜像编译完成后,利用上一步编译好的镜像运行容器:docker run --name "swoft-v1-dev" -p 18306:18306 swoft:v1.1
,如果需要在后在后台运行,再加入-d
的参数,而日志的查看可以通过docker logs
命令。
我们可以看看典型的Dockerfile
的样子。
接下来再看看如何使用docker-compose
进行项目的使用,docker-compose
作为三剑客之一,使用yaml格式的配置信息,它的目的是解决本地docker容器编排问题,能够快速部署分布式应用,里面的内容就容器启动的配置信息,就像我们写的脚本一样,典型的格式是:docker-compose.yml
,它没有和docker一起安装,需要自己单独安装,安装方式有多种,但是最方便的还是直接使用pip3 install docker-compose
。
比较常见的一把梭命令是docker-compose up -d
,在后台运行。
我们在看看典型的docker-compose文件。
以前面说的为基础,再进阶一点部署项目的就使用CI/CD(持续集成与持续部署)了,ppt展示的上面是属于集成,包括打包->测试->返回结果->发布等,之前在学习的时候使用的coding.net
的CI(持续集成)服务进行测试。在使用CI时,因为时间问题,没来得及熟悉jenkinsfile
的写法,又刚好看到了它们提供了一个laravel用docker进行部署的demo,于是在coding官方提供的这个demo上面进行swoft项目构建的修改。,整个流程也走通了。
中间也遇到了一个问题,整个构建过程在push到镜像仓库的时候报了一个Get https:///v2/: http: no Host in request URL
,在这里卡了挺久,最后搜索知道问题的原因镜像名里不能带下划线
。而因为coding.net的镜像仓库默认分配的域名是自己的用户名开头的子域名,我在coding.net里的用户名刚好是有个下划线,因此最后是联系上了coding.net的技术支持,让我发邮件找他们客服更换了域名才总算解决构建成功但是无法推送到仓库的问题。
下面开始讲第二部分,目前swoft内进行了封装调整,因为ppt放代码看不清,读git的日志与代码,更容易上手。所以就走马观花的说一下主要注意的点。
- 应该重点关注什么
- 目前框架内封装到了什么
- 如何业务开发
做了张脑图,理了一下关键字。我们的用途是api开发,我觉得宏观层面更多的是关注http部分,微观层面则可以关注在图中所示。
封装的话,目前封装了可能会用到中间件,响应,以及其他的辅助方法等。
开发流程,更重要的是人为的约定,然后大家共同遵守,尽量做到千人一面。
- 业务开发流程与laravel开发大同小异
- sowft模型与laravel相比多了实体的概念
- 缓存管理与消息队列的使用统一封装
- 开发中多思考能否使用协程并发
说到这里,差不多也该结尾了,对于我们一线打码人员来说,最重要的还是从战争中学习战争,从编码中学习编码,日积月累的提升自己。
谢谢!