原文地址:https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-part-5-deploy-83e790545c23
原文作者:Igor Kantor
翻译君:CODING 戴维奥普斯

让我们简要回顾下我们的 DevOps 之旅:
在第一篇,我们介绍了 DevOps 文化以及相关的基础技能;
在第二篇,我们讨论了如何为将来的代码部署奠定基础;
在第三篇,我们讨论了如何有组织地管理代码;
在第四篇,我们讨论如何简单地打包代码。
以下是我们贯穿前后的路线图:

如果在上图每列的技术栈上花费一个月左右的话,那么我们现在处于第 4 个月。基于前文的学习,我们已经知道了如何配置将要运行代码的服务器基础架构、如何正确地对代码进行版本管理、如何将代码打包以备部署。今天我们要讨论如何部署代码。

部署代码

注意到了吗?我没有说“如何轻松地部署代码”,因为代码从开发环境到正确部署仍然是一个充满了错误和失败的痛苦过程。

原因很多,但在我看来,这主要归结为差异。具体而言,创建代码的环境与实际代码运行的环境之间存在差异。我认为减少这些差异意味着你不仅可以在整体代码部署中实现最大的改进,还可以在代码部署后的运行时达到一定的优化。那么,我们如何减少或消除生产和非生产环境之间的差异呢?

在我的机器上明明是可以跑的

如果你的开发基础设施是这样的:


用“温柔的爱和关怀”手工组装而成的开发基础设施

但你的生产环境基础设施看起来像这样:

那你就会遇到麻烦。

如果你使用基础设施即为代码的方式而不是手动配置,那么差异这事儿你已经搞定得七七八八了。如果不是,请不要绝望 —— 你并不孤单。花一个下午,找出你所碰到的所有差异(培训、文化、人员、流程等),并逐一消除它们。

最重要的是,如果你仍在手动配置,那你可能很难去管理现代技术栈。因此你需要做的第一件事是确保涉及产品的所有内容都是由部署服务器构建的版本化软件包。假设上述事情你已经完成,我会告诉你部署代码的最佳方法是不部署代码

现代化的代码部署

将代码部署到生产环境机器是一件非常 90 年代的事情。


现有技术的“代码部署装置”

将代码部署到一组固定生产环境机器的最大问题是:你的生产环境服务器(代码运行的地方)与你的开发环境服务器(编写代码的地方)不同。这就难怪在部署后会立即出现大量问题。

因此,你需要尽一切可能确保构建产物(而不是一小段代码)一直处在运行环境当中。换句话说,将代码一次性部署到开发环境,克隆运行代码的整个机器环境,然后将其复制到需要的任何位置。这被称为“不可变部署”,是一个非常强大的模式,可以避免你数小时部署后的头痛。当然,如果你运行容器,同样的想法也是适用的:在任何地方部署相同的容器即可。

“但是我的生产环境和开发环境就是不同的!”你可能会说。数据库用户名密码,连接字符串,S3 存储桶位置等等,这些都是不同的。解决这个问题的方法是使用 12 因子应用配置原则。所有配置都需要外部化并作为环境变量传递到服务器。

例如,如果在 AWS,可以使用 SSM 作为外部参数存储,它很好地集成了 CloudFormation。直接通过 aws ssm cli 命令行工具设置环境变量也非常容易。当然,其它云厂商也提供了类似的机制。

当出现问题时,你需要压制“修理”生产环境机器的冲动。这些机器是不可变的,这意味着你所做的任何修复都必须来自开发环境。事实上,你的终极目标应该是根本不允许任何在生产环境服务器上的接入。没有 ssh、没有 scp、没有人有任何访问权限,不是你,更不是觊觎中的黑客。

但如果我需要日志来解决问题呢?所以日志也应该外部化。理想情况下可以通过ElasticSearch / Logstash / Kibana(ELK)技术栈或商业软件(如 SumoLogic 或Datadog)将日志转储到其它地方。

无论你做什么,你的产品都是“黄牛” —— 它们会在出现最轻微的不健康信号时就被替换。它们不是“宠物”,需要耗费数小时进行故障排除来恢复健康。我知道这个比喻被太多人使用了,并且我听到那些真正养牛的人说过实际上他们的工作原理和我们刚所讨论的不同,但重点事务确实如此。不要“修复”你的生产环境机器,而是修复你的开发环境并重新部署。

