天天看點

開發函數計算的正确姿勢 —— 安裝第三方依賴

前言

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

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

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

fun install: fun install 是 fun 工具的一個子指令,用于安裝 pip 和 apt 依賴,提供了指令行接口和 fun.yml 描述檔案兩種形式。

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

函數計算安裝第三方依賴一大痛點,文章

函數計算安裝依賴庫方法小結

對可能會遇到的問題和解決方法做了細緻總結,fun install 是基于之前的經驗和成果将最佳實踐的方法固化到工具中,友善使用者便捷的安裝依賴。

初始化

使用

fun install init

在目前目錄初始化一個 fun.yml 檔案。(這一步不是必須的,如果您打算手寫 fun.yml 然後通過 fun install 指令批量執行 task,init 是一個好的開始。)

在函數計算項目根目錄執行

fun install init

指令,選擇一個 runtime。

$ fun install init
? Select runtime (Use arrow keys)
 python2.7
  python3
  nodejs6
  nodejs8
  java8
  php7.2           

然後會在目前目錄生成一個 fun.yml 檔案,内容如下:

runtime: python2.7
tasks: []           

安裝 pip 包依賴

下面的指令安裝 python 的 tensorflow 包

$ fun install --runtime python2.7 --package-type pip tensorflow
skip pulling image aliyunfc/runtime-python2.7:build-1.2.0...
Task => [UNNAMED]
     => PYTHONUSERBASE=/code/.fun/python pip install --user tensorflow           

說明

  • --runtime

    指定 runtime,如果已經初始化 fun.yml 檔案, 由于 fun.yml 裡聲明了 runtime ,該選項可以省略。
  • --package-type

    指定安裝依賴的類型,pip 和 apt 是目前的兩個可選值。
  • tensorflow 是一個 pip 包名。

指令執行在 fc-docker 提供的 container 中,容器内部執行的指令會逐行列印出來,比如上面指令中内部真實執行了

PYTHONUSERBASE=/code/.fun/python pip install --user tensorflow

指令。

安裝完成以後會在生成一個 .fun 目錄, 可執行檔案會被放置到

.fun/python/bin

目錄下,庫檔案放置到

.fun/python/lib/python2.7/site-packages

下。

.fun
└── python
    ├── bin
    │   ├── freeze_graph
    │   ├── markdown_py
    │   ├── pbr
    │   ├── saved_model_cli
    │   ├── tensorboard
    │   ├── tflite_convert
    │   ├── toco
    │   └── toco_from_protos
    └── lib
        └── python2.7
            └── site-packages
                ├── tensorboard
                ├── tensorboard-1.12.2.dist-info
                ├── tensorflow
                ├── tensorflow-1.12.0.dist-info
                ├── termcolor-1.1.0.dist-info
                ...           

相比之前的

pip install -t . <package-name>

方式,fun install 安裝檔案的存放位置更有組織,依賴檔案和代碼檔案分離開了,便于清理、拆分後借助 OSS 或 NAS 初始化依賴檔案。但是組織過後也帶來一個新問題,需要使用者自定義環境變量庫檔案才能被程式找到。為了友善使用者使用提供了一個

fun install env

列印出必要的環境變量。

$ fun install env
LD_LIBRARY_PATH=/code/.fun/root/usr/lib/x86_64-linux-gnu:/code:/code/lib:/usr/local/lib
PATH=/code/.fun/root/usr/local/bin:/code/.fun/root/usr/local/sbin:/code/.fun/root/usr/bin:/code/.fun/root/usr/sbin:/code/.fun/root/sbin:/code/.fun/root/bin:/code/.fun/python/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin
PYTHONUSERBASE=/code/.fun/python           

關于如果設定函數計算的環境變量,請參考

https://help.aliyun.com/document_detail/69777.html

。如果您使用

fun local

fun deploy

進行調試和部署,您無需關注環境變量問題,已經幫您設定好了。

使用 --save 持久化

install 指令加上 --save 參數,會将指令持久化成 task 儲存到 fun.yml 檔案中。

$ fun install --runtime python2.7 --package-type pip --save tensorflow
skip pulling image aliyunfc/runtime-python2.7:build-1.2.0...
Task => [UNNAMED]
     => PYTHONUSERBASE=/code/.fun/python pip install --user tensorflow           

上面的指令多加了一行

--save

參數,檢視 fun.yml 内容:

runtime: python2.7
tasks:
  - pip: tensorflow
    local: true           

之後直接執行

fun install

不帶參數,就可以依次執行任務。

$ fun install
skip pulling image aliyunfc/runtime-python2.7:build-1.2.0...
Task => [UNNAMED]
     => PYTHONUSERBASE=/code/.fun/python pip install --user tensorflow           

使用 -v 顯示詳細日志

$ fun install -v
skip pulling image aliyunfc/runtime-python3.6:build-1.2.0...
Task => [UNNAMED]
     => apt-get update (if need)
Ign http://mirrors.aliyun.com stretch InRelease
Get:1 http://mirrors.aliyun.com stretch-updates InRelease [91.0 kB]
Get:2 http://mirrors.aliyun.com stretch-backports InRelease [91.8 kB]
Get:3 http://mirrors.aliyun.com stretch/updates InRelease [94.3 kB]
Hit http://mirrors.aliyun.com stretch Release.gpg
Hit http://mirrors.aliyun.com stretch Release
Get:4 http://mirrors.aliyun.com stretch-updates/main Sources [3911 B]
....           

