【20181205】阿里云函数计算使用体验 - 图1

环境安装

  • 在此案例中,使用阿里云服务器。(Linux)

  • 使用官方安装脚本自动安装

  1. curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
  • 安装fun
  1. npm install @alicloud/fun -g
  • 配置fun,按提示输入信息
  1. fun config

基础:创建Helloworld文件

  1. 1. 创建一个文件夹,如image_crawler
  2. 2. 创建一个文件template.yml,内容
  3. ROSTemplateFormatVersion: '2015-09-01'
  4. Transform: 'Aliyun::Serverless-2018-04-03'
  5. Resources:
  6. localdemo:
  7. Type: 'Aliyun::Serverless::Service'
  8. Properties:
  9. Description: 'local invoke demo'
  10. image-crawler:
  11. Type: 'Aliyun::Serverless::Function'
  12. Properties:
  13. Handler: index.handler
  14. CodeUri: code/
  15. Description: 'Hello world with python2.7!'
  16. Runtime: python2.7
  17. 3. 创建一个code文件夹,在文件夹中编写helloworld代码
  18. def handler(event, context):
  19. return 'hello world!'
  20. 4. 运行函数
  21. fun local invoke image-crawler

【20181205】阿里云函数计算使用体验 - 图2

进阶:设置oss转存任务,如一个image_crawler

  • 获取网页源代码,按上述语句运行image-crawler,可看到变化。
  1. import logging
  2. import json
  3. import urllib
  4. logger = logging.getLogger()
  5. def handler(event, context):
  6. logger.info("event: " + event)
  7. evt = json.loads(event)
  8. url = evt['url']
  9. html = get_html(url)
  10. logger.info("html content length: " + str(len(html)))
  11. return 'Done!'
  12. def get_html(url):
  13. page = urllib.urlopen(url)
  14. html = page.read()
  15. return html
  • 运行以下语句可看到变化
  1. echo '{"url":"http://huaban.com/search/?q=%e5%a3%81%e7%ba%b8"}' | fun local invoke image-crawler
  • 添加函数,从源代码中抽取图片路径
  1. def get_img(html):
  2. reg = r'https:\/\/[^\s,"]*\.jpg'
  3. imgre = re.compile(reg)
  4. return re.findall(imgre, html)
  • 调整替换原先的handler函数,使之从“获取网页源代码”功能转变为“获取图片路径功能”。
  1. def handler(event, context):
  2. logger.info("event: " + event)
  3. evt = json.loads(event)
  4. url = evt['url']
  5. html = get_html(url)
  6. img_list = get_img(html)
  7. logger.info(img_list)
  8. return 'Done!'
  • 将图片上传到OSS中,在 template 中配置环境变量(需提前创建好 oss bucket):
  1. EnvironmentVariables:
  2. OSSEndpoint: oss-cn-hangzhou.aliyuncs.com
  3. BucketName: fun-local-test
  • 然后就可以直接在函数中获取到这两个环境变量了:
  1. endpoint = os.environ['OSSEndpoint']
  2. bucket_name = os.environ['BucketName']
  • 设置OSS的STS权限控制,参考如下代码
  1. creds = context.credentials
  2. if (local):
  3. auth = oss2.Auth(creds.access_key_id,
  4. creds.access_key_secret)
  5. else:
  6. auth = oss2.StsAuth(creds.access_key_id,
  7. creds.access_key_secret,
  8. creds.security_token)
  9. bucket = oss2.Bucket(auth, endpoint, bucket_name)
  • 遍历所有图片文件,并且转存到OSS中
  1. count = 0
  2. for item in img_list:
  3. count += 1
  4. logging.info(item)
  5. # Get each picture
  6. pic = urllib.urlopen(item)
  7. # Store all the pictures in oss bucket, keyed by timestamp in microsecond unit
  8. bucket.put_object(str(datetime.datetime.now().microsecond) + '.png', pic)
  • 完整的代码
  1. import logging,datetime
  2. import json,re,oss2
  3. import requests,urllib,os
  4. logger = logging.getLogger()
  5. endpoint = os.environ['OSSEndpoint']
  6. bucket_name = os.environ['BucketName']
  7. local = 1
  8. def handler(event, context):
  9. logger.info("event: " + event)
  10. evt = json.loads(event)
  11. url = evt['url']
  12. print(url)
  13. creds = context.credentials
  14. if (local):
  15. auth = oss2.Auth(creds.access_key_id,creds.access_key_secret)
  16. else:
  17. auth = oss2.StsAuth(creds.access_key_id,creds.access_key_secret,creds.security_token)
  18. bucket = oss2.Bucket(auth, endpoint, bucket_name)
  19. html = get_html(url)
  20. img_list = get_img(html)
  21. logger.info(img_list)
  22. iii(img_list,bucket)
  23. return 'Done!'
  24. def iii(img_list,bucket):
  25. count = 0
  26. for item in img_list:
  27. count += 1
  28. logging.info(item)
  29. pic = urllib.urlopen(item)
  30. if pic != None:
  31. bucket.put_object(str(datetime.datetime.now().microsecond) + '.jpg', pic)
  32. def get_img(html):
  33. reg = r'http:\/\/[^,"]*\.jpg'
  34. imgre =re.compile(reg)
  35. return re.findall(imgre,html)
  36. def get_html(url):
  37. page = requests.get(url)
  38. html = page.content
  39. return html
  • 此时运行如下命令可看到成功效果。
    1. echo '{"url":"http://huaban.com/search/?q=%e5%a3%81%e7%ba%b8"}' | fun local invoke image-crawler

