Python独享运行环境

运行环境说明

工作流程

Python运行环境是新浪云推出的本地可写的Python运行环境,通过Git hook触发自动构建逻辑,将提交的代码打包为docker镜像,然后由新浪云的容器管理引擎启动生成的镜像实例运行。

工作流程示意图

容器运行环境示意图

总体的流程分为以下步骤:

  1. 从本地通过Git客户端提交代码到仓库,如何部署请参考容器环境Git管理示例
  2. 新浪云的Git仓库通过触发器启动一个同步构建镜像的任务,解析代码中指定的需要安装的python版本、下载依赖的包等,制作一个docker的镜像;
  3. 如果以上过程没有错误,则将镜像推送到新浪云的镜像中心,并通知托管服务管理系统;如果出错,从git的回显通知具体的错误;
  4. 调度新建或者替换正在运行的镜像实例,启动后将更新后的运行环境更新到负载均衡;
  5. 所有的实例更新或则启动完成后,通过Git回显告知提交成功。

支持的Python版本

以下是当前支持的所有python的版本:

  • python-2.4.6
  • python-2.5.5
  • python-2.6.9
  • python-2.7.0 ~ python-2.7.15
  • python-3.4.0 python-3.4.1 python-3.4.2 python-3.4.3
  • python-3.5.0 python-3.5.1 python-3.5.2 python-3.5.3
  • python-3.6.0 ~ python-3.6.6
  • python-3.7.0

支持的pypy版本

以下是所有支持的pypy版本:

  • pypy3-2.4.0
  • pypy3-5.5.0
  • pypy3-5.7.1
  • pypy3-5.8.0
  • pypy-5.3.1
  • pypy-5.6.0
  • pypy-5.7.0
  • pypy-5.7.1
  • pypy-5.8.0

创建应用

  1. 登录云应用管理平台https://sae.sinacloud.com,如果没有账号请先注册;

  2. 点击“+创建应用”进入应用的创建页面; 点击创建应用进入应用管理页面

  3. 开发语言选择“Python”;

  4. 运行环境选择“独享环境”;

  5. 选择单实例的配置; 选择Python应用配置

  6. 选择实例个数,开发阶段可以选择1,可以随时调整;

  7. 输入应用的二级域名前缀,二级域名的组成规则请参考应用名,应用名称(应用的中文介绍); 输入应用名、应用描述等

  8. 点击“确认创建”完成创建。

说明

  • 每个实例中将会拥有相同的代码,每个实例的资源配额为创建时指定的单实例配置
  • 实例的个数可以随时修改;
  • 计费的规则为:单实例价格 * 实例总数 * 实例的运行时长,按分钟计费。

计费说明

计费规则

计费的规则为:单实例价格 * 实例总数 * 实例的运行时长,按分钟计费。

其中单实例的价格可以从价格中心查询。

例如单实例的配置为标准型,单价为0.06元每实例每小时,开启的实例个数为2,则一天的价格为:

0.06 * 2 * 24 = 2.88元

流量计费

当前独享型Python的流量不计费。

指定python的版本

在代码的根目录下创建一个runtime.txt,写入python的版本号即可,例如:

python-2.7.9

表示当前应用使用python的2.7.9版本,所有支持的python版本请参加支持的python版本

指定依赖

在代码的根目录下创建一个requirements.txt,写入需要的依赖即可,一行一个,例如:

tornado==4.2.1
pillow 

表示程序依赖版本为4.2.1的tornado和pillow,如果不指定版本号,则默认下载最新版本。

Hello World

准备工作

  1. 创建应用,选择python的独享型环境,如果没有创建应用,请参考创建应用章节说明;
  2. https://github.com/sinacloud/python-getting-started下载示例代码;下载后的目录结构为:
$ ls
Procfile README.md main.py requirements.txt runtime.txt

这个示例程序是一个使用 Tornado 框架写的 HTTP Web 服务器,我们依次来看下每个文件的作用,首先,main.py 文件,这个是应用主要的代码。

import os
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado import gen
from tornado.httpclient import AsyncHTTPClient

