{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-08-12-serverless-express","result":{"data":{"currentBlog":{"id":"1f8be8e0-2d12-5df8-a762-f7ffc07ec3b4","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020812/1597230581474-002.jpg","authors":["粟俊娥"],"categories":["best-practice"],"date":"2020-08-12T00:00:00.000Z","title":"腾讯云 Severless-Express 项目开发和灰度发布最佳实践","description":"本文教你快速了解 Severless-Express 项目开发和灰度发布，全是干货！","authorslink":["https://github.com/June1991"],"translators":null,"translatorslink":null,"tags":["Serverless","Express"],"keywords":"Serverless, Serverless Framework","outdated":null},"wordCount":{"words":294,"sentences":64,"paragraphs":63},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-08-12-serverless-express.md","fields":{"slug":"/best-practice/2020-08-12-serverless-express/","keywords":["serverless","spa","云函数","serverless","express","feature","版本"]},"html":"<h2 id=\"serverless-应用基本概念\"><a href=\"#serverless-%E5%BA%94%E7%94%A8%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5\" aria-label=\"serverless 应用基本概念 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Serverless 应用基本概念</h2>\n<p>一个 Serverless 应用是由单个或者多个组件实例构成的。每个组件中都会有一个 <code class=\"language-text\">serverless.yml</code> 文件，该文件定义了组件的一些参数，这些参数在部署时用于生成实例的信息。例如 region 参数，定义了资源的所在区。</p>\n<p>组织是在 Serverless 应用上层的概念，主要是为了管理。例如，一个公司会有不同部门进行 Serverless 应用开发，设置不同组织名称，方便做后期的权限管理。</p>\n<p>示例：开发一个 express 应用，最基本的是引入 express 组件，业务中间可能会涉及到其他一些云产品（如对象存储 COS），所以整个应用目录如下：</p>\n<p><img src=\"https://main.qcloudimg.com/raw/a8f05b681228498b2d41981cd7e5d4fb.svg\"></p>\n<h2 id=\"serverlessyml-文件\"><a href=\"#serverlessyml-%E6%96%87%E4%BB%B6\" aria-label=\"serverlessyml 文件 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Serverless.yml 文件</h2>\n<p>serverless.yml 文件中定义了应用组织描述及组件 inputs 参数，每次部署时会根据 serverless.yml 文件中的配置信息进行资源的创建、更新和编排。</p>\n<p>一份简单的 serverless.yml 文件如下：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"># serverless.yml\n\norg: xxx-department #  用于记录组织信息,默认为您的腾讯云 APPID\napp: expressDemoApp #  应用名称，默认为与组件实例名称\nstage: ${env:STAGE} #  用于开发环境的隔离，默认为 dev\n\n\ncomponent: express # (必填) 引用 component 的名称，当前用到的是 express-tencent 组件\nname: expressDemo # (必填) 组件创建的实例名称\n\n\ninputs:\n  src:\n    src: ./ \n    exclude:\n      - .env\n  region: ap-guangzhou \n  runtime: Nodejs10.15\n  functionName: ${name}-${stage}-${app}-${org} #云函数名称\n  apigatewayConf:\n    protocols:\n      - http\n      - https\n    environment: release</code></pre></div>\n<p>yml 文件中的配置信息：</p>\n<p><img src=\"https://img.serverlesscloud.cn/2020812/1597229144629-%E6%88%AA%E5%B1%8F2020-08-12%20%E4%B8%8B%E5%8D%886.45.19.png\"></p>\n<h2 id=\"操作场景\"><a href=\"#%E6%93%8D%E4%BD%9C%E5%9C%BA%E6%99%AF\" aria-label=\"操作场景 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>操作场景</h2>\n<p>本文以 Tencent-Express 组件部署一个 Express 网站为例，模拟 Serverless Framework 开发项目、管理项目和部署发布上线全流程。<a href=\"https://github.com/June1991/serverless-express\">>> 示例链接</a></p>\n<h2 id=\"流程说明\"><a href=\"#%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E\" aria-label=\"流程说明 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>流程说明</h2>\n<p>一个项目的开发上线流程大致如下：</p>\n<p><img src=\"https://main.qcloudimg.com/raw/af7fe3252a3607f929ad0c6e1736b6dc.svg\"></p>\n<ol>\n<li>初始化项目：将项目进行初始化。例如选择一些开发框架和模板完成基本的搭建工作。</li>\n<li>开发阶段：对产品功能进行研发。可能涉及到多个开发者协作，开发者拉取不同的 feature 分支，开发并测试自己负责的功能模块；最后合并到 dev 分支，联调各个功能模块。</li>\n<li>测试阶段：测试人员对产品功能进行测试。</li>\n<li>发布上线：对于已完成测试的产品功能发布上线。由于新上线的版本可能有不稳定的风险，所以一般会进行灰度发布，通过配置一些规则监控新版本的稳定性，等到版本稳定后，流量全部切换到新版本。</li>\n</ol>\n<p>开发项目过程可能会涉及以下分支：</p>\n<p><img src=\"https://img.serverlesscloud.cn/2020812/1597229259283-%E6%88%AA%E5%B1%8F2020-08-12%20%E4%B8%8B%E5%8D%886.47.25.png\"></p>\n<h2 id=\"操作步骤\"><a href=\"#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4\" aria-label=\"操作步骤 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>操作步骤</h2>\n<h3 id=\"初始化项目\"><a href=\"#%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%B9%E7%9B%AE\" aria-label=\"初始化项目 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>初始化项目</h3>\n<ol>\n<li>参考 <a href=\"https://cloud.tencent.com/document/product/1154/43224\">部署 Express.js 应用</a> 文档，创建一个 <code class=\"language-text\">express 项目</code>，修改 yml 文件为以下内容：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">#serverless.yml\norg: xxx-department #  用于记录组织信息,默认为您的腾讯云appid\napp: expressDemoApp #  应用名称，默认为与组件实例名称\nstage: ${env:STAGE} #  用于开发环境的隔离，默认为dev\n\n\ncomponent: express # (必填) 引用 component 的名称，当前用到的是 express-tencent 组件\nname: expressDemo # (必填) 组件创建的实例名称\n\ninputs:\n  src:\n    src: ./ \n    exclude:\n      - .env\n  region: ap-guangzhou\n  runtime: Nodejs10.15\n  funcitonName: ${name}-${stage}-${app}-${org} #云函数名称\n  apigatewayConf:\n    protocols:\n      - http\n      - https\n    environment: release</code></pre></div>\n<ol start=\"2\">\n<li>在项目根目录下的 <code class=\"language-text\">.env 文件</code>中配置：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">TENCENT_SECRET_ID=xxxxxxxxxx #您账号的 SecretId\nTENCENT_SECRET_KEY=xxxxxxxx #您账号的 SecretKey\nSTAGE=prod #STAGE为prod环境，也可以sls deploy --stage=prod 参数传递的方式设置</code></pre></div>\n<ol start=\"3\">\n<li>执行 <code class=\"language-text\">sls deploy</code> 部署成功后，访问生成的 url 链接，效果如下：</li>\n</ol>\n<p><img src=\"https://main.qcloudimg.com/raw/ed180d13d3010d49ec102567c235d461.svg\"></p>\n<ol start=\"4\">\n<li>创建远程仓库（<a href=\"https://github.com/June1991/serverless-express\">示例链接</a>），将项目代码提交到远程 master 分支。同时创建 testing、dev。此时三个分支的代码在同一个版本上（假设为版本0）。\n<img src=\"https://main.qcloudimg.com/raw/f8ae1d7e0ca59d1b0c49d6878ba4f37d.svg\"></li>\n</ol>\n<h3 id=\"开发与测试\"><a href=\"#%E5%BC%80%E5%8F%91%E4%B8%8E%E6%B5%8B%E8%AF%95\" aria-label=\"开发与测试 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>开发与测试</h3>\n<p><strong>背景</strong></p>\n<p>现在需要开发某个功能模块。假设需要有两位开发者：Tom、Jorge。两位开发者分别从 dev（版本 0）上创建特性分支为 feature1、feature2 进行研发。</p>\n<p><img src=\"https://main.qcloudimg.com/raw/8716ab86706ce857897d81d2538e9253.svg\"></p>\n<p>Tom 开始开发 feature1。在本示例中，为新增一个 feature.html，里面写文案「This is a new feature 1.」</p>\n<p><strong>开发</strong></p>\n<ol>\n<li>在 sls.js 文件中新增路由器配置：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">// Routes\napp.get(`/feature`, (req, res) =&gt; {\n res.sendFile(path.join(__dirname, &#39;feature.html&#39;))\n})</code></pre></div>\n<ol start=\"2\">\n<li>新增 feature.html：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!DOCTYPE html&gt;\n&lt;html lang=&quot;en&quot;&gt;\n &lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot; /&gt;\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n  &lt;title&gt;Serverless Component - Express.js&lt;/title&gt;\n &lt;/head&gt;\n &lt;body&gt;\n  &lt;h1&gt;\n   This is a new feature 1.\n  &lt;/h1&gt;\n &lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n<ol start=\"3\">\n<li>在 <code class=\"language-text\">.env</code> 文件中设置自己的 stage，以便在开发过程中得到独立的运行和调试环境。例如 Tom 在 serverless.yml 的项目目录下配置 .env 如下：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">TENCENT_SECRET_ID=xxxxxxxxxx\nTENCENT_SECRET_KEY=xxxxxxxx\nSTAGE=feature1</code></pre></div>\n<ol start=\"4\">\n<li>执行 <code class=\"language-text\">sls deploy</code> 部署成功后，返回显示如下：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">region: ap-guangzhou\napigw:\n  serviceId:   service-xxxxxx\n  subDomain:   service-xxxxxx-123456789.gz.apigw.tencentcs.com\n  environment: release\n  url:         https://service-xxxxxx-123456789.gz.apigw.tencentcs.com/release/\nscf:\n  functionName: express-demo-feature1\n  runtime:      Nodejs10.15\n  namespace:    default\n  lastVersion:  $LATEST\n  traffic:      1\n\nFull details: https://serverless.cloud.tencent.com/instances/expressDemoApp%3Afeature1%3AexpressDemo\n\n10s » expressDemo » Success</code></pre></div>\n<ol start=\"5\">\n<li>访问生成的 url (<a href=\"https://service-xxxxxx-123456789.gz.apigw.tencentcs.com/release/feature\">https://service-xxxxxx-123456789.gz.apigw.tencentcs.com/release/feature</a>)，效果如下：</li>\n</ol>\n<p><img src=\"https://main.qcloudimg.com/raw/ca56e34cbc2f1216871e03bd79d250c9.svg\"></p>\n<p>至此，Tom 开发功能完成并自测通过。</p>\n<p>假设同时，Jorge 同时也完成自己的特性开发，并自测通过。在本示例中，为新增一个 feature.html，里面写文案「This is a new feature 2.」。</p>\n<p><strong>联调</strong></p>\n<ol>\n<li>两人把各自 feature 分支的代码合并到 dev 分支。（可能会存在冲突需要人为解决）\n<img src=\"https://main.qcloudimg.com/raw/fc9297f775bda0eb0bbc7db2b3305285.svg\"></li>\n<li>在 dev 进行联调。联调环境中的 <code class=\"language-text\">.env</code> 配置如下</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">TENCENT_SECRET_ID=xxxxxxxxxx\nTENCENT_SECRET_KEY=xxxxxxxx\nSTAGE=dev</code></pre></div>\n<ol start=\"3\">\n<li>执行 sls deploy 联调部署后，访问 url (ttps://service-xxxxxx-123456789.gz.apigw.tencentcs.com/release/feature)，效果如下。至此联调完成，整个功能已经开发完毕。</li>\n</ol>\n<p><img src=\"https://main.qcloudimg.com/raw/c6a28dff690869c62e0a767944150a87.svg\"></p>\n<p><strong>测试</strong></p>\n<ol>\n<li>把联调通过的 dev 分支合并到 testing 代码，进入测试。</li>\n</ol>\n<p><img src=\"https://main.qcloudimg.com/raw/09d23fc99205b8ac078da6cbf4d7f700.svg\"></p>\n<ol start=\"2\">\n<li>测试环境中的 .env 配置如下：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">TENCENT_SECRET_ID=xxxxxxxxxx\nTENCENT_SECRET_KEY=xxxxxxxx\nSTAGE=testing</code></pre></div>\n<ol start=\"3\">\n<li>执行 sls deploy 部署成功后，测试人员开始进行相关测试，直至功能稳定通过。</li>\n</ol>\n<p><strong>发布上线</strong></p>\n<p>测试通过后，将测试代码合并到 master 分支，准备发布上线。</p>\n<p><img src=\"https://main.qcloudimg.com/raw/dcfb979dd18f198b2764d77d0cb7b517.svg\"></p>\n<p>设置生产环境中的 <code class=\"language-text\">.env</code> 为：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">TENCENT_SECRET_ID=xxxxxxxxxx\nTENCENT_SECRET_KEY=xxxxxxxx\nSTAGE=prod</code></pre></div>\n<p>执行部署命令：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">sls deploy </code></pre></div>\n<p>至此，我们完成了一 个<code class=\"language-text\">severless-express</code> 项目的开发和上线发布。</p>\n<h2 id=\"灰度发布\"><a href=\"#%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83\" aria-label=\"灰度发布 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>灰度发布</h2>\n<h3 id=\"操作场景-1\"><a href=\"#%E6%93%8D%E4%BD%9C%E5%9C%BA%E6%99%AF-1\" aria-label=\"操作场景 1 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>操作场景</h3>\n<p>在业务进行版本更新及切换时，为了保证线上业务稳定，建议采取灰度发布的方式。本文以已部署的 express 项目为例，为您介绍灰度发布的操作步骤。</p>\n<p>前提条件：已完成 <a href=\"https://cloud.tencent.com/document/product/1154/47288\">开发项目</a>。</p>\n<h3 id=\"操作步骤-1\"><a href=\"#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4-1\" aria-label=\"操作步骤 1 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>操作步骤</h3>\n<ol>\n<li>设置生产环境中的 <code class=\"language-text\">.env</code>：</li>\n</ol>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"66521730105574320000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`TENCENT_SECRET_ID=xxxxxxxxxx\nTENCENT_SECRET_KEY=xxxxxxxx\nSTAGE=prod`, `66521730105574320000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"plaintext\"><pre class=\"language-plaintext\"><code class=\"language-plaintext\">TENCENT_SECRET_ID=xxxxxxxxxx\nTENCENT_SECRET_KEY=xxxxxxxx\nSTAGE=prod</code></pre></div>\n<ol start=\"2\">\n<li>部署到线上环境 <code class=\"language-text\">$latest</code>，并切换 10% 的流量在 <code class=\"language-text\">$latest</code> 版本（90% 的流量在最后一次发布的云函数版本 N 上）：</li>\n</ol>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"5387519459448776000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`sls deploy --inputs.traffic=0.1 `, `5387519459448776000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"plaintext\"><pre class=\"language-plaintext\"><code class=\"language-plaintext\">sls deploy --inputs.traffic=0.1 </code></pre></div>\n<ol start=\"3\">\n<li>对 <code class=\"language-text\">$latest</code> 版本进行监控与观察，等版本稳定之后把流量100%切到该版本上：</li>\n</ol>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"37411117950522745000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`sls deploy --inputs.traffic=1.0`, `37411117950522745000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"plaintext\"><pre class=\"language-plaintext\"><code class=\"language-plaintext\">sls deploy --inputs.traffic=1.0</code></pre></div>\n<ol start=\"4\">\n<li>流量全部切换成功后，对于一个稳定版本，我们需要对它进行标记，以免后续发布新功能时，如果遇到线上问题，方便快速回退版本。部署并发布函数版本 N+1，切换所有流量到版本 N+1：</li>\n</ol>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"98371736341570290000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`sls deploy --inputs.publish --inputs.traffic=0 `, `98371736341570290000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"plaintext\"><pre class=\"language-plaintext\"><code class=\"language-plaintext\">sls deploy --inputs.publish --inputs.traffic=0 </code></pre></div>\n<hr>\n<hr>\n<div id='scf-deploy-iframe-or-md'></div>\n<hr>\n<blockquote>\n<p><strong>传送门：</strong></p>\n<ul>\n<li>GitHub: <a href=\"https://github.com/serverless/serverless/blob/master/README_CN.md\">github.com/serverless</a></li>\n<li>官网：<a href=\"https://serverless.com/\">serverless.com</a></li>\n</ul>\n</blockquote>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#serverless-%E5%BA%94%E7%94%A8%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5\">Serverless 应用基本概念</a></li>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#serverlessyml-%E6%96%87%E4%BB%B6\">Serverless.yml 文件</a></li>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#%E6%93%8D%E4%BD%9C%E5%9C%BA%E6%99%AF\">操作场景</a></li>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E\">流程说明</a></li>\n<li>\n<p><a href=\"/best-practice/2020-08-12-serverless-express/#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4\">操作步骤</a></p>\n<ul>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%B9%E7%9B%AE\">初始化项目</a></li>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#%E5%BC%80%E5%8F%91%E4%B8%8E%E6%B5%8B%E8%AF%95\">开发与测试</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/best-practice/2020-08-12-serverless-express/#%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83\">灰度发布</a></p>\n<ul>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#%E6%93%8D%E4%BD%9C%E5%9C%BA%E6%99%AF-1\">操作场景</a></li>\n<li><a href=\"/best-practice/2020-08-12-serverless-express/#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4-1\">操作步骤</a></li>\n</ul>\n</li>\n</ul>"},"previousBlog":{"id":"a68be5c7-9013-5f9b-a4d7-df0a149c8326","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/202099/1599650772819-1599646529564-%E8%98%91%E8%8F%87%E8%A1%97.jpg","authors":["Tianyun"],"categories":["best-practice"],"date":"2020-09-09T00:00:00.000Z","title":"腾讯云 Serverless ETL —— 蘑菇街实战落地","description":"轻量、快速、灵活、省心、低成本的 Serverless 通用数据处理解决方案！","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","ETL"],"keywords":"Serverless, Serverless ETL","outdated":null},"wordCount":{"words":355,"sentences":68,"paragraphs":68},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-09-09-serverless-etl.md","fields":{"slug":"/best-practice/2020-09-09-serverless-etl/","keywords":["serverless","云函数","函数","serverlesscloud","Ckafka","Serverless","腾讯"]}},"nextBlog":{"id":"d2255c44-05c8-5daa-b9fa-d3bdf84b36ce","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/202087/1596785478341-%E4%B8%89%E8%A1%8C_%E7%B4%AB%E8%89%B2.jpg","authors":["Mason"],"categories":["best-practice"],"date":"2020-08-06T00:00:00.000Z","title":"腾讯云 Serverless 云函数实现 CKafka 数据转存到 ES","description":"内附部署实战步骤，欢迎体验！","authorslink":null,"translators":null,"translatorslink":null,"tags":["CKafka","ES"],"keywords":"Serverless, Serverless Framework, CKafka","outdated":null},"wordCount":{"words":204,"sentences":51,"paragraphs":51},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-08-07-ckafka.md","fields":{"slug":"/best-practice/2020-08-07-ckafka/","keywords":["serverless","无服务器","云函数","函数","Ckafka","serverlesscloud"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"1f8be8e0-2d12-5df8-a762-f7ffc07ec3b4","previousBlogId":"a68be5c7-9013-5f9b-a4d7-df0a149c8326","nextBlogId":"d2255c44-05c8-5daa-b9fa-d3bdf84b36ce"}}}