Skip to content

函数构建

由于函数计算的运行环境(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.txtapt-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:

  1. 在 build 过程中注入自定义环境变量和使用指定的 pypi 源,可以使用如下命令 s build --custom-env '{"myenv": "test"}' --custom-args='-i https://pypi.tuna.tsinghua.edu.cn/simple'
  2. 如果不想使用 s build 的默认行为
  3. 2.1 直接输入命令 s build --command="pip install -t . flask -i https://pypi.tuna.tsinghua.edu.cn/simple",command 工作的目录对应 s.yaml 中指定的 codeUri
  4. 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.yamlimage 字段处填写好 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