class MainHandler(tornado.web.RequestHandler):

    @gen.coroutine
    def get(self):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch("http://www.sinacloud.com")
        self.set_header('content-type', 'text/plain')
        self.write('Hello, World! ' + str(response.body[:100]))

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(5050 or os.environ['PORT'])
tornado.ioloop.IOLoop.current().start()

这段程序就是设置了一些 HTTP Handler,最后启动一个 Web 服务器,监听在环境变量 PORT 指定的端口上。

requirements.txt文件:

tornado==4.2.1
pillow 

指定了程序的依赖,表示依赖4.2.1的tornado和pillow。

runtime.txt文件:

python-2.7.9

表示程序指定的python版本为2.7.9。

克隆项目到本地

如果你的本地没有Git客户端,请参考 Git部署说明

从应用的管理中心,选择左侧导航“运行环境管理”,“代码管理”进入代码管理页面即可查询应用的Git仓库信息: 查询应用的Git仓库信息

执行:

git clone 'https://git.sinacloud.com/你的应用名' .

输入用户名、密码将仓库克隆到本地,示例如下:

$ git clone 'https://git.sinacloud.com/dockerpython' .
Cloning into '.'...
warning: You appear to have cloned an empty repository.

拷贝文件到git本地的目录

https://github.com/sinacloud/python-getting-started下载的代码拷贝到git的本地目录下,拷贝后的文件列表为:

$ ls -al
total 19
drwxr-xr-x 1 37708 197609   0 9月  27 20:14 ./
drwxr-xr-x 1 37708 197609   0 9月  27 20:12 ../
drwxr-xr-x 1 37708 197609   0 9月  27 20:12 .git/
-rw-r--r-- 1 37708 197609 781 8月  16 16:50 main.py
-rw-r--r-- 1 37708 197609  20 8月  16 16:50 Procfile
-rw-r--r-- 1 37708 197609 721 8月  16 16:50 README.md
-rw-r--r-- 1 37708 197609  23 8月  16 16:50 requirements.txt
-rw-r--r-- 1 37708 197609  13 8月  16 16:50 runtime.txt

git add --all

执行

git add --all

将所有的文件加到git的版本管理中,执行输出:

$ git add --all
warning: LF will be replaced by CRLF in Procfile.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in README.md.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in main.py.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in requirements.txt.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in runtime.txt.
The file will have its original line endings in your working directory.

说明

warning: LF will be replaced by CRLF是换行的提示,这个是Windows环境下才可能出现,不影响。

git commit增加commit信息

提交前需要增加一些commit信息记录本次改动的标示信息,执行

git commit -m '修改为你的备注信息'

例如:

$ git commit -m '修改为你的备注信息'
[master (root-commit) 1124d05] 修改为你的备注信息
 5 files changed, 61 insertions(+)
 create mode 100644 Procfile
 create mode 100644 README.md
 create mode 100644 main.py
 create mode 100644 requirements.txt
 create mode 100644 runtime.txt

git push origin master推送代码

执行:

git push origin master

将代码提交到远程,示例输出:

$ git push origin master
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (7/7), 1.34 KiB | 1.34 MiB/s, done.
Total 7 (delta 0), reused 0 (delta 0)
remote: 导出 Git 代码中...
remote: 构建程序中...
-----> Python app detected
-----> Network Connection Success
       !     The latest version of Python 2 is python-2.7.15 (you are using python-2.7.9, which is unsupported).
       !     We recommend upgrading by specifying the latest version (python-2.7.15).
