AWS Lambda Container 方式部署 Flask 應用并通過 API Gateway 提供訪問

前言

一年前寫過一篇 Lambda 運行 Flask 應用的博文:
https://lpwmm.blog.csdn.net/article/details/139756140

當時使用的是 ZIP 包方式部署應用代碼, 對于簡單的 API 開發用起來還是可以的, 但是如果需要集成到 CI/CD pipeline 里面就有點不太優雅. 本文將介紹使用容器方式部署 Flask 應用到 Lambda, 并實現通過 API Gateway 進行訪問.

開發一個簡單的 Flask 應用

使用 uv 作為項目管理工具, 如果你還不了解 uv, 可以參考之前的這篇文章:
https://lpwmm.blog.csdn.net/article/details/146774376

完整的項目代碼開源在 Gitee:
https://gitee.com/lpwm/flask-on-lambda

主要涉及到以下常用的場景:

  • 靜態文件訪問, 模板中引入了自定義的 CSS 樣式文件
  • 表單處理
  • 路由重定向

實現效果:
在這里插入圖片描述

容器化封裝

Dockerfile

# 使用 ECR 提供的 Alpine 環境的 Python 3.12
FROM public.ecr.aws/docker/library/python:3.12-alpine
# [重要] 添加 Lambda Web Adapter (LWA)
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.1 /lambda-adapter /opt/extensions/lambda-adapter# 使用清華源安裝 uv
RUN sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories \&& apk add --no-cache uv# [重要] 配置 uv 的緩存文件夾路徑, Lambda 中只有 /tmp 具有 RW 權限
ENV UV_CACHE_DIR="/tmp"
# 配置 uv 使用清華源
ENV UV_DEFAULT_INDEX="https://pypi.tuna.tsinghua.edu.cn/simple"WORKDIR /var/task# 先將 uv 項目相關的文件復制并初始化 .venv 和依賴
COPY pyproject.toml uv.lock .python-version ./
RUN uv sync# 再將其他文件復制, 這樣可以有效減少后面代碼發生更新時重新 build 鏡像所需要的操作時間
COPY static ./static
COPY templates ./templates
COPY app.py ./# Lambda 執行時只能在一個運行環境中跑一個 Worker, 所以注意加參數 -w=1, 監聽端口直接用 LWA 默認的 8080, 不用再改 LWA 的參數了
CMD ["uv", "run", "gunicorn", "-b=:8080", "-w=1", "app:app"]

測試容器

docker build -t flask-on-lambda .
docker run -it --rm -p 8080:8080 flask-on-lambda

AWS 資源創建

ECR & Lambda

REPO_NAME=flask-on-lambda
# 創建 ECR repository
aws ecr create-repository --repository-name $REPO_NAME# 將 ECR repository 的 URI 存入變量, 方便后面調用
REPO_URI=$(aws ecr describe-repositories --repository-names $REPO_NAME --query 'repositories[0].repositoryUri' --output text)# 從 URI 拆分出來 ECR 的主域名, 用于 Docker 登錄訪問
ECR_HOST=$(echo $REPO_URI | awk -F'/' '{print $1}')# Docker 登錄 ECR
aws ecr get-login-password --region cn-northwest-1 | docker login --username AWS --password-stdin $ECR_HOST# 推送 Docker image 到 ECR
docker tag $REPO_NAME:latest $REPO_URI:latest
docker push $REPO_URI:latest# [可選] 獲取最新 Image 的哈希值
LATEST_DIGEST=$(aws ecr describe-images --repository-name $REPO_NAME --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageDigest' --output text)# [可選] 更新 Lambda
aws lambda update-function-code --function-name $REPO_NAME --image-uri $REPO_URI@$LATEST_DIGEST --no-cli-pager# 創建 IAM Role
aws iam create-role \--role-name lambda-execution-role-$REPO_NAME \--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}' \
&& aws iam attach-role-policy \--role-name lambda-execution-role-$REPO_NAME \--policy-arn arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole# 獲取 Role ARN
ROLE_ARN=$(aws iam get-role --role-name lambda-execution-role-$REPO_NAME --query 'Role.Arn' --output text)# 創建和 REPO 相同名稱的 Lambda
aws lambda create-function \--function-name $REPO_NAME \--package-type Image \--code ImageUri=$REPO_URI:latest \--role $ROLE_ARN

