函数构建
由于函数计算的运行环境(Linux debian9 或 debian10)与本地的开发环境可能存在比较大的不同,这就导致一部分本地安装/构建的依赖(比如第三方库)或代码包,在线上无法正常运行。Serverless Devs 开发者工具在 build 命令中提供了两种构建方式:
- 本地构建:通过启动本地 Docker 容器,在容器中进行项目构建,以尽可能地保证构建出来的依赖/产物在线上可以正常运行
- 云端构建:将代码和构建脚本上传到阿里云函数计算的云端环境进行构建,无需本地 Docker
目前支持的能力如下:
不同的运行时,在进行依赖安装/项目构建的时候,可能会有不同的依赖描述文件,其系统默认的对应关系如下:
-
Python:
requirements.txt -
NodeJS:
package.json -
PHP:
composer.json -
Custom:
requirements.txt package.json composer.json -
Custom Container:
dockerfile
⚠️ 注意:
- 依赖描述文件需要放在 s.yaml 中 code 属性指定的文件夹里面
- 在部分语言完成项目构建之后,部署的时候可能会出现交互式操作,提醒用户是否要将安装的依赖路径加入到环境变量中,以便线上可以正确地加载到这些依赖内容。此时可以通过交互式的方法,根据提醒输入
y,也可以在部署时通过-y命令,默认进行环境变量等内容的添加。- apt-get.list 可用于所有非 Custom Container 的运行时,详情见 apt-get.list 文件,是一个可选项,绝大部分场景不需要。
命令解析
当执行命令build -h/build --help时,可以获取帮助文档。
参数解析
| 参数全称 | 参数缩写 | 参数含义 |
|---|---|---|
| publish-layer | 无 | 将构建后的产物发布成一个 layer |
| use-sandbox | 无 | 进入对应 runtime 的 sandbox 容器 |
| custom-env | 无 | build 时注入的自定义环境变量 |
| custom-args | 无 | 使用默认 build 行为时的附加参数,比如指定 pypi 或 npm 源,需要配合 use-docker 或 use-buildkit 使用,默认是 use-docker |
| command | 无 | 使用自定义命令 |
| script-file | 无 | 使用自定义脚本 |
| dockerfile | f | 指定构建自定义镜像的文件,构建 Custom Container 运行时的镜像时使用 |
| context | 无 | Custom Container 构建镜像时的上下文,构建 Custom Container 运行时的镜像时使用 |
| cloud-build-config | 无 | 云端构建配置文件,默认查找当前目录 fc3-cloud-build.yaml |
| debug-instance | 无 | 仅用于云端构建,构建完成后启动交互调试窗口 |
当前命令还支持部分全局参数(例如
-a/--access,--debug,--help等),详情可参考 Serverless Devs 全局参数文档
本地构建
⚠️ 注意:本地构建对 Docker 有所依赖,在使用本地构建时,需要先进行 Docker 安装,版本 >= 19.03。
操作案例
基础操作
以 Python 应用为例:在具有 requirements.txt 的 Python 项目下,可以通过s build命令实现依赖安装:
Step1. 开发编辑源代码
Step2. s build之后,自动根据 requirements.txt 和 apt-get.list 下载对应的依赖到本地,并且和源码一起组成交付物,同时会提示完成依赖包的环境变量配置:
⌛ Steps for [build] of [test-py-app]
====================
build-3.0.0: Pulling from aliyunfc/runtime-python3.10
Digest: sha256:55b362eb353734ee290d6142b60e62f32fb1da32e8ff5a2e0b888ada403a0efd
Status: Image is up to date for registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.10:build-3.0.0
registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.10:build-3.0.0
Ign:1 http://mirrors.aliyun.com/debian-archive/debian stretch InRelease
Get:2 http://mirrors.aliyun.com/debian-archive/debian stretch-backports InRelease [78.5 kB]
...
Fetched 329 kB in 0s (1487 kB/s)
Download complete and in download only mode
Preparing to unpack jq_1.5+dfsg-1.3_amd64.deb
Preparing to unpack libjq1_1.5+dfsg-1.3_amd64.deb
Preparing to unpack libonig4_6.1.3-2+deb9u2_amd64.deb
Looking in indexes: https://mirrors.aliyun.com/pypi/simple/
Collecting beautifulsoup4
Downloading https://mirrors.aliyun.com/pypi/packages/57/f4/a69c20ee4f660081a7dedb1ac57f29be9378e04edfcb90c526b923d4bebc/beautifulsoup4-4.12.2-py3-none-any.whl (142 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.0/143.0 kB 1.7 MB/s eta 0:00:00
Collecting flask
Downloading https://mirrors.aliyun.com/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl (96 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 96.1/96.1 kB 1.8 MB/s eta 0:00:00
...
Installing collected packages: soupsieve, MarkupSafe, itsdangerous, click, blinker, Werkzeug, Jinja2, beautifulsoup4, flask
Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.3 Werkzeug-2.3.7 beautifulsoup4-4.12.2 blinker-1.6.2 click-8.1.7 flask-2.3.3 itsdangerous-2.1.2 soupsieve-2.5
[2023-09-20 17:16:19][INFO][fcDemo] You need to add a new configuration env configuration dependency in yaml to take effect. The configuration is as follows:
environmentVariables:
LD_LIBRARY_PATH: /code/apt-archives/usr/local/lib:/code/apt-archives/usr/lib:/code/apt-archives/usr/lib/x86_64-linux-gnu:/code/apt-archives/usr/lib64:/code/apt-archives/lib:/code/apt-archives/lib/x86_64-linux-gnu:/code
PYTHONPATH: /code/python
PATH: /code/apt-archives/usr/bin:/code/python/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/code:/code/bin:/opt:/opt/bin
✔ [fcDemo] completed (27.54s)
Step3. 按照提示在 s.yaml 中完成依赖包的环境变量配置 s.yaml#L19-L22, 然后执行 s deploy 将整个交付物 zip 打包,创建函数
最佳实践:
如果您觉得函数代码包过大,影响部署效率,可以将构建的第三方包直接发布成一个层,然后在 s.yaml 中引入这个层即可。只需执行 s build --publish-layer,您可以在输出日志看到如下提示:
environmentVariables:
LD_LIBRARY_PATH: /opt/apt-archives/usr/local/lib:/opt/apt-archives/usr/lib:/opt/apt-archives/usr/lib/x86_64-linux-gnu:/opt/apt-archives/usr/lib64:/opt/apt-archives/lib:/opt/apt-archives/lib/x86_64-linux-gnu:/opt
PYTHONPATH: /opt/python
PATH: /opt/apt-archives/usr/bin:/opt/python/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/code:/code/bin:/opt:/opt/bin
layers:
- acs:fc:cn-huhehaote:1431999136518149:layers/fc3-event-python310-layer/versions/1
该命令同时在 s.yaml 指定的 code 目录下面自动增加了 .fcignore 文件,这样函数代码包就可以大大减小,提高部署效率,毕竟第三方依赖的构建变动是不频繁的。
Tips:
- 在 build 过程中注入自定义环境变量和使用指定的 pypi 源,可以使用如下命令
s build --custom-env '{"myenv": "test"}' --custom-args='-i https://pypi.tuna.tsinghua.edu.cn/simple'- 如果不想使用
s build的默认行为- 2.1 直接输入命令
s build --command="pip install -t . flask -i https://pypi.tuna.tsinghua.edu.cn/simple",command 工作的目录对应 s.yaml 中指定的 codeUri- 2.2 直接输入命令
s build --script-file my_script.sh,my_script.sh 工作的目录对应 s.yaml 中指定的 codeUri
Node.js 项目、PHP 项目与 Python 项目类似,都是在开发代码之后,可以通过 s build 进行依赖安装,此时工具将会自动根据相关依赖文件(例如 Node.js 是 package.json,PHP 是 composer.json)下载对应的依赖到本地,并且和源码一起组成交付物,同时会提示完成依赖包的环境变量配置;按照提示完成配置,接下来可以通过 s deploy 进行项目部署,此时工具会将整个交付物 ZIP 打包,创建函数,让函数可以直接 require 对应的代码依赖包。
Custom Container,则需要先开通 ACR/CR 容器镜像服务,然后在 s.yaml 的 image 字段处填写好 ACR 镜像地址,通过 s build --dockerfile ./Dockerfile 进行项目构建;接下来可以通过 s deploy -y 将项目部署到线上,此时工具会自动先将构建完成的镜像推送到 ACR 服务,然后再进行函数的创建,示例可参考 custom-container example
💡 在使用
build命令时,可以通过环境变量FC_DOCKER_VERSION控制镜像的版本,例如export FC_DOCKER_VERSION=3.0.0(所有可用版本可查看 https://hub.docker.com/u/aliyunfc),对于 fc3 组件来说,使用的 FC_DOCKER_VERSION 大于等于 3.0.0💡 在代码包的场景中,除了各自语言的库以外,还有更加复杂的情况,例如在函数计算的 Python Runtime 中想使用 jq 这个工具,此时还需要 apt-get.list 的支持。
高阶自定义操作 use-sandbox
为了满足用户自定义操作的需求,Serverless Devs 开发者工具在 build 命令中增加了 --use-sandbox 参数,只需输入:
$ s build --use-sandbox
# or
$ s build --use-sandbox --custom-env '{"myenv": "test"}'
Serverless Devs 开发者工具会根据 s.yaml 中的 runtime,自动拉起一个模拟线上运行环境的真实容器,并且将 s.yaml 中 codeUri 指定的目录挂载到容器的 /code 目录下面,之后可以在容器里面执行 npm install 等满足需求的命令。
在这里推荐使用内置的 apt-get-install 工具解决可能遇到的高阶难题,比如:
第三方 lib 依赖底层的 so 文件
比如在 Node.js 14 运行时部署 puppeteer 应用,但是 puppeteer 依赖的一些底层 so 库在 Node.js 14 运行时中不存在,可以借助 apt-get-install 完成目标:
root@6e9f82d4644a:/code# apt-get-install libblas3 fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libgtk-3-0 libnspr4 libnss3 libpangocairo-1.0-0 libxcb-dri3-0 libx11-xcb1 libxcb1 libxss1 libxtst6 lsb-release xdg-utils libatspi2.0-0 libatk1.0-0 libxkbcommon0 libepoxy0 libglapi-mesa libnspr4 libgbm-dev
Ign:1 http://mirrors.aliyun.com/debian-archive/debian stretch InRelease
Hit:2 http://mirrors.aliyun.com/debian-archive/debian stretch-backports InRelease
Hit:3 http://mirrors.aliyun.com/debian-archive/debian-security stretch/updates InRelease
Hit:4 http://mirrors.aliyun.com/debian-archive/debian stretch Release
Reading package lists... Done
...
The following additional packages will be installed:
adwaita-icon-theme dconf-gsettings-backend dconf-service distro-info-data glib-networking glib-networking-common
glib-networking-services gsettings-desktop-schemas libasound2-data libblas-common libcolord2 libdbusmenu-glib4
libdbusmenu-gtk3-4 libdconf1 libegl1-mesa libgbm1 libgfortran3 libgtk-3-common libindicator3-7 libjson-glib-1.0-0
libjson-glib-1.0-common libproxy1v5 librest-0.7-0 libsoup-gnome2.4-1 libsoup2.4-1 libwayland-client0 libwayland-cursor0
libwayland-egl1-mesa libwayland-server0 libxcb-dri2-0 libxcb-present0 libxcb-sync1 libxcb-xfixes0 libxshmfence1 xkb-data
Suggested packages:
libasound2-plugins alsa-utils colord gvfs lsb gvfs-bin
...
Need to get 25.4 MB of archives.
After this operation, 91.7 MB of additional disk space will be used.
Get:1 http://mirrors.aliyun.com/debian-archive/debian stretch/main amd64 libxss1 amd64 1:1.2.2-1 [17.5 kB]
Get:2 http://mirrors.aliyun.com/debian-archive/debian stretch/main amd64 adwaita-icon-theme all 3.22.0-1+deb9u1 [11.5 MB]
...
Fetched 25.4 MB in 10s (2528 kB/s)
Download complete and in download only mode
Preparing to unpack adwaita-icon-theme_3.22.0-1+deb9u1_all.deb
...
Preparing to unpack xkb-data_2.19-1+deb9u1_all.deb
root@6e9f82d4644a:/code# ls
apt-archives index.js
root@6e9f82d4644a:/code# ls apt-archives/
etc usr
如上所示,so 底层 lib 全部安装到 apt-archives 目录下面,为了使函数能正确地使用这些 so 文件,部署时给函数增加下面两个环境变量即可:
LD_LIBRARY_PATH=/code/apt-archives/usr/local/lib:/code/apt-archives/usr/lib:/code/apt-archives/usr/lib/x86_64-linux-gnu:/code/apt-archives/usr/lib64:/code/apt-archives/lib:/code/apt-archives/lib/x86_64-linux-gnu:/code
PATH=/code/apt-archives/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/code:/code/bin:/opt:/opt/bin
云端构建
云端构建是指:不在本地电脑上构建镜像,而是将代码和构建脚本上传到阿里云函数计算的云端环境进行构建。这种方式适合以下场景:
- 本地没有安装 Docker,无法进行本地镜像构建
- 本地操作系统与线上环境差异较大(例如在 macOS 上构建 Linux x86 镜像)
- 团队协作中需要统一的构建环境
⚠️ 注意:云端构建仅适用于 Custom Container 运行时(即使用自定义容器镜像的函数)。
使用步骤
Step 1:创建配置文件
在 s.yaml 文件同级目录下,创建一个名为 fc3-cloud-build.yaml 的配置文件,内容如下:
fcDemo:
props:
region: cn-hangzhou # 函数所在的地域,需要与 s.yaml 中保持一致
build:
setup: ./scripts/setup.sh # 构建脚本的路径,会在云端构建时执行
code: ./code # 代码目录的路径,会被上传到云端作为构建输入
timeoutMinutes: 20 # 构建超时时间,单位为分钟,默认值为 20
baseContainerConfig:
image: serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai/docker-image-builder-worker:20260514-111141-2d80effe # 云端构建使用的构建环境镜像,基于 Ubuntu 24.04,预装了 Node.js、Python、Go 等常用编译环境
runtime:
image: xxxxx:tag # 构建完成后的目标镜像地址
username: ${env('CLOUD_BUILD_REGISTRY_USERNAME')} # 镜像仓库的用户名。推送镜像仓库时需要填写。可通过环境变量 CLOUD_BUILD_REGISTRY_USERNAME 传入或者在 yaml 中配置
password: ${env('CLOUD_BUILD_REGISTRY_PASSWORD')} # 镜像仓库的密码。属于敏感信息,建议不要将真实值提交到代码仓库,可通过环境变量 CLOUD_BUILD_REGISTRY_PASSWORD 传入
cpu: 4 # 可选;云端构建使用的 CPU 核数,默认为 4
memory: 8192 # 可选;云端构建使用的内存大小,单位 MB,默认为 8192
💡
baseContainerConfig.image指定的是云端构建使用的构建环境镜像,而非最终部署的函数镜像。示例中的serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai/docker-image-builder-worker:20260514-111141-2d80effe是 Serverless Devs 提供的默认构建环境镜像,基于 Ubuntu 24.04,预装了 Node.js、Python、Go 等常用编译环境,可以满足大多数项目的构建需求。如果您有特殊的构建环境要求,也可以指定自定义的构建环境镜像。
配置文件中各字段的说明:
| 字段 | 必填 | 说明 |
|---|---|---|
region |
是 | 函数所在地域,需与 s.yaml 中一致 |
build.setup |
是 | 构建脚本的路径,该脚本在云端容器内执行,用于安装依赖、编译代码等 |
build.code |
是 | 代码目录路径,该目录内容会被上传到云端 |
build.timeoutMinutes |
否 | 构建超时时间(分钟),默认 20 |
build.baseContainerConfig.image |
否 | 云端构建使用的构建环境镜像。默认为 Serverless Devs 提供的镜像(基于 Ubuntu 24.04,预装了 Node.js、Python、Go 等常用编译环境)。如有特殊需求可指定自定义镜像 |
runtime.image |
是 | 目标镜像地址。支持格式:registry/repo(仓库+镜像名)、registry/repo:tag(完整地址)。不指定 tag 时会自动生成 |
runtime.username |
是 | 镜像仓库用户名,推送私有仓库时需要 |
runtime.password |
是 | 镜像仓库密码,推送私有仓库时需要。建议通过环境变量传入 |
runtime.cpu |
否 | 云端构建 CPU 核数,默认 4 |
runtime.memory |
否 | 云端构建内存(MB),默认 8192 |
Step 2:编写构建脚本
构建脚本(如 setup.sh)是在云端容器内执行的脚本,用于完成镜像的构建准备工作。常见的操作包括安装系统依赖、编译代码、配置环境等。
一个简单的 Node.js 项目构建脚本示例:
#!/bin/bash
# 安装 Node.js 依赖
cd /code
npm install --production
项目目录结构示例:
my-project/
├── s.yaml # 函数计算配置文件
├── fc3-cloud-build.yaml # 云端构建配置文件
├── code/ # 代码目录(与 fc3-cloud-build.yaml 中 build.code 对应)
│ ├── index.js # 函数入口文件
│ ├── package.json # Node.js 依赖声明
│ └── scripts/
│ └── setup.sh # 构建脚本(与 fc3-cloud-build.yaml 中 build.setup 对应)
💡 构建脚本中
/code目录对应的就是您在配置中指定的code目录,脚本中的操作都基于这个目录执行。
Step 3:执行构建命令
s build --cloud-build-config fc3-cloud-build.yaml
如果不指定 --cloud-build-config 参数,工具会自动检查当前目录是否存在 fc3-cloud-build.yaml 文件。如果存在,直接执行:
s build
构建完成后,工具会输出目标镜像地址,并提示需要在 s.yaml 中将 customContainerConfig.image 替换为该地址:
Please replace customContainerConfig.image: xxxxx:tag
云端构建调试
如果云端构建失败,需要进入构建环境排查问题,可以使用 --debug-instance 参数:
s build --cloud-build-config fc3-cloud-build.yaml --debug-instance
该参数会在构建完成后启动一个交互式的 SSH 调试窗口,可以直接进入云端构建容器中检查构建环境、查看日志、手动执行命令来排查问题。
⚠️ 注意:
- 云端构建仅适用于 Custom Container 运行时
runtime.password属于敏感信息,不要将真实密码提交到代码仓库,建议通过环境变量CLOUD_BUILD_REGISTRY_PASSWORD传入
apt-get.list
此文件顾名思义,就是声明可以使用 apt-get 命令安装函数计算运行时环境中没有的系统包。
使用方式是在 code 目录的根目录下,创建一个 apt-get.list 的文件,文件内容如下所示。然后部署之前执行 s build 即可。
jq
git