天天看點

Serverless 實戰 —— 移植 spring-petclinic 到函數計算

前言

首先介紹下在本文出現的幾個比較重要的概念:

函數計算(Function Compute):函數計算是一個事件驅動的服務,通過函數計算,使用者無需管理伺服器等運作情況,隻需編寫代碼并上傳。函數計算準備計算資源,并以彈性伸縮的方式運作使用者代碼,而使用者隻需根據實際代碼運作所消耗的資源進行付費。函數計算更多資訊 參考

Funcraft:Funcraft 是一個用于支援 Serverless 應用部署的工具,能幫助您便捷地管理函數計算、API 網關、日志服務等資源。它通過一個資源配置檔案(template.yml),協助您進行開發、建構、部署操作。Fun 的更多文檔

spring-petclinic: Petclinic 是一個 Spring Boot 、Spring MVC 和 Spring Data 結合使用的示例項目,是學習 Spring Boot 經典案例。

備注: 本文介紹的技巧需要 Funcraft 版本大于等于 3.1.0 。

環境準備

該教程依賴如下工具:

  • Funcraft
  • Git
  • Maven

Funcraft 的

安裝文檔

裡介紹的方法将 Funcraft 安裝到本機。安裝完成後,可以執行

fun --version

檢查 Fun 是否安裝成功。

初始化項目

首先在本地運作 Petclinic 項目,Petclinic 是一個使用 Maven 建構的 Spring Boot 應用。您可以使用指令行建構出 Jar 檔案并在本地運作。

git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic
./mvnw package
java -jar target/*.jar           

然後您可以通路本地位址:

http://localhost:8080/
Serverless 實戰 —— 移植 spring-petclinic 到函數計算

移植到函數計算

本示例中,我們打算使用函數計算的

Custom Runtime

來移植 Petclinic 項目。顧名思義, Custom Runtime 就是自定義的執行環境, 使用者基于 Custom Runtime 可以完成以下目标:

  • 可以随心所欲持定制個性化語言執行環境(例如 Golang、Lua、Ruby)以及各種語言的小版本(例如Python3.7、Nodejs12 )等,打造屬于自己的自定義 Runtime
  • 現有的 Web 應用或基于傳統開發 Web 項目基本不用做任何改造,即可将項目一鍵遷移到函數計算平台

在閱讀 Custom Runtime 的技術文檔後,我們要将 Petclinic 移植到函數計算,需要解決如下兩個問題:

  1. 通過建立函數并啟動服務
  2. 将 Petclinic 啟動在 9000 端口

于是在 spring-petclinic 項目根目錄新增如下三個檔案:

  • template.yml 用于聲明函數和 HTTP Trigger
  • bootstrap 用于啟動服務
  • .funignore 用于忽略運作時無關的檔案,減小部署檔案的尺寸。

template.yml

template.yml 檔案内容如下:

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  springboot: # service name
    Type: 'Aliyun::Serverless::Service'
    Properties:
      Description: This is a FC service for springboot
    petclinic: # function name
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: com.example.demo.DemoApplication::main
        Runtime: custom
        CodeUri: ./
        MemorySize: 1024
        Timeout: 15
      Events:
        httpTrigger:
          Type: HTTP
          Properties:
            AuthType: ANONYMOUS
            Methods: ['HEAD', 'GET', 'POST', 'PUT', 'DELETE']
  petclinic.codelife.me: # domain name
    Type: 'Aliyun::Serverless::CustomDomain'
    Properties:
      Protocol: HTTP
      RouteConfig:
        routes:
          '/*':
            ServiceName: springboot
            FunctionName: petclinic                       

其中 Runtime 指定為 custom。Handler 對于 custom 類型的運作時是多餘的,任意寫一個符合文法的就 OK 了。這裡還注冊了一個 HTTP 類型的觸發器,開啟了匿名驗證,支援 5 種常見的 HTTP 方法。

bootstrap

bootstrap 檔案是 custom 運作時約定的引導檔案可以是二進制也可以是腳本,打包上傳的時要保證該檔案具備可執行權限。bootstrap 檔案内容如下:

#!/usr/bin/env bash
java  -Dserver.port=9000 \
        -jar target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar           

其中

  • -Dserver.port=9000

    将 Spring Boot 的啟動端口改為 9000
  • -jar target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar

    指定要啟動的 jar 包,這個 jar 是 spring-petclinic 項目通過 maven 建構的結果檔案。

.funignore

.funignore 檔案的作用是 fun deploy 的時候會忽略掉運作時不相關的檔案(比如建構時依賴,某些編譯過程産物,源碼檔案等)以減少打封包件的體積。

.idea/
.mvn/
.vscode/
push-to-pws/
src/
*.yml
mvnw*
*.xml
*.md
target/*
!target/*.jar           

本地預覽

$ fun local start petclinic.codelife.me
using template: template.yml
CustomDomain petclinic.codelife.me of springboot/petclinic was registered
        url: http://localhost:8000/*
        methods: [ 'HEAD', 'GET', 'POST', 'PUT', 'DELETE' ]
        authType: ANONYMOUS

function compute app listening on port 8000!           

這裡

fun local start + domain_name

,會在本地端口啟動該 domain 的路徑映射關系,免去直接調試函數時長長的 contextPath ( /2016-08-15/proxy/springboot/petclinic/ ) ,注意該功能依賴 3.1.0 以上版本的 funcraft。

然後浏覽器打開

http://localhost:8000/

即可本地預覽 petclinic 應用。

打包并部署

$ mvn package -Dmaven.test.skip=true && fun deploy

....
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  30.612 s
[INFO] Finished at: 2019-11-01T11:23:40+08:00
[INFO] ------------------------------------------------------------------------
using template: template.yml
using region: cn-hongkong
using accountId: ***********4733
using accessKeyId: ***********EUz3
using timeout: 600

Waiting for service springboot to be deployed...
        Waiting for function petclinic to be deployed...
                Waiting for packaging function petclinic code...
                The function petclinic has been packaged. A total of 12 files files were compressed and the final size was 39.91 MB
                Waiting for HTTP trigger httpTrigger to be deployed...
                triggerName: httpTrigger
                methods: HEAD,GET,POST,PUT,DELETE
                url: https://1751705494334733.cn-hongkong.fc.aliyuncs.com/2016-08-15/proxy/springboot/petclinic/
                function httpTrigger deploy success
        function petclinic deploy success
service springboot deploy success

Waiting for custom domain petclinic.codelife.me to be deployed...
custom domain petclinic.codelife.me deploy success           

這裡選擇了 cn-hongkong region,這是因為要想正常的顯示 http 服務,需要綁定域名,否則 html 檔案會預設下載下傳而不是顯示。而海外的 region 可以免去域名備份的繁瑣事宜。

其中域名 petclinic.codelife.me 請換成您自己的,并将 DNS 的 cname 記錄指向

<accountID>.<region>.fc.aliyuncs.com

浏覽器打開

http://petclinic.codelife.me
Serverless 實戰 —— 移植 spring-petclinic 到函數計算

FAQ

  1. 如何使用 MySQL 資料庫

spring-petclinic 預設使用的是記憶體資料 hsqldb,而函數之間記憶體不共享,是以在多次請求可能出現通路到不同的函數執行個體,出現資料不一緻的情況。對于真實的系統可以通過給

函數配置 VPC

,然後建立一個阿裡雲的

RDS

服務,所有的函數都通路同一個 RDS 服務。

  1. Aliyun Serverless VSCode Extension
  2. Custom Runtime 使用者手冊
  3. 項目源碼