部署

  • 添加OSS权限到yaml中,此次是添加了policies:AliyunOSSFullAccess。注意localdemo这个函数计算项目及image-crawler这个函数,fun-local-test这个OSS项目bucket需要事先在阿里云官网后台配置过。
  1. ROSTemplateFormatVersion: '2015-09-01'
  2. Transform: 'Aliyun::Serverless-2018-04-03'
  3. Resources:
  4. localdemo:
  5. Type: 'Aliyun::Serverless::Service'
  6. Properties:
  7. Description: 'local invoke demo'
  8. Policies: AliyunOSSFullAccess
  9. image-crawler:
  10. Type: 'Aliyun::Serverless::Function'
  11. Properties:
  12. Handler: index.handler
  13. CodeUri: code/
  14. Description: 'Hello world with python2.7!'
  15. Runtime: python2.7
  16. EnvironmentVariables:
  17. OSSEndpoint: oss-cn-hangzhou.aliyuncs.com
  18. BucketName: fun-local-test
  • 使用fun deploy 即看到运行成功。

【20181205】阿里云函数计算使用体验 - 图3

  • 登录阿里云函数计算后台,可以看到这个项目代码,可以线上修改配置。

思考:函数计算适合做什么用途?

  • 定时任务,如爬虫类。(图片转存、文字转存等)

  • pipeline类别,如接受A信息,转存到B信息及格式。根据if,else等来分类的任务。

  • 微信,钉钉等公众号的后端(Flask),免去搭建服务器。

  • 可以一个函数就解决的任务与项目,特别简单的项目。

  • 阿里云官方函数计算后台提供Flask-web类型的函数计算模块,可以快速搭建外网api可访问的接口与页面。

  • 似乎不适合多轮交互的情况(也可能是我不知道)。

威胁建模与安全方面考虑:

  • 通过这种方式,若是允许外网访问(触发器允许HTTP),似乎易受CSRF、越权漏洞攻击。

  • 近期阿里云函数计算更新模块,所有HTTP通过浏览器访问会默认变成将Response下载到本地,因此不会存在XSS风险。(除非本地又渲染了)

  • Json劫持模块还没测试,如果返回值写的是Jsonp,那么因写法太灵活,也是易受Json劫持漏洞攻击的。

  • 如果以一个serverless租户的身份写扫描器去扫描宿主机,会不会影响到其他租户的安全与稳定性?(待测试)

参考资料