”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 适用于 AWS 云的简单 SaaS 的技术堆栈

适用于 AWS 云的简单 SaaS 的技术堆栈

发布于2024-11-08
浏览:286

The Tech Stack of a Simple SaaS for AWS Cloud

介绍


注1:这里是托管的交互式演示:demo.saasconstruct.com

注 2:我每个 SaaS 设置的每月账单为 3-5 美元,其中大部分是 CI/CD 成本。

注3:模板在这里:saasconstruct.com。


我在 AWS 上完成了多个 AI PoC 和 MVP,而且总是类似的事情

  • 在某处托管前端
  • 调用后端
  • 后端从二进制存储/数据库获取/更新数据
  • 后端执行一些AI逻辑或调用另一个服务并返回结果
  • 有两个独立的 AWS 账户:dev 和 prod
  • 用于部署的 CI/CD
  • 云资源声明的基础设施即代码

因此,我想构建一个简单的解决方案来在 AWS 上引导此类内容。并写一篇关于它的博客文章。

我决定添加一些功能,例如 Stripe 付款(如果您不想担心销售税/增值税,则可以添加 LemonSqueezy 付款)以及付款管理、身份验证、交通警报等。我还认为它需要是可配置的,例如用 ELB 和 ECS 替换 API Gateway 和 AWS Lambda 来执行较长的任务。

前端

我选择了普遍认为最简单的框架作为开始。它是 Vue,据我所知,它是第二受欢迎的框架。我选择它不仅是因为它是最简单的,而且我也有一些使用它的经验。

该网站是一个标准的SPA应用程序,以Vite为构建工具。对于样式设计,我使用 Bootstrap,因为它也非常易于使用,而且还因为从一个版本的前端框架迁移到另一个版本时它不会造成很多痛苦。

前端托管

有两个选项:

  • S3 和 CloudFront (CDN)
  • AWS Amplify Hosting,它是 S3 和 CloudFront 的包装器,易于使用,但可配置性较差。例如,您无法使用 CloudFront 分发执行任何操作,因为它不可见。除了使用重定向之外,您也无法对您的应用程序进行地理阻止。

我选择Amplify Hosting作为AWS在前端托管解决方案中的主要焦点,因为它很容易设置、附加域等。

由于是按量付费,我设置了流量警报:如果每10秒的点击次数超过一定数量,我会收到通知。

后端

后端是API Gateway,它执行速率限制,以及AWS Lambda (Python),它执行业务和一般逻辑:

  • 检查用户是否通过身份验证
  • 处理付款和管理订阅(客户门户)
  • 发送电子邮件
  • ETC。

我还有另一个 AWS Lambda 函数,可以在 Cognito 中注册后在数据库中创建用户。

有共享实用程序,我在其中放置了一些共享功能,例如电子邮件。此外,还有记录功能,例如,如果出现付款错误,则会向我发送电子邮件。

验证

我知道身份验证很痛苦,而且我不想使用第三方服务。所以我继续使用 AWS Cognito。还蛮便宜的。

您可以说,只需使用AWS Amplify Auth(这是 AWS Cognito 的包装器),但我遇到了一些问题。我什至在 Reddit 上写了一篇文章:

我的 Amplify 身份验证问题列表

还有另一篇文章,其中包含来自一些沮丧的用户的更大列表(尽管这是一篇旧文章)。

这里

此外,如果您只使用 Amplify,您就会被整个生态系统困住,没有机会做出改变。例如,如果您想访问 CloudFront 发行版(例如,当您想对某些区域进行地理封锁时),那么运气不好,您无法通过 Amplify Hosting 看到它。我还有其他问题:其中一个例子是从 Amplify 资源创建 CDK,这对我来说是一个痛点。

因此,我采用了一种混合方法(根据 Reddit 的说法,这种方法有些流行):AWS Amplify JS 库 允许您导入自己创建的云资源,例如用户池,因此我创建了它们使用 CDK,然后仅使用 Amplify JS 库进行身份验证。

在这种情况下,我可以随时更改我想要的任何内容,交换云资源(例如,如果我需要访问 CloudFront 发行版,我可以从 Amplify Hosting 转到 CloudFront S3)。

电子邮件

