阿里云 Serverless Computing + 关注
手机版

部署基于 python wsgi web 框架的工程到函数计算

  1. 云栖社区>
  2. 阿里云 Serverless Computing>
  3. 博客>
  4. 正文

部署基于 python wsgi web 框架的工程到函数计算

cici是夏莞 2018-05-19 15:24:34 浏览2768 评论3

摘要: 本文旨在介绍如何将基于 WSGI web 框架构建的工程部署到函数计算 python runtime 的具体操作过程,在介绍操作过程之前,先了解几个概念。 相关概念导读 函数计算 HTTP 触发器 HTTP 触发器是众多函数计算触发器中的一种,通过发送 HTTP 请求触发函数执行。

本文旨在介绍如何将基于 WSGI web 框架构建的工程部署到函数计算 python runtime 的具体操作过程,在介绍操作过程之前,先了解几个概念。

相关概念导读

函数计算 HTTP 触发器

HTTP 触发器是众多函数计算触发器中的一种,通过发送 HTTP 请求触发函数执行。主要适用于快速构建 Web 服务等场景。HTTP 触发器支持 HEAD、POST、PUT、GET 和 DELETE 方式触发函数。具体详情可以参考 HTTP 触发器

什么是WSGI

WSGI的全称是 Web Server Gateway Interface,简单翻译就是 Web 服务器网关接口。具体来说,WSGI 是一个规范,定义了 Web 服务器如何与 Python 应用程序进行交互,使得使用 Python 写的 Web 应用程序可以和 Web 服务器对接起来。最新官方版本是在 Python 的 PEP-3333 定义的。

WSGI 如何工作

在 WSGI 中定义了两个角色,Web 服务器端称为 server 或者 gateway,应用程序端称为 application 或者 framework(因为 WSGI 的应用程序端的规范一般都是由具体的框架来实现的,下面统一使用 server 和 application 这两个术语,WSGI 相当于是 Web 服务器和 Python 应用程序之间的桥梁。
server 端会先收到用户的请求,然后会根据规范的要求调用 application 端,然后 server 会将调用 application 返回的结果封装成 HTTP 响应后再发送给客户端,如下图所示:

wsgi-fc

如果想了解更多关于WSGI的内容,请查阅 PEP-3333

函数计算遇见 WSGI

FC python runtime 是 server,用户的函数是 application,applicaiton 可以完全自己实现,也可以基于 wsgi 的 web 框架上进行函数开发,具体可以参考 HTTP 触发器 Python-Runtime , 本文主要讲解如何运用 python wsgi 的 web 框架开发的工程部署到函数计算环境中。

Frameworks that run on WSGI

目前有很不少 Frameworks 是基于 WSGI 协议的,比如 Flask,Django 等,具体可以参考 Frameworks that run on WSGI, 本文讲解两个框架的的工程如何部署在函数计算中:

函数计算部署flask工程

本示例中我们会部署一个简单的基于 flask 的工程到函数计算中,runtime 是基于python2.7 , ( python3 步骤一样),具体步骤如下:

完整的示例代码包可以点击 flask-demo 下载 (如果显示 AccessDenied,请在地址栏敲下回车~)。
代码包目录结构示意图:
f

1. 利用pip install -t . flask 命令将flask lib下载到和代码在同一个目录中,如下图所示:

flask
main.py 代码如下:

  #!/usr/bin/env python
# coding=utf-8
from flask import Flask
from flask import request
from flask import make_response
import urlparse 

app = Flask(__name__)

base_path = ''

@app.route('/', methods=['GET', 'POST'])
def home():
    resp = make_response('<h1>Home<h1>', 200)
    return resp

@app.route('/signin', methods=['GET'])
def signin_form():
    html = '''<form action="/signin" method="post">
         <p><input name="username"></p>
         <p><input name="password" type="password"></p>
         <p><button type="submit">Sign In</button></p>
         </form>'''

    resp = make_response(html, 200)
    return resp

@app.route('/signin', methods=['POST'])
def signin():
    if request.form['username']=='admin' and request.form['password']=='password':
        html = '<h3>Hello, admin!</h3>'
    else:
        html = '<h3>Bad username or password.</h3>'
    resp = make_response(html, 200)
    return resp

def handler(environ, start_response):

    parsed_tuple = urlparse.urlparse(environ['fc.request_uri'])
    li = parsed_tuple.path.split('/')
    global base_path
    if not base_path:
        base_path = "/".join(li[0:5])

    context = environ['fc.context']
    environ['HTTP_HOST'] = '{}.{}.fc.aliyuncs.com'.format(context.account_id, context.region)
    environ['SCRIPT_NAME'] = base_path + '/'
    return app(environ, start_response)
2. 执行下面的脚本,创建对应的 service,function 和 HTTP 触发器
  #!/usr/bin/env python
  # coding=utf-8
  import fc2
  client = fc2.Client(
      endpoint='<your endpoint>', # your endpoint
      accessKeyID='<your ak_id>', # your ak_id
      accessKeySecret='<your ak_secret>' # your ak_secret
      )

  service_name = 'flask-demo'
  funciton_name = 'test'
  trigger_name = "my_trigger"

  client.create_service(service_name)
  
  client.create_function(
      service_name, funciton_name, 'python2.7',  'main.handler',
      codeDir='./flaskDir/')

  res = client.get_function(service_name, funciton_name)
  print res.data
  trigger_config = {
              "authType" : "anonymous",
              "methods" : ["GET", "POST"],
      }
  client.create_trigger(service_name, funciton_name , trigger_name, "http", trigger_config, "dummy_arn", "")
  print client.get_trigger(service_name,  funciton_name, trigger_name).data
3. 脚本执行成功后,给函数创建了 HTTP 触发器,就可以通过 url ($(account-id).$(region).fc.aliyuncs.com/2016-08-15/proxy/serviceName/functionName/action?hello=world) 访问函数,打开浏览器可以看到如下效果:

注:如果 account-id 为 12345 ,region 为 cn-shanghai , serviceName为flask-demo, functionName 为test, 那么访问函数的 url 就是 12345.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/flask-demo/test/

  • Home
    p1
  • Sign In
    p2
  • 提交正确的用户名和密码
    p3
  • 提交错误的用户名和密码
    p4

函数计算部署 django 工程

本示例中我们会部署一个简单的基于 django 的工程到函数计算中,runtime 是基于python 2.7 , (python 3 步骤一样), 具体步骤如下:

完整的示例代码包可以点击 django-demo 下载(如果显示 AccessDenied ,请在地址栏敲下回车哈~)。
代码包目录结构示意图:
d

1. 利用pip install -t . django 命令将 django lib 下载到和代码在同一个目录中。

main.py 代码如下:

# coding=utf-8
import sys
import os

# load local django
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "HelloWorld"))