測試 Lambda 調用

aws lambda invoke \--function-name flask-on-lambda \--payload '{"httpMethod": "GET","path": "/","headers": {"Host": "example.com","User-Agent": "curl/7.68.0"},"requestContext": {"resourcePath": "/","httpMethod": "GET"},"body": null,"isBase64Encoded": false}' \--cli-binary-format raw-in-base64-out \/dev/stdout

預期響應:

{"statusCode": 200,"headers": {},"multiValueHeaders": {"server": ["gunicorn"],"date": ["Sun, 13 Jul 2025 12:02:04 GMT"],"connection": ["close"],"content-type": ["text/html; charset=utf-8"],"content-length": ["585"]},"body": "<html>\n\n<head>\n    <title>Flask on Lambda</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/style.css\">\n</head>\n\n<body>\n    <section>\n        <h1>Welcome to the Flask on Lambda</h1>\n        <p>This is a simple Flask application powered by Lambda.</p>\n    </section>\n    <section>\n        <form action=\"\" method=\"post\">\n            <label for=\"name\">Name:</label>\n            <input type=\"text\" id=\"name\" name=\"name\" required placeholder=\"Enter your name\">\n            <br>\n            <button type=\"submit\">Submit</button>\n        </form>\n    </section>\n</body>\n\n</html>","isBase64Encoded": false
}

后面關于 API Gateway 的配置用 CLI 會很麻煩, 就都在 Console 操作了

API Gateway - HTTP API

  • 創建 HTTP API
    在這里插入圖片描述
    在這里插入圖片描述
  • 添加 Lambda 集成
    在這里插入圖片描述
  • 修改路由:
    Method: ANY
    Resource path: /{proxy+}
    在這里插入圖片描述
  • 使用默認 Stage
    在這里插入圖片描述
  • 完成創建
    在這里插入圖片描述
  • 在 Deploy > Stages 中找到 Invoke URL
    在這里插入圖片描述
  • 使用瀏覽器訪問測試, 受到 Lambda 的 Cold start 機制的影響, 首次加載和交互的速度會有點慢.
    在這里插入圖片描述
    后面刷新后再次交互速度就很快了.
    在這里插入圖片描述

性能優化

為了保證用戶能在首次訪問的時候也有友好的體驗, 我們可以為 Lambda 配置 Provisioned concurrency (額外收費的喲)

  • 首先為 Lambda function 創建 Version
    在這里插入圖片描述
    在這里插入圖片描述
  • 在 Version 視圖中編輯 Provisioned concurrency
    在這里插入圖片描述
    在這里插入圖片描述
  • 此時 Status 為 In progress, 需要等幾分鐘
    在這里插入圖片描述
    狀態變成 Ready 就好了
    在這里插入圖片描述
  • 復制當前 Version 界面的 Function ARN
    在這里插入圖片描述
  • 回到 HTTP API 控制臺修改 Integration, 將 Lambda function 對應的 ARN 更新為上面復制的帶有 Version 信息的
    在這里插入圖片描述
  • 確認目前使用的集成設置中 Lambda 包含了版本信息(后面多了 :1)
    在這里插入圖片描述
    因為 HTTP API 默認開啟了 Auto deploy 的選項, 所以這種修改都不需要手動重新 Deploy 操作. 再次使用瀏覽器訪問測試, 速度嘎嘎的~

當然, 我們前面配置的 Provisioned concurrency = 1, 對于生產環境業務負載較高的場景, 可以酌情提升.

