GitHub Actions 部署 FastAPI 到阿里云函数计算:代码适配与完整发布流程

#FastAPI #GitHub Actions #阿里云 #函数计算 #Docker

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 服务模式要特别注意三件事:

  1. 监听地址使用 0.0.0.0,使平台能够连接应用。
  2. 应用实际监听的端口,与函数配置的端口一致。
  3. 启动命令能够找到应用模块及其依赖,并在平台要求的时间内启动完成。

本文统一使用 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 / SecretGitHub 中的 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-ciServerless Devs 的凭据别名,须与 CI 注册的名称一致
runtime: custom-container通过镜像运行应用
customContainerConfig.image这次构建推送的完整镜像地址
customContainerConfig.port平台连接 Uvicorn 的端口
role函数计算使用的 RAM 角色 ARN
authType: functionHTTP 请求需要阿里云签名认证
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_REGIONcn-hongkong,与 ACR 地域一致
FC_FUNCTION_NAMEfastapi-github-demo
FC_FUNCTION_ROLE_ARN从 RAM 控制台复制函数角色 ARN
ACR_REGISTRYACR 登录域名,不含 https:// 和仓库路径
ACR_NAMESPACEfc-demo
ACR_REPOSITORYfastapi-api

在 Secrets 中创建:

名称内容
ALIYUN_ACCESS_KEY_ID专用 RAM 部署身份的 AccessKey ID
ALIYUN_ACCESS_KEY_SECRET对应的 AccessKey Secret
ACR_USERNAMEACR 控制台提供的 Docker 登录用户名
ACR_PASSWORDACR 登录密码

这些值由工作流读取,不需要写进源码。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 页面,进入本次运行,依次查看:

  1. 配置检查是否通过。
  2. uv export 是否成功。
  3. Docker 镜像是否构建并推送成功。
  4. 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.0edition: 3.0.0
servicesresources
component: fccomponent: fc3
service.name 与 function.name本例使用 functionName
function.caPort: 9000customContainerConfig.port: 9000
triggers[].name/type/configtriggerName/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,需要完成三个部分:

  1. 在 DNS 中添加指向函数计算要求目标的记录。
  2. 在 FC 中绑定该域名,并配置到目标函数的路由。
  3. 配置覆盖该域名的 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 路由确认应用响应。