import django

print (django.__version__)

base_path = None

from HelloWorld.wsgi import application

def handler(environ, start_response):
    import urlparse    
    parsed_tuple = urlparse.urlparse(environ['fc.request_uri'])
    li = parsed_tuple.path.split('/')
    global base_path
    if not base_path:
        base_path = "/".join(li[0:5])

    context = environ['fc.context']
    environ['HTTP_HOST'] = '{}.{}.fc.aliyuncs.com'.format(context.account_id, context.region)
    environ['SCRIPT_NAME'] = base_path + '/'

    return application(environ, start_response)  
2. HelloWorld 工程目录如下:
  |____HelloWorld
  | |______init__.py
  | |____view.py
  | |____settings.py # 视图文件
  | |____urls.py # 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
  | |____wsgi.py 
  |____db.sqlite3
  |____manage.py

urls.py 代码如下:

  from django.conf.urls import url
  from django.contrib import admin
  from . import view

  urlpatterns = [
      url(r'^admin/', admin.site.urls),
      url(r'^$', view.home),
      url(r'^signin$', view.signin),
      url(r'^signin_form$', view.signin_form),
  ]

view.py 代码如下:

# coding=utf-8
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

def home(request):
    return HttpResponse("<h1>Home</h1>", status=200)

def signin_form(request):
    # action url 中的service_name,function_name need replace
    html = '''<form action="/signin" method="post">
         <p><input name="username"></p>
         <p><input name="password" type="password"></p>
         <p><button type="submit">Sign In</button></p>
         </form>'''

    resp = HttpResponse(html,status=200)
    return resp

@csrf_exempt
def signin(request):
    if request.POST['username']=='admin' and request.POST['password']=='password':
        html = '<h3>Hello, admin!</h3>'
    else:
        html = '<h3>Bad username or password.</h3>'
    resp = HttpResponse(html, status=200)
    return resp
3. 执行下面的脚本,创建对应的 service ,function 和 HTTP 触发器
  #!/usr/bin/env python
  # coding=utf-8
  import fc2
  client = fc2.Client(
      endpoint='<your endpoint>', # your endpoint
      accessKeyID='<your ak_id>', # your ak_id
      accessKeySecret='<your ak_secret>' # your ak_secret
      )

  service_name = 'django-demo'
  funciton_name = 'test'
  trigger_name = "my_trigger"

  client.create_service(service_name)
  
  client.create_function(
      service_name, funciton_name, 'python2.7',  'main.handler',
      codeDir='./djangoDir/')

  res = client.get_function(service_name, funciton_name)
  print res.data
  trigger_config = {
              "authType" : "anonymous",
              "methods" : ["GET", "POST"],
      }
  client.create_trigger(service_name, funciton_name , trigger_name, "http", trigger_config, "dummy_arn", "")
  print client.get_trigger(service_name,  funciton_name, trigger_name).data
4. 脚本执行成功后,给函数创建了 HTTP 触发器,就可以通过 url ($(account-id).$(region).fc.aliyuncs.com/2016-08-15/proxy/serviceName/functionName/action?hello=world) 访问函数,打开浏览器可以看到如下效果:

注:如果 account-id 为 12345,region 为 cn-shanghai , serviceName 为 fcService , functionName 为 test , 那么访问函数的 url 就是 12345.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fcService/test/

  • home

d1

  • signin_form

d2

  • 提交正确的用户名和密码

d3

  • 提交错误的用户名和密码

d4

【云栖快讯】一站式开发者服务,海量学习资源免费学  详情请点击

网友评论