結尾

至此, 我們成功使用 Docker 容器的方式將一個 Flask 應用部署到了 Lambda 上, 并通過 API Gateway (HTTP API) 對外提供了可訪問的 URL 地址, 實現了 Serverless 部署傳統 Web 應用. 🎉🎉🎉
由于應用全部都封裝在了 ECR 鏡像, 所以在實際項目中, 也可以很方便的融入到 CI/CD pipeline 中.

關于之前撰稿期間使用 REST API 踩坑的經歷, 有興趣可以繼續閱覽. 😂

REST API 踩坑記錄

由于 REST API 生成的 Stage URL 中必然會包含 stage 名稱, 而經過 LWA 轉發到后面的 Lambda 在進行路由地址生成的時候, 并不會包含這個 stage 的名稱. 例如: stage = default
第一次請求的地址: https://api.com/default/, 頁面中 Flask 跳轉后本來應該是定向到 https://api.com/default/success/abc 但是實際跳轉后的地址是 https://api.com/success/abc, 由于缺少了 stage 信息, 所以就 4XX 了. 如果 stage 名稱是固定的, 那么其實也可以在 Flask 應用里面直接寫死, 跟 REST API 傳來的保持一致, 理論上應該也能解決. 不過懶得折騰了…下面是之前配置 REST API 的記錄, 歸檔了.

  • 添加 Trigger
    在這里插入圖片描述
  • 創建新的 REST API
    在這里插入圖片描述
  • 打開自動創建好的 API
    在這里插入圖片描述
  • 刪除自動創建的資源路徑
    在這里插入圖片描述
  • 在根路徑下創建資源
    在這里插入圖片描述
  • 創建 Proxy 資源
    在這里插入圖片描述
  • 編輯集成
    在這里插入圖片描述
  • Execution role 可以留空
    在這里插入圖片描述
  • 測試 GET 方法
    在這里插入圖片描述
    在這里插入圖片描述
  • 部署 API
    在這里插入圖片描述
  • 繼續返回 Lambda function 設置, 添加環境變量 AWS_LWA_REMOVE_BASE_PATH, Value 值為 REST API 中的 Stage 名稱
    在這里插入圖片描述

REST API 存在問題

完成上面的配置后, 如果從瀏覽器直接訪問 Stage URL 根路徑報錯:
在這里插入圖片描述
訪問子路徑 success/變量 可以加載出來頁面
在這里插入圖片描述
但是靜態 CSS 文件加載失敗, 因為請求路徑中并沒有包含 stage 的名稱
在這里插入圖片描述
先來解決直接訪問 Stage 根路徑報錯的問題. 這是因為前面只給 /{proxy+} 創建了 ANY 方法和集成, 對于 / 來說, 還是空的設置. 再單獨選中 / 資源路徑, 創建 ANY 方法, 相同的方式配置 Lambda proxy 集成
在這里插入圖片描述

重新部署后就可以訪問到了:
在這里插入圖片描述
當提交表單后, 重新定向的 URL 又出現了和 CSS 加載相同的問題, Stage 名稱丟失了:
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88886.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88886.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88886.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

React虛擬DOM的進化之路

引言 在Web前端開發中&#xff0c;用戶交互的流暢性和頁面性能一直是核心挑戰。早期&#xff0c;開發者直接操作真實DOM&#xff08;Document Object Model&#xff09;時&#xff0c;頻繁的重排&#xff08;reflow&#xff09;和重繪&#xff08;repaint&#xff09;導致性能…

(7)機器學習小白入門 YOLOv:機器學習模型訓練詳解

— (1)機器學習小白入門YOLOv &#xff1a;從概念到實踐 (2)機器學習小白入門 YOLOv&#xff1a;從模塊優化到工程部署 (3)機器學習小白入門 YOLOv&#xff1a; 解鎖圖片分類新技能 (4)機器學習小白入門YOLOv &#xff1a;圖片標注實操手冊 (5)機器學習小白入門 YOLOv&#xff…

