开发函数计算的正确姿势———为 PHP 运行时添加自定义扩展
PHP 語言提供了一種擴展機制(Extension),通過 PHP 擴展可以增強語法、調用 C/C++ 實現(xiàn)的庫函數(shù)以及優(yōu)化執(zhí)行性能。PHP 擴展是與平臺相關的動態(tài)鏈接庫,在 Linux 和 Mac 平臺是 .so 文件,在 Windows 平臺是 .dll 文件。由于函數(shù)計算的開發(fā)通常在 Mac 和 Windows 平臺,而運行時是 Linux(Debain)環(huán)境,所以為函數(shù)計算 PHP 運行時添加擴展會遇到由于動態(tài)鏈接庫平臺相關而導致要么本地無法調試,要么遠端無法運行的問題。本文介紹借助 Funcraft 工具提供的模擬環(huán)境進行 PHP 擴展的安裝、本地運行調試以及構建發(fā)布。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-GNmXgrBB-1582682697497)(https://data-analysis.cn-shanghai.log.aliyuncs.com/logstores/article-logs/track_ua.gif?APIVersion=0.6.0&title=%E5%BC%80%E5%8F%91%E5%87%BD%E6%95%B0%E8%AE%A1%E7%AE%97%E7%9A%84%E6%AD%A3%E7%A1%AE%E5%A7%BF%E5%8A%BF%20%E2%80%94%E2%80%94%20%E4%B8%BA%20PHP%20%E8%BF%90%E8%A1%8C%E6%97%B6%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%A9%E5%B1%95&author=%E5%80%9A%E8%B4%A4&src=article)]
準備工作
依賴工具
本項目是在 MacOS 下開發(fā)的,涉及到的工具是平臺無關的,對于 Linux 和 Windows 桌面系統(tǒng)應該也同樣適用。在開始本例之前請確保如下工具已經正確的安裝,更新到最新版本,并進行正確的配置。
- Docker
- Fun
Fun 和 Fcli 工具依賴于 docker 來模擬本地環(huán)境。
對于 MacOS 用戶可以使用 homebrew 進行安裝:
Windows 和 Linux 用戶安裝請參考:
安裝好后,記得先執(zhí)行 fun config 初始化一下配置。
注意, 如果你已經安裝過了 fun,確保 fun 的版本在 3.6.1 以上。
$ fun --version 3.6.1PHP 自定義擴展
在函數(shù)代碼目錄創(chuàng)建一個名為 extension 的目錄,并且將擴展對應的 .ini 和 .so 文件放在 extension 目錄下。例如,以下為一個 hello 的自定義擴展,假設該擴展里有一份 hello_world 函數(shù):
. |____extension | |____hello.ini | |____hello.so |____main.phphello.ini
extension=/code/extension/hello.somain.php
<?phpfunction handler($event, $context) {var_dump(extension_loaded('hello'));hello_world();return "ok";}上述方法是函數(shù)計算PHP 運行時提供的擴展方法。實踐過程中會碰到如下兩個問題:
完整示例
下面會基于借用 PHP 訪問 MongoDB 的例子來介紹如何借助于 Funcraft 進行 PHP 開發(fā),因為 composer 依賴 mongodb/mongodb 需要安裝 extension。
初始化項目
# 創(chuàng)建工程目錄并進入 $ mkdir fc-mongodb && cd fc-mongodb# 初始化 $ fun init event-php7.2通過 Funfile 安裝
我們在 Linux 平臺下通常會通過 pecl 工具進行 PHP 的擴展安裝。比如 pecl install mongodb。該命令會觸發(fā)源代碼下載、編譯并拷貝到系統(tǒng) PHP 目錄。pecl 需要執(zhí)行在 Linux 環(huán)境中才能裝linux 版本的 .so 文件。在函數(shù)計算這里可以通過 fun install 機制進行安裝。
新建一個 Funfile 文件,內容如下:
RUNTIME php7.2 RUN apt-get update && apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev RUN pecl install mongodb RUN mkdir -p /code/extension && mv /usr/local/lib/php/extensions/*/mongodb.so /code/extension RUN echo "extension=/code/extension/mongodb.so" > /code/extension/mongodb.ini逐行解釋一下上面五行指令
然后執(zhí)行
fun install -f php using template: template.yml ...Install Success安裝以后會多處一個 extension 目錄,包含 mongodb.so 和 mongodb.ini 文件
╰─? tree . ├── Funfile ├── extension │ ├── mongodb.ini │ └── mongodb.so ├── index.php └── template.yml安裝 mongodb 依賴
執(zhí)行下面命令通過 composer 安裝依賴 ‘mongodb/mongodb’
$ fun install sbox -f fc-mongodb -c "composer require mongodb/mongodb" using template: template.yml skip pulling image aliyunfc/runtime-php7.2:build-1.9.0... Using version ^1.6 for mongodb/mongodb ./composer.json has been created Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 1 install, 0 updates, 0 removals- Installing mongodb/mongodb (1.6.0): Downloading (100%) Writing lock file Generating autoload files安裝成功后會在代碼目錄多處 composer.json 文件、composer.lock 文件和 vendor 目錄
╰─? tree -L 2 . ├── Funfile ├── composer.json ├── composer.lock ├── extension │ ├── mongodb.ini │ └── mongodb.so ├── index.php ├── template.yml └── vendor├── autoload.php├── composer└── mongodb本地調試
更新 index.php 文件
<?phprequire 'vendor/autoload.php'; function handler($event, $context) {$db_name = $_ENV['MONGO_DATABASE'];$uri = $_ENV['MONGO_URL'];$client = new MongoDB\Client($uri);$collection = $client->$db_name->fc_col;$result = $collection->insertOne(['DEMO' => 'FC', 'MSG' => 'Hello FunctionCompute For MongoDB']);echo "Inserted with Object ID '{$result->getInsertedId()}'", "\n";$cursor = $collection->find(['DEMO' => 'FC']);$result = '';foreach ($cursor as $entry) {echo json_encode($entry->getArrayCopy()), "\n";$result = $result . json_encode($entry->getArrayCopy()) . "\n";}return $result; }借助 docker 啟動一個臨時的 mongodb 數(shù)據(jù)庫
docker run --rm --name mongo_for_fc \-e MONGO_INITDB_ROOT_USERNAME=mongoadmin \-e MONGO_INITDB_ROOT_PASSWORD=secret \-p 27017:27017 \mongo更新 template.yml 文件,添加 MONGO_DATABASE 和 MONGO_URL 環(huán)境變量。
ROSTemplateFormatVersion: '2015-09-01' Transform: 'Aliyun::Serverless-2018-04-03' Resources:fc-mongodb:Type: 'Aliyun::Serverless::Service'Properties:Description: 'helloworld'fc-mongodb:Type: 'Aliyun::Serverless::Function'Properties:Handler: index.handlerRuntime: php7.2CodeUri: './'EnvironmentVariables:MONGO_DATABASE: adminMONGO_URL: mongodb://mongoadmin:secret@host.docker.internal:27017/admin使用 fun local 本地模擬運行
$ fun local invoke using template: template.ymlMissing invokeName argument, Fun will use the first function fc-mongodb/fc-mongodb as invokeNameskip pulling image aliyunfc/runtime-php7.2:1.9.2... FunctionCompute php7.2 runtime inited. FC Invoke Start RequestId: b1764771-896b-4c27-9ad8-6c325cc3d749 Inserted with Object ID '5e539d08c42dc23cf23863e2' {"_id":{"$oid":"5e539d08c42dc23cf23863e2"},"DEMO":"FC","MSG":"Hello FunctionCompute For MongoDB"} FC Invoke End RequestId: b1764771-896b-4c27-9ad8-6c325cc3d749 {"_id":{"$oid":"5e539d08c42dc23cf23863e2"},"DEMO":"FC","MSG":"Hello FunctionCompute For MongoDB"}RequestId: b1764771-896b-4c27-9ad8-6c325cc3d749 Billed Duration: 214 ms Memory Size: 1989 MB Max Memory Used: 27 MB如果希望本地斷點調試可以使用 Aliyun Serverless VSCode Extension,如下圖
發(fā)布并調用
請將 template.yml 配置文件中的 MONGO_DATABASE 和 MONGO_URL 環(huán)境變量更新為您線上系統(tǒng)的相應配置,然后發(fā)布
$ fun deploy using template: template.yml using region: cn-shanghai using accountId: ***********4733 using accessKeyId: ***********EUz3 using timeout: 60Collecting your services information, in order to caculate devlopment changes...Resources Changes(Beta version! Only FC resources changes will be displayed):┌────────────┬──────────────────────────────┬────────┬──────────────────────┐ │ Resource │ ResourceType │ Action │ Property │ ├────────────┼──────────────────────────────┼────────┼──────────────────────┤ │ fc-mongodb │ Aliyun::Serverless::Service │ Modify │ Description │ ├────────────┼──────────────────────────────┼────────┼──────────────────────┤ │ │ │ │ Handler │ │ │ │ ├──────────────────────┤ │ │ │ │ Runtime │ │ fc-mongodb │ Aliyun::Serverless::Function │ Modify ├──────────────────────┤ │ │ │ │ CodeUri │ │ │ │ ├──────────────────────┤ │ │ │ │ EnvironmentVariables │ └────────────┴──────────────────────────────┴────────┴──────────────────────┘? Please confirm to continue. Yes Waiting for service fc-mongodb to be deployed...Waiting for function fc-mongodb to be deployed...Waiting for packaging function fc-mongodb code...The function fc-mongodb has been packaged. A total of 761 files files were compressed and the final size was 2.81 MBfunction fc-mongodb deploy success service fc-mongodb deploy success最使用 fun invoke 命令驗證調用結果。
小結
本文主要介紹如何結合 fun install 和 fun local invoke 進行附帶 extension 的 PHP 項目開發(fā)和調試。Funfile 文件可以描述 extension 的安裝命令,如果您有 Dockerfile 的使用經驗,那你會發(fā)現(xiàn)兩者使用體驗非常類似。雖然這里只舉了一個 mongodb 的示例,但是這個示例是比較完整的,對于其他類似需要安裝 PHP extension 的場景也同樣適用。
參考閱讀
加入我們
團隊介紹
阿里云函數(shù)服務是一個全新的,支持事件驅動編程模式的計算服務。 他幫助用戶聚焦自身業(yè)務邏輯,以 Serverless的方式構建應用,快速的實現(xiàn)低成本,可擴展,高可用的系統(tǒng),而無需考慮服務器等底層基礎設施的管理。 用戶能夠快速的創(chuàng)建原型,同樣的架構能隨業(yè)務規(guī)模平滑伸縮。讓計算變得更高效,更經濟,更彈性,更可靠。無論小型創(chuàng)業(yè)公司,還是大型企業(yè),都受益其中。我們的團隊正在迅速擴張,求賢若渴。我們想尋找這樣的隊友:
基本功扎實。既能閱讀論文追蹤業(yè)界趨勢,又能快速編碼解決實際問題。
嚴謹?shù)?#xff0c;系統(tǒng)化的思維能力。既能整體考慮業(yè)務機會,系統(tǒng)架構,運維成本等諸多因素,又能掌控設計/開發(fā)/測試/發(fā)布的完整流程,預判并控制風險。
好奇心和使命感驅動。樂于探索未知領域,不僅是夢想家,也是踐行者。
堅韌、樂觀、自信。能在壓力和困難中看到機會,讓工作充滿樂趣!
如果您對云計算充滿熱情,想要構建一個有影響力計算平臺和生態(tài)體系,請加入我們,和我們一起實現(xiàn)夢想!
職位描述
構建新一代 Serverless 計算平臺,包括:
職位要求
簡歷提交
yixian.dw AT alibaba-inc.com
“阿里巴巴云原生技術圈關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦云原生流行技術趨勢、云原生大規(guī)模的落地實踐,做最懂云原生開發(fā)者的技術圈。”
總結
以上是生活随笔為你收集整理的开发函数计算的正确姿势———为 PHP 运行时添加自定义扩展的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 轻松构建基于 Serverless 架构
- 下一篇: 架构师成长系列 | 云原生时代的 Dev