-----> Installing python-2.7.9
-----> Installing pip
-----> Installing SQLite3
-----> Installing requirements with pip
       Collecting tornado==4.2.1 (from -r /tmp/build/requirements.txt (line 1))
       Downloading http://mirrors.aliyun.com/pypi/packages/ec/af/c40ad78dacdef134f3e08b3103c3c859b14ceb9639d344811339227b6444/tornado-4.2.1.tar.gz (434kB)
       Collecting pillow (from -r /tmp/build/requirements.txt (line 2))
       Downloading http://mirrors.aliyun.com/pypi/packages/86/56/14563445c372825b20ea285687a8daf0ef1c09ac0a72f30f72181c008dec/Pillow-5.2.0-cp27-cp27m-manylinux1_x86_64.whl (2.0MB)
       Collecting backports.ssl_match_hostname (from tornado==4.2.1->-r /tmp/build/requirements.txt (line 1))
       Downloading http://mirrors.aliyun.com/pypi/packages/76/21/2dc61178a2038a5cb35d14b61467c6ac632791ed05131dda72c20e7b9e23/backports.ssl_match_hostname-3.5.0.1.tar.gz
       Collecting certifi (from tornado==4.2.1->-r /tmp/build/requirements.txt (line 1))
       Downloading http://mirrors.aliyun.com/pypi/packages/df/f7/04fee6ac349e915b82171f8e23cee63644d83663b34c539f7a09aed18f9e/certifi-2018.8.24-py2.py3-none-any.whl (147kB)
       Installing collected packages: backports.ssl-match-hostname, certifi, tornado, pillow
       Running setup.py install for backports.ssl-match-hostname: started
       Running setup.py install for backports.ssl-match-hostname: finished with status 'done'
       Running setup.py install for tornado: started
       Running setup.py install for tornado: finished with status 'done'
       Successfully installed backports.ssl-match-hostname-3.5.0.1 certifi-2018.8.24 pillow-5.2.0 tornado-4.2.1

-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 39M
remote: Generating docker image...
remote: Pushing image registry.docker.sae.sina.com.cn/dockerpython:1124d05 .......
remote: 部署程序中 ............
To https://git.sinacloud.com/dockerpython
 * [new branch]      master -> master

查看实例状态

push成功后,系统会自动启动您指定的容器,个数和配置为开启时指定,从“运行环境管理” -> "容器管理"可以看到实例的状态:

python容器列表

访问应用

访问应用的链接地址 https://YOUR-APP-NAME.applinzi.com可以看到输出:

python容器应用访问

到此,示例程序就已经在运行了。

协议支持

应用支持http、https和websocket协议(ws、wss)。

端口映射

工作原理

应用的负载均衡(新浪云提供)监听80和443端口,然后将请求转发到容器中的5050端口,示意图如下:

协议及端口示意

支持的端口

容器中可以启动多个端口,但是仅5050端口会映射到负载均衡上,其他的端口只能在本地访问。可以从环境变量中获取支持的端口,环境变量的key为:

PORT 

可以通过:

os.environ['PORT']

获取支持的端口。

请注意

  • 另外HTTP等服务器应该监听在0.0.0.0,不要监听在127.0.0.1,如果监听在127.0.0.1,仅在容器上运行的程序才可以访问,外部无法访问;
  • 如果使用HTTPS访问,在负载均衡到容器间会转变为HTTP协议,可以从HTTP的header头中判断是否有HTTP-X-PROTO头,如果这个header头的值为SSL表示本次请求为HTTPS访问;
  • 如上所述,HTTPS证书应该传到负载均衡处(从管理面板的域名绑定处上传),不应该放到容器中。

日志系统

容器日志分类

容器日志分类stdoutstderr分类,分别是标准输出和标准错误输出的捕获。

因为容器的磁盘空间有限,大量的写入可能会占满磁盘导致服务不可用,请从程序中配置日志输出路径,将日志写到stdoutstderr分类,其中:

  • /proc/1/fd/1stdout的绝对路径
  • /proc/1/fd/2stderr的绝对路径

查询容器stdout日志

  1. 进入应用的列表页面https://sae.sinacloud.com
  2. 点击操作处的管理进入应用的管理中心
  3. 左侧导航选择“日志及监控”,选择“日志中心”进入日志管理
  4. 选择“容器日志”的“stdout”分类 查询stdout分类日志

查询容器stderr日志

  1. 进入应用的列表页面https://sae.sinacloud.com
  2. 点击操作处的管理进入应用的管理中心
  3. 左侧导航选择“日志及监控”,选择“日志中心”进入日志管理
  4. 选择“容器日志”的“stderr”分类 查询stderr分类日志

