如何建立一个有效的初始部署管道

本文概述

  • 老派:创建一个基本应用程序并将其部署到Heroku
  • 完美的初始部署管道
  • 本文总结和进一步的步骤
我喜欢构建东西, 而开发人员却没有?我喜欢为有趣的问题想出解决方案, 编写实现并创建漂亮的代码。但是, 我不喜欢操作。操作是构建出色软件所不涉及的一切, 从设置服务器到将代码交付生产都应运而生。
这很有趣, 因为作为一名自由的Ruby on Rails开发人员, 我经常不得不创建新的Web应用程序并重复弄清楚DevOps方面的过程。幸运的是, 在创建了数十个应用程序之后, 我终于确定了一个完美的初始部署管道。不幸的是, 并不是每个人都能像我一样弄清楚这一点。最终, 这种知识使我投入了很多精力并记录了我的过程。
在本文中, 我将引导你完成在项目开始时使用的完善流程。使用我的管道, 将测试每个推送, 将master分支部署到生产环境中的新数据库转储中进行登台, 并将版本化的标签部署到生产中, 并自动进行备份和迁移。
请注意, 由于这是我的工作流程, 因此它也很适合我的需求;但是, 你可以随意交换不想要的任何东西, 并用任何你喜欢的东西替换。对于我的管道, 我们将使用:
  • GitLab托管代码。
    • 原因:我的客户希望自己的代码保密, 而GitLab的免费版很棒。此外, 集成的免费CI也很棒。感谢GitLab!
    • 替代方案:GitHub, BitBucket, AWS CodeCommit等。
  • GitLab CI来构建, 测试和部署我们的代码。
    • 原因:它与GitLab集成并且是免费的!
    • 替代方案:TravisCI, Codeship, CircleCI, 使用Fabric8进行DIY等。
  • Heroku托管我们的应用程序。
    • 原因:它开箱即用, 是启动的理想平台。你将来可以更改此设置, 但并非每个新应用都需要在专门构建的Kubernetes集群上运行。甚至Coinbase也从Heroku开始。
    • 替代方案:AWS, DigitalOcean, Vultr, 使用Kubernetes进行DIY等。
老派:创建一个基本应用程序并将其部署到Heroku 首先, 让我们为不使用任何精美的CI / CD管道而只想部署其应用程序的人重新创建一个典型的应用程序。
如何建立一个有效的初始部署管道

文章图片
创建哪种应用都没有关系, 但是你需要使用Yarn或npm。在我的示例中, 我正在创建Ruby on Rails应用程序, 因为该应用程序附带了迁移和CLI, 并且已经为其编写了配置。欢迎使用你喜欢的任何框架或语言, 但是你需要使用Yarn进行以后的版本控制。我正在创建一个简单的CRUD应用, 仅使用一些命令并且不进行身份验证。
让我们测试一下我们的应用程序是否按预期运行。为了确定, 我继续创建了一些帖子。
如何建立一个有效的初始部署管道

文章图片
然后通过推送代码并运行迁移, 将其部署到Heroku
$ heroku create srcmini-pipeline Creating ? srcmini-pipeline... done https://srcmini-pipeline.herokuapp.com/ | https://git.heroku.com/srcmini-pipeline.git $ git push heroku master Counting objects: 132, done. ... To https://git.heroku.com/srcmini-pipeline.git * [new branch]master -> master $ heroku run rails db:migrate Running rails db:migrate on ? srcmini-pipeline... up, run.9653 (Free) ...

最后, 让我们在生产中对其进行测试
如何建立一个有效的初始部署管道

文章图片
就是这样!通常, 这是大多数开发人员离开运营的地方。将来, 如果你进行更改, 则必须重复上述部署和迁移步骤。如果你不晚饭, 甚至可以进行测试。这是一个很好的起点, 但让我们再考虑一下这种方法。
优点
  • 快速设置。
  • 部署很容易。
缺点
  • 不干燥:每次更改都需要重复相同的步骤。
  • 没有版本说明:” 我将从昨天的部署回滚到上周的部署” , 从现在起的三周内并不是很明确。
  • 并非代码不正确:你知道应该进行测试, 但是没人看, 因此尽管偶尔测试失败, 你还是可以继续进行测试。
  • 不是很糟糕的演员:如果一个心怀不满的开发人员决定通过推送代码并提示有关你如何为团队订购不足的披萨消息来破坏你的应用程序, 该怎么办?
  • 无法扩展:允许每个开发人员都具有部署能力, 这将使他们在生产级别上可以访问该应用程序, 这违反了最小特权原则。
  • 没有暂存环境:在生产之前, 不会显示特定于生产环境的错误。
