三十分鐘快速搭建serverless網盤服務

HitTwice發表於2018-07-25

作者:清宵 文章來源:雲棲社群

原文連結: https://yq.aliyun.com/articles/613861?spm=a2c4e.11153940.bloghomeflow.289.603b291aakVqfZ


前言

函式計算支援以無伺服器架構快速構建企業和開發者的軟體系統,以其全託管事件觸發模式、超彈性伸縮以及低廉的計費方式,相對於傳統伺服器架構,在開發效能和運維模式上都取得了明顯優勢。另外還提供了各種服務間的觸發功能,作為雲端各種產品的黏合劑,適用於各種應用場景。

本節,將帶領大家利用函式計算,快速搭建一個功能完整的網盤服務。網盤服務的專案見(即將開源):

網盤服務簡介

功能

網盤服務功能詳細介紹請參考文章 網盤服務系統 和相應的專案  repo  。

本文重點不是介紹網盤功能,所以,請大家通過已經搭建好的 網盤 demo  自行體驗,這裡不做過多贅述。

網盤系統無伺服器架構

image.png

網盤服務功能集較多,這裡就以上傳檔案功能為例,展現其網盤的實現架構。

網盤服務自身模組以及資源依賴

網盤服務的模組實現分為三個部分,如下圖所示:

image.png

  • apis : 提供了網盤的 API 介面功能,這部分功能是 serverless 架構實現的核心,使用 FC+API Gateway 架構模式實現主體功能,如上圖無伺服器架構圖中展現的。

  • Site : 提供了網盤例項的管理控制檯,還有對應的網盤宣傳、使用文件以及 api 文件等。

  • UI : 提供使用者使用和維護網盤的客戶端。

這裡,Site 和 UI 這兩個子模組的實現都是靜態網站模式,可以直接使用 OSS bucket 的 website 特性實現。為了簡化整個部署流程和自動化資源編排過程,將 Site 和 UI 的部署方式也整合到 FC 中統一維護,見下面的詳細的部署流程描述。

網盤服務功能後臺依賴資源羅列如下:

image.png

fun 介紹

fun  是  have Fun with Serverless  的縮寫,是一款 Serverless 應用開發的工具,可以幫助使用者定義函式計算、API 閘道器、日誌服務等資源,旨在與阿里雲 ROS 相容(儘管到目前為止 ROS 還不支援函式計算。但是,fun 作為 ROS 的子集是我們的目標)。

使用 fun 能夠解決複雜服務的資源依賴維護問題,能夠快速部署、更新,簡化資源編排運維。針對該網盤服務的眾多資源依賴,使用 fun 能夠很方便、迅速的解決各種資源的搭建和維護過程。下面我們將演示如何使用 fun 部署網盤服務系統。

具體部署過程

網盤服務目前實現了三種身份登入驗證功能: 釘釘、支付寶和特殊賬號密碼(用於測試)。
因為釘釘、支付寶登入方式需要走一些申請流程獲取對應的 appID 和 appSecret ,這裡為了簡化流程,我們僅僅使用特殊賬號密碼方式。

