天天看點

部署基于 python wsgi web 架構的工程到函數計算

本文旨在介紹如何将基于 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 響應後再發送給用戶端,如下圖所示:

部署基于 python wsgi web 架構的工程到函數計算

如果想了解更多關于WSGI的内容,請查閱

函數計算遇見 WSGI

FC python runtime 是 server,使用者的函數是 application,applicaiton 可以完全自己實作,也可以基于 wsgi 的 web 架構上進行函數開發,具體可以參考

HTTP 觸發器 Python-Runtime

, 本文主要講解如何運用 python wsgi 的 web 架構開發的工程部署到函數計算環境中。

Frameworks that run on WSGI

目前有很不少 Frameworks 是基于 WSGI 協定的,比如 Flask,Django 等,具體可以參考

, 本文講解兩個架構的的工程如何部署在函數計算中:

函數計算部署flask工程

本示例中我們會部署一個簡單的基于 flask 的工程到函數計算中,runtime 是基于python2.7 , ( python3 步驟一樣),具體步驟如下:

完整的示例代碼包可以點選 flask-demo

下載下傳 (如果顯示 AccessDenied,請在位址欄敲下回車~)。

代碼包目錄結構示意圖:

部署基于 python wsgi web 架構的工程到函數計算
1. 利用

pip install -t . flask

指令将flask lib下載下傳到和代碼在同一個目錄中,如下圖所示:
部署基于 python wsgi web 架構的工程到函數計算

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):
    # 如果沒有使用自定義域名
    if environ['fc.request_uri'].startswith("/2016-08-15/proxy"):
      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
    部署基于 python wsgi web 架構的工程到函數計算
  • Sign In
    部署基于 python wsgi web 架構的工程到函數計算
  • 送出正确的使用者名和密碼
    部署基于 python wsgi web 架構的工程到函數計算
  • 送出錯誤的使用者名和密碼
    部署基于 python wsgi web 架構的工程到函數計算

函數計算部署 django 工程

本示例中我們會部署一個簡單的基于 django 的工程到函數計算中,runtime 是基于python 2.7 , (python 3 步驟一樣), 具體步驟如下:

django-demo 下載下傳(如果顯示 AccessDenied ,請在位址欄敲下回車哈~)。
部署基于 python wsgi web 架構的工程到函數計算

pip install -t . django

指令将 django lib 下載下傳到和代碼在同一個目錄中。
# 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):
      # 如果沒有使用自定義域名
    if environ['fc.request_uri'].startswith("/2016-08-15/proxy"):
      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) 通路函數,打開浏覽器可以看到如下效果:

12345

cn-shanghai

, serviceName 為

fcService

, functionName 為

test

, 那麼通路函數的 url 就是

12345.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/fcService/test/

  • home
部署基于 python wsgi web 架構的工程到函數計算
  • signin_form
部署基于 python wsgi web 架構的工程到函數計算
部署基于 python wsgi web 架構的工程到函數計算
部署基于 python wsgi web 架構的工程到函數計算