完美的初始部署管道 今天, 我将尝试一些不同的事情:让我们进行假设的对话。我将给” 你” 一个声音, 我们将讨论如何改善当前流程。来吧, 说点什么。
说什么?等等-我可以说话吗?
是的, 这就是我要给你表达声音的意思。你好吗?
我很好。这感觉很奇怪
我了解, 但是随它去吧。现在, 让我们谈谈我们的管道。关于运行部署, 最令人讨厌的部分是什么?
哦, 很简单。我浪费的时间。你是否尝试过推向Heroku?
是的, 看着你的依赖项下载和作为git push的一部分而构建的应用程序太可怕了!
我知道, 对吧?太疯狂了我希望我不必这样做。还有一个事实, 就是我必须在部署之后进行迁移, 因此我必须观看节目并检查以确保我的部署能够顺利进行
好的, 你实际上可以通过将两个命令与& & 链接起来来解决后一个问题, 例如git push heroku master & & heroku run rails db:migrate, 或者只是创建一个bash脚本并将其放入你的代码中, 但仍然是一个很好的答案, 时间和重复是一个真正的痛苦。
是的, 真的很烂
如果我告诉你可以立即使用CI / CD管道修复该问题怎么办?
现在呢?那是什么?
CI / CD代表持续集成(CI)和持续交付/部署(CD)。我很难一开始就确切地了解它是什么, 因为每个人都使用模糊的术语, 例如” 开发与运营的融合” , 但简单地说:
  • 持续集成:确保所有代码都在一个地方合并在一起。让你的团队使用Git, 你将使用CI。
  • 持续交付:确保你的代码可以连续交付。意味着可以快速生成产品的读取到分发版本。
  • 持续部署:无缝地从连续交付中获取产品, 然后将其部署到你的服务器中。
哦, 我明白了。这是关于使我的应用神奇地部署到全世界!
我最喜欢的解释CI / CD的文章是Atlassian在这里。这应该清除你的任何问题。无论如何, 回到问题。
是的, 回到那个。如何避免手动部署?
设置CI / CD管道以在Push to master上部署
如果我告诉你可以立即使用CI / CD修复该问题怎么办?你可以将你的GitLab遥控器(原点)推送到计算机上, 然后只需将你的代码推送到Heroku即可生成计算机。
没门!
是的!让我们再次跳回代码。
如何建立一个有效的初始部署管道

文章图片
使用以下内容创建一个.gitlab-ci.yml, 将srcmini-pipeline替换为你的Heroku应用的名称:
image: ruby:2.4before_script: - > : "${HEROKU_EMAIL:?Please set HEROKU_EMAIL in your CI/CD config vars}" - > : "${HEROKU_AUTH_TOKEN:?Please set HEROKU_AUTH_TOKEN in your CI/CD config vars}" - curl https://cli-assets.heroku.com/install-standalone.sh | sh - | cat > ~/.netrc < < EOF machine api.heroku.com login $HEROKU_EMAIL password $HEROKU_AUTH_TOKEN machine git.heroku.com login $HEROKU_EMAIL password $HEROKU_AUTH_TOKEN EOF - chmod 600 ~/.netrc - git config --global user.email "[email  protected]" - git config --global user.name "CI/CD"variables: APPNAME_PRODUCTION: srcmini-pipelinedeploy_to_production: stage: deploy environment: name: production url: https://$APPNAME_PRODUCTION.herokuapp.com/ script: - git remote add heroku https://git.heroku.com/$APPNAME_PRODUCTION.git - git push heroku master - heroku pg:backups:capture --app $APPNAME_PRODUCTION - heroku run rails db:migrate --app $APPNAME_PRODUCTION only: - master

在项目的” 管道” 页面中将其向上推, 然后观察失败。那是因为它缺少你的Heroku帐户的身份验证密钥。但是, 修复起来非常简单。首先, 你需要使用Heroku API密钥。从” 管理帐户” 页面获取它, 然后在GitLab存储库的CI / CD设置中添加以下秘密变量:
  • HEROKU_EMAIL:你用于登录Heroku的电子邮件地址
  • HEROKU_AUTH_KEY:你从Heroku获得的密钥
如何建立一个有效的初始部署管道

文章图片
这应该导致在每次推送时都能正常运行的GitLab到Heroku的部署。关于发生的事情:
  • 一经推向高手
    • Heroku CLI已在容器中安装并通过身份验证。
    • 你的代码被推送到Heroku。
    • 在Heroku中捕获数据库的备份。
    • 运行迁移。