代码部署机制

所以你知道要做些啥了,但怎么做呢?

“不幸”的是,这就是 Jenkins 的用武之地,Jenkins 是最受欢迎的开源部署自动化服务器之一。我说“不幸”是因为 Jenkins(及其前任 Hudson)已经存在了近十年,并且在漫长的使用过程当中我们发现了:它的设置很复杂,维护起来更复杂。它带有数以百万计的可疑质量插件。这些插件往往会在最不合适的时候崩溃,把所有事情搞砸。实际上,真正具有弹性的分布式 Jenkins 设置很少见,通常只有最大的研发组织里才能看到。

那为什么我还建议你从 Jenkins 开始呢?因为尽管存在各种缺陷,它仍然非常受欢迎,并且在我们的行业中被大量使用。了解 Jenkins,特别是 Jenkinsfile 的结构,对就业前景会是一个巨大并且不容忽视的好处。当你学习 Jenkins 时,请确保你遵循较新的 Pipeline BlueOcean 技术路径,而不是更旧的“Jenkins jobs”。

参考阅读:
Jenkinsfile:https://jenkins.io/doc/book/pipeline/jenkinsfile/
Pipeline BlueOcean:https://jenkins.io/doc/book/blueocean/

当你希望 CI/CD 流水线被直接包含在代码仓库当中后,持续集成工具会变得非常重要,这样的话流水线本身就是一段版本化的代码。

一切都是代码

你的应用程序如何被部署、监控、配置等等——说到底最终都化作为存储在代码仓库里被正确版本化的代码片段。

我们的目标是为核心开发人员(编写功能代码的软件工程师)创建一个真正无摩擦的环境。例如,我应该能够编写我自己的微服务、添加我认为必要的测试、添加监控即代码的配置、在一些“env.yaml” 文件中指定我的参数、将它们全部存储在一个代码仓库中;通过 CI/CD 流水线自动触发构建、测试、部署(金丝雀发布或蓝绿发布),并在完成后给我发送电子邮件。事实上,这是 DevOps 工程师核心使命的本质。

Jenkins 的替代品

就像我之前说过的那样,Jenkins 已经被广大开发者使用很长一段时间了。现在还有其它的工具,在我看来更好,即使没有 Jenkins 那么为人所知。

  • 一个是 AWS 自己的 CodeDeploy 服务。它有局限性,但 CodeDeploy 背后的开发人员在过去一年做了很大的改进,如果你在用 AWS,建议你试一试。
  • 另一个是 GitLab CI。如果你的研发组织运行在 GitLab 上,你可以考虑使用,因为它与 GitLab 的其它部分良好地集成在一起。
  • 去年十月 GitHub 宣布了 Actions(目前仍处在公测中),用于 GitHub 用户的自动化工作流场景。

我认为这里的工具并不是最重要的。重要的是要记住包括代码部署流水线在内的所有内容都是版本化的软件部件,它首先得来自于开发环境,而不是生产环境。

如果你从 Jenkins 开始学习持续集成,请尝试将其设置为容器模式。这并不是一件非常困难的事情,反而会是一个很不错的学习机会,你可以找到弹性的、容器化的 Jenkins 机器节点来部署容器化的 Jenkins。

你也完全可以从简单的、没有任何容器编排的方式开始,这是下一篇文章的主题,敬请关注。

写在最后

原文作者给我们介绍了一个非常重要的实践:在部署环境遇到的问题要去调整和修改开发环境,让生产环境与开发环境保持一致,修改生产环境治标不治本。同时也给我们介绍了一些他喜欢的国外持续集成工具。针对国内的工具,译者推荐你还可以考虑使用 CODING 持续集成,它是 CODING 提供的一站式 DevOps 解决方案中重要的一环。其构建脚本在语法上全面兼容 Jenkins,又免除开发者部署和维护持续集成环境的繁杂事务。

同时 CODING 支持包括 Docker 镜像、Jar、APK 等软件包的构建,预置了主流开发语言的构建环境:Java、PHP、Go、Python 等等;开启缓存加速功能可以平均提高 300% 的构建速度。对于包括 Maven,NPM 在内的主流镜像源有专用网络优化,保证拉取速度; 支持单项目并行构建,以满足重度持续集成用户的需求。对不太喜欢脚本的同学还提供了完善的图形化编排能力,以降低使用门槛。