初識MySQL(三)之主從配置與讀寫分離實戰

主重復制 主重復制原理master開啟二進制日志記錄slave開啟IO進程&#xff0c;從master中讀取二進制日志并寫入slave的中繼日志slave開啟SQL進程&#xff0c;從中繼日志中讀取二進制日志并進行重放最終&#xff0c;達到slave與master中數據一致的狀態&#xff0c;我們稱作為主從…

RabbitMQ面試精講 Day 2:RabbitMQ工作模型與消息流轉

【RabbitMQ面試精講 Day 2】RabbitMQ工作模型與消息流轉 開篇 歡迎來到"RabbitMQ面試精講"系列的第2天&#xff0c;今天我們將深入探討RabbitMQ的工作模型與消息流轉機制。這是面試中最常被問到的核心知識點之一&#xff0c;90%的RabbitMQ面試都會涉及消息流轉流程…

基于SpringBoot3集成Kafka集群

1. build.gradle依賴引入 implementation org.springframework.kafka:spring-kafka:3.2.02. 新增kafka-log.yml文件 在resource/config下面新增kafka-log.yml&#xff0c;配置主題與消費者組 # Kafka消費者群組 kafka:consumer:group:log-data: log-data-grouptopic:log-data: …

wpf Canvas 導出圖片

在WPF中將Canvas導出為圖片主要涉及以下關鍵步驟和注意事項: ?核心實現方法?使用RenderTargetBitmap將Canvas渲染為位圖,再通過PngBitmapEncoder保存為PNG文件。需注意臨時移除Canvas的布局變換(LayoutTransform)以避免渲染異常?1。示例代碼片段:CanvasExporter.cs pu…

lvs負載均衡實操模擬

目錄 一、配置準備 二、NET模式 修改LVS端 開啟路由 修改對內網卡 ens160 修改對外網卡 ens224 加載網卡配置文件 修改web1端 修改網卡信息 重啟網絡 檢測 配置web2 檢測 驗證配置是否正常 啟動nginx服務 驗證以上配置 添加lvs規則 驗證 三、DR模式 修改…

Spring Boot 是如何簡化 IoC 的配置的?

首先Spring Boot 并沒有發明新的 IoC 理論&#xff0c;它做的也不是替換掉 Spring IoC 容器。相反&#xff0c;Spring Boot 是 Spring IoC 思想的實踐者和簡化者。它通過**“約定優于配置”&#xff08;Convention over Configuration&#xff09;**的理念&#xff0c;將原本繁…

Go語言中的組合式接口設計模式

文章目錄Go語言中的組合式接口設計模式背景和需求組合式接口設計Go語言中的組合式接口設計模式 背景和需求 在微服務架構和復雜業務系統中&#xff0c;我們經常需要調用多個外部服務或內部模塊。傳統的做法是將所有方法都放在一個大接口中&#xff0c;但這種設計會導致接口臃…

React - createPortal

什么是createPortal&#xff1f;注意這是一個API&#xff0c;不是組件&#xff0c;他的作用是&#xff1a;將一個組件渲染到DOM的任意位置&#xff0c;跟Vue的Teleport組件類似。用法 import { createPortal } from react-dom;const App () > {return createPortal(<div…

Cursor的使用

Cursor的使用 Ctrl L 打開歷史對話記錄 Tab智能助手 1.單行/多行補全 已有代碼片段&#xff1a; //需求&#xff1a;寫一個工具類計算數組平均值 public class ArrayUtils {//按tab會完成補全 }按tab鍵- Cursor 自動生成代碼: //需求&#xff1a;寫一個工具類計算數組平均值 p…

17.使用DenseNet網絡進行Fashion-Mnist分類

