具有无服务器框架的 AWS codeBuild/codePipeline
AWS codeBuild/codePipeline with serverless framework
我正在尝试为我的应用程序自动化 部署管道。这是我想出的自动化架构:
如您所见,我正在使用 codePipeline 和 codeBuild 来自动化我的部署。我的后端基于 Serverless Framework,它在触发 sls deploy
命令时部署 lambda 函数。这是原因,我没有使用codeDeploy做传统部署。 buildspec.yml
文件如下所示:
version: 0.1
phases:
install:
commands:
– apt-get -y update
– npm install -g serverless@1.9.0
build:
commands:
– cd nj2jp/serverless && npm install
post_build:
commands:
– serverless deploy –verbose
artifacts:
files:
– serverless.yml
discard-paths: yes
现在,关于 CodeBuild 和 Serverless,我有 3 个问题:
问题 1: 命令 sls deploy
依赖于一个名为 config.yml
的文件,该文件包含数据库密码等机密信息。此文件将不会签入 git。您认为在 codeBuild 中包含 config.yml
的最佳方式是什么?
问题 2:回滚 可以通过 AWS 完成,如果我们必须使用 codeDeploy 部署传统的 EC2 应用程序。在无服务器的情况下,我们不使用 codeDeploy 并且无服务器还支持 rollback 功能。我们如何在 codePipeline?
中利用无服务器回滚
问题 3: 在发生 拉取请求 时触发 codePipeline。我看到一些帖子说,codePipeline 不支持它。但是那些帖子是去年的,Pull Request now supported by codePipeline?
Hack Answers(不正确,但有效。需要您提供更好的答案。)
答案 1: config.yml
文件可以保存在私有 S3 存储桶中 并且可以拉到 codeBuild as pre-build
设置的一部分,或者我们可以将所有秘密添加到 codeBuild 的 Env 变量中。我不喜欢第二种选择,因为我希望在所有环境中保持一致。这个问题有更好的解决方案吗?
答案 2: 我想不出解决这个问题的方法。期待您的解答。
答案 3: 我看到一些博客文章使用 [APIGateway + Lambda + S3] 来触发 codePipeline 进行拉取请求。但我觉得,这个功能必须作为开箱即用的功能提供。此功能的 codePipeline 是否有任何更新?
问题 1
更新:
Serverless 框架现在支持从 Parameter Store 引用变量。这意味着您可以跳过在 CodeBuild 中定义它们,因为无服务器将在部署时从 Parameter Store 检索它们。
示例:
serverless.yaml
provider:
name: aws
runtime: nodejs8.10
region: us-west-2
stage: ${env:REGION}
environment:
S3_BUCKET: ${env:/s3/bucket}
# Use ~true for SecureString parameters
DB_USERNAME: ${ssm:/db/username~true}
DB_PASSWORD: ${env:/db/password~true}
原答案:
如果您想坚持使用您的 config.yml
,那么让它工作的唯一方法是通过类似于您已经在做的事情的黑客攻击,因为它不受版本控制。
我的建议是将您的环境变量存储在 EC2 Parameter Store 中,您可以在 CodeBuild buildspec.yml
中引用它。这些变量可以在您的 serverless.yml
中使用 ${env:VARIABLE_NAME}
.
访问
对于本地开发,您还应该使用真实的环境变量而不是将它们存储在 config.yml
中。 direnv 等工具在这方面做得很好。
问题 2
您可以通过重新运行 之前的 CodeBuild 作业进行手动回滚。我想不出像 CodeDeploy 那样自动执行此操作的简单方法。也许 Lambda 函数可以进行 post-部署测试,如果失败,它可以触发重新 运行 之前的 CodeBuild 作业。
问题 3
CodePipelines 绑定到单个分支,因此要使其在 PR 分支上运行,您必须像您提到的文章那样进行修改。我已经求助于使用 API Gateway + Lambda + CodeBuild (没有 CodePipeline) 来做到这一点。
只是添加到问题 1 的已接受答案中(感谢@dashmug 和@Lakshman Diwaakar)
这确实解决了如何将 Parameter Store 值获取到您的 Lambda 中的问题。但是,这些值在 Lambda 控制台中显示为纯文本。我接下来需要解决的是如何添加加密。
参数存储
在 AWS Systems Manager > Parameter store
中添加您的环境变量作为参数
https://eu-west-1.console.aws.amazon.com/systems-manager/parameters
buildspec.yml
version: 0.2
phases:
install:
commands:
- npm install
- npm install -g serverless
build:
commands:
- serverless deploy
serverless.yml
引用serverless.yml中创建的Params
为安全字符串附加 ~true。
provider:
name: aws
runtime: nodejs6.10
region: eu-west-1
stage: prod
environment:
FOO: ${ssm:/app/production/foo}
DB_USERNAME: ${ssm:/app/production/myDatabase/username~true}
DB_PASSWORD: ${ssm:/app/production/myDatabase/password~true}
handler.js
在您的处理程序中使用环境变量
export async function main (event, context, callback) {
console.log('process.env.FOO', process.env.FOO)
console.log('process.env.DB_USERNAME', process.env.DB_USERNAME)
console.log('process.env.DB_PASSWORD', process.env.DB_PASSWORD)
callback(null, ok('success'))
}
我正在尝试为我的应用程序自动化 部署管道。这是我想出的自动化架构:
如您所见,我正在使用 codePipeline 和 codeBuild 来自动化我的部署。我的后端基于 Serverless Framework,它在触发 sls deploy
命令时部署 lambda 函数。这是原因,我没有使用codeDeploy做传统部署。 buildspec.yml
文件如下所示:
version: 0.1
phases:
install:
commands:
– apt-get -y update
– npm install -g serverless@1.9.0
build:
commands:
– cd nj2jp/serverless && npm install
post_build:
commands:
– serverless deploy –verbose
artifacts:
files:
– serverless.yml
discard-paths: yes
现在,关于 CodeBuild 和 Serverless,我有 3 个问题:
问题 1: 命令 sls deploy
依赖于一个名为 config.yml
的文件,该文件包含数据库密码等机密信息。此文件将不会签入 git。您认为在 codeBuild 中包含 config.yml
的最佳方式是什么?
问题 2:回滚 可以通过 AWS 完成,如果我们必须使用 codeDeploy 部署传统的 EC2 应用程序。在无服务器的情况下,我们不使用 codeDeploy 并且无服务器还支持 rollback 功能。我们如何在 codePipeline?
中利用无服务器回滚问题 3: 在发生 拉取请求 时触发 codePipeline。我看到一些帖子说,codePipeline 不支持它。但是那些帖子是去年的,Pull Request now supported by codePipeline?
Hack Answers(不正确,但有效。需要您提供更好的答案。)
答案 1: config.yml
文件可以保存在私有 S3 存储桶中 并且可以拉到 codeBuild as pre-build
设置的一部分,或者我们可以将所有秘密添加到 codeBuild 的 Env 变量中。我不喜欢第二种选择,因为我希望在所有环境中保持一致。这个问题有更好的解决方案吗?
答案 2: 我想不出解决这个问题的方法。期待您的解答。
答案 3: 我看到一些博客文章使用 [APIGateway + Lambda + S3] 来触发 codePipeline 进行拉取请求。但我觉得,这个功能必须作为开箱即用的功能提供。此功能的 codePipeline 是否有任何更新?
问题 1
更新:
Serverless 框架现在支持从 Parameter Store 引用变量。这意味着您可以跳过在 CodeBuild 中定义它们,因为无服务器将在部署时从 Parameter Store 检索它们。
示例:
serverless.yaml
provider:
name: aws
runtime: nodejs8.10
region: us-west-2
stage: ${env:REGION}
environment:
S3_BUCKET: ${env:/s3/bucket}
# Use ~true for SecureString parameters
DB_USERNAME: ${ssm:/db/username~true}
DB_PASSWORD: ${env:/db/password~true}
原答案:
如果您想坚持使用您的 config.yml
,那么让它工作的唯一方法是通过类似于您已经在做的事情的黑客攻击,因为它不受版本控制。
我的建议是将您的环境变量存储在 EC2 Parameter Store 中,您可以在 CodeBuild buildspec.yml
中引用它。这些变量可以在您的 serverless.yml
中使用 ${env:VARIABLE_NAME}
.
对于本地开发,您还应该使用真实的环境变量而不是将它们存储在 config.yml
中。 direnv 等工具在这方面做得很好。
问题 2
您可以通过重新运行 之前的 CodeBuild 作业进行手动回滚。我想不出像 CodeDeploy 那样自动执行此操作的简单方法。也许 Lambda 函数可以进行 post-部署测试,如果失败,它可以触发重新 运行 之前的 CodeBuild 作业。
问题 3
CodePipelines 绑定到单个分支,因此要使其在 PR 分支上运行,您必须像您提到的文章那样进行修改。我已经求助于使用 API Gateway + Lambda + CodeBuild (没有 CodePipeline) 来做到这一点。
只是添加到问题 1 的已接受答案中(感谢@dashmug 和@Lakshman Diwaakar)
这确实解决了如何将 Parameter Store 值获取到您的 Lambda 中的问题。但是,这些值在 Lambda 控制台中显示为纯文本。我接下来需要解决的是如何添加加密。
参数存储
在 AWS Systems Manager > Parameter store
中添加您的环境变量作为参数https://eu-west-1.console.aws.amazon.com/systems-manager/parameters
buildspec.yml
version: 0.2
phases:
install:
commands:
- npm install
- npm install -g serverless
build:
commands:
- serverless deploy
serverless.yml
引用serverless.yml中创建的Params
为安全字符串附加 ~true。
provider:
name: aws
runtime: nodejs6.10
region: eu-west-1
stage: prod
environment:
FOO: ${ssm:/app/production/foo}
DB_USERNAME: ${ssm:/app/production/myDatabase/username~true}
DB_PASSWORD: ${ssm:/app/production/myDatabase/password~true}
handler.js
在您的处理程序中使用环境变量
export async function main (event, context, callback) {
console.log('process.env.FOO', process.env.FOO)
console.log('process.env.DB_USERNAME', process.env.DB_USERNAME)
console.log('process.env.DB_PASSWORD', process.env.DB_PASSWORD)
callback(null, ok('success'))
}