CODING 还对构建产物提供了统一的制品库管理,目前制品库已支持 Docker 镜像、NPM、Helm 等常见包类型的制品管理。后续 CODING 会逐步支持多种主流的软件包类型来进一步完善 DevOps 工作流,敬请期待。

DevOps 工程师成长日记系列五:部署的更多相关文章

  1. DevOps 工程师成长日记系列二:配置

    原文地址:https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-part-2-config ...

  2. DevOps 工程师成长日记系列一:必备知识与技能组合

    原文地址:https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-366097df7737 ...

  3. DevOps 工程师成长日记系列四:打包

    原文地址:https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-part-4-packag ...

  4. DevOps 工程师成长日记系列三:版本

    原文地址:https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-part-3-versio ...

  5. DevOps工程师的成长路线图

    DevOps工程师的成长路线图 我们推崇的是 Reducing the gap between Devs and Operation teams. 来自kamranahmedse you built ...

  6. Web前端工程师成长之路

    一.何为Web前端工程师?        前端工程师,也叫Web前端开发工程师.他是随着web发展,细分出来的行业.Web前端开发工程师,主要职责是利用(X)HTML/CSS/JavaScript/D ...

  7. 前端架构师亲述:前端工程师成长之路的 N 问 及 回答

    问题回答者:黄轶,目前就职于 Zoom 公司担任前端架构师,曾就职于滴滴和百度. 1. 前端开发 问题 大佬,能分享下学习路径么,感觉天天忙着开发业务,但是能力好像没有太大提升,不知道该怎么充实自己 ...

  8. 菜鸟成长日记之新手备忘录-IOS开发第一个项目总结

    2013年5月3号,开始找IOS开发工作(自学了大半年,做了一个功能不全的Demo,该出去见见世面了!),5月4号面试了第一家公司(是家刚成立一段时间的外包公司),5月5号第一家公司已二轮电话面试,5 ...

  9. scrapy爬虫学习系列五:图片的抓取和下载

    系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备:      http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...

随机推荐

  1. Display a Detail View with a List View 主子视图-列表视图与详细信息视图同时显示

    In this lesson, you will learn how to display a Detail View together with a List View. For this purp ...

  2. CronExpression表达式详解和案例

    1. cron表达式格式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)} 2. cron表达式各占位符解释: {秒数} ==> 允许值范围: 0~59 ,不允许 ...

  3. NIO基础方法一

    1.remaining();返回当前位置与limit之间得元素数. int[] intArray={1,2,3,4}; IntBuffer intBuffer=IntBuffer.wrap(intAr ...

  4. javascript模块化开发(二)

    模块化开发(一) ES6模块化 详解 ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict". 顶层的this指向undefined,即不应该在顶层代码 ...

  5. vue发送ajax请求

    一.vue-resource 1.简介 一款vue插件,用于处理ajax请求,vue1.x时广泛应用,现不被维护. 2.使用流程 step1:安装 [命令行输入] npm install vue-re ...

  6. CSS学习笔记-背景属性

    一.背景尺寸属性:    1.含义:        背景尺寸属性是CSS3中新增的一个属性,专门用于设置背景图片大小 2.格式:        1.1具体像素:             backgro ...

  7. CamlQuery对SharePointOnline List 发起查询请求

    最近的项目中遇到了一个需求,需要向SharePointList 查询Item是否存在,找到了CamlQuery这样一个方法,但是没有找到使用这个接口的频率限制说明文档,于是就有了这篇随笔. 新接触这个 ...

  8. Android Service 启动流程

    执行顺序 : startService -> bindService -> unbindService -> stopService 回调的结果为: 执行顺序 : startServ ...

  9. 通过存储过程(SP)实现SQL Server链接服务器(LinkServer)的添加

    1. 背景 当系统的微服务化做的不是很高的时候,部分功能要通过DB LinkServer 来实现跨 Server 查询,当然,有时候BI抽数据.DBA数据库维护可能也会创建LinkServer. 特别 ...

  10. 并发编程 ~~~ 多进程~~~进程创建的两种方式, 进程pid, 验证进程之间的空间隔离, 进程对象join方法, 进程对象其他属性

    一 进程创建的两种方式 from multiprocessing import Process import time def task(name): print(f'{name} is runnin ...