前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >腾讯云Serverless架构安装Python依赖的小工具(包括对外的API,基于SCF)

腾讯云Serverless架构安装Python依赖的小工具(包括对外的API,基于SCF)

原创
作者头像
None-xiaomi
修改2020-01-03 13:44:45
2.1K1
修改2020-01-03 13:44:45
举报

很久很久之前,做了一个在线下载依赖包的工具,但是由于是放在了CVM上,收费比较高昂,而自己比较清贫,所以没能坚持多久,那个工具就被我下掉了,后来有小伙伴就给我留言问我为啥工具不能用了?对啊,有Serverless架构,为什么要用CVM这种鬼东西呢?那么今天我就弄一个Python安装依赖的小工具。

众所周知,在SCF的Runtime中,实际上,并不能很好的执行pip,也就是说并没有默认的安装pip,而且就算已经默认安装了pip,我们也不能每次函数启动都去pip一下,这样会导致程序进入状态变得很慢,所以我们通常都是把依赖打到我们的程序包中,例如在安装的时候: pip install ***==*** -t . 但是,有一种情况是非常尴尬的,那就是有一些依赖是需要编译的,例如opencv这些,可能在不同的系统上或者python版本中编译出来的文件是不同的,这就导致部分依赖如果想要放在SCF Runtime中正常执行,就要在Centos+对应的版本,例如Python2.7,Python3.6等指定环境上进行操作。那么问题来了,我们有多少人是在Centos上开发呢?难不成要弄一个虚拟机或者什么东西单独来做这个处理么?这显然不是很好的操作。所以,我就做了这样一个小工具: http://serverless.0duzhan.com/app/new_year_greeting_card/

选择好Python版本之后,输入包名和版本信息(版本信息可以不写),输入之后点击确定:

会看到下面提示系统处理中,稍等片刻:

点击下载压缩包,就可以获得到对应的package在100% SCF的环境下生成的安装包。

当然,这个是简单的网页工具,如果要用一个工具批量处理也是ok的,可以考虑这个接口:

请求方法:POST Python2: http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/scf_python2_package_download Python3: http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/scf_python3_package_download 输入参数: name: 包名 versioin: 版本 输出参数: error: 真/假,表示是否有错误 result: 结果,如果error为False,则此处输出下载地址,如果error为True,此处输出错误信息 效果:

接下来,分享一下代码(Python2/3代码基本一致,只是稍微修改一下Python2/3的标记):

代码语言:javascript
复制
# -*- coding: utf8 -*-
import pip._internal.main
import json
import os
import zipfile
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client

secret_id = ''  # 替换为用户的 secretId
secret_key = ''  # 替换为用户的 secretKey
region = 'ap-shanghai'  # 替换为用户的 Region
token = None  # 使用临时密钥需要传入 Token,默认为空,可不填
scheme = 'https'  # 指定使用 http/https 协议来访问 COS,默认为 https,可不填
config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token, Scheme=scheme)
client = CosS3Client(config)
bucket_name = 'serverless-cache-1256773370'


def zipDir(dirpath, outFullName):
    """
    压缩指定文件夹
    :param dirpath: 目标文件夹路径
    :param outFullName: 压缩文件保存路径+xxxx.zip
    :return: 无
    """
    zip = zipfile.ZipFile(outFullName, "w", zipfile.ZIP_DEFLATED)
    for path, dirnames, filenames in os.walk(dirpath):
        # 去掉目标跟路径,只对目标文件夹下边的文件及文件夹进行压缩
        fpath = path.replace(dirpath, '')

        for filename in filenames:
            zip.write(os.path.join(path, filename), os.path.join(fpath, filename))
    zip.close()


def main_handler(event, context):
    try:
        packageName = json.loads(event["body"])["name"]
    except:
        packageName = None

    try:
        packageVersion = json.loads(event["body"])["version"]
    except:
        packageVersion = None

    if packageName:
        if packageVersion:
            packageInfor = "%s==%s" % (packageName, packageVersion)
        else:
            packageInfor = "%s" % (packageName)

        response = client.list_objects(
            Bucket=bucket_name,
            Prefix="python2_%s" % packageInfor
        )

        if 'Contents' in response and response['Contents'] and len(response['Contents']) > 0:
            for eve in response['Contents']:
                response = client.get_presigned_download_url(
                    Bucket=bucket_name,
                    Key=eve['Key']
                )
                return {
                    "error": False,
                    "result": str(response)
                }

        try:
            os.makedirs("/tmp/%s" % packageName)
        except:
            pass
        try:
            install_list = ["install", packageInfor, "-t", "/tmp/%s"%(packageName), "-i", "https://pypi.tuna.tsinghua.edu.cn/simple"]
            pip._internal.main.main(install_list)
            if os.listdir("/tmp/%s" % packageName):
                zipDir("/tmp/%s" % packageName, "/tmp/%s.zip" % packageInfor)
                response = client.upload_file(
                    Bucket=bucket_name,
                    LocalFilePath="/tmp/%s.zip" % packageInfor,
                    Key="python2_%s.zip" % packageInfor,
                )
                print(response['ETag'])
                response = client.get_presigned_download_url(
                    Bucket=bucket_name,
                    Key="/python2_%s.zip" % packageInfor
                )
                return {
                    "error": False,
                    "result": str(response)
                }
            else:
                return {
                    "error": True,
                    "result": "依赖安装失败"
                }
        except Exception as e:
            print(e)
            return {
                "error": True,
                "result": str(e)
            }
    else:
        return {
            "error": True,
            "result": "未获得到包名,请检查输入"
        }

整个逻辑就是,接收到数据,去存储桶寻找是否已存在,如果已存在直接返回,如果不存在则通过pip下载,保存到存储桶,然后返回。

另外还需要对PIP的部分内容修改,主要有cache_dir等。例如在:

以及:

修改的原因是因为SCF部分的目录并为给我们权限。

有问题随时沟通。欢迎提出问题。


原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云函数
云函数(Serverless Cloud Function,SCF)是腾讯云为企业和开发者们提供的无服务器执行环境,帮助您在无需购买和管理服务器的情况下运行代码。您只需使用平台支持的语言编写核心代码并设置代码运行的条件,即可在腾讯云基础设施上弹性、安全地运行代码。云函数是实时文件处理和数据处理等场景下理想的计算平台。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档