GitHub Actions 部署 FastAPI 到阿里云函数计算:代码适配与完整发布流程
Table of Contents
写好的 FastAPI 项目,为什么放进函数计算以后不能直接运行?通常要先检查选了哪一种运行时,以及云端怎样启动这个程序。
本文记录一条完整的发布路线:在 GitHub 保存代码,由 GitHub Actions 构建 Docker 镜像,推送到阿里云容器镜像服务,再用 Serverless Devs 更新函数计算。 以后改动代码并推送到 main,同一条流程就会再次执行。
文中配置按 2026 年 10 月 10 日查阅的官方资料整理,使用 FC 3.0 和自定义容器运行时。它是一份可复用的参考配置;本文整理时未在阿里云账号里执行这套新流程。
一、先弄明白:FastAPI 要不要改成“函数”?
FastAPI 平时的工作方式,是由 Uvicorn 启动一个 HTTP 服务,再根据请求路径调用路由函数。函数计算提供几种不同的启动方式:
| 方式 | 云端接收程序的方式 | FastAPI 需要做什么 |
|---|---|---|
| 内置 Python 事件运行时 | 加载指定的处理函数,例如 main.handler | 遵循 handler(event, context) 等运行时契约,或使用经过核实的 ASGI 适配器 |
| 自定义运行时 | 上传代码和依赖,由启动命令运行 HTTP 服务 | 保留普通 FastAPI 路由,配置启动命令、依赖和监听端口 |
| 自定义容器 | 拉取镜像,按容器启动命令运行 HTTP 服务 | 把 Python、依赖和应用放进镜像,配置镜像地址和监听端口 |
因此,app = FastAPI() 和 @app.get("/tasks") 可以继续使用。本文选择自定义容器,让 Uvicorn 提供 HTTP 服务;main:app 这种 ASGI 导入路径,则不能直接当成内置 Python 事件运行时的 Handler。自定义运行时机制、Python 事件处理函数
Web 服务模式要特别注意三件事:
- 监听地址使用
0.0.0.0,使平台能够连接应用。 - 应用实际监听的端口,与函数配置的端口一致。
- 启动命令能够找到应用模块及其依赖,并在平台要求的时间内启动完成。
本文统一使用 9000。如果改成 8000,Uvicorn 和函数配置也要一起修改。
二、整个发布过程,各部分负责什么?
修改代码并推送到 GitHub 的 main
↓
GitHub Actions 取出代码、导出依赖
↓
Docker 构建 linux/amd64 镜像
↓
推送到阿里云 ACR 镜像仓库
↓
Serverless Devs 根据 s.yaml 创建或更新函数
↓
函数计算拉取新镜像、启动 Uvicorn
↓
通过 HTTP 触发器访问 /health 等应用路由
| 部件 | 作用 |
|---|---|
app/main.py | 实际的 FastAPI 接口 |
pyproject.toml、uv.lock | 记录并锁定 Python 依赖 |
Dockerfile | 定义镜像里的运行环境和启动命令 |
| ACR | 保存构建好的镜像,供函数计算拉取 |
s.yaml | 描述函数名称、地域、资源、镜像、端口和触发器 |
| GitHub Actions | 自动串起构建、推送镜像和更新函数 |
| RAM 身份和角色 | 分别授权部署、推送镜像、拉取镜像等操作 |
GitHub 仓库里有代码,并不会自动让函数计算更新。需要工作流实际执行构建、镜像推送和部署命令,才能形成这条自动发布链路。
三、第一次部署前,准备阿里云资源
1. 选定地域与镜像仓库
先选一个函数计算和 ACR 都可用的地域,例如 cn-hongkong。在该地域准备私有镜像仓库,示例命名如下:
- 命名空间:
fc-demo - 仓库名称:
fastapi-api - 函数名称:
fastapi-github-demo
从 ACR 控制台复制实际的镜像仓库地址,以及 Docker 登录所需的用户名和密码。地址通常由“登录域名 / 命名空间 / 仓库名”组成;不要仅凭地域猜出登录域名。
本文的主配置适用于已有 ACR 个人版仓库的情况。私人镜像使用与函数相同账号、相同地域的 ACR;构建目标使用 linux/amd64。新账号能否开通个人版,需要以控制台当前可用情况为准;使用企业版时,还要填写下文说明的实例 ID。ACR 经济版目前不在 FC 自定义容器支持范围内。自定义容器要求与仓库准备、镜像运行环境要求
第一次试用时,选一个新的函数名。部署工具会创建不存在的函数;名称已经存在时,会更新对应函数的配置。
2. 配置函数使用的 RAM 角色
函数计算需要获得拉取私有镜像的权限。可以在 RAM 控制台创建以函数计算为可信云服务的角色,再为它授权读取 ACR 镜像。
官方给出的镜像拉取权限示例包括 AliyunContainerRegistryReadOnlyAccess。如果账号有更细的权限管理要求,可以按目标仓库缩小授权范围。保存该角色的 ARN,形如:
acs:ram::<你的账号ID>:role/<函数角色名称>
稍后将它填入 FC_FUNCTION_ROLE_ARN,最终成为 s.yaml 的 role 字段。函数角色的镜像读取权限
3. 准备 GitHub 部署身份
为发布流程准备专用 RAM 身份和 AccessKey,按官方权限示例授权目标函数的创建、更新、读取及 HTTP 触发器管理,并允许它把前面准备的角色交给函数计算,即对目标角色授予 ram:PassRole。CLI 执行中需要的额外读取操作,也应按实际资源补齐。函数计算权限示例
这里有两组不同的凭据:
| 凭据 | 谁使用 | 做什么 |
|---|---|---|
| 阿里云 AccessKey ID / Secret | GitHub 中的 Serverless Devs | 调用函数计算 API,更新函数及触发器 |
| ACR 登录用户名 / 密码 | GitHub 中的 Docker 登录步骤 | 推送镜像到指定仓库 |
云端函数拉取镜像时使用前面配置的 RAM 角色。把 ACR 密码设置到 GitHub,并不等于函数计算也获得了读取镜像的权限。
四、准备应用文件
一个最小项目可以这样组织:
fastapi-demo/
├── app/
│ ├── __init__.py
│ └── main.py
├── pyproject.toml
├── uv.lock
├── Dockerfile
├── .dockerignore
├── .gitignore
├── s.yaml
└── .github/
└── workflows/
└── deploy-fc.yml
1. 普通的 FastAPI 应用
app/__init__.py 可以留空。app/main.py 放一个首页和一个用于检查应用是否正常响应的路由:
from fastapi import FastAPI
app = FastAPI(title="FastAPI on Function Compute")
@app.get("/")
async def home():
return {"message": "FastAPI is running"}
@app.get("/health")
async def health():
return {"ok": True}
原有的 Pydantic 模型、路由拆分和 include_router 可以继续保留。后面的启动命令导入 app.main:app,意思是找到 app/main.py 里的 app 对象。
2. 锁定依赖
pyproject.toml 示例:
[project]
name = "fastapi-fc-demo"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"fastapi",
"uvicorn",
]
第一次准备项目时,安装好 uv 后,在项目根目录执行:
uv lock
把生成的 uv.lock 与 pyproject.toml 一起提交。CI 用锁文件导出 requirements.txt,Docker 再用它安装依赖:
uv export --locked --no-dev --no-hashes --format requirements.txt --output-file requirements.txt
--locked 会检查依赖描述与锁文件是否一致。修改依赖后,应先更新并提交锁文件;部署时临时重新解析依赖,可能让相同代码的安装结果变化。uv 导出依赖说明、uv 参数参考
3. Dockerfile:把启动方式写清楚
FROM python:3.12-slim
WORKDIR /code
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
COPY requirements.txt ./
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY app ./app
EXPOSE 9000
CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "9000", "--timeout-keep-alive", "86400"]
这里通过 python -m uvicorn 启动服务,应用导入路径是 app.main:app。有额外的模板、静态文件或其他代码目录时,应相应增加 COPY。
EXPOSE 9000 描述容器使用的端口。真正的监听端口仍由 Uvicorn 的 --port 9000 决定,函数计算也需要配置相同的值。
--timeout-keep-alive 86400 用于保持平台与应用之间的连接,按阿里云对 Web Server 连接超时的建议设置。它与函数一次请求的 timeout: 60 是两个不同的参数。Uvicorn 连接超时排错
4. 排除本地配置和临时文件
.dockerignore:
.git
.github
.venv
.env
.env.*
.s
__pycache__
*.pyc
.DS_Store
.gitignore:
.venv/
.env
.env.*
.s/
__pycache__/
*.pyc
requirements.txt
.DS_Store
requirements.txt 在构建前生成,所以可以不提交;uv.lock 要提交。示例只把 app 复制进镜像,同时用 .dockerignore 排除本地环境和配置。
五、写 FC 3.0 的 s.yaml
在项目根目录创建以下配置:
edition: 3.0.0
name: fastapi-fc3
access: fc-ci
resources:
api:
component: fc3
props:
region: ${env('FC_REGION')}
functionName: ${env('FC_FUNCTION_NAME')}
runtime: custom-container
cpu: 0.5
memorySize: 1024
diskSize: 512
timeout: 60
instanceConcurrency: 1
role: ${env('FC_FUNCTION_ROLE_ARN')}
customContainerConfig:
image: ${env('FC_IMAGE_URI')}
port: 9000
triggers:
- triggerName: http
triggerType: http
qualifier: LATEST
triggerConfig:
authType: function
disableURLInternet: false
methods:
- GET
- POST
- PUT
- PATCH
- DELETE
- HEAD
- OPTIONS
${env('FC_REGION')} 表示部署工具从执行环境中读取变量。它不会自动读取 GitHub 设置,后面的工作流要明确把 GitHub Variables 映射成环境变量。Serverless Devs 变量语法
几个容易混淆的字段:
| 字段 | 含义 |
|---|---|
access: fc-ci | Serverless Devs 的凭据别名,须与 CI 注册的名称一致 |
runtime: custom-container | 通过镜像运行应用 |
customContainerConfig.image | 这次构建推送的完整镜像地址 |
customContainerConfig.port | 平台连接 Uvicorn 的端口 |
role | 函数计算使用的 RAM 角色 ARN |
authType: function | HTTP 请求需要阿里云签名认证 |
qualifier: LATEST | 触发器指向函数当前的 LATEST 配置 |
CPU、内存、磁盘、超时和并发值是教学起点,可以按实际应用调整。FC 3.0 自定义容器使用嵌套的 port 字段;不要把旧版的 caPort 混进这份配置。FC3 YAML 规范
企业版 ACR 的补充
使用企业版时,将镜像地址换成实际企业版仓库地址,再在容器配置中补充实例 ID:
customContainerConfig:
image: ${env('FC_IMAGE_URI')}
port: 9000
acrInstanceId: ${env('ACR_INSTANCE_ID')}
同时在 GitHub Variables 中增加 ACR_INSTANCE_ID,并在工作流的 env 中增加 ACR_INSTANCE_ID: ${{ vars.ACR_INSTANCE_ID }}。
FC3 API 定义了这个字段。当前 fc3 部署源码会把它传给 SDK,但公开 YAML 表格未完整列出它;实际使用时,应核对安装的组件版本以及 ACR 网络、权限配置。FC3 API 镜像配置、当前部署实现、SDK 容器模型
六、在 GitHub 保存配置与凭据
进入目标仓库的 Settings → Secrets and variables → Actions。
在 Variables 中创建这些普通配置:
| 名称 | 示例或填写方式 |
|---|---|
FC_REGION | cn-hongkong,与 ACR 地域一致 |
FC_FUNCTION_NAME | fastapi-github-demo |
FC_FUNCTION_ROLE_ARN | 从 RAM 控制台复制函数角色 ARN |
ACR_REGISTRY | ACR 登录域名,不含 https:// 和仓库路径 |
ACR_NAMESPACE | fc-demo |
ACR_REPOSITORY | fastapi-api |
在 Secrets 中创建:
| 名称 | 内容 |
|---|---|
ALIYUN_ACCESS_KEY_ID | 专用 RAM 部署身份的 AccessKey ID |
ALIYUN_ACCESS_KEY_SECRET | 对应的 AccessKey Secret |
ACR_USERNAME | ACR 控制台提供的 Docker 登录用户名 |
ACR_PASSWORD | ACR 登录密码 |
这些值由工作流读取,不需要写进源码。GitHub 自带的 GITHUB_TOKEN 用于 GitHub 权限,不能替代阿里云的凭据。缺少的 Secret 会被表达式读成空字符串,所以工作流应先检查配置是否齐全。GitHub Actions Secrets
也可以在已登录 GitHub CLI 的项目目录里执行:
gh secret set ALIYUN_ACCESS_KEY_ID
gh secret set ALIYUN_ACCESS_KEY_SECRET
gh secret set ACR_USERNAME
gh secret set ACR_PASSWORD
按交互提示输入对应值。普通 Variables 可通过同一设置页面填写。
七、添加完整的 GitHub Actions 工作流
创建 .github/workflows/deploy-fc.yml:
name: Deploy FastAPI to Function Compute
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: fc-production
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
env:
FC_REGION: ${{ vars.FC_REGION }}
FC_FUNCTION_NAME: ${{ vars.FC_FUNCTION_NAME }}
FC_FUNCTION_ROLE_ARN: ${{ vars.FC_FUNCTION_ROLE_ARN }}
ACR_REGISTRY: ${{ vars.ACR_REGISTRY }}
ACR_NAMESPACE: ${{ vars.ACR_NAMESPACE }}
ACR_REPOSITORY: ${{ vars.ACR_REPOSITORY }}
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
- name: Set up Node.js for Serverless Devs
uses: actions/setup-node@v7.1.0
with:
node-version: "22"
- name: Set up uv and Python
uses: astral-sh/setup-uv@v10.3.0
with:
python-version: "3.12"
enable-cache: false
- name: Check required configuration
shell: bash
env:
ALIYUN_ACCESS_KEY_ID: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
ALIYUN_ACCESS_KEY_SECRET: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
ACR_USERNAME: ${{ secrets.ACR_USERNAME }}
ACR_PASSWORD: ${{ secrets.ACR_PASSWORD }}
run: |
set -euo pipefail
required=(
FC_REGION FC_FUNCTION_NAME FC_FUNCTION_ROLE_ARN
ACR_REGISTRY ACR_NAMESPACE ACR_REPOSITORY
ALIYUN_ACCESS_KEY_ID ALIYUN_ACCESS_KEY_SECRET
ACR_USERNAME ACR_PASSWORD
)
for name in "${required[@]}"; do
if [[ -z "${!name}" ]]; then
echo "::error::Missing configuration: $name"
exit 1
fi
done
- name: Export locked dependencies
run: |
uv export --locked --no-dev --no-hashes \
--format requirements.txt \
--output-file requirements.txt
- name: Select image tag
shell: bash
run: |
image="$ACR_REGISTRY/$ACR_NAMESPACE/$ACR_REPOSITORY:$GITHUB_SHA"
echo "FC_IMAGE_URI=$image" >> "$GITHUB_ENV"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4.4.1
- name: Log in to ACR
uses: docker/login-action@v4.6.0
with:
registry: ${{ env.ACR_REGISTRY }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Build and push image
uses: docker/build-push-action@v7.4.0
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: true
tags: ${{ env.FC_IMAGE_URI }}
- name: Install Serverless Devs
run: npm install --global @serverless-devs/s@3.1.10
- name: Deploy function
env:
ALIYUN_ACCESS_KEY_ID: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
ALIYUN_ACCESS_KEY_SECRET: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
run: |
s config add \
--AccessKeyID "$ALIYUN_ACCESS_KEY_ID" \
--AccessKeySecret "$ALIYUN_ACCESS_KEY_SECRET" \
-a fc-ci -f
s deploy --skip-push --assume-yes
示例使用整理时已核对的 Action 版本和 Serverless Devs CLI 版本。以后更新工具时,应先阅读相应项目的发布说明;CLI 版本与它下载使用的 fc3 组件版本也要分开记录。GitHub Docker 发布教程、Docker GitHub Actions、Serverless Devs 安装
这份工作流有几个细节:
workflow_dispatch允许在 Actions 页面手动发布一次;文件需要先进入默认分支。工作流触发说明context: .让 Docker 构建读取上一步导出的requirements.txt。- 镜像使用完整提交 SHA 作为标签,方便判断哪一次代码对应哪一个镜像。保留旧标签,后续才能回退。
linux/amd64明确目标架构;本地电脑是 Apple Silicon,也不能直接把 ARM 镜像当作本例的部署产物。- Docker 已经推送镜像,
s deploy --skip-push让 fc3 使用现成镜像更新函数。 - 自动确认参数使用
--assume-yes或-y。当前 fc3 参数解析没有把--yes当作同一个选项。FC3 部署参数、官方参数解析
八、第一次发布与之后的更新
将前面的文件提交到自己的仓库:
git add app pyproject.toml uv.lock Dockerfile .dockerignore .gitignore s.yaml .github/workflows/deploy-fc.yml
git commit -m "Add FastAPI deployment to Function Compute"
git push origin main
然后打开 GitHub 的 Actions 页面,进入本次运行,依次查看:
- 配置检查是否通过。
uv export是否成功。- Docker 镜像是否构建并推送成功。
- Serverless Devs 是否成功创建或更新目标函数。
ACR 中应出现以此次提交 SHA 命名的镜像标签,函数配置中的镜像地址也应指向它。登录阿里云函数计算控制台,在所选地域找到函数,打开 HTTP 触发器,复制它的实际访问 URL。
之后修改应用,执行提交和推送即可再次发布。若更新依赖,应先运行 uv lock 并提交新的锁文件。不要只在云端控制台手动修改启动参数,却让仓库里的配置一直保持旧值;下次部署可能再次覆盖这些设置。
九、部署成功以后,怎样确认接口真的能用?
工作流的部署步骤成功,说明发布命令完成了。接下来还要检查应用是否能启动,以及目标路由是否返回正确结果。
1. 理解签名认证
本文使用 authType: function。触发器有互联网访问地址,但调用者仍需进行签名认证;直接在浏览器打开,或者执行没有签名的 curl,可能返回认证错误。
如果只是公开的学习 Demo,可以明确把 authType 改为 anonymous 后部署,再用浏览器和 curl 检查。此时允许的方法和应用路由会对访问者开放,新增、修改、删除接口也包含在内。公网触发器鉴权和应用自己的用户登录,需要分别设计。HTTP 触发器配置
2. 使用签名请求检查 /health
保存下面的脚本为 check_health.py。它按官方签名接口构造一个没有请求体、没有查询参数的 GET /health:
import os
from datetime import datetime, timezone
from urllib.parse import urlsplit
import requests
from Tea.request import TeaRequest
from alibabacloud_openapi_util.client import Client as Signing
endpoint = os.environ["FC_HTTP_URL"].rstrip("/") + "/health"
headers = {
"x-acs-date": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
}
if token := os.getenv("ALIBABA_CLOUD_SECURITY_TOKEN"):
headers["x-acs-security-token"] = token
request = TeaRequest()
request.method = "GET"
request.pathname = urlsplit(endpoint).path
request.query = {}
request.headers = headers
headers["authorization"] = Signing.get_authorization(
request,
"ACS3-HMAC-SHA256",
"",
os.environ["ALIBABA_CLOUD_ACCESS_KEY_ID"],
os.environ["ALIBABA_CLOUD_ACCESS_KEY_SECRET"],
)
response = requests.get(endpoint, headers=headers, timeout=30)
print(response.status_code, response.text)
response.raise_for_status()
在自己的终端环境中设置以下值:
FC_HTTP_URL:从触发器复制的基础 URL,例如https://<实际主机>.cn-hongkong.fcapp.run。ALIBABA_CLOUD_ACCESS_KEY_ID、ALIBABA_CLOUD_ACCESS_KEY_SECRET:有权限调用该函数的身份凭据。ALIBABA_CLOUD_SECURITY_TOKEN:仅在使用 STS 临时凭据时一并设置。
本地检查变量沿用官方 SDK 命名,和 GitHub Secrets 的 ALIYUN_... 名称不同,要填写正确。随后运行:
uv run --with alibabacloud-openapi-util --with requests python check_health.py
最小应用的预期响应是 HTTP 200 和 {"ok":true}。签名脚本不要打印凭据或完整请求头;改变方法、路径、查询参数或请求体时,也要同步修改签名输入。HTTP 触发器签名认证教程
另外,s invoke 与请求 GET /health 并不等价。Web 服务模式下,InvokeFunction 调用会映射为 POST /invoke;应用没有该路由时可能返回 404,不能据此断定所有 HTTP 接口都不可用。Web 函数调用映射
十、以前的配置为什么容易让人记混?
早期练习中用过下面这些 FC 2.0 写法:
| 旧练习的字段 | 本文 FC 3.0 的写法 |
|---|---|
edition: 1.0.0 | edition: 3.0.0 |
services | resources |
component: fc | component: fc3 |
service.name 与 function.name | 本例使用 functionName |
function.caPort: 9000 | customContainerConfig.port: 9000 |
triggers[].name/type/config | triggerName/triggerType/triggerConfig |
旧练习是 FastAPI 任务 CRUD 示例,包含 Dockerfile 和 s.yaml。它的部署前钩子会导出 requirements.txt,但没有 GitHub Actions 工作流,也没有明确的 Docker 构建、推送步骤。因此,单凭那份配置不能复原一条已经存在的 GitHub 自动发布链路;本文把这些缺少的步骤补齐。
还有一个值得记住的区别:s.yaml 写了镜像地址,只是告诉函数计算要使用哪个镜像。镜像必须先构建并出现在仓库中,本例用 Docker Actions 完成这件事。
Serverless Devs 提供 FC2 到 FC3 的配置转换命令,转换后仍要检查运行时、触发器和代码语义是否匹配。FC2 配置转换说明
十一、如果不用 Docker,代码包怎样适配?
也可以选自定义运行时,上传代码目录和依赖。下面用 custom.debian12 展示启动配置的结构,替换前面示例的 runtime 和容器块:
runtime: custom.debian12
code: ./code
environmentVariables:
PYTHONPATH: /code/python
customRuntimeConfig:
command:
- /usr/bin/python3
args:
- -m
- uvicorn
- app.main:app
- --host
- 0.0.0.0
- --port
- "9000"
- --timeout-keep-alive
- "86400"
port: 9000
在这份例子里,上传目录包含 code/app/ 与 code/python/:前者放应用,后者放安装好的第三方依赖。目录名 python 是这里的安排,PYTHONPATH 要与实际布局一致。
依赖要匹配云端 Linux、CPU 架构及 Python 版本;尤其包含二进制扩展的包,不能直接拿 macOS 的虚拟环境上传。Debian 12 的可用地域和预装 Python 版本也要按控制台及当前文档确认;其自带 Python 版本不能直接等同于前面容器里的 Python 3.12。自定义运行时支持情况
选择这条路线时,GitHub 工作流需要改成准备 Linux 代码包及依赖,再执行部署。本节只说明代码包的运行契约,前面完整的构建和推送工作流配套的是容器路线。
十二、常见问题怎么定位?
| 现象 | 优先检查 |
|---|---|
构建时找不到 requirements.txt | 导出步骤有没有执行,Docker 是否使用 context: . |
uv export --locked 报错 | pyproject.toml 改动后,有没有更新并提交 uv.lock |
| Docker 登录或推送失败 | 登录域名、用户名、密码、仓库路径及推送权限 |
| 函数拉取镜像失败 | 镜像标签是否存在、账号地域是否一致、函数角色的读取权限 |
| 企业版镜像拉取失败 | acrInstanceId、实例网络及 RAM 配置 |
出现 exec format error | 是否构建了 linux/amd64 镜像 |
| 服务连接失败或启动超时 | 导入路径、依赖、0.0.0.0、监听端口、容器启动日志 |
| HTTP 认证错误 | 触发器是否要求签名,调用身份权限、签名方法与时间 |
| 接口返回 404 | 请求方法和路径是否匹配,是否误用 s invoke 检查普通路由 |
| 修改依赖后仍像旧版本 | 函数镜像地址是否指向此次提交 SHA,部署步骤是否真的成功 |
| 数据一会有、一会没有 | 是否把数据保存在进程内存,是否发生实例切换或回收 |
| 自定义域名 HTTPS 失败 | DNS、FC 域名绑定、路由及该域名的证书 |
观察日志时,应分别看 GitHub 构建日志、部署 API 返回以及云端应用启动日志。只有镜像构建成功,还不能说明 Uvicorn 启动成功;认证失败,也需要先判断请求是否到达应用。
内存列表为什么不能当数据库?
任务练习常用 db = [] 保存数据。这个列表只属于某一个 Python 进程:实例回收后会丢失,不同实例也不会共享它。instanceConcurrency: 1 只限制单实例并发,并不能把所有流量固定到一个永久进程。
需要保存业务数据时,应接数据库或其他持久化服务;容器内临时文件也不能默认当成永久存储。实例生命周期与隔离
自定义域名还要配置什么?
例如想用 api.example.com,需要完成三个部分:
- 在 DNS 中添加指向函数计算要求目标的记录。
- 在 FC 中绑定该域名,并配置到目标函数的路由。
- 配置覆盖该域名的 HTTPS 证书与协议。
只添加 CNAME 并不能代替函数计算里的域名和证书配置。首次验证可先使用触发器原始地址,应用确认正常后再绑定域名。函数计算自定义域名配置
十三、发布出问题时怎样回退?
使用提交 SHA 作为镜像标签,可以找到上一个已经验证过的镜像。在完成本地 Serverless Devs 凭据配置、并设置与 GitHub 相同的地域、函数名和角色变量后:
export FC_IMAGE_URI="<实际ACR登录域名>/<命名空间>/<仓库>:<上一个正常提交SHA>"
s deploy --skip-push --assume-yes
本地使用前,可执行 s config add 按交互提示配置阿里云凭据,别名填 fc-ci,与 s.yaml 一致。Serverless Devs 凭据配置
这会让 LATEST 配置重新使用旧镜像;它不会回退数据库变更,也不构成基于发布版本和别名的完整流量切换方案。还要把 GitHub 中有问题的代码或配置修正,再走正常发布流程,否则下一次推送可能重新部署有问题的版本。
十四、保留文档以后,清理项目时记住什么?
以后再做同类项目,可以从本文的目录结构、Dockerfile、s.yaml 和工作流开始,重新填写自己的地域、仓库、角色及凭据。
删除 GitHub 源码仓库,是源码管理操作。已经部署的函数、HTTP 触发器、ACR 镜像和其他云资源有各自的生命周期,仍需在阿里云单独管理。需要停止服务时,要另行检查并处理云端资源。
这条流程最值得记住的是:选择 Web 服务运行方式,让应用按指定地址和端口启动;先把镜像构建并推送成功,再让函数计算使用它;最后通过真实 HTTP 路由确认应用响应。