{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-03-10-serverless-env","result":{"data":{"currentBlog":{"id":"a91ae766-b090-5f4d-891f-3332b7d58e00","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/20191230/1577673977066-16ef85f25ee1af09.jpg","authors":["yugasun"],"categories":["best-practice"],"date":"2020-03-10T00:00:00.000Z","title":"Serverless 多环境配置方案探索","description":"业务开发完了，如何管理不同环境的配置呢？","authorslink":["https://github.com/yugasun"],"translators":null,"translatorslink":null,"tags":["Serverless","管理环境"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":241,"sentences":54,"paragraphs":54},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-03-10-serverless-env.md","fields":{"slug":"/best-practice/2020-03-10-serverless-env/","keywords":["koa","nodejs","python","serverless","云函数","serverless","dotenv","yml","配置","release"]},"html":"<p>相信读完前面几篇有关 Serverless Component 文章的小伙伴已经体验到，它给我们开发带来的遍历。但是实际我们的日常开发项目中，并不仅仅只是单纯地一个项目部署那么简单，我们的敏捷开发流程中，还有开发、联调、测试、预发布、正式环境等关键词。那么有小伙伴就有疑惑了，我的业务开发完了，如何管理不同环境的配置呢？比如测试环境的数据库配置和正式环境的如何切换？于是抛转引入，写了此篇文章，来跟大家一起学习和探讨。</p>\n<p>读完本篇将你将了解到：</p>\n<ol>\n<li>Serverless Component 部署原理</li>\n<li>dotenv 模块的基本使用</li>\n<li>如何基于 dotenv 来切换多环境配置</li>\n<li>如何在 <code class=\"language-text\">serverless.yml</code> 提炼通用配置</li>\n</ol>\n<h2 id=\"serverless-component\"><a href=\"#serverless-component\" aria-label=\"serverless component 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 Component</h2>\n<blockquote>\n<p>理论指导实践</p>\n</blockquote>\n<p>在介绍方法之前，这里需要先对 <code class=\"language-text\">Serverless Component</code> 部署原理做个简单介绍。当我们在 <code class=\"language-text\">serverless.yml</code> 文件中配置好项目，执行 <code class=\"language-text\">sls --debug</code> 命令后，究竟发生了什么？</p>\n<p>核心步骤如下：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">1. 初始化 context：包括分析component依赖树，通过 dotenv 注入环境变量等。\n2. 安装依赖组件模块：不同于 `npm install`, serverless component 会将 `component` 指定的 npm 模块下载并解压放到 `~/.serverless/components/registry/npm/@serverless/xxx@x.x.x` 中。\n3. 执行组件模块的 `default` 函数：这个 default 函数就是开发者提供的部署逻辑代码，比如将打包压缩好的代码上传到cos，然后部署到scf。</code></pre></div>\n<p>本篇只需要关心第一步的环境变量注入就好。</p>\n<p>可以发现，<code class=\"language-text\">Serverless Framework</code> 部署命令默认会帮我们注入 <code class=\"language-text\">.env</code> 文件中的环境变量到部署流程中，这也是为什么我们在使用腾讯云的组件时，需要创建一个内容如下的 <code class=\"language-text\">.env</code> 文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"18486244083361190000\"\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=xxx\nTENCENT_SECRET_KEY=xxx`, `18486244083361190000`)\"\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=\"dotenv\"><pre class=\"language-dotenv\"><code class=\"language-dotenv\">TENCENT_SECRET_ID=xxx\nTENCENT_SECRET_KEY=xxx</code></pre></div>\n<blockquote>\n<p>注意：当然腾讯云的组件都是支持扫码一键登录的，如果你不想配置 <code class=\"language-text\">.env</code> 文件。是不是很炫酷 ~</p>\n</blockquote>\n<p>基于此，我们就可以利用 <code class=\"language-text\">.env</code> 文件做很多事了。 比如在 <code class=\"language-text\">serverless.yml</code> 中可以通过 <code class=\"language-text\">${env.xxx}</code> 方式来获取注入的环境变量。</p>\n<h2 id=\"dotenv-模块\"><a href=\"#dotenv-%E6%A8%A1%E5%9D%97\" aria-label=\"dotenv 模块 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>dotenv 模块</h2>\n<blockquote>\n<p><a href=\"https://github.com/motdotla/dotenv\">Dotenv</a> 是一个能够通过 <code class=\"language-text\">.env</code> 文件将环境变量注入到 <a href=\"https://nodejs.org/docs/latest/api/process.html#process_process_env\">process.env</a> 的模块。</p>\n</blockquote>\n<p>具体使用很简单，先安装 <code class=\"language-text\">npm install dotenv --save</code>，然后在你的项目入口文件中引入即可：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"7201341829651508000\"\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(`require(&quot;dotenv&quot;).config();`, `7201341829651508000`)\"\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=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"dotenv\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">config</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h2 id=\"管理多环境配置\"><a href=\"#%E7%AE%A1%E7%90%86%E5%A4%9A%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%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>管理多环境配置</h2>\n<p>说了这么多，终于到了本篇的正题。这里以 <a href=\"https://github.com/serverless-components/tencent-koa\">tencent-koa</a> 组件为例，我们先初始化我们的项目：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"42574141015549575000\"\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(`# 此命令会将指定包含 \\`serverless.yml\\` 的 github 目录作为项目模板，拷贝到本地\n\\$ serverless create --template-url https://github.com/yugasun/tencent-serverless-demo/tree/master/serverless-env\n\n# 安装依赖\n\\$ cd severless-env && npm install`, `42574141015549575000`)\"\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=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># 此命令会将指定包含 `serverless.yml` 的 github 目录作为项目模板，拷贝到本地</span>\n$ serverless create --template-url https://github.com/yugasun/tencent-serverless-demo/tree/master/serverless-env\n\n<span class=\"token comment\"># 安装依赖</span>\n$ <span class=\"token builtin class-name\">cd</span> severless-env <span class=\"token operator\">&amp;&amp;</span> <span class=\"token function\">npm</span> <span class=\"token function\">install</span></code></pre></div>\n<p>然后新建两个配置文件，分别为：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"42176870204267150000\"\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(`# .env.test 文件内容\nUSER_NAME=yugasun_test\nUSER_EMAIL=yugasun_test@163.com\n\n# .env.release 文件内容\nUSER_NAME=yugasun_release\nUSER_EMAIL=yugasun_release@163.com`, `42176870204267150000`)\"\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=\"dotenv\"><pre class=\"language-dotenv\"><code class=\"language-dotenv\"># .env.test 文件内容\nUSER_NAME=yugasun_test\nUSER_EMAIL=yugasun_test@163.com\n\n# .env.release 文件内容\nUSER_NAME=yugasun_release\nUSER_EMAIL=yugasun_release@163.com</code></pre></div>\n<p>然后新建入口文件 <code class=\"language-text\">app.js</code>：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"45184057015223280000\"\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(`const dotenv = require(&quot;dotenv&quot;);\nconst Koa = require(&quot;koa&quot;);\nconst KoaRouter = require(&quot;koa-router&quot;);\n\nconst { CODE_ENV } = process.env;\ndotenv.config({\n  path: \\`\\${__dirname}/.env.\\${CODE_ENV}\\`\n});\n\nconst app = new Koa();\nconst router = new KoaRouter();\n\nrouter.get(&quot;/&quot;, async ctx => {\n  ctx.body = {\n    name: process.env.USER_NAME,\n    email: process.env.USER_EMAIL\n  };\n});\n\napp.use(router.allowedMethods()).use(router.routes());\n\n// don't forget to export!\nmodule.exports = app;`, `45184057015223280000`)\"\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=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> dotenv <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"dotenv\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> Koa <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"koa\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> KoaRouter <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"koa-router\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> <span class=\"token constant\">CODE_ENV</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">;</span>\ndotenv<span class=\"token punctuation\">.</span><span class=\"token function\">config</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  path<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>__dirname<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/.env.</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token constant\">CODE_ENV</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> app <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Koa</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> router <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">KoaRouter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nrouter<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">async</span> <span class=\"token parameter\">ctx</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  ctx<span class=\"token punctuation\">.</span>body <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    name<span class=\"token punctuation\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">USER_NAME</span><span class=\"token punctuation\">,</span>\n    email<span class=\"token punctuation\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">USER_EMAIL</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\napp<span class=\"token punctuation\">.</span><span class=\"token function\">use</span><span class=\"token punctuation\">(</span>router<span class=\"token punctuation\">.</span><span class=\"token function\">allowedMethods</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">use</span><span class=\"token punctuation\">(</span>router<span class=\"token punctuation\">.</span><span class=\"token function\">routes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// don't forget to export!</span>\nmodule<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> app<span class=\"token punctuation\">;</span></code></pre></div>\n<p>这是一个简单的 demo，通过云函数注入的环境变量 <code class=\"language-text\">CODE_ENV</code>，来读取不同的 <code class=\"language-text\">.env.xxx</code> 配置，从而实现不同环境的配置切换，核心代码就是:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"22839136953554550000\"\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(`const { CODE_ENV } = process.env;\ndotenv.config({\n  path: \\`\\${__dirname}/.env.\\${CODE_ENV}\\`\n});`, `22839136953554550000`)\"\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=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> <span class=\"token constant\">CODE_ENV</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">;</span>\ndotenv<span class=\"token punctuation\">.</span><span class=\"token function\">config</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  path<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>__dirname<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/.env.</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token constant\">CODE_ENV</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<blockquote>\n<p>备注：这里 dotenv 的 config 函数是可以指定 <code class=\"language-text\">path</code> 为目标 <code class=\"language-text\">.env</code> 文件路径。</p>\n</blockquote>\n<p>所以只需要给云函数配置一个环境变量 <code class=\"language-text\">CODE_ENV</code> 就可以了，接下来我们来编写 <code class=\"language-text\">serverless.yml</code> 文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"2475097425080097300\"\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(`# 当前运行环境\nCODE_ENV: test\n\nMyExpress:\n  component: &quot;@serverless/tencent-koa&quot;\n  inputs:\n    region: ap-guangzhou\n    functionName: express-function\n    code: ./\n    functionConf:\n      timeout: 10\n      memorySize: 128\n      environment:\n        variables:\n          CODE_ENV: \\${CODE_ENV}\n    apigatewayConf:\n      protocols:\n        - http\n        - https\n      environment: \\${CODE_ENV}`, `2475097425080097300`)\"\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=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token comment\"># 当前运行环境</span>\n<span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> test\n\n<span class=\"token key atrule\">MyExpress</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-koa\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">functionName</span><span class=\"token punctuation\">:</span> express<span class=\"token punctuation\">-</span>function\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span> ./\n    <span class=\"token key atrule\">functionConf</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">timeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">10</span>\n      <span class=\"token key atrule\">memorySize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">128</span>\n      <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">apigatewayConf</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">protocols</span><span class=\"token punctuation\">:</span>\n        <span class=\"token punctuation\">-</span> http\n        <span class=\"token punctuation\">-</span> https\n      <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span></code></pre></div>\n<p>相信大家都知道可以通过 <code class=\"language-text\">functionConf.environment.variables</code> 来配置环境变量。\n这里不仅配置了云函数的环境变量，同时也配置了 <code class=\"language-text\">apigatewayConf.environment</code>，以此来区分 API 网关的测试和发布环境。</p>\n<blockquote>\n<p>小技巧：可以在 <code class=\"language-text\">yml</code> 文件的顶端定义公共变量 <code class=\"language-text\">CODE_ENV</code>，然后通过 <code class=\"language-text\">${CODE_ENV}</code> 的方式引用变量。</p>\n</blockquote>\n<p>然后执行部署命令 <code class=\"language-text\">sls --debug</code>，部署成功后访问创建成功的 <code class=\"language-text\">url</code> 链接，就可以看到配置的环境变量结果了：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"50061205711771574000\"\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(`{\n  &quot;name&quot;: &quot;yugasun_test&quot;,\n  &quot;email&quot;: &quot;yugasun_test@163.com&quot;\n}`, `50061205711771574000`)\"\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=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"yugasun_test\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"email\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"yugasun_test@163.com\"</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>当我们开发完，需要部署到发布环境，只需要修改 <code class=\"language-text\">serverless.yml</code> 中的 <code class=\"language-text\">CODE_ENV</code> 值为 <code class=\"language-text\">release</code>，然后重新部署就行。</p>\n<h2 id=\"配置优化-1\"><a href=\"#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%8C%96-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>配置优化 1</h2>\n<p>细心的小伙伴会发现：部署成功的云函数，虽然可以成功地读取不同环境配置，但是每次部署都会将 <code class=\"language-text\">.env.test</code> 和 <code class=\"language-text\">.env.release</code> 两份配置文件同时上传。有时我们并不想暴露生产环境的配置在测试环境，因此需要每次部署时，只上传对应配置文件。要做到这一点，只需要在 <code class=\"language-text\">serverless.yml</code> 配置文件中新增 <code class=\"language-text\">exclude</code> 和 <code class=\"language-text\">incldue</code> 配置:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"59480570440947410000\"\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(`CODE_ENV: release\n\nMyExpress:\n  component: &quot;@serverless/tencent-koa&quot;\n  inputs:\n    region: ap-guangzhou\n    functionName: express-function\n    code: ./\n    exclude:\n      - .env.release\n      - .env.test\n    include:\n      - .env.\\${CODE_ENV}\n    functionConf:\n      timeout: 10\n      memorySize: 128\n      environment:\n        variables:\n          CODE_ENV: \\${CODE_ENV}\n    apigatewayConf:\n      protocols:\n        - http\n        - https\n      environment: \\${CODE_ENV}`, `59480570440947410000`)\"\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=\"yml\"><pre class=\"language-yml\"><code class=\"language-yml\"><span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> release\n\n<span class=\"token key atrule\">MyExpress</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-koa\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">functionName</span><span class=\"token punctuation\">:</span> express<span class=\"token punctuation\">-</span>function\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span> ./\n    <span class=\"token key atrule\">exclude</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.release\n      <span class=\"token punctuation\">-</span> .env.test\n    <span class=\"token key atrule\">include</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.$<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">functionConf</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">timeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">10</span>\n      <span class=\"token key atrule\">memorySize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">128</span>\n      <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">apigatewayConf</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">protocols</span><span class=\"token punctuation\">:</span>\n        <span class=\"token punctuation\">-</span> http\n        <span class=\"token punctuation\">-</span> https\n      <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span></code></pre></div>\n<p>这里先通过 <code class=\"language-text\">exclude</code> 配置忽略所有配置文件，然后通过 <code class=\"language-text\">include</code> 来包含指定的配置文件。之所以这么做，是因为我们指定了 <code class=\"language-text\">code</code> 字段为 <code class=\"language-text\">./ - 项目根目录</code> ，因此会默认上传项目根目录的所有文件。</p>\n<h2 id=\"配置优化-2\"><a href=\"#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%8C%96-2\" aria-label=\"配置优化 2 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>配置优化 2</h2>\n<p>当然也可以将 <code class=\"language-text\">serverless.yml</code> 中的任何固定参数写到 <code class=\"language-text\">.env</code> 文件中，比如这里的 <code class=\"language-text\">CODE_ENV</code> 变量，然后通过 <code class=\"language-text\">${env.CODE_ENV}</code> 引用即可。比如我们将 <code class=\"language-text\">CODE_ENV</code> 写入到 <code class=\"language-text\">.env</code> 中：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"3416071151663979500\"\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(`CODE_ENV=release`, `3416071151663979500`)\"\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=\"dotenv\"><pre class=\"language-dotenv\"><code class=\"language-dotenv\">CODE_ENV=release</code></pre></div>\n<p>然后修改 <code class=\"language-text\">serverless.yml</code> 配置：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"54667149116827380000\"\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(`MyExpress:\n  component: &quot;@serverless/tencent-koa&quot;\n  inputs:\n    region: ap-guangzhou\n    functionName: express-function\n    code: ./\n    exclude:\n      - .env.release\n      - .env.test\n    include:\n      - .env.\\${env.CODE_ENV}\n    functionConf:\n      timeout: 10\n      memorySize: 128\n      environment:\n        variables:\n          CODE_ENV: \\${env.CODE_ENV}\n    apigatewayConf:\n      protocols:\n        - http\n        - https\n      environment: \\${env.CODE_ENV}`, `54667149116827380000`)\"\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=\"yml\"><pre class=\"language-yml\"><code class=\"language-yml\"><span class=\"token key atrule\">MyExpress</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-koa\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">functionName</span><span class=\"token punctuation\">:</span> express<span class=\"token punctuation\">-</span>function\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span> ./\n    <span class=\"token key atrule\">exclude</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.release\n      <span class=\"token punctuation\">-</span> .env.test\n    <span class=\"token key atrule\">include</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.$<span class=\"token punctuation\">{</span>env.CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">functionConf</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">timeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">10</span>\n      <span class=\"token key atrule\">memorySize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">128</span>\n      <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>env.CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">apigatewayConf</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">protocols</span><span class=\"token punctuation\">:</span>\n        <span class=\"token punctuation\">-</span> http\n        <span class=\"token punctuation\">-</span> https\n      <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>env.CODE_ENV<span class=\"token punctuation\">}</span></code></pre></div>\n<p>需要说明的是 <code class=\"language-text\">.env</code> 文件有个缺点，就是无法定义对象和数组。但是对于私密的配置，还是放到 <code class=\"language-text\">.env</code> 中比较合适，这样就可以基于文件去忽略部署。</p>\n<h2 id=\"配置优化-3\"><a href=\"#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%8C%96-3\" aria-label=\"配置优化 3 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>配置优化 3</h2>\n<p>当需要将同一份业务代码部署到不同的地区，但是函数参数配置和 API 网关配置都是一致时，如何配置呢？这里一样可以提炼出通用配置，如下：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"45174755877755370000\"\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(`# global config\nCODE_ENV: release\n\n# function config\nFUNC_CONF:\n  name: express-function\n  memorySize: 128\n  timeout: 10\n  environment:\n    variables:\n      CODE_ENV: \\${CODE_ENV}\n\n# apigw config\nAPI_CONF:\n  protocols:\n    - http\n    - https\n  environment: \\${CODE_ENV}\n\n# guangzhou service\nMyExpressGZ:\n  component: &quot;@serverless/tencent-koa&quot;\n  inputs:\n    region: ap-guangzhou\n    functionName: \\${FUNC_CONF.name}\n    code: ./\n    exclude:\n      - .env.release\n      - .env.test\n    include:\n      - .env.\\${CODE_ENV}\n    functionConf: \\${FUNC_CONF}\n    apigatewayConf: \\${API_CONF}\n\n# beijing service\nMyExpressBJ:\n  component: &quot;@serverless/tencent-koa&quot;\n  inputs:\n    region: ap-beijing\n    functionName: \\${FUNC_CONF.name}\n    code: ./\n    exclude:\n      - .env.release\n      - .env.test\n    include:\n      - .env.\\${CODE_ENV}\n    functionConf: \\${FUNC_CONF}\n    apigatewayConf: \\${API_CONF}`, `45174755877755370000`)\"\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=\"yml\"><pre class=\"language-yml\"><code class=\"language-yml\"><span class=\"token comment\"># global config</span>\n<span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> release\n\n<span class=\"token comment\"># function config</span>\n<span class=\"token key atrule\">FUNC_CONF</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> express<span class=\"token punctuation\">-</span>function\n  <span class=\"token key atrule\">memorySize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">128</span>\n  <span class=\"token key atrule\">timeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">10</span>\n  <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">CODE_ENV</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\"># apigw config</span>\n<span class=\"token key atrule\">API_CONF</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">protocols</span><span class=\"token punctuation\">:</span>\n    <span class=\"token punctuation\">-</span> http\n    <span class=\"token punctuation\">-</span> https\n  <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\"># guangzhou service</span>\n<span class=\"token key atrule\">MyExpressGZ</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-koa\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">functionName</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>FUNC_CONF.name<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span> ./\n    <span class=\"token key atrule\">exclude</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.release\n      <span class=\"token punctuation\">-</span> .env.test\n    <span class=\"token key atrule\">include</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.$<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">functionConf</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>FUNC_CONF<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">apigatewayConf</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>API_CONF<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\"># beijing service</span>\n<span class=\"token key atrule\">MyExpressBJ</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-koa\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>beijing\n    <span class=\"token key atrule\">functionName</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>FUNC_CONF.name<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span> ./\n    <span class=\"token key atrule\">exclude</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.release\n      <span class=\"token punctuation\">-</span> .env.test\n    <span class=\"token key atrule\">include</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> .env.$<span class=\"token punctuation\">{</span>CODE_ENV<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">functionConf</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>FUNC_CONF<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">apigatewayConf</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>API_CONF<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"如何选择配置方案\"><a href=\"#%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9%E9%85%8D%E7%BD%AE%E6%96%B9%E6%A1%88\" 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<ol>\n<li>通过 <code class=\"language-text\">.env</code> 配置</li>\n<li>通过在 <code class=\"language-text\">serverless.yml</code> 中定义变量</li>\n</ol>\n<p>他们都可以定义全局变量，那么在实际开发中如何去抉择使用呢？</p>\n<blockquote>\n<p>注意：<code class=\"language-text\">serverless.yml</code> 定义的变量，或者 <code class=\"language-text\">.env</code> 中自动注入的变量，只有在执行 <code class=\"language-text\">sls --debug</code> 命令后，才能够获取到。实际部署成功的代码，是需要通过 <code class=\"language-text\">dotenv</code> 模块来指定 <code class=\"language-text\">.env</code> 文件来手动加载注入的。当然如果你也可以通过解析 <code class=\"language-text\">serverless.yml</code> 文件来获取需要的变量也是可以的。</p>\n</blockquote>\n<p>通常我会将跟 <code class=\"language-text\">执行部署时的配置</code> 放到 <code class=\"language-text\">serverless.yml</code> 中，将 <code class=\"language-text\">业务相关的配置</code> 放到 <code class=\"language-text\">.env</code> 文件中。当然，这里只是个人建议，具体如何去配置还是要看个人使用习惯。</p>\n<h2 id=\"其他语言\"><a href=\"#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80\" 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>虽然本文只是讲述了如何在 <code class=\"language-text\">Nodejs</code> 项目中管理多环境配置，但是其他语言基本都实现了 <code class=\"language-text\">dotenv</code> 模块，所以此方法是通用的，比如 <code class=\"language-text\">Python</code> 的 <code class=\"language-text\">python-dotenv</code> 模块，使用起来基本差不多：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"41423088401377610000\"\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(`# settings.py\nfrom dotenv import load_dotenv\nfrom pathlib import Path  # python3 only\nenv_path = Path('.') / '.env.test'\nload_dotenv(dotenv_path=env_path)`, `41423088401377610000`)\"\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=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># settings.py</span>\n<span class=\"token keyword\">from</span> dotenv <span class=\"token keyword\">import</span> load_dotenv\n<span class=\"token keyword\">from</span> pathlib <span class=\"token keyword\">import</span> Path  <span class=\"token comment\"># python3 only</span>\nenv_path <span class=\"token operator\">=</span> Path<span class=\"token punctuation\">(</span><span class=\"token string\">'.'</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token string\">'.env.test'</span>\nload_dotenv<span class=\"token punctuation\">(</span>dotenv_path<span class=\"token operator\">=</span>env_path<span class=\"token punctuation\">)</span></code></pre></div>\n<h2 id=\"总结\"><a href=\"#%E6%80%BB%E7%BB%93\" 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>本篇涉及到所有源码都维护在开源项目 <a href=\"https://github.com/yugasun/tencent-serverless-demo\">tencent-serverless-demo</a> 中 <a href=\"https://github.com/yugasun/tencent-serverless-demo/tree/master/serverless-env\">serverless-env</a></p>\n<p>全文到这里就结束了，当然这只是本人在日常开发中总结的经验而已，如果你有更好的实践方式，欢迎一起为 Serverless 开源社区做贡献。</p>\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-03-10-serverless-env/#serverless-component\">Serverless Component</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#dotenv-%E6%A8%A1%E5%9D%97\">dotenv 模块</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E7%AE%A1%E7%90%86%E5%A4%9A%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE\">管理多环境配置</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%8C%96-1\">配置优化 1</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%8C%96-2\">配置优化 2</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E9%85%8D%E7%BD%AE%E4%BC%98%E5%8C%96-3\">配置优化 3</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9%E9%85%8D%E7%BD%AE%E6%96%B9%E6%A1%88\">如何选择配置方案</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80\">其他语言</a></li>\n<li><a href=\"/best-practice/2020-03-10-serverless-env/#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>"},"previousBlog":{"id":"1f1b1317-32a1-50c4-a77f-df648ee9128f","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207418152-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-03-12T00:00:00.000Z","title":"让 Serverless 为你的头像增加点装饰","description":"无论是国庆还是新年，经常会有一个平台为我们提供一个生成头像的小工具，本文手把手教你实现头像加装饰的工具","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","图像处理"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":106,"sentences":29,"paragraphs":29},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-03-12-avatar-decoration.md","fields":{"slug":"/best-practice/2020-03-12-avatar-decoration/","keywords":["go","java","python","serverless","website","云函数","mui","pic","base","shape"]}},"nextBlog":{"id":"d45150eb-b890-55be-b616-dc19cf459c38","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/202034/1583323516946-v2-1a569e74722930de772e470209db3c05_1200x500.jpg","authors":["Anycodes"],"categories":["guides-and-tutorials","user-stories"],"date":"2020-03-03T00:00:00.000Z","title":"Serverless 组件开发尝试：全局变量组件和单独部署组件","description":"为了方便，我开发了这样的 Component","authorslink":["https://www.zhihu.com/people/liuyu-43-97"],"translators":null,"translatorslink":null,"tags":["Serverless","Component"],"keywords":"Serverless 全局变量组件,Serverless 单独部署组件,Serverless Component","outdated":true},"wordCount":{"words":212,"sentences":34,"paragraphs":33},"fileAbsolutePath":"/opt/build/repo/content/blog/2020-03-03-global-Component.md","fields":{"slug":"/blog/2020-03-03-global-Component/","keywords":["go","koa","serverless","website","云函数","serverless","website","tencent","mysql"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"a91ae766-b090-5f4d-891f-3332b7d58e00","previousBlogId":"1f1b1317-32a1-50c4-a77f-df648ee9128f","nextBlogId":"d45150eb-b890-55be-b616-dc19cf459c38"}}}