SSH登录

说明

独享型python容器支持通过在线SSH终端登录到容器中查看进程的状态和系统的信息。

如何登录

  1. 进入应用的列表页面https://sae.sinacloud.com
  2. 点击操作处的管理进入应用的管理中心
  3. 左侧导航选择“运行环境管理”,选择“容器管理”进入应用的容器列表页面
  4. 点击需要管理的容器示例的“操作”区域的“终端”即可进入web版本的终端 进入web terminal
  5. 输入Linux命令可以查询进程的状态、执行其他的操作 在web terminal执行ps -ef命令

文件系统

本地文件系统

实例在创建时将会分配5GB的本地磁盘,用于存放程序的代码和系统文件等,你可以从程序往本地写文件,但本地的文件不是持久化存储,在重启后文件会删除

警告

  • 如果你需要持久化存储文件,请不要将文件写到本地文件系统,可以通过以下几种方式存储文件:

挂载共享存储

共享存储服务是为容器云提供的分布式存储服务,利用多副本写入实现数据高可靠性,并提升读取性能,可以提供数十M/S的峰值读写性能。

您可以通过挂载,将对应的共享存储卷映射进容器中,是容器获得本地文件读写和数据持久化功能。

通过共享存储,还可以在不同的容器之间共享数据,实现跨容器的数据共享和交互。

有关共享存储的更多介绍,请参考共享存储章节,请参考以下步骤挂载共享存储:

  1. 共享存储管理面板创建一个共享存储;
  2. 云应用管理平台应用列表页面点击“管理”进入应用的管理中心;
  3. 左侧导航选择“运行环境管理”,“容器管理”进入容器管理页面; 如何进入容器管理页面
  4. 点击“挂载管理”进入挂载管理页面; 进入磁盘挂载的页面
  5. 点击“+新增挂载”,存储的分类选择“共享存储”,从下拉列表选择刚刚创建的存储,输入一个挂载路径。 填写挂载的信息

    说明

    挂载路径是系统的绝对路径,如果你挂载的路径在本地文件系统已经存在,则挂载后本地的文件系统将被覆盖。

  6. 选择“立即重启容器”后挂载会立即生效,挂载完成后可以看到挂载的详情: 挂载详情

挂载完成后,从容器的实例中可以看到挂载的路径: 在容器中查看挂载的路径

共享存储中的文件支持FTP管理,详情请参考共享存储的FTP管理章节。

挂载完共享存储到本地的路径后,就可以在程序中将需要存储的文件写到挂载的路径下了。

挂载本地存储

本地存储服务是为容器云提供的本地问年间存储服务,可以和本地磁盘读写一样速度的磁盘。

您可以通过挂载,将对应的本地存储卷映射进容器中,是容器获得本地文件读写和数据持久化功能。

有关共享存储的更多介绍,请参考本地存储章节,请参考以下步骤挂载本地存储:

  1. 本地存储管理面板创建一个本地存储;
  2. 云应用管理平台应用列表页面点击“管理”进入应用的管理中心;
  3. 左侧导航选择“运行环境管理”,“容器管理”进入容器管理页面; 如何进入容器管理页面
  4. 点击“挂载管理”进入挂载管理页面; 进入磁盘挂载的页面
  5. 点击“+新增挂载”,存储的分类选择“本地存储”,从下拉列表选择刚刚创建的存储,输入一个挂载路径。 填写挂载的信息

    说明

    挂载路径是系统的绝对路径,如果你挂载的路径在本地文件系统已经存在,则挂载后本地的文件系统将被覆盖。

  6. 选择“立即重启容器”后挂载会立即生效,挂载完成后可以看到挂载的详情: 挂载详情

挂载完成后,从容器的实例中可以看到挂载的路径: 在容器中查看挂载的路径

本地存储中的文件支持FTP管理,详情请参考本地存储的FTP管理章节。

挂载完地存储到本地的路径后,就可以在程序中将需要存储的文件写到挂载的路径了。