AWS SES。它是主要的 AWS 电子邮件服务。它会发送所有内容,包括 Cognito 身份验证电子邮件、联系表单中的请求等。您唯一需要了解的是,在您的开发 AWS 帐户中,您需要首先创建经过验证的身份才能发送(我通过IaC),并且在生产 AWS 账户中,您需要请求生产访问权限(只需单击几下)。

使用 AWS SES,在以下场景中发送电子邮件通知:

  • 发生付款错误时。
  • 如果网络流量出现峰值。
  • 如果 CI/CD 部署失败。
  • 对于其他情况,例如身份验证电子邮件和联系表单的查询等

贮存

DynamoDB 作为数据库。简单、快速且易于管理。是的,我必须考虑访问模式,但一般来说,它很好用,而且在验证/构建时也不会花费我任何费用。由于我计划开发多个产品并希望将它们隔离,因此我无法将 RDS/DocumentDB 放入每个项目的开发和生产帐户中(成本太高)。

付款方式

我添加了两个支付系统,可以选择使用哪一个,因为它们的工作原理相似:

  • Stripe 很流行且易于集成,简单明了。当用户购买产品时,我使用 Stripe 结帐,而为了管理订阅,我使用 Stripe 客户门户。
  • LemonSqueezy 与 Stripe 非常相似,但它也是记录商家,这意味着它为您处理销售税/增值税。它还具有用于购买订阅的结帐和用于管理订阅的客户门户。

我为 Stripe/LemonSqueezy webhooks 编写了端点,它们处理所有逻辑。

基础设施即代码

所以有很多东西可供选择:

  • 类似 Terraform 或 OpenTofu(基于 Terraform 的完全开源替代方案)
  • 普鲁米
  • CDK
  • 云形成

我选择了AWS CDK,这是我的原因:

  • 使用起来很容易
  • 流行且足够成熟
  • 我认为它比 AWS CloudFormation 好得多
  • 这是一个AWS库,我使用AWS
  • 我可以用 Python、TypeScript 或其他语言编写它。由于我在后端使用Python,在前端使用TypeScript,所以这是一个不错的选择。

我没有选择Terraform的原因是CDK更容易;至少在我看来,它允许以简单的方式创建资源。我喜欢 OOP,并尝试相应地构建我的云基础设施。一个很大的好处是包含了 CI/CD(CDK 管道),所以我不必发明它。

持续集成/持续交付

我选择了CDK pipelines,因为它同样很简单。只需将管道连接到 GitHub 存储库,就可以开始了。 Git 推送到开发分支 -> 它将被推送到开发帐户。 Git 推送到主(或拉取请求)-> 生产部署。

警报和速率限制

我设置了速率限制以防止通过 API 网关收到垃圾邮件。我设置了两个 CloudWatch 警报:

  • 当托管网站收到大量请求时提醒我。
  • 当 API 网关收到大量请求时提醒我。

我还设置了计费警报,以通知我是否要花费太多。

记录

CloudWatch 记录事件,您可以在 AWS 控制台中查看它们,也可以通过扩展直接在 IDE 中查看它们。

人工智能

选择是使用 OpenAI(使用 GPT 模型)或 AWS Bedrock(使用 Claude 模型)。这一决定具有挑战性,因为虽然 AWS Bedrock with Claude 可以轻松地与 AWS 集成,但 OpenAI 更常用。两家公司都提供顶级人工智能模型。目前,我选择坚持使用 AWS Bedrock。这将来可能会改变,但就目前而言,我很欣赏这种简单性。对于矢量数据库,我使用 Pinecone,它具有无服务器索引。

我在这里构建的人工智能应用程序的一个示例是RAG系统,它本质上是一个聊天机器人,可以根据您的数据回答问题。您将信息存储在向量数据库中,并在查询时进行相似性搜索,然后使用 LLM 根据该搜索结果给出答案。我目前使用简单的模型来避免成本,但切换到不同的模型就像更改一行代码一样简单。

编程语言

我最初是一名 Java 开发人员,但后来因为开发机器学习和深度学习服务而成为一名 Python 开发人员。该领域的大多数库都是用 Python 开发的或具有 Python 包装器。此外,Python 与 AWS 无缝集成,无论是在 AWS Lambda(例如,使用 AWS Lambda Powertools 库)还是在 CDK 中。所以最终,后端和云基础设施(通过 CDK)都是用 Python 实现的。