你已经看到, 不仅通过将所有内容自动化到git push中来节省时间, 而且还在每次部署中创建数据库的备份!如果发生任何问题, 你将拥有数据库副本以供还原。
创建暂存环境
但是, 等等, 一个简单的问题, 你的生产特定问题会如何处理?如果你的开发环境与生产环境大相径庭而遇到怪异的错误怎么办?进行迁移时, 我曾经遇到过一些奇怪的SQLite 3和PostgreSQL问题。细节让我难以理解, 但这很有可能。
我在开发中严格使用PostgreSQL, 我从来不会像这样错配数据库引擎, 并且我会认真监视我的堆栈是否存在潜在的不兼容性。
【如何建立一个有效的初始部署管道】好吧, 那是乏味的工作, 我为你的纪律表示赞赏。就个人而言, 我太懒了。但是, 你是否可以保证所有潜在的未来开发人员, 合作者或贡献者的勤奋程度?
Errrr-是的, 不。你让我在那里。其他人会把它弄乱。不过, 你的意思是什么?
我的观点是, 你需要一个暂存环境。就像生产, 但不是。在暂存环境中, 你可以练习部署到生产环境, 并尽早发现所有错误。我的暂存环境通常镜像生产, 并且在暂存部署中转储生产数据库的副本, 以确保不会出现烦人的极端情况而干扰我的迁移。在暂存环境中, 你可以停止像豚鼠一样对待用户。
这很有道理!那么我该怎么做呢?
这就是有趣的地方。我喜欢直接将master部署到暂存。
等等, 这不是我们现在要部署生产的地方吗?
是的, 但是现在我们将部署到暂存。
但是, 如果将master部署到暂存, 我们如何部署到生产?
通过使用几年前应该做的事情:版本化代码并推送Git标签。
git标签?谁使用Git标签?这听起来像是很多工作。
确实可以, 但是值得庆幸的是, 我已经完成了所有工作, 你只需转储我的代码即可使用。
如何建立一个有效的初始部署管道

文章图片
首先, 在你的.gitlab-ci.yml文件中添加一个有关暂存部署的块, 我创建了一个名为srcmini-pipeline-staging的新Heroku应用程序:
…variables: APPNAME_PRODUCTION: srcmini-pipeline APPNAME_STAGING: srcmini-pipeline-stagingdeploy_to_staging: stage: deploy environment: name: staging url: https://$APPNAME_STAGING.herokuapp.com/ script: - git remote add heroku https://git.heroku.com/$APPNAME_STAGING.git - git push heroku master - heroku pg:backups:capture --app $APPNAME_PRODUCTION - heroku pg:backups:restore `heroku pg:backups:url --app $APPNAME_PRODUCTION` --app $APPNAME_STAGING --confirm $APPNAME_STAGING - heroku run rails db:migrate --app $APPNAME_STAGING only: - master - tags...

