封闭无网络服务器部署Python项目的经验与总结
前言
与新公司一起从2017跨到了2018,很幸运认识了很多小伙伴,也学到了很多东西,非常感谢.
最近压力挺大的,好几个项目一起混合着干,而且都是不太重要的边缘项目,常常加班感觉很忙,很多事情都没有来得及做.
今天主要总结下前几天做的一个Python项目,由于是给大公司做,安全方面做的有点过分,要在一个封闭不联网的环境部署程序,自己摸索着试了一种方式,特别记录一下.
会有详细步骤,仅供自己以后参考速查,对于其它不同实验环境还得多试,更主要的思维方式,可供借鉴之道.
说明
本方法部署的Python应用不依赖服务器任何先要条件
开发环境: ubuntu16.04 64位
服务器环境: redhat6.8 64位
开发的Python版本: Python2.7
用到的工具及文件
文件或工具名 | 作用说明 | 下载链接 |
---|---|---|
docker | 模拟出一个和服务器相同的环境,用于实验 |
具体实验步骤
安装docker(已安装的自行略过)
# 安装docker
curl -sSL https://get.docker.com/ | sh
# 将指定用户添加到操作docker的用户组里
sudo usermod -aG docker $USER && exec sg docker newgrp `id -gn`
# 启动docker程序
sudo systemctl start docker
创建实验环境
由于部署到redhat6的服务器上,我们应该创建一个和服务器相似的试验环境.
- pull一个centos6的系统:
docker pull centos:6
- 进入这个系统:
docker run -it centos:6
- 更换源,并重新生成缓存
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
yum clean all
yum makecache
- 安装可能用到的工具: yum install -y openssh-clients openssh-server gcc openssl-devel wget vim xz
- 新建目录/deploy用于部署,之后文件都会放在这里.
- 由于开发用的是Python2.7,而centos6默认为Python2.6,安装Python2.7来保持开发和部署环境的一致,推荐用自己编译的方式安装来保证可控性
# 下载并解压源代码包
wget https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tar.xz
xz Python-2.7.12.tar.xz
tar -xvf Python-2.7.12.tar
# 进入源代码目录,并编译安装
mkdir /usr/local/Python2.7
# 默认情况,安装程序会为你自动选择ucs2,此时最大unicode编码值为65535,之后运行程序cx_Oracle会报错误`undefined symbol: PyUnicodeUCS4_AsASCIIString`,因此切记一定要手动选择为ucs4
./configure --prefix=/usr/local --enable-unicode=ucs4
make
make altinstall
# 安装pip, 会同时自动安装setuptools 和 wheel
curl https://bootstrap.pypa.io/get-pip.py | python2.7 -
- 进入deploy目录,用virtualenv创建虚拟环境
pip install virtualenv
cd /deploy
virtualenv myenv --python=python2.7 --no-site-packages --unzip-setuptools
其中—no-site-packages参数表示不能访问全局的site-packages目录,这样确保虚拟环境不被污染,—unzip-setuptools参数表示向虚拟环境中加入setuptools工具包.此时有疑惑为何不直接在开发环境中执行这一步创建虚拟环境?我试过,ubuntu16.04创建出来的虚拟环境移到redhat6中python都打不开,会提示两个重要文件不存在,可能和系统环境有关.
8. 替换myenv/lib/python2.7
目录下的所有文件: rm -rf /deploy/myenv/lib/python2.7 && cp -r /usr/local/lib/python2.7/* /deploy/myenv/lib/python2.7/
移值项目
经过以上步骤,独立的虚拟环境就创建好了,此时可以用docker commit cont-current-id cont-name
保存当前容器状态供下次使用.
部署时在/deploy中放入要部署的python程序,执行source /deploy/myenv/bin/activate
启动虚拟环境,用pip安装所用到的依赖包,然后程序可以正常执行后边可以将整个/deploy目录压缩,接着便可以移到没网的redhat服务器中,然后启动虚拟环境像开发时一样执行你的程序文件即可.
关于source /path/activate
的思考
用linux的都知道,在linux中一切都是文件,可能用windows的开发人员会很不习惯,安装程序几乎都是用命令的,没有组策略也没有注册表,linux安装程序不过就是把程序文件放在指定目录后配置一下环境变量而已,而source命令实质做的就是更新环境而已,当执行source /path/activate
后环境变量会发生改变,非python用的环境变量不深究,python程序会通过sys.path
变量查找依赖包的位置.当用crontab打计划的时候,source命令会失效,我们可以通过手动修改sys.path
的方式手动控制.
遇到的问题
- 用crontab定时定点执行任务时,如何让source命令生效.
- 当crontab中的程序跑的时候,requests会出现报错
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='xxx.com', port=xxx): Max retries exceeded with url
,网上查说是请求太频繁,加个延时就好,不过我加了没用,但在正常sh窗体中用命令跑就不会出现这种问题,不知道是何原因.
总结
其实可以用docker部署的,但有一点就是docker生成的系统体积太大,在没网的环境下更新程序代码资源消耗大且不方便.也可以自己到pypi仓库自己找依赖包手动安装,但这种方式肯定没有虚拟环境方便,且虚拟环境保持了开发环境和部署环境的一致,这点手动安装依赖包的方式是不能比的,而且手动安装依赖包的方式确实太幼稚.经过此次实验详细更多人会对python的虚拟环境有更深入的了解,也体会到了docker的实用性.