安裝 apt 包依賴

函數計算使用 apt-get 安裝依賴是另一類常見的安裝問題,使用 fun install 也可以友善的安裝。

$ fun install --runtime python3 --package-type apt libzbar0
skip pulling image aliyunfc/runtime-python3.6:build-1.2.0...
Task => [UNNAMED]
     => apt-get update (if need)
     => apt-get install -y -d -o=dir::cache=/code/.fun/tmp libzbar0
     => bash -c 'for f in $(ls /code/.fun/tmp/archives/*.deb); do dpkg -x $f /code/.fun/root; done;'
     => bash -c 'rm -rf /code/.fun/tmp/archives'           

使用方法及其參數和 pip 包依賴類似,隻需要将

--package-type

設定成

apt

, 包名使用日常 apt-get 可以安裝的 deb 包名即可。

使用 fun.yml

fun.yml 由一組 task 組成,執行 fun install 指令時會依次執行 task ,達到批量安裝的效果。

fun.yml 的檔案格式如下

runtime: python3
tasks:
  - name: install libzbar0
      apt: libzbar0
    local: true
  - name install Pillow by pip
      pip: Pillow
    local: true
  - name: just test shell task
      shell: echo '111' > 1.txt           

runtime

是必填的字段。目前 task 有三種類型:apt, pip 和 shell。fun.yml 檔案放置在 template.yml 檔案中函數 codeUri 指向的目錄,如果 template.yml 裡聲明了多個函數,并且放置在不同的 codeUri 目錄,需要建立多個 fun.yml 檔案。

所有 task 的 name 字段是可選的,沒有 name 字段的時候執行的時候會輸出為

Task => [UNNAMED]           

apt/pip task

apt 和 pip 類型的 task 都是 install task 的子類型,描述格式類似

name: install libzbar0
apt: libzbar0
local: true           

上面的 task 描述與下面的指令是等價的

fun install --package-type apt libzbar0           

在使用 fun install 安裝的過程中,使用

--save

參數可以在目前目錄的 fun.yml 檔案中生成上面 task 的描述結構。

local

字段預設為 true,表示依賴會被裝在目前目錄的 .fun 子目錄下,打包 zip 的時候回一并打包進去。設定為 false,依賴安裝到系統目錄,這種情況一般用于編譯依賴,比如某個執行檔案或者庫是編譯或者建構期需要的,運作期不要,那可以設定

local: false

,打包的時候會被忽略,不影響最終 zip 包的檔案尺寸。

shell task

shell 類型的 task 是為基于源碼編碼的安裝場景設計的。

name: install from source
shell: ./autogen.sh --disable-report-builder --disable-lpsolve --disable-coinmp           

示例

下面是一個 python3 實作簡單二維碼識别程式部署到函數計算的例子。源碼位于

https://github.com/aliyun/fun/tree/master/examples/install/pyzbar_example

本例子使用 pip 的 pyzbar 庫進行二維碼識别,pyzbar 依賴 apt-get 安裝的 libzbar0 庫。裝載圖檔需要 pip 的 Pillow 庫。是以 fun.yml 的檔案描述如下

runtime: python3
tasks:
  - apt: libzbar0
    local: true
  - pip: Pillow
    local: true
  - pip: pyzbar
    local: true           

使用 fun install 安裝依賴

$ fun install
skip pulling image aliyunfc/runtime-python3.6:build-1.2.0...
Task => [UNNAMED]
     => apt-get update (if need)
     => apt-get install -y -d -o=dir::cache=/code/.fun/tmp libzbar0
     => bash -c 'for f in $(ls /code/.fun/tmp/archives/*.deb); do dpkg -x $f /code/.fun/root; done;'
     => bash -c 'rm -rf /code/.fun/tmp/archives'
Task => [UNNAMED]
     => PYTHONUSERBASE=/code/.fun/python pip install --user Pillow
Task => [UNNAMED]
     => PYTHONUSERBASE=/code/.fun/python pip install --user pyzbar           

template.yml 檔案内容如下

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  pyzbar-srv:
    Type: 'Aliyun::Serverless::Service'
    pyzbar-fun:
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: index.handler
        Runtime: python3
        Timeout: 60
        MemorySize: 128
        CodeUri: .           

index.py 檔案内容如下:

from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol
from PIL import Image

def handler(event, context):
    img = Image.open('./qrcode.png')
    return decode(img, symbols=[ZBarSymbol.QRCODE])[0].data           

使用 fun local 在本地執行

fun local invoke pyzbar-fun
skip pulling image aliyunfc/runtime-python3.6:1.2.0...
Thalassiodracon

RequestId: 964980d1-1f1b-4f91-bfd8-eadd26a307b3          Billed Duration: 630 ms         Memory Size: 1998 MB    Max Memory Used: 32 MB           

Thalassiodracon

即為識别後的輸出結果。

小結

本文介紹了 fun 工具的一個新特性 fun install ,使用 fun install 可以友善的安裝 apt 和 pip 軟體包,對于多次安裝的工程化需求可以考慮将安裝步驟持久化為 fun.yml 檔案. fun.yml 檔案提供了比指令行更多的功能,可以編寫 shell 類型的 task,以支援源碼安裝的場景。可以通過設定

local: false

将依賴安裝的系統目錄,以解決編譯依賴而非運作依賴的情況。