本文介绍Python运行环境的相关内容,包括打印日志、错误处理、内置模块、自定义模块以及调用外部命令。
背景信息
函数计算目前支持以下Python运行环境:
- Python 2.7(runtime = python2.7)
- Python 3.6(runtime = python3)
打印日志
函数stdout打印的内容会被收集到创建服务时指定的Logstore中,在这里有两种打印日志的方法:
- 使用logging模块打印日志。该方法打印的每条日志中都包含时间、RequestId、日志级别等信息。
import logging def my_handler(event, context): logger = logging.getLogger() logger.info('hello world') return 'done'
执行上面的代码输出的日志内容如下所示。
message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad****e5 [INFO] hello world
说明 在这里推荐使用logging模块打印日志。因为该方法打印的日志自动包含RequestId信息,方便在出错的时候定位问题日志。 - 直接使用
print
打印,把内容原样地输出到日志中。def my_handler(event, context): print 'hello world' return 'done'
执行上面的代码输出的日志内容如下所示。
message:hello world
错误处理
函数在执行过程如果抛出异常,那么函数计算会把异常捕获并将异常信息返回,示例如下所示。
def my_handler(event, context):
raise Exception('something is wrong')
调用函数时收到的响应如下所示。
{
"errorMessage": "something is wrong",
"errorType": "Exception",
"stackTrace": [
[
"File \"/code/index.py\"",
"line 2",
"in my_handler",
"raise Exception('something is wrong')"
]
]
}
发生异常时,函数调用的响应的HTTP header中会包含X-Fc-Error-Type: UnhandledInvocationError
。函数计算的错误类型的更多信息,请参见错误处理。
内置模块
除了Python的标准模块,函数计算的Python运行环境中还包含了一些常用模块,您可以直接引用,目前包含的模块如下所示。
模块名称 | 模块介绍 |
---|---|
oss2 2.6.0 | OSS SDK |
tablestore 4.6.0 | 表格存储SDK |
aliyun-fc2 2.1.0 | 函数计算SDK |
aliyun-python-sdk-ecs 4.10.1 | 云服务器SDK |
aliyun-python-sdk-vpc 3.0.2 | 专用网络SDK |
aliyun-python-sdk-rds 2.1.4 | 云数据库SDK |
aliyun-python-sdk-kms 2.5.0 | 密钥管理服务SDK |
pydatahub 2.11.2 | DataHub SDK |
aliyun-mns 1.1.5 | 消息服务 |
aliyun-python-sdk-cdn 2.6.2 | CDN服务 |
aliyun-python-sdk-ram 3.0.0 | 访问控制RAM |
aliyun-python-sdk-sts 3.0.0 | 访问控制STS |
aliyun-python-sdk-iot 7.8.0 | 物联网平台IOT |
aliyun-log-python-sdk 0.6.38 | 日志服务SLS |
wand 0.4.4 | 图片处理库 |
opencv 3.3.0.10 | 计算机视觉库 |
numpy 1.13.3 | 科学计算库 |
scipy 1.0.0 | 科学计算库 |
matplotlib 2.0.2 | 绘图库 |
scrapy 1.4.0 | 数据抓取库 |
访问OSS的示例代码如下所示。
import json
import oss2
def my_handler(event, context):
evt = json.loads(event)
creds = context.credentials
# do not forget security_token
auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token)
bucket = oss2.Bucket(auth, evt['endpoint'], evt['bucket'])
bucket.put_object(evt['objectName'], evt['message'])
return 'success'
自定义模块
如果您需要使用自定义的模块,则需要将自定义模块与代码一起打包上传。您可以通过pip包管理器进行依赖管理,如果您使用Funcraft部署应用,可以使用fun install
命令来安装依赖。
- 使用pip包管理器进行依赖管理
通过
pip install -t .
命令安装依赖库至函数根目录下。上传代码库时将依赖库一同打包上传。下文以安装PyMySQL库为例进行详细介绍。- 建立一个目录,用于存放代码和依赖模块。
mkdir /tmp/code
- 在/tmp/code目录下安装依赖。
cd /tmp/code pip install -t . PyMySQL
- 新建代码文件,例如/tmp/code/index.py,在代码中使用PyMySQL。
import pymysql.cursors # Connect to the database connection = pymysql.connect(host='localhost', user='user', password='passwd', db='db', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor) def handler(event, context): with connection.cursor() as cursor: # Read a single record sql = "SELECT count(*) FROM `users`" cursor.execute(sql) result = cursor.fetchone() print(result) return result
- 打包上传。
打包时,需要针对文件进行打包,而不是针对代码整体目录进行打包。打包完成后,入口函数文件需要位于包内的根目录。
- 在Windows下打包时,可以进入函数代码目录,全选所有文件以后,单击鼠标右键,选择压缩为zip包,生成代码包。
- 在Linux下打包时,通过调用zip命令时,将源文件指定为代码目录下的所有文件,实现生成部署代码包,例如
zip code.zip /home/code/*
。
打包后,您通过函数计算控制台代码执行页面,您可以选择OSS上传或代码包上传方式上传代码包。
- 建立一个目录,用于存放代码和依赖模块。
- 使用
fun install
安装依赖。如果您使用Funcraft部署应用,可以使用
fun install
命令来安装依赖。关于使用Funcraft的部署应用请参见功能概览,关于fun install
的详细信息请参见使用fun install安装第三方依赖。下文以安装PyMySQL库为例进行详细介绍。
- 在函数根目录下初始化Funfile文件。
fun install init ? Select a runtime nodejs8 nodejs10 python2.7 ? python3 java8 php7.2 dotnetcore2.1 (Move up and down to reveal more choices)
- 选择python3后,会在当前目录生成一个名为Funfile的文件,编辑文件内容。
RUNTIME python3 RUN fun-install pip install PyMySQL
- 新建template.yml文件,例如/tmp/code/template.yml,详情请参见template.yml,内容如下。
ROSTemplateFormatVersion: '2015-09-01' Transform: 'Aliyun::Serverless-2018-04-03' Resources: FunDemo: Type: 'Aliyun::Serverless::Service' pythondemo: Type: 'Aliyun::Serverless::Function' Properties: Handler: index.handler Runtime: python3 CodeUri: './'
这个template.yml的含义如下:声明名为FunDemo的服务,在这个服务下,声明一个名为pythondemo的函数,配置函数入口为index.handler,函数的runtime为python3,并指定CodeUri为当前目录。在部署时,Fun会将CodeUri指定的目录打包上传。
- 在函数根目录下执行
fun install
命令安装依赖。fun install
返回结果如下。using template: template.yml start installing function dependencies without docker building FunDemo/pythondemoFunfile exist, Fun will use container to build forcely Step 1/2 : FROM registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:build-1.9.4 ---> 702c91653452 Step 2/2 : RUN fun-install pip install PyMySQL ---> Using cache ---> 8f59062f15bb sha256:8f59062f15bb7a86bd59b85e3b61bd0e4ed711c536fe0cd10fdefebc78eae152 Successfully built 8f59062f15bb Successfully tagged fun-cache-a6f4221c-33c8-4050-93b8-015e42396475:latest copying function artifact to /Users/txd123/Desktop/express Install Success Tips for next step ====================== * Invoke Event Function: fun local invoke * Invoke Http Function: fun local start * Build Http Function: fun build * Deploy Resources: fun deploy
- 执行以下命令部署应用。
fun deploy -y
返回结果如下。
using template: template.yml using region: cn-hangzhou using accountId: ***********3743using accessKeyId: ***********Ptgk using timeout: 60 Collecting your services information, in order to caculate devlopment changes... Resources Changes(Beta version! Only FC resources changes will be displayed): ┌────────────┬──────────────────────────────┬────────┬──────────┐ │ Resource │ ResourceType │ Action │ Property │ ├────────────┼──────────────────────────────┼────────┼──────────┤ │ │ │ │ Handler │ │ │ │ ├──────────┤ │ pythondemo │ Aliyun::Serverless::Function │ Add │ Runtime │ │ │ │ ├──────────┤ │ │ │ │ CodeUri │ └────────────┴──────────────────────────────┴────────┴──────────┘ Waiting for service FunDemo to be deployed... Waiting for function pythondemo to be deployed... Waiting for packaging function pythondemo code... The function pythondemo has been packaged. A total of 51 files were compressed and the final size was 114.35 KB function pythondemo deploy success service FunDemo deploy success
登录函数计算控制台,即可看到相关的服务、函数被创建成功,且触发执行可以返回正确的结果。
- 在函数根目录下初始化Funfile文件。
调用外部命令
您的函数可能会用到一些工具,而这些工具并不是用Python写的(例如Shell、C++ 、Go编译出来的可执行文件)。您仍然可以将这些工具与代码一起打包,然后在函数中通过运行外部命令的方法来使用这些工具。
- Linux内核版本:Linux 4.4.24-2.al7.x86_64。
- Docker基础镜像:docker pull python:2.7 ; docker pull python:3.6。
您可以使用Funcraft工具安装依赖,具体内容请参见使用fun install安装第三方依赖。下文以运行环境为python2.7,安装mysql-python(含有.so文件)为例。
可以直接在代码目录执行fun install --runtime python2.7 --package-type pip mysql-python
命令 ,即可安装好依赖。
- 第一次执行这个命令由于要拉取镜像,可能要耗费不少时间,请耐心等待。
- 依赖(含有mysql.so)会被装在.fun目录下,只需要在template.yml中通过CodeUri属性配置将
.fun
以及代码包含进来就可以了。
下面的代码演示了如何运行一个Shell脚本。
import os
import subprocess
def my_handler(event, context):
script_path = os.environ.get('FC_FUNC_CODE_PATH') + '/script.sh'
ret = subprocess.check_output(['bash', script_path])
return ret