如何优雅的处理Python环境及程序部署

简介

随着这几年AI的火热,Python 也强势进入编程语言前三甲行列。Python 是一种跨平台的计算机程序设计语言是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。以上抄了一段百度百科介绍,Python 自我感觉和如今ES的标准类似,写法也类似,当然 Python 有其独有的语法特征,比如它的缩进规则等等,不满足它的规则,编译是会报错的。简洁的语法,应用性广应该是Python 热火的重要因素吧。

最近经常使用 Python 来完成一些自动化工具,代码生成工具什么的,由于第三方库的强大,很多复杂的功能找到对应的第三方库就能很快完成,同时可以实验许多很有意思的功能,比如机器学习啊,爬虫等等。好了,废话不多说,这篇文章主题不是要介绍 Python 的语法,主要是想介绍下自己在搭建环境及发布上的一些心得。

开发环境配置

Python 的程序开发,严格意义上来说其实不需要什么特别的环境,装好编译器后,你就可以在命令行环境中通过简单的命令 python run.py 来运行程序了。但为了更好的维护开发环境,我们需要一些辅助工具来帮助我们。

virtualenv

第一个要介绍的就是 virtualenv了,它能够帮助我们对于每一个独立的项目维护一个独立的包环境,简单来说A项目需要使用第三方abc库的1.0版本,而B项目需要使用abc库的2.0版本,如果全部使用系统环境来安装是没法区分的。所以我们通过 virtualenv 来给每个项目独立创建包管理环境,并且可以独立出 Python 的运行环境。通过 pip install virtualenv 安装好对应的包后,在对应的工程目录下执行 virtualenv virt 就会以默认配置创建虚拟环境了。当然我们指定额外配置,例如 --no-site-packages 不安装系统包,-p PYTHON_EXE, --python=PYTHON_EXE 指定创建的 Python 运行环境。具体配置选项还有好多,请参考官网 Reference Guide

pipenv

实际 Python 开发,需要我们区分出开发环境和产品环境。以前我们的做法,一般都是通过 requriements.txt 文件来管理,针对不同的环境我们可能需要创建多个 requriements.txt 文件,例如 requriements-dev.txt 或者 requriements-prod.txt 什么的。有过 node.js 开发经验的小伙伴可能会很惊讶,WTF!这是什么鬼,依赖还要自己维护!不得不说,之前我们只能这么干,安装完包以后,通过 pip freeze 命令来导出项目依赖的第三方包。但是这个命令有个问题,会将目标包及其包含的其他依赖包都给导出来,这让有洁癖的我肯定受不了啊。如果我们勤奋一点,自己管理 requriements.txt 文件,那可能解决了目标包管理问题,但是目标包包含的其他依赖包会在每次重新安装的时候保持最新版本,谁TM知道最新版本会不会有问题呢,如果有个类似 npmyarn 之类的包管理工具就好了。pipenv 解决了我们这个问题,它具有以下几个特点:

  • 集成了 pipvirtualenv
  • 通过 PipfilePipfile.lock 的自动管理来替代手动管理的requriements.txt
  • 通过hash来管理包更加的准确, 安全。
  • pipenv graph 能够让你了解工程依赖关系图。
  • 通过加载.env文件简化开发流程。

使用上也非常简单,通过在工作根目录下执行 pipenv install 命令创建虚拟环境,此处是使用了集成的 virtualenv。完成以后根目录会创建 PipfilePipfile.lock 2个文件来自动管理项目所使用的包,这时候我们执行任何安装命令都会更新 PipfilePipfile.lock了。

简单的用法示例一览:

使用Python 3.7创建一个新项目:
$ pipenv --python 3.7

删除项目virtualenv:
$ pipenv --rm

安装项目的所有依赖项(包括dev):
$ pipenv install --dev

创建包含预发布的lock文件:
$ pipenv lock --pre

显示已安装的依赖项的图表关系:
$ pipenv graph

检查已安装的依赖项是否存在问题:
$ pipenv check

将本地setup.py安装到虚拟环境/ Pipfile中:
$ pipenv install -e