17.1 DenseNet網絡結構設計import torch from torch import nn from torchsummary import summary #卷積層 def conv_block(input_channels,num_channels):netnn.Sequential(nn.BatchNorm2d(input_channels),nn.ReLU(),nn.Conv2d(input_channels,num_channels,kernel_size3,pad…

網安系列【16】之Weblogic和jboss漏洞

文章目錄一 Weblogic1.1 Weblogic相關漏洞1.2 Weblogic漏洞發現1.3 Weblogic漏洞利用二 Jboss2.1 Jboss漏洞2.2 Jboss識別與漏洞利用一 Weblogic WebLogic 是由 Oracle公司 開發的一款基于Java EE&#xff08;現稱Jakarta EE&#xff09;的企業級應用服務器&#xff0c;主要用…

Unity URP + XR 自定義 Skybox 在真機變黑問題全解析與解決方案(支持 Pico、Quest 等一體機)

在使用 Unity 的 URP 渲染管線開發 XR 應用&#xff08;如 Pico Neo、Pico 4、Quest 2/3 等一體機&#xff09;時&#xff0c;很多開發者遇到一個奇怪的問題&#xff1a;打包后&#xff0c;Skybox&#xff08;天空盒&#xff09;在某些角度下突然變黑&#xff0c;只在轉動頭部后…

Cursor、飛算JavaAI、GitHub Copilot、Gemini CLI 等熱門 AI 開發工具合集

Cursor&#xff1a;代碼編寫的智能伙伴?Cursor 是 Anysphere 公司推出的一款 AI 編程工具&#xff0c;它基于微軟開源代碼編輯器 VS Code 開發&#xff0c;將 AI 技術深度整合到開發人員的工作流程中。Cursor 的功能十分強大&#xff0c;不僅能夠自動用純英文編寫代碼&#xf…

如何安裝歷史版本或指定版本的 git

背景 有的時候&#xff0c;我們需要安裝指定版本的git&#xff0c;或者希望舊一點的&#xff0c;畢竟我就遇到最新的2.50.1在win10安裝后打開就一閃而過&#xff0c;而安裝2.49.1就不會 下載 官網可能比較難找&#xff0c;但是這個github倉庫&#xff1a;https://github.com/gi…

LaCo: Large Language Model Pruning via Layer Collapse

發表&#xff1a;EMNLP_FINDING_2024 機構&#xff1a;Shanghai Jiao Tong University 連接&#xff1a;LaCo: Large Language Model Pruning via Layer Collapse - ACL Anthology 代碼&#xff1a;https://github.com/yangyifei729/LaCo Abstract 基于 Transformer 的大語…

服務器內核級故障排查

目錄 **檢查內核級故障(Oops/Panic)的具體操作步驟****1. 查看完整 `dmesg` 日志(含時間戳)****2. 過濾關鍵錯誤信息****3. 檢查系統日志中的內核消息****4. 分析最近一次啟動的日志****5. 檢查是否有 `vmcore` 轉儲文件****常見內核錯誤示例及含義**補充說明:檢查內核級故…

Flink學習筆記:整體架構

開一個新坑&#xff0c;系統性的學習下 Flink&#xff0c;計劃從整體架構到核心概念再到調優方法&#xff0c;最后是相關源碼的閱讀。 今天就來學習 Flink 整體架構&#xff0c;我們先看官網的架構圖圖中包含三部分&#xff0c;分別是 Client、JobManager 和 TaskManager。其中…

【LeetCode 熱題 100】105. 從前序與中序遍歷序列構造二叉樹——(解法二)O(n)

Problem: 105. 從前序與中序遍歷序列構造二叉樹 給定兩個整數數組 preorder 和 inorder &#xff0c;其中 preorder 是二叉樹的先序遍歷&#xff0c; inorder 是同一棵樹的中序遍歷&#xff0c;請構造二叉樹并返回其根節點。 【LeetCode 熱題 100】105. 從前序與中序遍歷序列構…