Python Web CloudNative [未完]
现在 CloudNative 那么火,当前基础设施环境也越来越成熟。诸如 Docker,K8s 到现在 DCI 标准的出现,使得 DevOps 越来越方便。本文以个人开发时总结的
一套 Python Web 开发在使用 gitalb-ci 和 Docker 环境上的实践。当然这只是第一版,以后也会在使用中不断优化开发管理和运维流程。
一、说明
本项目以单 Web 项目为示例,以抛砖引玉。项目不注重业务功能,以最简单业务功能,模拟 Web 访问场景。但项目开发和组织是结合当前个人总结的开发实践来做的。如有缺陷,还望斧正。
项目以前后端分离。后端采用 fastapi 框架开发,现在仅提供一个访问端点,后续优化可能会逐步增加数据库访问等依赖服务,尽可能模拟真实中小型 Web 开发场景。前端项目采用 react 开发,使用 nodejs 构建成静态文件后由 nginx 加载后对外提供访问地址。前端页面调用后端服务。
二、后端开发
项目以 httpbin
命名,目的是在做示例项目之后,该项目可以像正常 httpbin 一样可用。
项目 Python 环境为 Python3.7
。主要是 fastapi
是一个 ASGI Web 框架,在 Python 3.7
异步支持更好。
1. 项目初始化
安装 cookiecutter
1 | pip install cookiecutter |
使用已有项目模板创建项目,这个项目模板也是个人在实践过程中总结的通用 Python 项目模板。
如果无法使用,可以手动创建
1 | cookiecutter http://git.tendata.com.cn/tendata/bigdata/cookiecutter-tendata-python.git |
项目模板结构如下:
1 | . |
1.1 项目内容
如果已经使用模板生成可以跳过
httpbin/__init__.py
1 | __version__ = '0.1.0' |
Pipfile
1 | [[source]] |
项目依赖使用 pipenv 管理。初始模板带有四个开发环境时要使用的库。
README.md
1 | # httpbin |
setup.cfg
1 | [metadata] |
为了减少源数据散落各处,项目打包源数据放在 setup.cfg
中,这是 setuptools 30.3.0 后新增的功能,所以在使用的时候,要注意版本。此文件中还放了其他库的要配置源数据。
项目依赖 install_requires
中包含了两个库,一个是 Web 框架 fastapi
,两一个是 ASGI
库 uvicorn
。这是运行 fastapi
程序需要用到的。
注意:
version = attr: httpbin.__version__
使用了attr:
特殊指令,
其作用相当于import
,如果httpbin/__init__.py
中导入了第三方依赖,在执行tox
或者在没有外部依赖的环境下执行python setup.py
打包的时候会报缺少外部依赖的问题。
因为依赖调用,而环境中又没有安装。此时要么把依赖从httpbin/__init__.py
中移出去,要么在setuo.py
中使用open
方法读取httpbin/__init__.py
文件,
然后用正则匹配出对版本号。re.search(r"__version__ = ['\"]([^'\"]+)['\"]", open(['httpbin', '__version__.py']).read(), re.M).group(1)
setup.py
1 | import setuptools |
这个文件就不需要写太多参数啦。
tox.ini
1 | [tox] |
至此,项目模板就是这样。
1.2 初始开发环境
使用 pipenv 初始化虚拟环境
1 | pipenv install |
使用 pipenv 安装 fastapi
1 | pipenv install fastapi |
1.3 初始化git
1 | git init |
初始化 git 仓库,用于版本管理。这里记得创建 .gitignore
文件。
2. 项目开发
1.1 接口和路由
新建文件 httpbin/routers.py
,文件内容如下:
1 | from datetime import datetime |
这里仅创建了一个接口,接口默认返回 JSON 数据。
1.2 主程序
新建 httpbin/server.py
,内容如下:
1 | from fastapi import FastAPI, __version__ |
首先初始化一个 FastAPI
对象,然后把前面定义的路由加载进去。
3. 测试
测试框架使用 pytest ,由于其强大的的特性和丰富的扩展插件,在编写测试的上更高效。
3.1. 配置测试
新建 tests/conftest.py
,内容如下:
1 | import pytest |
conftest.py
为 pytest 的配置文件,在这里定义其他测试所依赖的内容。
fixture
是一个很强大的功能,在使用 yield
关键字的时候可以让你直接在编写测试方法的情况下获得 setup
和 teardown
的效果。其 scope
参数可以配置 function
、 class
或者其他级别。具体请参考文档。
测试接口使用 starlette.TestClient
,其依赖 requests
库,所以要记得安装
1 | pipenv install -d requests |
3.2.编写测试文件
新建测试文件 tests/test_api.py
,内容如下:
1 | import json |
3.3. 运行测试
1 | pytest |
4. 代码质量提升
4.1 运行 isort
isort 是一款自动格式化到包顺序的工具,运行后根据提示操作。格式化完成后,每个文件的导包会根据配置格式化。运行后有助于提升代码风格。
1 | isort |
4.2 运行 flake8
flake8 是一款检测你的代码是否符合 PEP8 规范的工具。运行后有助于提升代码质量。
1 | flake8 |
5. 自动化
tox 是一个自动化工具,通过配置可以编排需要执行的操作。
1 | tox |
在 tox.ini
文件中已经编写了对应的规则。一般在最后确定开发完成之后再运行一遍,用于最后检查项目是否还存在问题。
6. 运行项目
以可编辑模式安装项目
1 | pip install -e . |
运行
1 | uvicorn httpbin.server:app --port 8000 --host 127.0.0.1 |
端口和地址可以不指定。
访问地址 http://127.0.0.1:8000 即可访问首页内容。
fastapi
还提供了 openapi 3.0规范
的接口文档页面和对应的 schema 。访问 http"//127.0.0.1:8000/docs 页面就能看到当前所有接口,方便前后端对接和调试。
在运行过程中如果发现异常问题,要及时排查和调整。修复后重复运行 tox
对项目重新自动化检测。
7. 提交代码
提交代码前一定要运行一次 tox
。
1 | git add . |
三、后端-云原生
1. 增加 Dockerfile
创建 ``Dockerfile` ,文件内容如下:
1 | # ########################################################## |
为了减少生成镜像的层数,构建过程采用多阶段构建,最后阶段为发布的镜像,使用的依赖在前一阶段构建。
记得生成 .dockerignore
文件,排除不必要的内容,尽量缩减镜像层数和每层的大小。
1.1 测试 Docker
构建 Docker 镜像
1 | docker build -t httpbin:latest . |
构建完成后会生成对应镜像
1.2 运行
1 | docker run --rm httpbin |
2. 增加 ci/cd
我使用的是 gitlab,所以后面 gitlab-ci 内容。以后有机会会增加其他 ci 工具。
新建 .gitlab-ci.yml
,内容如下
1 | stages: |
此 CI 逻辑为一般提交只运行测试和构建 whl 文件,当发布的时候会根据 release 的版本号,构建 Docker 镜像,同时将归档文件上传到 pypi 索引服务器。