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

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

很久很久之前,做了一个在线下载依赖包的工具,但是由于是放在了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的标记):

# -*- 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部分的目录并为给我们权限。

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


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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【视频】腾讯云API使用指南

    云API团队在云学院上线了一套视频教程,目的是和大家分享如何进行API、SDK和CLI的使用。

    Dfounderliu
  • 关于云API3.0就近原则的一个“小故事”

    1:云API 3.0版本,是支持就近接入,也就是说,系统会根据你的IP,就近接入你的请求,给你反馈结果

    Dfounderliu
  • 【非官方工具】腾讯云API代码生成工具 2.0

    1:本工具并非腾讯云官方数据,仅供大家学习使用,使用过程中不要透露自己的SecretId和SecretKey

    Dfounderliu
  • 高并发服务器的设计--架构与瓶颈的设计

    做架构设计,难免有时候被人问及系统的瓶颈在哪,那首先来了解下什么是瓶颈? 打个形象的比方,人的嘴巴可以吞下一整个面包,但是却咽不下去,因为食管不给力,它比较细,...

    李海彬
  • Netty+MUI从零打造一个仿微信的高性能聊天项目,兼容iPhone/iPad/安卓

    要说到微信,我相信是个人都应该知道,几乎人人都会安装这款社交APP吧,它已经成为了我们生活中不可缺少的一份子。

    风间影月
  • nginx0.1.0之http模块初始化源码分析(2)

    本文讲解http各个模块create_srv_conf和create_loc_conf钩子,还有指令的解析。 各模块的create_srv_conf和creat...

    theanarkh
  • 浅析软件开发的3个层次

    早上在微博上看到郭安定老师的微博,我在微博上也改了下发了一条,萌生写这篇文章。 ? 已故的中国社会学家费孝通认为文化应包含三个层次:第一个层次是生产、生活的工具...

    张善友
  • 04_有监督学习--分类模型--K 近邻(kNN)

    有监督学习--分类模型--K 近邻(kNN)0.引入依赖1.数据的加载和预处理2.核心算法实现3.测试4.自动化测试

    黑泽君
  • EM算法及其应用

    EM算法简介 首先上一段EM算法的wiki定义: expectation–maximization (EM) algorithm is an iterative...

    GavinZhou
  • 基于Django的电子商务网站开发(连载24)

    在这里r'^view_goods/(?P<good_id>[0-9]+)/$'表示view_goods/后面跟着一个由数字组成的字符串,这个字符串定义为变量go...

    小老鼠

扫码关注云+社区

领取腾讯云代金券