使用pip命令:
$ pipenv run pip freeze

程序运行及发布

先介绍下案例项目的结构,如下所示:

flask-app/
└─ flask-app/
   └─ templates
      └─ index.html
      └─ layout.html
   └─ __init__.py
 run.py

这个案例采用 Flask 来完成的,Flask 是一个 Python 实现的 Web 开发微框架,这里实现了一个简单的欢迎页面。

docker

使用Docker容器来部署程序,可以标准化我们的产品环境,让我们可以不用关注硬件,同时为了更好对接各大云平台,以后更好的扩展自动化测试和持续的集成/部署等,使用Docker来管理实现我们的部署方案成了首选。

根目录创建 Dockerfile,来定义如何打包及准备环境

# 以python3.7为基础镜像构建
FROM python:3.7
# 安装nginx与supervisor
RUN apt-get update && apt-get install -y nginx supervisor
# 安装gevent与gunicorn
RUN pip install gunicorn pipenv
# 解决输出可能的中文乱码
ENV PYTHONIOENCODING=utf-8

# 创建并设置工作目录
WORKDIR /project/flask-app
# 拷贝包文件到工作目录
COPY Pipfile* /project/flask-app/
# 安装包
RUN pipenv install --system

# nginx配置相关
# 删除默认的有效配置,sites-enabled 目录下的配置文件才能够真正被用户访问
RUN rm /etc/nginx/sites-enabled/default
# 将配置文件链接到sites-available目录
RUN ln -s /etc/nginx/sites-available/nginx.conf /etc/nginx/sites-enabled/nginx.conf
# 添加自定义CMD时,添加此命令到nginx全局配置中保证容器可以跟踪到进程,防止容器退出
RUN echo "daemon off;" >> /etc/nginx/nginx.conf

# supervisord配置相关
RUN mkdir -p /var/log/supervisor
# 指定容器运行启动命令
CMD ["/bin/bash"]

docker容器的实质是进程,而且是按照分层存储的,所以以上文件每一行对应 Docker 的一层,因此定义容器时,不必要的分层可能会导致容器文件过大。

apt-get update && apt-get install -y nginx supervisor 保证了每次执行都会安装最新包,我们预计通过 nginx 做网站的反向代理,supervisor 进程管理工具来管理容器进程。WORKDIR 创建工作目录,之后所有工作目录都已此目录为根目录。我们这里没有将实际的项目文件复制到容器中,而是准备采用挂载的方式。

docker-compose

根目录创建 docker-compose.yml

version: "3.3"

services:
  web:
    stdin_open: true
    tty: true
    # 根据Dockerfile生成镜像文件
    build: .
    image: nginx-gunicorn-flask:latest
    # 挂载代码到容器对应目录
    volumes:
      - ./flaskr:/project/flask-app/flaskr
      - ./run.py:/project/flask-app/run.py
      - ./nginx.conf:/etc/nginx/sites-available/nginx.conf
      - ./gunicorn.conf:/etc/supervisor/conf.d/gunicorn.conf
      - ./supervisord.conf:/etc/supervisor/conf.d/supervisord.conf
    # 主机与容器端口映射
    ports:
      - "80:80"
    command: "/usr/bin/supervisord"

docker-compose 作为Docker三剑客之一,主要用于管理多个容器,例如我们这里的nginx 可以作为单独的 webserver容器独立出来,如果有数据库也可以单独创建容器。我们这里主要完成了代码挂载及进程管理supervisord的启动等配置。

分别再创建gunicorn.conf

[program:gunicorn]
command=gunicorn --workers=3 run:app -b localhost:5000
directory=/project/flask-app

nginx.conf

server {
    listen 80;
    location / {
        proxy_pass http://localhost:5000/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location ^~ /static/ {
        root /project/flask-app/;
    }
}

nginx.conf

[supervisord]
nodaemon=true

[program:nginx]
command=/usr/sbin/nginx

如果本地已经安装好了docker,那么可以直接运行docker-compose up命令执行创建镜像,运行容器等操作。如下图所示:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容