Home  >  Article  >  Backend Development  >  Python 项目的部署,目前互联网公司有哪些成熟的方案?

Python 项目的部署,目前互联网公司有哪些成熟的方案?

WBOY
WBOYOriginal
2016-06-06 16:11:072545browse

想做一些Python项目的自动上线部署工具,但是Python的包依赖,不能像Java那样把具体的jar打包部署时直接解压再改个配置文件就好,必须在部署之前要一个个安装所依赖的模块,这样一个是效率低不说,而且在安装的过程中出错的几率也比较高,
想知道目前各互联网公司都是如何做的,有哪些成熟的方案 ?

回复内容:

> Python 的包依赖,不能像 Java 那样把具体的 jar 打包部署时直接解压

在一定程度上这是可以做到的。 类似 Java 的 jar 包,Python 长久以来存在一种 egg 包 (其实 wheel 包也可以,但我后面介绍的工具不支持), 只要放在 sys.path 中就可直接被 import。

比如我的这个项目 GitHub - youngking/buildout-package: My Custom buildout script
参考下 bin/buildout 的写法, 代码拖到哪里都可以直接在项目下运行 bin/buildout。

使用 zc.buildout 这个工具能够自动做我上面那个项目的封装。这个工具可以把项目所有依赖的包 download 下来,并打成 egg 包。默认egg 包放在你的项目下的 eggs 目录, 同时会生成一个 bin 目录, 里面放着根据当前项目的 setup.py 定义的 entrypoint 生成的各种命令, buildout 会修改命令脚本的 sys.path, 把依赖的egg 都加进去。

假如你的项目之前是这样的:

project/
       setup.py
       src/
       tests/
       .....
  • Docker 不是银弹。开发偷懒了,运维、平台就要还债。如果想在生产环境使用它,你的团队需要有成熟的运维,和有追踪上游 Bug 的能力的工程师,以及能从业务需求中抽身出来填技术坑的条件。所以,小公司小团队请慎用。
  • 复制 virtualenv 部署可行,但移植性不好。一来 virtualenv 不允许绝对路径变动,二来 virtualenv 中一些已经装上的包可能依赖系统的动态库(如 OpenSSL),直接复制可能遇到 ABI 兼容问题。
  • 仅仅对于 Python 项目部署来说,利用 setup.py 打包是个不错的选择。一般 Web 应用中只有 requirements.txt 没有 setup.py,那么可以写一个仅用于打包的 setup.py,其中 install_require 部分读入 requirements.txt 的数据
setup.py 打包 Web 应用的话,需要一个 CI 服务器,Travis CI、GitLab CI、Jenkins 等均可。setup.py 默认不支持滚动发行,所以读入 JOB_IDBUILD_ID 之类的 CI 环境变量作为版本号,或者用当前日期时间生成一个。CI 服务中,可以设置主仓库 master 通过测试以后,自动向内部的 PyPI 发版本(如果用 Jenkins 也可以用 Jenkins 自带的静态文件服务)。在部署时再在内部 PyPI 中选择一个版本,pip install 到生产环境节点上。

基于 setup.py,可以通过 MANIFEST.in 的定义,将资源文件也打到发行包中,例如 gulp 编译产生的前端静态文件。而且如果有其他项目(比如独立的管理员后台)依赖当前应用,做服务又太麻烦时,可以直接向内部 PyPI 援引当前应用作为依赖。这样可以诸如避免手动修改 sys.path 那样的高度环境绑定且不可移植的 hack。

我在我现在就职的公司已经尝试推行了这种方法,目前看来没有遇到什么坑的问题。而且打成 wheel 包之后,部署速度也变快了(省下了部署时编译附加资源的时间)。这里贴出我们在用的配置,供参考: setup.py - GitHub

其他的一些信息:
  • 如果需要搭建内网 PyPI,推荐 devpi
  • setup.pyclassifiers 一节请记得加入 Private :: Do Not Upload,公共 PyPI 会拒绝收录有这个标记的包。这样可以防止萌萌哒队友手滑把公司代码传到公网 PyPI。
  • 如果把项目的其他依赖也打成 wheel 发布到内网 PyPI,可以省下很多构建编译的时间。但是要当心,wheel 格式目前无法做到 ABI 兼容(这也是公共 PyPI 暂时只允许针对 Windows 和 OS X 发布 wheel 的原因),请尽量保持打包环境(即 CI 服务器)所用的 Linux 发行版和生产环境一致
  • 配置 CI 时不应该将内网 PyPI 的登录密码提交到版本库。绝大多数 CI 系统都支持私密环境变量
  • 不管用不用 setup.py 来做打包,Python 项目的生产环境部署都应该使用 virtualenv,即使一台机器只部署一个应用。virtualenv 至少能将项目依赖和 Linux 发行版的依赖隔离开。
