From fa0358b85f2ca9af1abe86e1c815c7d9e3ef63ac Mon Sep 17 00:00:00 2001 From: yugasun Date: Thu, 6 Aug 2020 17:24:19 +0800 Subject: [PATCH] fix: support eip config --- docs/configure.md | 56 ++++++------ example/README.md | 229 ++++++++++++++++++++++++++++++++++++++++++---- src/package.json | 2 +- src/utils.js | 13 +-- 4 files changed, 246 insertions(+), 54 deletions(-) diff --git a/docs/configure.md b/docs/configure.md index 68addfa..c1ecc30 100644 --- a/docs/configure.md +++ b/docs/configure.md @@ -32,6 +32,7 @@ inputs: version: 1 # 版本 functionConf: # 函数配置相关 timeout: 10 # 超时时间,单位秒 + eip: false # 是否固定出口IP memorySize: 128 # 内存大小,单位MB environment: # 环境变量 variables: # 环境变量数组 @@ -98,8 +99,8 @@ inputs: | 参数名称 | 是否必选 | 默认值 | 描述 | | ------------------------------------ | :------: | :-------------: | :------------------------------------------------------------------ | -| runtime | 否 | Nodejs10.15 | 执行环境, 目前支持: Nodejs6.10, Nodejs8.9, Nodejs10.15, Nodejs12.16 | -| region | 否 | ap-guangzhou | 项目部署所在区域,默认广州区 | +| runtime | 否 | `Nodejs10.15` | 执行环境, 目前支持: Nodejs6.10, Nodejs8.9, Nodejs10.15, Nodejs12.16 | +| region | 否 | `ap-guangzhou` | 项目部署所在区域,默认广州区 | | functionName | 否 | | 云函数名称 | | serviceName | 否 | | API 网关服务名称, 默认创建一个新的服务名称 | | serviceId | 否 | | API 网关服务 ID,如果存在将使用这个 API 网关服务 | @@ -113,12 +114,12 @@ inputs: ## 执行目录 -| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | -| -------- | :------: | :-------------: | :----: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| src | 否 | String | | 代码路径。与 object 不能同时存在。 | -| exclude | 否 | Array of String | | 不包含的文件或路径, 遵守 [glob 语法](https://github.com/isaacs/node-glob) | -| bucket | 否 | String | | bucket 名称。如果配置了 src,表示部署 src 的代码并压缩成 zip 后上传到 bucket-appid 对应的存储桶中;如果配置了 object,表示获取 bucket-appid 对应存储桶中 object 对应的代码进行部署。 | -| object | 否 | String | | 部署的代码在存储桶中的路径。 | +| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | +| -------- | :------: | :------: | :----: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| src | 否 | String | | 代码路径。与 object 不能同时存在。 | +| exclude | 否 | String[] | | 不包含的文件或路径, 遵守 [glob 语法](https://github.com/isaacs/node-glob) | +| bucket | 否 | String | | bucket 名称。如果配置了 src,表示部署 src 的代码并压缩成 zip 后上传到 bucket-appid 对应的存储桶中;如果配置了 object,表示获取 bucket-appid 对应存储桶中 object 对应的代码进行部署。 | +| object | 否 | String | | 部署的代码在存储桶中的路径。 | ## 层配置 @@ -133,7 +134,7 @@ inputs: | 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | | ---------- | :------: | -------- | :----: | :---------------------------------------------- | -| ttl | 否 | Number | 600 | TTL 值,范围 1 - 604800,不同等级域名最小值不同 | +| ttl | 否 | Number | `600` | TTL 值,范围 1 - 604800,不同等级域名最小值不同 | | recordLine | 否 | String[] | | 记录的线路名称 | ### 指定区配置 @@ -148,12 +149,13 @@ inputs: 参考: https://cloud.tencent.com/document/product/583/18586 -| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | -| ----------- | :------: | :----: | :----: | :------------------------------------------------------------------------------ | -| timeout | 否 | Number | 3 | 函数最长执行时间,单位为秒,可选值范围 1-900 秒,默认为 3 秒 | -| memorySize | 否 | Number | 128 | 函数运行时内存大小,默认为 128M,可选范围 64、128MB-3072MB,并且以 128MB 为阶梯 | -| environment | 否 | Object | | 函数的环境变量, 参考 [环境变量](#环境变量) | -| vpcConfig | 否 | Object | | 函数的 VPC 配置, 参考 [VPC 配置](#VPC-配置) | +| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | +| ----------- | :------: | :-----: | :-----: | :------------------------------------------------------------------------------ | +| timeout | 否 | Number | `3` | 函数最长执行时间,单位为秒,可选值范围 1-900 秒,默认为 3 秒 | +| memorySize | 否 | Number | `128` | 函数运行时内存大小,默认为 128M,可选范围 64、128MB-3072MB,并且以 128MB 为阶梯 | +| environment | 否 | Object | | 函数的环境变量, 参考 [环境变量](#环境变量) | +| vpcConfig | 否 | Object | | 函数的 VPC 配置, 参考 [VPC 配置](#VPC-配置) | +| eip | 否 | Boolean | `false` | 是否固定出口 IP | ##### 环境变量 @@ -170,16 +172,16 @@ inputs: ### API 网关配置 -| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | -| -------------- | :------: | :------- | :------- | :--------------------------------------------------------------------------------- | -| protocols | 否 | String[] | ['http'] | 前端请求的类型,如 http,https,http 与 https | -| environment | 否 | String | release | 发布环境. 目前支持三种发布环境: test(测试), prepub(预发布) 与 release(发布). | -| usagePlan | 否 | | | 使用计划配置, 参考 [使用计划](#使用计划) | -| auth | 否 | | | API 密钥配置, 参考 [API 密钥](#API-密钥配置) | -| customDomain | 否 | Object[] | | 自定义 API 域名配置, 参考 [自定义域名](#自定义域名) | -| enableCORS | 否 | Boolean | `false` | 开启跨域。默认值为否。 | -| serviceTimeout | 否 | Number | `15` | Api 超时时间,单位: 秒 | -| isDisabled | 否 | Boolean | `false` | 关闭自动创建 API 网关功能。默认值为否,即默认自动创建 API 网关。 | +| 参数名称 | 是否必选 | 类型 | 默认值 | 描述 | +| -------------- | :------: | :------- | :--------- | :--------------------------------------------------------------------------------- | +| protocols | 否 | String[] | `['http']` | 前端请求的类型,如 http,https,http 与 https | +| environment | 否 | String | `release` | 发布环境. 目前支持三种发布环境: test(测试), prepub(预发布) 与 release(发布). | +| usagePlan | 否 | | | 使用计划配置, 参考 [使用计划](#使用计划) | +| auth | 否 | | | API 密钥配置, 参考 [API 密钥](#API-密钥配置) | +| customDomain | 否 | Object[] | | 自定义 API 域名配置, 参考 [自定义域名](#自定义域名) | +| enableCORS | 否 | Boolean | `false` | 开启跨域。默认值为否。 | +| serviceTimeout | 否 | Number | `15` | Api 超时时间,单位: 秒 | +| isDisabled | 否 | Boolean | `false` | 关闭自动创建 API 网关功能。默认值为否,即默认自动创建 API 网关。 | ##### 使用计划 @@ -190,7 +192,7 @@ inputs: | usagePlanId | 否 | String | 用户自定义使用计划 ID | | usagePlanName | 否 | String | 用户自定义的使用计划名称 | | usagePlanDesc | 否 | String | 用户自定义的使用计划描述 | -| maxRequestNum | 否 | Int | 请求配额总数,如果为空,将使用-1 作为默认值,表示不开启 | +| maxRequestNum | 否 | Number | 请求配额总数,如果为空,将使用-1 作为默认值,表示不开启 | ##### API 密钥配置 @@ -209,7 +211,7 @@ Refer to: https://cloud.tencent.com/document/product/628/14906 | ---------------- | :------: | :------: | :----: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | domain | 是 | String | | 待绑定的自定义的域名。 | | certificateId | 否 | String | | 待绑定自定义域名的证书唯一 ID,如果设置了 type 为 https,则为必选 | -| isDefaultMapping | 否 | String | `true` | 是否使用默认路径映射,默认为 true。为 false 时,表示自定义路径映射,此时 pathMappingSet 必填。 | +| isDefaultMapping | 否 | String | `true` | 是否使用默认路径映射。为 false 时,表示自定义路径映射,此时 pathMappingSet 必填。 | | pathMappingSet | 否 | Object[] | `[]` | 自定义路径映射的路径。使用自定义映射时,可一次仅映射一个 path 到一个环境,也可映射多个 path 到多个环境。并且一旦使用自定义映射,原本的默认映射规则不再生效,只有自定义映射路径生效。 | | protocol | 否 | String[] | | 绑定自定义域名的协议类型,默认与服务的前端协议一致。 | diff --git a/example/README.md b/example/README.md index 06b9f04..982bb23 100644 --- a/example/README.md +++ b/example/README.md @@ -1,30 +1,227 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app). +[![Serverless Nextjs Tencent Cloud](https://img.serverlesscloud.cn/2020224/1582553715762-next.js_%E9%95%BF.png)](http://serverless.com) -## Getting Started +  -First, run the development server: +# 腾讯云 Next.js Serverless Component + +简体中文 | [English](https://github.com/serverless-components/tencent-nextjs/blob/v2/README.en.md) + +## 简介 + +**腾讯云[Next.js](https://github.com/zeit/next.js) 组件** - 通过使用[**Tencent Serverless Framework**](https://github.com/serverless/components/tree/cloud) , 基于云上 Serverless 服务(如 API 网关、云函数等),实现“0”配置,便捷开发,极速部署采用 Next.js 框架的网页应用,Next.js 组件支持丰富的配置扩展,提供了目前便捷实用,开发成本低的网页应用项目的开发/托管能力。 + +特性介绍: + +- [x] **按需付费** - 按照请求的使用量进行收费,没有请求时无需付费 +- [x] **"0"配置** - 只需要关心项目代码,之后部署即可,Serverless Framework 会搞定所有配置。 +- [x] **极速部署** - 部署速度快,仅需几秒,部署你的整个应用。 +- [x] **实时日志** - 通过实时日志的输出查看业务状态,便于直接在云端开发应用。 +- [x] **云端调试** - 可在云端直接进行项目调试,从而避免本地环境的差异。 +- [x] **便捷协作** - 通过云端控制台的状态信息和部署日志,方便进行多人协作开发。 + +## 快速开始 + +0. [**准备**](#0-准备) +1. [**安装**](#1-安装) +1. [**配置**](#2-配置) +1. [**部署**](#3-部署) +1. [**开发调试**](#4-开发调试) +1. [**查看状态**](#5-查看部署状态) +1. [**移除**](#6-移除) + +更多资源: + +- [**账号配置**](#账号配置) +- [**架构说明**](#架构说明) +- [**更多组件**](#更多组件) +- [**FAQ**](#FAQ) + +### 0. 准备 + +#### 初始化 Next.js 项目 + +首先,在本地创建一个 Next.js 项目并初始化: + +```bash +$ npm init next-app serverless-next + +# cd into project folder after init +$ cd serverless-next +``` + +### 1. 安装 + +通过 npm 全局安装 [serverless cli](https://github.com/serverless/serverless) + +```bash +$ npm install -g serverless +``` + +### 2. 配置 + +在项目根目录创建 `serverless.yml` 文件,在其中进行如下配置 + +```bash +$ touch serverless.yml +``` + +```yml +# serverless.yml +component: nextjs # (必填) 组件名称,此处为nextjs +name: nextjsDemo # (必填) 实例名称 +org: orgDemo # (可选) 用于记录组织信息,默认值为您的腾讯云账户 appid +app: appDemo # (可选) 该 next.js 应用名称 +stage: dev # (可选) 用于区分环境信息,默认值是 dev + +inputs: + src: ./ + functionName: nextjsDemo + region: ap-guangzhou + runtime: Nodejs10.15 + exclude: + - .env + apigatewayConf: + protocols: + - http + - https + environment: release +``` + +- 点此查看[更多配置及说明](https://github.com/serverless-components/tencent-nextjs/tree/v2/docs/configure.md) + +### 3. 部署 + +#### 3.1 构建静态资源 + +```bash +$ npm run build +``` + +#### 3.2 部署到云端 + +在 serverless.yml 文件下的目录中运行以下指令进行部署: ```bash -npm run dev -# or -yarn dev +$ sls deploy ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +部署时需要进行身份验证,如您的账号未 [登陆](https://cloud.tencent.com/login) 或 [注册](https://cloud.tencent.com/register) 腾讯云,您可以直接通过 `微信` 扫描命令行中的二维码进行授权登陆和注册。 + +> 注意: 如果希望查看更多部署过程的信息,可以通过`sls deploy --debug` 命令查看部署过程中的实时日志信息,`sls`是 `serverless` 命令的缩写。 +> `sls` 是 `serverless` 命令的简写。 + +### 4. 开发调试 + +部署了 Next.js 应用后,可以通过开发调试能力对该项目进行二次开发,从而开发一个生产应用。在本地修改和更新代码后,不需要每次都运行 `serverless deploy` 命令来反复部署。你可以直接通过 `serverless dev` 命令对本地代码的改动进行检测和自动上传。 -You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. +可以通过在 `serverless.yml`文件所在的目录下运行 `serverless dev` 命令开启开发调试能力。 -## Learn More +`serverless dev` 同时支持实时输出云端日志,每次部署完毕后,对项目进行访问,即可在命令行中实时输出调用日志,便于查看业务情况和排障。 -To learn more about Next.js, take a look at the following resources: +### 5. 查看部署状态 -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +在`serverless.yml`文件所在的目录下,通过如下命令查看部署状态: + +``` +$ serverless info +``` + +### 6. 移除 + +在`serverless.yml`文件所在的目录下,通过以下命令移除部署通过以下命令移除部署的 API 网关,移除后该组件会对应删除云上部署时所创建的所有相关资源。 + +```bash +$ sls remove +``` + +和部署类似,支持通过 `sls remove --debug` 命令查看移除过程中的实时日志信息,`sls`是 `serverless` 命令的缩写。 + +### 账号配置 + +当前默认支持 CLI 扫描二维码登录,如您希望配置持久的环境变量/秘钥信息,也可以本地创建 `.env` 文件 + +```bash +$ touch .env # 腾讯云的配置信息 +``` + +在 `.env` 文件中配置腾讯云的 SecretId 和 SecretKey 信息并保存 + +如果没有腾讯云账号,可以在此 [注册新账号](https://cloud.tencent.com/register)。 + +如果已有腾讯云账号,可以在 [API 密钥管理](https://console.cloud.tencent.com/cam/capi) 中获取 `SecretId` 和`SecretKey`. + +```text +# .env +TENCENT_SECRET_ID=123 +TENCENT_SECRET_KEY=123 +``` + +## 架构说明 + +Next.js 组件将在腾讯云账户中使用到如下 Serverless 服务: + +- [x] **API 网关** - API 网关将会接收外部请求并且转发到 SCF 云函数中。 +- [x] **SCF 云函数** - 云函数将承载 Next.js 应用。 +- [x] **CAM 访问控制** - 该组件会创建默认 CAM 角色用于授权访问关联资源。 +- [x] **COS 对象存储** - 为确保上传速度和质量,云函数压缩并上传代码时,会默认将代码包存储在特定命名的 COS 桶中 +- [x] **SSL 证书服务** - 如果你在 yaml 文件中配置了 `apigatewayConf.customDomains` 字段,需要做自定义域名绑定并开启 HTTPS 时,也会用到证书管理服务和域名服务。Serverless Framework 会根据已经备案的域名自动申请并配置 SSL 证书。 + +## 更多组件 + +可以在 [Serverless Components](https://github.com/serverless/components) repo 中查询更多组件的信息。 + +## 项目迁移 - 自定义 express 服务 + +如果你的 Next.js 项目本身运行就是基于 `express` 自定义服务的,那么你需要在项目中自定义入口文件 `sls.js`,需要参考你的服务启动文件进行修改,以下是一个模板文件: + +```js +const express = require('express') +const next = require('next') + +const app = next({ dev: false }) +const handle = app.getRequestHandler() + +// not report route for custom monitor +const noReportRoutes = ['/_next', '/static'] + +async function createServer() { + await app.prepare() + const server = express() + + server.all('*', (req, res) => { + noReportRoutes.forEach((route) => { + if (req.path.indexOf(route) !== -1) { + req.__SLS_NO_REPORT__ = true + } + }) + return handle(req, res) + }) + + // define binary type for response + // if includes, will return base64 encoded, very useful for images + server.binaryTypes = ['*/*'] + + return server +} + +module.exports = createServer +``` + +## 自定义监控 + +当在部署 Next.js 应用时,如果 `serverless.yml` 中未指定 `role`,默认会尝试绑定 `QCS_SCFExcuteRole`,并且开启自定义监控,帮助用户收集应用监控指标。对于为自定义入口文件的项目,会默认上报除含有 `/_next` 和 `/static` 的路由。如果你想自定义上报自己的路由性能,那么可以自定义 `sls.js` 入口文件,对于无需上报的路由,在 express 服务的 `req` 对象上添加 `__SLS_NO_REPORT__` 属性值为 `true` 即可。比如: + +```js +server.get('/no-report', (req, res) => { + req.__SLS_NO_REPORT__ = true + return handle(req, res) +}) +``` -You can check out [the Next.js GitHub repository](https://github.com/zeit/next.js/) - your feedback and contributions are welcome! +那么用户在访问 `GET /no-report` 路由时,就不会上报自定义监控指标。 -## Deploy on ZEIT Now +## License -The easiest way to deploy your Next.js app is to use the [ZEIT Now Platform](https://zeit.co/) from the creators of Next.js. +MIT License -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +Copyright (c) 2020 Tencent Cloud, Inc. diff --git a/src/package.json b/src/package.json index 389b0b7..a0d541c 100644 --- a/src/package.json +++ b/src/package.json @@ -2,7 +2,7 @@ "dependencies": { "adm-zip": "^0.4.14", "download": "^8.0.0", - "tencent-component-toolkit": "^1.13.0", + "tencent-component-toolkit": "^1.13.2", "type": "^2.0.0" } } diff --git a/src/utils.js b/src/utils.js index a09f8df..4dff6b7 100644 --- a/src/utils.js +++ b/src/utils.js @@ -353,7 +353,9 @@ const prepareInputs = async (instance, credentials, inputs = {}) => { }), publish: inputs.publish, traffic: inputs.traffic, - lastVersion: instance.state.lastVersion + lastVersion: instance.state.lastVersion, + eip: tempFunctionConf.eip === true, + l5Enable: tempFunctionConf.l5Enable === true } // validate traffic @@ -366,15 +368,6 @@ const prepareInputs = async (instance, credentials, inputs = {}) => { default: null }) - functionConf.include = ensureIterable( - tempFunctionConf.include ? tempFunctionConf.include : inputs.include, - { default: [], ensureItem: ensureString } - ) - functionConf.exclude = ensureIterable( - tempFunctionConf.exclude ? tempFunctionConf.exclude : inputs.exclude, - { default: [], ensureItem: ensureString } - ) - functionConf.exclude.push('.git/**', '.gitignore', '.serverless', '.DS_Store') if (inputs.functionConf) { functionConf.timeout = inputs.functionConf.timeout ? inputs.functionConf.timeout