部署的具體步驟如下:

  1. 準備工作:

  • 雲賬號準備

  • 程式碼準備

  • fun 下載和配置

  • 配置 fun 的 template.yml

  • 部署 template.yml 定義資源,獲取二級域名等資訊

  • 更新 apis function

  • 部署 Site ,建立 groupID 例項

  • 部署 UI,配置 storage 例項

  • 準備工作

    雲賬號準備

    首先,準備一個能夠登入 阿里雲官網 的雲賬號, 登入控制檯獲取這個賬號的 UID ( accountID )、 accessKeyID 和 accessKeySecret 。部署演示使用的資源全部在華東 2 ( cn-shanghai )。也可以使用其他 region 資源,但是必須保證所有的服務都在同一個 region 中。

    然後開通如下服務:
    image.png

    程式碼準備

    函式計算支援 多種程式碼上傳方式 ,這裡統一打包成 zip 檔案,並上傳到該雲賬號的某個 bucket 上(使用者自行在華東 2 建立即可)。參考程式碼如下連線:

    • apis.zip

      • 注意: apis 使用 nodejs 實現,在打包之前需要執行  tnpm i  命令安裝專案依賴。

      • 解壓後目錄結構如下:

        
          |-- controllers # 控制層,主要邏輯
        
         |-- routes        # api路由
         |-- services     # 公共方法,包含呼叫各個雲產品的方法
         |-- utils    
         |-- models
         |-- node_modules   # 專案依賴
         |-- index.js     # 服務入口
         |-- conf.js       # config 配置
         |-- package.json
    • site.zip

      
          |-- deploy.py   # 部署函式
      
         |-- site             # site程式碼目錄
        |-- 404.html  
        |-- index.html    
        |-- docs
        |-- static  
      • 解壓後檔案結構如下:

    • ui.zip

      
          |-- deploy.py   # 部署函式
      
         |-- ui                # ui程式碼目錄
        |-- 404.html  
        |-- index.html    
        |-- static  
      • 解壓後檔案結構如下:

    fun 下載和配置

    如果您的系統已經安裝有 node 8 及以上的環境配置,那麼可以直接執行如下命令進行 fun 的安裝

    
    npm install @alicloud/fun -g
    

    如果您不想安裝 node 執行環境,那麼可以直接下載 fun 的 binary 執行,參考 各種環境 fun 的 release binary 

    然後設定 accountID、accessKeyID 和 accessKeySecret 以及 region,請使用準備步驟中的已經申請的雲賬號的引數進行配置,本示例中 region 選擇 cn-shanghai :

    
    # 如果是 binary ,執行 ./${binary_name} configfun config
    

    template.yml 配置

    template.yml 模板配置是本部署中最重要的部分,因為網盤服務依賴的資源項比較多(主要是 API閘道器資源和表格儲存資源), 建議 下載參考模板 直接修改,需要修改的內容已經使用 "TODO" 標識。

    template.yml 的語法規範參考  fun 規範文件

    這面具體介紹配置中的相關部分:

    
    ROSTemplateFormatVersion: '2015-09-01'Transform: 'Aliyun::Serverless-2018-04-03'Resources:
    
     apsaradrivefc:
       Type: 'Aliyun::Serverless::Service'
       Properties:
         Description: apsara drive
         Policies:
           - AliyunOTSFullAccess
           - AliyunSTSAssumeRoleAccess
           - AliyunOTSFullAccess
           - AliyunLogFullAccess
           - AliyunFCInvocationAccess
         LogConfig:
           Project: log-yunpan # TODO replace sls project name
           Logstore: fclog
       apis:
         Type: 'Aliyun::Serverless::Function'
         Properties:
           Description: apis
           Runtime: nodejs8
           Timeout: 30
           MemorySize: 128
           Handler: index.handler
           CodeUri: oss://apsaradrive-ui/download/apis.zip # TODO replaced the code location
           EnvironmentVariables: # TODO replace all the values which has 'TODO' tag
             ENV_CONFIG: '...'
       DeploySite: # function name which deploys site
            Type: 'Aliyun::Serverless::Function'
            Properties:
               Handler: 'deploy.my_handler'
               Runtime: 'python2.7'
               Description: 'function to deploy site'
               MemorySize: 128
               Timeout: 30
               CodeUri: 'oss://apsaradrive-ui/download/site.zip' # TODO replaced by the code location
       DeployUI: # function name witch deploys ui
            Type: 'Aliyun::Serverless::Function'
            Properties:
               Handler: 'deploy.my_handler'
               Runtime: 'python2.7'
               Description: 'function to deploy ui'
               MemorySize: 128
               Timeout: 30
               CodeUri: 'oss://apsaradrive-ui/download/ui.zip' # TODO replaced by the code location
     apsaradriveapis:
       Type: 'Aliyun::Serverless::Api'
       ...

     ts-yunpan: # TODO replace ots instance name
       Type: 'Aliyun::Serverless::TableStore'
       Properties:
         ClusterType: HYBRID
         Description: for apsaradrive
        ...  log-yunpan: # TODO replace sls project name
       Type: 'Aliyun::Serverless::Log'
       Properties:
         Description: log
       fclog:
         Type: 'Aliyun::Serverless::Log::Logstore'
         Properties:
           TTL: 10
           ShardCount: 1

    上面定義的 yaml 檔案主要做了以下幾件事情:

    1. 建立一個名為 'apsaradrivefc' 的 Service , 並且為這個 Service 建立一個具有  AliyunOTSFullAccess  、 AliyunSTSAssumeRoleAccess  、  AliyunOTSFullAccess  、  AliyunLogFullAccess  和 AliyunFCInvocationAccess  這幾大許可權的 Service Role。然後在這個 Service 下面建立三個 Function ,分別名為 'apis', 'DeploySite' 和 'DeployUI' 。

    2. 建立一個 LOG Project名為 'log-yunpan' , 然後在這個LOG Project 下面建立一個名為 'fclog' 的 Logstore ,作為 apsaradrivefc 這個 Service 下 Function 執行的日誌收集 store 。

    3. 建立一個名為 'ts-yunpan' 的 OTS Instance , 並且在這面生成各種 Table 。

    4. 建立一個 API 閘道器分組: apsaradriveapis ,以及其下的各種 API 定義。

    需要修改的內容:

    1. OTS Instance name: 全域性有三處地方需要修改,請統一,因為 OTS Instance 在 region 範圍全域性唯一,儘量保持命名唯一性,注意:  OTS Instance 命名規範

    2. LOG Project name: 全域性有兩處地方需要修改,請統一,因為 LOG Project在region範圍全域性唯一,儘量保持命名唯一性,注意:  LOG Project 命名規範

    3. 三處 CodeUri ,分別是 apis ,Site 和 UI 三個模組的程式碼位置,目前 template.yml 中的預設配置可用,可以不修改。

    4. apis 這個 Function 中的 EnvironmentVariables 屬性內部需要配置 API 閘道器分組的二級域名,因為當前步驟還沒有生成這個引數,這裡先不修改。

    部署 template.yml 定義資源

    直接執行如下命令:

    
    # 在 template.yml 所在目錄執行# 如果是 binary ,執行 ./${binary_name} configfun deploy
    

    這個時候,你可以在 OTS、SLS、RAM、API 閘道器和 FC 的控制檯上分別看到 fun 為網盤服務建立的各種資源,如下圖:

    image.png

    image.png

    image.png

    image.png

    更新 apis function

    從上一步 fun 的部署輸出日誌中可以找到對應的 API 閘道器分組的二級域名,如下:
    image.png

    修改 apis 這個 Function 中的 EnvironmentVariables 屬性內部需要配置 API 閘道器分組的二級域名,如下圖位置:

    image.png

    仍然執行如下命令,進行function的環境變數更新

    
    fun deploy
    

    至此,apis 模組部署完畢。

    部署 Site ,建立 groupID 例項

    Site 模組的實現其實就是一個靜態網站,我們可以利用 OSS 的靜態網站功能實現,步驟如下:

    1. 修改 static/global.js 中的 endpoint ( apis 的二級域名)和 ui_endpoint (如果在華東2, 那麼就是 ${uid}-ui.oss-cn-shanghai.aliyuncs.com )

    2. 建立 ${uid}-site 這個 bucket ,並設定為 public-read ACL

    3. 設定這個 bucket 的 website 的預設首頁和 404 頁面

    4. 上傳整個程式碼目錄

    將所有的步驟按照函式計算程式設計模型封裝如下,並建立為 Function: DeploySite 。封裝的 Function 實現如下所示:

    
    import oss2import loggingimport jsonimport shutilimport osimport sys
    

    reload(sys)
    sys.setdefaultencoding('utf8')from oss2.models import BucketWebsitedef delete_file(filePath):
       if os.path.exists(filePath):        for fileList in os.walk(filePath):            for name in fileList[2]:
                   os.remove(os.path.join(fileList[0],name))
           shutil.rmtree(filePath)def my_handler(event, context):
       # event is json string, parse it
       evt = json.loads(event)
       logger = logging.getLogger()
       endpoint = 'oss-cn-shanghai-internal.aliyuncs.com'
       creds = context.credentials
       auth = oss2.StsAuth(creds.accessKeyId, creds.accessKeySecret, creds.securityToken)    # create bucket for site named ${uid}-site, and set the ACL to public read
       bucket_name = '%s-site' % (evt['uid'])
       bucket = oss2.Bucket(auth, endpoint, bucket_name)    try:
           bucket.create_bucket(permission=oss2.BUCKET_ACL_PUBLIC_READ)    except oss2.exceptions.BucketAlreadyExists:
           logger.info("Bucket %s is already exist" % bucket_name)    # set static website
       bucket.put_bucket_website(BucketWebsite('index.html', '404.html'))   # modify the config for site
       code_dir = '/tmp/site/'
       delete_file(code_dir)
       shutil.copytree('/code/site/', code_dir)
       data = u''
       with open(os.path.join(code_dir, 'static/global.js')) as f:        for line in f.readlines():            if line.startswith('var endpoint = '):
                   line = u'var endpoint = \'%s\';\n' % (evt['endpoint'])            elif line.startswith('var ui_endpoint = '):
                   line = u'var ui_endpoint = \'http://%s.oss-cn-shanghai.aliyuncs.com\';\n' % (bucket_name)
               data += line    with open(os.path.join(code_dir, '/tmp/site/static/global.js'), "w") as f:
           f.writelines(data)    # put all the static code to the bucket
       for root,dirs,files in os.walk(code_dir):        for filespath in files:
               full_file_name = os.path.join(root,filespath)
               bucket.put_object_from_file(full_file_name[len(code_dir):], full_file_name)

    所以,只需要 Invoke 這個 Function 就能夠完成 Site 模組的部署。接下來演示一下 Invoke 的過程。

    登入函式計算控制檯,找到對應的 Function: DeploySite ,修改觸發事件,然後點選執行:

    image.png

    
    {  "uid": "replace with you accountID",  "endpoint": "replace with the SLD"}
    

    然後開啟 Site 頁面(如果 uid 為 apsaradrive 的話,那麼 Site 的 URL 為:  http://apsaradrive-site.oss-cn-shanghai.aliyuncs.com  ),登入之後(使用預設的 username: admin, password: 1234 登入),建立 group 例項。

    image.png

    部署 UI,配置 storage 例項

    部署 UI 的過程和 Site 類似,同樣在控制檯上找到 DeployUI,修改觸發事件,注意事件格式定義如下:

    
    {  "uid": "replace with you accountID",  "group_id": "replace with the group_id you just create in the Site web"
    
     "endpoint": "replace with the SLD"}

    點選執行之後,就可以通過剛剛 Site 頁面的 Group 入口進入 UI 頁面:
    image.png

    在 UI 頁面配置相關的 Storage :

    image.png

    接下來,您就可以對您的網盤進行各種檔案操作了。
    image.png
    image.png


    來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31473948/viewspace-2158721/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章