考虑下将依赖打成wheel包来离线安装? 浏览了以上所有人的答案,结合我平常在项目中的实际经验,谈谈我们团队的Python部署与发布流程。
目前很多公司还是用着石器时代的部署方式,怎么做呢?

1. 本地写代码,可能还没有virtualenv环境,是的其实我的老东家就是这样的。

2. 写一个脚本,安装需要的依赖到系统global环境,比如说 MySQLdb,
可能还要用apt-get 或者 yum 安装 python-dev 等等系统依赖,然后用pip 安装Python依赖。

3. 提交到svn/git,然后在测试机器上拉代码下来,运行脚本安装完依赖后,
如果是一个web项目,那么可能会直接 python web.py 8080 测试一下会不会报错,
测试完几个接口发现没问题,关掉测试机器。

4. 在生产环境把代码拉下来,或者通过部署系统,这里的部署系统一般是一个web页面,
能够将svn/git 上的代码打包后执行某一个脚本,来完成相应的部署,
也有可能是直接在机器上执行:
nohup python /path/to/python/main.py 2&1 > /dev/null & 
就启动来这个进程,然后自己可能还有一些业务监控来定时的监控这个脚本的存活状态。

5. 这里可能nginx已经配置好,你发布的是一个Django应用,那么打开浏览器,
查看网页无误。
对于互联网应用,依赖问题的最佳解决方案就是静态联编式的打包——我指的是思路而不是具体技术。

按照这个思路,要么在语言层面上搞定它,比如说golang,如果是其它语言,用docker就对了 @松鼠奥利奥的答案已经很完全了。貌似都在说docker,这里我也说说docker的情况吧,毕竟我司也是重度docker依赖。

首先就回答一下 @alexsunmiu的那些疑问,显然这位老兄用docker的姿势不对:
1. Docker这个玩意,有容器和镜像两个主要的概念,担负的职责不同。镜像负责运行环境的包装,容器则是运行时的包装。至于提到的主流老操作系统,这个属于具体的业务依赖,没法使用Docker那也是没法的事情,但是请不要擅自断言那些老的系统是主流,每个厂都不一样的。
2. 容器移植打包其实是很方便的,你看到的容量大,只是表面的东西。Docker底层设计是高度复用的。一个镜像是很多个层叠在一起的,比如你有一个docker镜像,里面是ubuntu+python,另一个是ubuntu+java,如果两者的ubuntu版本一样,那么这部分的layer就是复用的。如果你之前已经pull过这个对应的ubuntu的镜像,那么这部分是不会重复下载的,只会下载对应的python和java的部分。
3. Docker通过cgroup隔离,安全性虽然没有内核级别隔离的vm那么高,但是控制好权限,也是没那么容易沦陷的。
4.你apt要那么久,是因为你没有替换原始ubuntu镜像里的sources.list,自然要被伟大的GFW制裁一番。事实上我国国情决定了无论使用啥外来工具,都得先改造一番。所以凡事用docker的厂子,都会先搞一个私有的registry和官方镜像,然后再依据厂内的环境构建几个基础的docker镜像。后面所有发布的app都是基于这些基础镜像来做。
5. Dockerfile的设计又不是给你做shell用的,这玩意是用来定义docker镜像构建信息的,你有复杂的构建逻辑,一样可以包装到专门的脚本里,然后ADD进去运行不就完事么。

运维关注Docker的地方,主要在于稳定性,监控,日志这几个传统方面。这些跟运维的KPI是挂钩的。因为这东西还很新,而且特性还在慢慢增加,隐含的bug还是不少的,只不过只有在有足够量,以及特定的一些场景(最常见的就是网络部分和日志部分)才会出现。不是每个问题都能用自己熟悉的方式绕过去的。所以当碰到这些问题的时候,组里有能追踪bug的人才,甚至有能直接改代码的人才会显得很重要,因为这才能保证问题是可控的,否则哪天出问题了大家都搞不定,轻则年终奖完蛋,重则卷铺子走人了。

=== update: 2016-01-15 ===
添加 @松鼠奥利奥 的评论:
除了运维问题之外,容器还有点像一个巨型“全静态链接”,所以安全也是一个需要关注的问题…… 此前 coreos 开发了clair 检查 quay.io 上的镜像,一堆堆的都存在 CVE 已公布的安全问题……

安全性确实也是一个问题。 没人提到 zc.buildout 么, 知乎正在用呀。 AWS Codedeploy ……只是作一下说明,其实依赖的包除了整体复制一份virtual environment这种主流做法外,还可以选择带着site package一起打包部署的…… pyenv + 自建pypi源,没有sei了。
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn