From 38676d1fb1f24a306318a66abd4c6f0201a1aa0a Mon Sep 17 00:00:00 2001 From: Jeff Tian Date: Sat, 20 Jan 2024 17:50:52 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=BC=95=E5=85=A5=20serverless=20?= =?UTF-8?q?=E5=92=8C=20sam=EF=BC=8C=E5=A2=9E=E5=8A=A0=20AWS=20Lambda=20?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E7=9B=AE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/lambda.yml | 33 ++++++++++++++++++++ .gitignore | 3 ++ README.md | 24 +++++++++++++-- app.js | 5 +-- package.json | 10 ++++-- sam/.aws-sam/build.toml | 5 +++ sam/.aws-sam/build/template.yaml | 17 ++++++++++ sam/template.yaml | 17 ++++++++++ server.js | 3 ++ serverless.js | 4 +++ yarn.lock | 53 ++++++-------------------------- 11 files changed, 123 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/lambda.yml create mode 100644 sam/.aws-sam/build.toml create mode 100644 sam/.aws-sam/build/template.yaml create mode 100644 sam/template.yaml create mode 100644 server.js create mode 100644 serverless.js diff --git a/.github/workflows/lambda.yml b/.github/workflows/lambda.yml new file mode 100644 index 0000000..a47368f --- /dev/null +++ b/.github/workflows/lambda.yml @@ -0,0 +1,33 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages + +name: Node.js Package + +on: + push: + branches: + - main +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm i -g yarn + - run: yarn && yarn ci + - run: yarn zip + - uses: aws-actions/setup-sam@v2 + - uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: us-east-1 + - run: | + cd sam + sam build --use-container + # Prevent prompts and failure when the stack is unchanged + - run: | + cd sam + sam deploy --no-confirm-changeset --no-fail-on-empty-changeset diff --git a/.gitignore b/.gitignore index cd0de1e..9f403ed 100644 --- a/.gitignore +++ b/.gitignore @@ -138,3 +138,6 @@ results3.txt script.ps1 script2.ps1 script3.ps1 + +.env +sam/*.zip diff --git a/README.md b/README.md index 3ea97b3..f9042ea 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ yarn test 如果采用了 Redis 缓存,可以设置成多个 Pod,但是,需要注意,如果 Pod 重启,缓存会丢失,所以,需要设置成多个 Pod 的时候,需要使用 Redis 缓存。 -本来本项目部署在 Okteto 提供的免费 Kubernetes 集群上,域名是 https://bedrock-backstage-jeff-tian.cloud.okteto.net/message ,但是在 2024 年 1 月 15 日,Okteto 关闭免费服务。于是对本项目进行了重新部署,选择 cyclic,它是一个无服务器平台,不能再使用内存缓存,因为微信服务的消息重试会打在不同的实例上。好在,cyclic 提供了方便的 DynamoDb 存储,于是,将缓存从内存缓存改成了 DynamoDb 缓存。 +本来本项目部署在 Okteto 提供的免费 Kubernetes 集群上,域名是 https://bedrock-backstage-jeff-tian.cloud.okteto.net/message ,但是在 2024 年 1 月 15 日,Okteto 关闭免费服务。于是对本项目进行了重新部署,选择 [cyclic](https://app.cyclic.sh/#/join/Jeff-Tian),它是一个无服务器平台,不能再使用内存缓存,因为微信服务的消息重试会打在不同的实例上。好在,[cyclic](https://app.cyclic.sh/#/join/Jeff-Tian) 提供了方便的 DynamoDb 存储,于是,将缓存从内存缓存改成了 DynamoDb 缓存。 ## 缓存 @@ -143,11 +143,29 @@ yarn test ### 代码依赖 -本项目基于 Koa js 和 AWS 的 Bedrock SDK,并依赖 Cyclic 提供的对 AWS SDK 的上层封装。 +本项目基于 Koa js 和 AWS 的 Bedrock SDK,并依赖 [Cyclic](https://app.cyclic.sh/#/join/Jeff-Tian) 提供的对 AWS SDK 的上层封装。 ### 基础设施依赖 -本项目依赖 AWS Bedrock 服务,并且需要 Cyclic 平台 或者 AWS DynamoDb 和任意的 Kubernetes 平台。 +本项目依赖 AWS Bedrock 服务,并且需要 [Cyclic 平台](https://app.cyclic.sh/#/join/Jeff-Tian) 或者 AWS DynamoDb 和任意的 Kubernetes 平台。 + +## 部署 + +可以部署到多个环境,包括本地、Vercel、AWS Lambda、Cyclic 和 Kubernetes 等等。推荐使用 GitHub Actions 进行自动部署。 + +### 部署到 Cyclic + +1. 在 [Cyclic](https://app.cyclic.sh/#/join/Jeff-Tian) 上创建一个项目 +2. 链接到你的 GitHub 仓库 +3. 自动部署 + +### 部署到 Kubernetes + +参考 GitHub Actions 的配置文件,将其中的环境变量替换成你自己的即可。 + +### 部署到 AWS Lambda + +参考 GitHub Actions 的配置文件,将其中的环境变量替换成你自己的即可。 ## 相关文章 diff --git a/app.js b/app.js index 1d6cafe..2f6c583 100644 --- a/app.js +++ b/app.js @@ -1,3 +1,5 @@ +require('dotenv').config(); + const container = require('./container'); const {BedrockRuntimeClient} = require("@aws-sdk/client-bedrock-runtime"); @@ -109,5 +111,4 @@ router.get('/recall', async (ctx) => { app.use(router.routes()); - -app.listen(8080); +module.exports = app; diff --git a/package.json b/package.json index f701d61..b835134 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,18 @@ "@aws-sdk/client-bedrock-runtime": "^3.478.0", "@cyclic.sh/dynamodb": "^0.0.35", "@koa/router": "^12.0.1", + "dotenv": "^16.3.2", "koa": "^2.14.2", "koa-body": "^6.0.1", + "serverless-http": "^3.2.0", "xml-js": "^1.6.11" }, "scripts": { - "start": "node app.js", - "ci": "echo 'success'", - "test": "mocha --recursive --exit" + "start": "node server.js", + "ci": "yarn test", + "test": "mocha --recursive --exit", + "zip": "zip -r sam/dist.zip .", + "serverless-local": "yarn zip&&cd sam&&sam build&&sam local start-api" }, "devDependencies": { "mocha": "^10.2.0" diff --git a/sam/.aws-sam/build.toml b/sam/.aws-sam/build.toml new file mode 100644 index 0000000..678bce4 --- /dev/null +++ b/sam/.aws-sam/build.toml @@ -0,0 +1,5 @@ +# This file is auto generated by SAM CLI build command + +[function_build_definitions] + +[layer_build_definitions] diff --git a/sam/.aws-sam/build/template.yaml b/sam/.aws-sam/build/template.yaml new file mode 100644 index 0000000..8dd2da7 --- /dev/null +++ b/sam/.aws-sam/build/template.yaml @@ -0,0 +1,17 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Resources: + EasySchoolBackendFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ../../dist.zip + Handler: dist/serverless/serverless.handler + Runtime: nodejs18.x + Timeout: 900 + PackageType: Zip + Events: + ApiEvent: + Type: Api + Properties: + Path: /{any+} + Method: ANY diff --git a/sam/template.yaml b/sam/template.yaml new file mode 100644 index 0000000..97d3c8d --- /dev/null +++ b/sam/template.yaml @@ -0,0 +1,17 @@ +AWSTemplateFormatVersion: "2010-09-09" +Transform: AWS::Serverless-2016-10-31 +Resources: + EasySchoolBackendFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./dist.zip + Handler: dist/serverless/serverless.handler + Runtime: nodejs18.x + Timeout: 900 + PackageType: Zip + Events: + ApiEvent: + Type: Api + Properties: + Path: /{any+} + Method: ANY diff --git a/server.js b/server.js new file mode 100644 index 0000000..79286e7 --- /dev/null +++ b/server.js @@ -0,0 +1,3 @@ +const app = require('./app'); + +app.listen(8080); diff --git a/serverless.js b/serverless.js new file mode 100644 index 0000000..38eb1b6 --- /dev/null +++ b/serverless.js @@ -0,0 +1,4 @@ +const ServerlessHttp = require("serverless-http"); +const app = require("./app"); + +module.exports.handler = ServerlessHttp(app); diff --git a/yarn.lock b/yarn.lock index d46a3df..a2823d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1780,11 +1780,6 @@ asap@^2.0.0: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== -assertion-error@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" - integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1854,17 +1849,6 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -chai@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-5.0.0.tgz#da1ae496fdac30e97062cbd59e6e2f7bb4c78cc0" - integrity sha512-HO5p0oEKd5M6HEcwOkNAThAE3j960vIZvVcc0t2tI06Dd0ATu69cEnMB2wOhC5/ZyQ6m67w3ePjU/HzXsSsdBA== - dependencies: - assertion-error "^2.0.1" - check-error "^2.0.0" - deep-eql "^5.0.1" - loupe "^3.0.0" - pathval "^2.0.0" - chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -1873,11 +1857,6 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -check-error@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.0.0.tgz#589a4f201b6256fd93a2d165089fe43d2676d8c6" - integrity sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog== - chokidar@3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -1966,11 +1945,6 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -deep-eql@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.1.tgz#21ea2c0d561a4d08cdd99c417ac584e0fb121385" - integrity sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw== - deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -2018,6 +1992,11 @@ diff@5.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== +dotenv@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.2.tgz#3cb611ce5a63002dbabf7c281bc331f69d28f03f" + integrity sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2117,11 +2096,6 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" @@ -2388,13 +2362,6 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -loupe@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.0.tgz#46ef1a4ffee73145f5c0a627536d754787c1ea2a" - integrity sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg== - dependencies: - get-func-name "^2.0.1" - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -2553,11 +2520,6 @@ path-to-regexp@^6.2.1: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== -pathval@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" - integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== - picomatch@^2.0.4, picomatch@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2621,6 +2583,11 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" +serverless-http@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/serverless-http/-/serverless-http-3.2.0.tgz#68acc7735f7c876733c04f038ee20f31f5ebfc9b" + integrity sha512-QvSyZXljRLIGqwcJ4xsKJXwkZnAVkse1OajepxfjkBXV0BMvRS5R546Z4kCBI8IygDzkQY0foNPC/rnipaE9pQ== + set-function-length@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"