我的第二语言是 TypeScript,因为它在前端框架中很受欢迎。虽然我曾经使用 JavaScript,但随着代码库变得越来越大,我发现类型的缺失令人困惑。 TypeScript 的静态类型在开发过程中提供了急需的清晰度和安全性,尤其是在大型项目中。

AWS 账单

由于我的流量负载不高,因此我的 AWS 成本非常低,通常 每月 3-5 美元,主要是由于 CI/CD 费用。

该设置包括 CDN(由 Amplify Hosting 提供)和 AWS Lambda 内的小型缓存层。此外,某些服务属于 AWS 免费套餐,这进一步降低了我的成本。

随着产品规模扩大并获得更多用户,我可能需要通过切换到配置的 DynamoDB 并实施 DAX(DynamoDB 加速器) 来优化资源。然而,就目前而言,此设置运行良好。

结论

这个解决方案有效地满足了我当前的需求。

我已将整个技术堆栈作为 样板文件(我积极开发和更新)包含在我的 SaaSConstruct 上的 AWS 模板中。

我将继续探索可以合并到此设置中的其他功能,以增强其功能...

版本声明 本文转载于:https://dev.to/server_kota/the-tech-stack-of-a-simple-saas-for-aws-cloud-4lhm?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Django 查询集可以通过模型属性过滤吗?
    Django 查询集可以通过模型属性过滤吗?
    按模型属性过滤 Django 查询集Django 模型上的查询通常使用标准过滤器根据预定义字段值选择特定实例。但是,如果您需要根据模型中定义的自定义属性进行过滤,该怎么办?您可以通过模型属性过滤查询集吗?不幸的是,Django 的过滤器主要运行在数据库级别,将它们转换为 SQL 命令以有效地检索数据...
    编程 发布于2024-11-08
  • 尽管配置正确,为什么我无法在 Laravel 中发送 TLS 电子邮件?
    尽管配置正确,为什么我无法在 Laravel 中发送 TLS 电子邮件?
    无法发送 TLS 电子邮件:解决 Laravel 证书验证错误尽管启用了不太安全的 Gmail 设置并正确配置了 Laravel 的 .env 文件,您在发送 TLS 电子邮件时遇到证书验证失败。错误消息表明 SSL 操作失败并且无法验证服务器证书。要解决此问题,如果您的操作系统没有自动管理受信任的...
    编程 发布于2024-11-08
  • 使用 Wasmtime 和 Wasm3 将 Golang 编译为 Wasm 时出现错误如何解决?
    使用 Wasmtime 和 Wasm3 将 Golang 编译为 Wasm 时出现错误如何解决?
    使用 Wasmtime 和 Wasm3 将 Golang 编译为 Wasm 时出现错误使用 GOOS=js 将 Golang 代码编译为 WebAssembly (Wasm) GOARCH=wasm go使用 Wasmtime 或 Wasm3 执行时,build -o main.wasm 可能会导致...
    编程 发布于2024-11-08
  • 如何访问 Iframe 的当前位置?
    如何访问 Iframe 的当前位置?
    访问 iframe 的当前位置:挑战和解决方法跨源资源共享 (CORS) 法规在尝试检索 iframe 时带来了重大挑战iframe 的当前位置。此安全措施可防止驻留在不同来源的 JavaScript 代码直接访问页面的 URL。虽然使用 JavaScript 访问 iframe 的 URL 不可行...
    编程 发布于2024-11-08
  • Spring Security 与 JWT
    Spring Security 与 JWT
    In this article, we will explore how to integrate Spring Security with JWT to build a solid security layer for your application. We will go through ea...
    编程 发布于2024-11-08
  • Google Sheets:如何花费数小时构建 SUMIFS
    Google Sheets:如何花费数小时构建 SUMIFS
    大家好!今天我想分享一个我创建的超级有用的脚本,用于解决日常生活中的常见问题。 如果您曾经尝试在 Google 表格中对“持续时间”求和,您可能已经注意到,SUMIF 和 SUMIFS 公式无法根据特定条件对事件或产品的持续时间求和。根据您需要执行的计算类型,这可能会成为一个障碍。但别担心! Goo...
    编程 发布于2024-11-08
  • WordPress 迁移插件终极指南
    WordPress 迁移插件终极指南
    迁移 WordPress 网站就像收拾房子搬到新房子一样。确保所有内容(内容、主题、插件、媒体文件甚至数据库)完美移动且没有任何损坏的挑战似乎令人望而生畏。但就像搬家公司让搬家变得更容易一样,WordPress 迁移插件简化了将网站从一台主机移动到另一台主机的复杂过程。 无论您是切换主机、从本地开发...
    编程 发布于2024-11-08
  • 如何使用稳健的解决方案增强 PHP 中的 HTML 抓取
    如何使用稳健的解决方案增强 PHP 中的 HTML 抓取
    PHP 中强大的 HTML 抓取解决方案由于其挑剔和脆弱的性质,在 PHP 中使用正则表达式进行 HTML 抓取可能具有挑战性。要获得更强大、更可靠的方法,请考虑使用专门构建的 PHP 包。强烈推荐的一个选项是 PHP Simple HTML DOM Parser。该库擅长处理 HTML(包括无效标...
    编程 发布于2024-11-08
  • 如何检测 Go 标准输入 (Stdin) 中的数据可用性?
    如何检测 Go 标准输入 (Stdin) 中的数据可用性?
    使用 Go 检测标准输入 (Stdin) 中的数据可用性在 Go 中,可以使用以下技术检查标准输入流 (os.Stdin) 中的数据:验证其文件大小。它的工作原理如下:os.Stdin 可以像任何常规文件一样对待,允许我们检查其属性。为此,我们使用 os.Stdin.Stat() 检索 FileIn...
    编程 发布于2024-11-08
  • Wasp:Web 开发中 Django 的 JavaScript 答案
    Wasp:Web 开发中 Django 的 JavaScript 答案
    Wasp v Django: Building a full stack application just got a lot easier Hey, I’m Sam, a backend engineer with a lot of experience with Django....
    编程 发布于2024-11-08
  • 如何在没有键盘中断的情况下通过按键中断 While 循环?
    如何在没有键盘中断的情况下通过按键中断 While 循环?
    通过按键中断 While 循环在使用 while 循环读取串行数据并将其写入 CSV 文件的场景中,您可能希望为用户提供终止循环以停止数据收集的选项。本文探讨了在不显式使用键盘中断的情况下实现此类功能的技术。一种简单的方法是利用 try- except 块来处理 KeyboardInterrupt ...
    编程 发布于2024-11-08
  • 周 oot 训练营学习
    周 oot 训练营学习
    我决定迈出大胆的一步,参加由 LuxDevHQ 组织的我的第一个数据职业训练营。这是一个为期 5 周的训练营,旨在培养实践数据技能。该训练营旨在让人们接触至少 4 个专业领域的各种数据技能。 第一周以信息会议开始,我进行了项目定向,并​​向我介绍了该项目并了解了整个项目的期望。 在这第一周,我学到了...
    编程 发布于2024-11-08
  • 如何使用 Homebrew 和 jenv 在 Mac OS X 上管理多个 Java 版本?
    如何使用 Homebrew 和 jenv 在 Mac OS X 上管理多个 Java 版本?
    在 Mac OS X 上管理多个 Java 版本由于 Java 管理其安装的方式,在 Mac OS X 上安装多个 Java 版本可能是一项挑战。不过,有一个解决方案可以让您轻松安装和管理不同的 Java 版本:Homebrew。使用 Homebrew 和 jenvHomebrew 是一个包管理器,...
    编程 发布于2024-11-08
  • 如何创建 React 应用程序?安装与环境设置
    如何创建 React 应用程序?安装与环境设置
    在开始使用 React 构建应用程序之前,拥有正确的开发环境非常重要。以下是帮助您入门的分步指南: 步骤 1. 安装 Node.js 和 npm 设置 React 环境的第一步是安装 Node.js,因为它提供了在浏览器外部执行代码所需的 JavaScript 运行时。当您安装 Node.js 时,...
    编程 发布于2024-11-08
  • python 并发.futures
    python 并发.futures
    未来 Future 是一个容器,可以保存计算结果或计算期间发生的错误。创建 future 时,它​​以 PENDING 状态开始。该库不打算手动创建此对象,除非出于测试目的。 import concurrent.futures as futures f = futures.Futu...
    编程 发布于2024-11-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3