然后将生产块的最后一行更改为在语义版本化的Git标记而不是master分支上运行:
deploy_to_production: ... only: - /^v(?'MAJOR'(?:0|(?:[1-9]\d*)))\.(?'MINOR'(?:0|(?:[1-9]\d*)))\.(?'PATCH'(?:0|(?:[1-9]\d*)))(?:-(?'prerelease'[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(?:\+(?'build'[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$/ # semver pattern above is adapted from https://github.com/semver/semver.org/issues/59#issuecomment-57884619

现在运行此命令将失败, 因为GitLab足够聪明, 只允许” 受保护的” 分支访问我们的秘密变量。要添加版本标签, 请转到你的GitLab项目的存储库设置页面, 然后将v *添加到受保护的标签中。
如何建立一个有效的初始部署管道

文章图片
让我们回顾一下现在发生的事情:
  • 推送至主节点或推送已标记的提交时
    • Heroku CLI已在容器中安装并通过身份验证。
    • 你的代码被推送到Heroku。
    • 在Heroku中捕获数据库生产的备份。
    • 备份将转储到你的暂存环境中。
    • 迁移在登台数据库上运行。
  • 在推送语义版本标记的提交时
    • Heroku CLI已在容器中安装并通过身份验证。
    • 你的代码被推送到Heroku。
    • 在Heroku中捕获数据库生产的备份。
    • 迁移在生产数据库上运行。
你现在感觉强大吗?我感觉很强大。我记得, 我第一次走到这一步时, 我给妻子打电话, 并详细解释了整个流程。而且她甚至都不熟练。我对自己留下深刻的印象, 你也应该如此!真是太好了!
测试每一次推送
但是还有更多, 因为计算机无论如何都会为你做事, 它也可以运行你懒得做的所有事情:测试, 消除错误, 几乎你想做的任何事情, 并且如果其中任何一项失败了, 它们就会赢了。不要继续部署。
我喜欢在我的管道中使用它, 这使我的代码审查很有趣。如果合并请求通过了我所有的代码检查, 则应进行审查。
如何建立一个有效的初始部署管道

文章图片
添加一个测试块:
test: stage: test variables: POSTGRES_USER: test POSTGRES_PASSSWORD: test-password POSTGRES_DB: test DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSSWORD}@postgres/${POSTGRES_DB} RAILS_ENV: test services: - postgres:alpine before_script: - curl -sL https://deb.nodesource.com/setup_8.x | bash - apt-get update -qq & & apt-get install -yqq nodejs libpq-dev - curl -o- -L https://yarnpkg.com/install.sh | bash - source ~/.bashrc - yarn - gem install bundler--no-ri --no-rdoc - bundle install -j $(nproc) --path vendor - bundle exec rake db:setup RAILS_ENV=test script: - bundle exec rake spec - bundle exec rubocop

让我们回顾一下现在发生的事情:
  • 每次推送或合并请求时
    • Ruby和Node是在容器中设置的。
    • 已安装依赖项。
    • 该应用程序已经过测试。
  • 仅当所有测试均通过时, 才可以推送到主节点或推送标记的提交
    • Heroku CLI已在容器中安装并通过身份验证。
    • 你的代码被推送到Heroku。
    • 在Heroku中捕获数据库生产的备份。
    • 备份将转储到你的暂存环境中。
    • 迁移在登台数据库上运行。
  • 推送语义版本标记的提交时, 并且仅当所有测试通过时
    • Heroku CLI已在容器中安装并通过身份验证。
    • 你的代码被推送到Heroku。
    • 在Heroku中捕获数据库生产的备份。
    • 迁移在生产数据库上运行。
退后一步, 惊叹于你已实现的自动化水平。从现在开始, 你要做的就是编写代码并推送。如果需要, 请在阶段中手动测试你的应用程序, 当你有足够的信心将其发布时, 请使用语义版本标记它!
自动语义版本控制
是的, 这很完美, 但是还缺少一些东西。我不喜欢查找应用程序的最新版本并对其进行明确标记。这需要多个命令, 并分散我几秒钟的注意力。
好吧, 伙计, 停下!够了你现在只是对其进行了过度设计。它行之有效, 非常出色, 不会因为掉下去而毁了一件好事。
好的, 我有充分的理由去做自己想做的事情。
祈祷, 启发我。
我曾经像你一样。我对此设置感到满意, 但后来又搞砸了。 git tag按字母顺序列出标签, v0.0.11高于v0.0.2。我曾经不小心标记了一个发行版, 并继续做了大约六个发行版, 直到我看到自己的错误为止。那时我也决定将其自动化。
再来一次
好的, 幸运的是, 我们可以使用npm的功能, 所以我找到了一个合适的软件包:运行yarn add – dev standard-version并将以下内容添加到package.json文件中:
"scripts": { "release": "standard-version", "major": "yarn release --release-as major", "minor": "yarn release --release-as minor", "patch": "yarn release --release-as patch" },

现在你需要做的最后一件事, 将Git配置为默认情况下推送标签。目前, 你需要运行git push – tags来向上推送标签, 但是在常规git push上自动执行就像运行git config – global push.followTags true一样简单。
要使用新管道, 每当你要创建发布运行时:
  • 纱线补丁用于补丁发布
  • 细纱用于细小释放
  • 纱线主要用于主要发行
如果不确定” 主要” , “ 次要” 和” 补丁” 这两个词的含义, 请在语义版本控制站点上阅读有关此内容的更多信息。
现在你终于完成了管道, 让我们回顾一下如何使用它!
  • 编写代码。
  • 提交并推送它以测试并将其部署到登台。
  • 使用毛线补丁标记补丁发布。
  • git push将其推向生产。
本文总结和进一步的步骤 我只是简单介绍了CI / CD管道可能实现的目标。这是一个相当简单的例子。你可以通过用Kubernetes替换Heroku来做更多的事情。如果你决定使用GitLab CI, 请阅读yaml文档, 因为你可以通过在部署之间缓存文件或保存工件来做更多的事情!
你可以对该管道进行的另一个巨大更改是引入外部触发器以运行语义版本控制和发布。目前, ChatOps是其付费计划的一部分, 我希望他们将其发布为免费计划。但是, 想象一下能够通过一个Slack命令触发下一个图像!
如何建立一个有效的初始部署管道

文章图片
最终, 随着你的应用程序开始变得复杂并需要系统级别的依赖性, 你可能需要使用容器。发生这种情况时, 请查看我们的指南:Docker入门:简化Devops。
这个示例应用程序确实是实时的, 你可以在此处找到其源代码。

    推荐阅读