活多人少,每个需求都紧急,多数项目延期,怎么破?

注意,下文所说的“老板”通常指业务提出方。 问题描述 上个星期,在持续交付2.0的群中,群主发出一个别人的提问。在我看来,这个问题在软件工程领域非常的典型,所以想单独写一篇博客来讨论。以下是问题原文: 我是一个开发部门的管理人员,团队规模还较小,开发需要兼任测试和部分应用运维的工作,但公司业务条线不算少(差不多有4个左右,目前部门中基本是按每个条线分配2-3个开发,出现某个组资源不足以满足需求时再进行调剂),之前这么做还算稳定,因为各业务对交付频率的要求一般很低,但近期各业务都提出了一个较紧急的项目需求,而且都还无法推迟或拒绝,资源一下子变得非常紧张(如果可以推迟某一个当然就会有富裕资源,但是这些项目由于各种原因公司都不能放弃,也很难推迟),如果依然每个组独立完成自己的项目,可能导致大部分项目因无法按时交付失败,而且每个组还必须保留少部分资源用于处理日常业务,如果临时招聘也来不及做培训,我们暂时是让资深一些的程序员和管理人员参与多个项目中的开发,但仍不能完全解决问题(他们抱怨任务太多都来不及测试),请问帮主遇到这类情况应该如何协调? 提问者所说的情况,在现实中,太普遍了: (无法拒绝的)紧急需求的插入,打乱原有的步骤 开发除了需求的开发,还需要处理日常业务 人员不足:临时招聘也解决不了 开发人员报怨任务太多,来不及测试(就上线?) 项目无法按时交付 可以看出,“人员不足”是“项目无法按时交付”这个“果”的其中一个“因”。而提问者希望通过业务线之间人员的调剂和临时招聘的方式增加人员,但仍不能完全解决问题。笔者每当听到增加人员的信息,都会想起《人月神话》所说的:向进度落后的项目中增加人手,只会使进度更加落后。 而从提问者口中也了解到,原来人员还算足(感觉是刚刚好),只是因为出现了一个无法拒绝的紧急需求,问题就暴露出来了。 问题解决 面对这样的问题?你是如何解决的呢?以下是我个人提出来的解法,不一定对,只做交流: 第1是把当前工作的优先级排出来 把所有的工作内容(包括日常维护和新功能实现)列出来,同时,也要找到这些工作的交集(避免重复开发)。工作内容列出来后,确定它们的业务价值及优先级,并预估其开发难度。有些新功能是老板直接下发的,但是实现难度过高且业务价值又不高(团队及产品经理觉得),能和老板谈就和老板谈。这部分工作是我觉得最难的。 这个工作的优先级一定要让老板看到。主要是避免老板中间随意的插入需求。当然,有时需要向现实妥协,但不是每次。同时也要让所有人达成共识,遵守这个优先级。 第2是找出团队平时工作中最耗时的环节(瓶颈),想办法在这个环节上减少耗时(自动化或者别的办法)。一般来说,经常工作在这个耗时环节的人会知道如何优化它。 第3是慢慢让人可以流动 意思是人没办法调剂到其它项目,通常是因为他不了解其它项目(业务或者技术)。所以,在平时,就要注意将项目的“知识”尽可能准确地传递给更多人。当然,也可以定向的传递。具体操作方式要看团队平时的协作方式。 最后,1,2,3步需要重复执行,同时1,2,3步也不是顺序的。 笔者提出这样的解法并不是笔者猜的,而是有依据的。依据如下: 人员不足只是表象,我们怎么知道是真的人员不足,还是没有真正发挥每个人的最大潜能呢?第2、3步是为了让每个人发挥最大的潜能。而工具方面,个人建议通过看板可视化人员的工作内容,来达到了解当前资源状态的目的。 即使每个人的潜能都发挥到了极致,但是还是出现人员不足的情况啊。这就是第1步要解决的问题。这时,我们要学会舍弃。但是为什么老板就不会舍弃,老爱插入一些所谓的紧急需求呢?个人认为是因为老板不了解你当前的工作内容及其优先级。所以,这个优先级一定要和老板达成共识。 小结 当我把解法提出来了,群里的同学就提出了质疑:如何确定老板提出新功能是业务价值不高的?毕竟老板从整个公司考虑问题的。 这位同学提出了一个软件工程领域内经常发生的问题:执行者怀疑业务提出者提出的需求的价值。个人觉得质疑是好事。但是质疑之后,双方有没有讨论及讨论结果才是关键。讨论了就容易形成共识,有了共识,大家才好力往一处使。题外话,“我只要结果,不管过程”的管理理念的适用范围是拿出来讨论的。 最后,以上解法,不一定适用所有的情况。比如在外包项目管理中,可能就不适合。

2019-03-01 · 1 min · 28 words · 翟志军 Jack Zhai

批量修改Jenkins任务的技巧

通过脚本命令行批量修改Jenkins任务 最近,笔者所在团队的 Jenkins 所在的服务器经常报硬盘空间不足。经查发现很多任务没有设置“丢弃旧的构建”。通知所有的团队检查自己的 Jenkins 任务有没有设置丢弃旧的构建,有些不现实。 一开始想到的是使用 Jenkins 的 API 来实现批量修改所有的 Jenkins 任务。笔者对这个解决方案不满意,经 Google 发现有同学和我遇到了同样的问题。他使用的更“技巧”的方式:在 Jenkins 脚本命令行中,通过执行 Groovy 代码操作 Jenkins 任务。 总的来说,就两步: 进入菜单:系统管理 –> 脚本命令行 在输入框中,粘贴如下代码: import jenkins.model.Jenkins import hudson.model.Job import jenkins.model.BuildDiscarderProperty import hudson.tasks.LogRotator // 遍历所有的任务 Jenkins.instance.allItems(Job).each { job -> if ( job.isBuildable() && job.supportsLogRotator() && job.getProperty(BuildDiscarderProperty) == null) { println " \"${job.fullDisplayName}\" 处理中" job.addProperty(new BuildDiscarderProperty(new LogRotator (2, 10, 2, 10))) println "$job.name 已更新" } } return; /** LogRotator构造参数分别为: daysToKeep: If not -1, history is only kept up to this days. numToKeep: If not -1, only this number of build logs are kept. artifactDaysToKeep: If not -1 nor null, artifacts are only kept up to this days. artifactNumToKeep: If not -1 nor null, only this number of builds have their artifacts kept. **/ 脚本命令行介绍 脚本命令行(Jenkins Script Console),它是 Jenkins 的一个特性,允许你在 Jenkins master 和 Jenkins agent 的运行时环境执行任意的 Groovy 脚本。这意味着,我们可以在脚本命令行中做任何的事情,包括关闭 Jenkins,执行操作系统命令 rm -rf /(所以不能使用 root 用户运行 Jenkins agent)等危险操作。 ...

2019-02-23 · 1 min · 183 words · 翟志军 Jack Zhai

最好的礼物是一个真诚的建议

李翔商业内参 9月15日(中秋)那期的主题是:最好的礼物是一个真诚的建议。我深表认同。 两年前,我被另一个资深的同事说了一通(当时我们正结对编程)。原因是我说了另一个同事的代码写得烂,还随手看了下提交记录,发现是当时的leader。 先不说这位同事教训得是不是。我心里很不爽:我说的就是真话嘛。 后来,我发邮件给总经理,说了一通,诚恳地向他请教,到底是谁的错。后来总经理给我回了一封邮件,邮件其中一段是这样的: 有个有意思的故事: 弟子问:”师父您有时候打人、骂人;有时候对人又彬彬有礼,这里面有什么玄机吗?” 师父说:对待上等人直指人心,可打可骂,以真面目待他;对待中等人最多隐喻他,要讲分寸,他受不起打骂;对待下等人要面带微笑,双手合十,他很脆弱、装不下太多指责和训斥,他只配用世俗的礼节 我想说的不是谁是上等人,谁不是,而是受众不一样,说话的方法就会不一样。 中国有句老话,世事洞明皆学问,人情练达即文章。能够把意见说的让人接受是个技能,要不断练习,你自己也多揣摩。 到底是谁的问题不重要, 严于律己,宽以待人对你的职业生涯会很有帮助。 每每对别人过于苛刻时,我都会想起“严于律己,宽以待人”。虽然,有时还会偶尔犯贱。但是它的确改变了我。 …不小心翻出自己2016年写的小短文。

2018-12-11 · 1 min · 14 words · 翟志军 Jack Zhai

阿里三面后的思考

你对你6年跳5次有什么感想? 上周进行了阿里三面。奇怪的是他们居然迟到10来分钟。上来直接问的都是我职业生涯的问题(不清楚面试官的岗位)。 从我第一份工作到最近的工作,一个个问入职时间,做了什么,离职时间,为什么离职。我也“老实”一一回复。这个过程,加上视频的网络质量不好,我感觉好像被压着说话。 最后,面试官问我:你对你6年跳5次是什么感想?(后来算算我应该是毕业6年,工作7年。而5次是指包括这次跳成功) 听到这个问题,我一下懵了。我从来没有仔细想过这个问题,想了一下,说出了自己的内心的声音:太年轻,太冲动。 面试官没有说下去。后来草草的结束了20多分钟的面试。 结束后,我问自己:你为什么在别人眼里就是不稳定?HR 眼里跳槽“多”就是不稳定? 回想自己的回答,的确给别人不稳定的感觉。因为一次主要是因为对 leader 不爽,一次是因为办公室政治干不过别人。所以,各位提前想好自己跳槽的“借口”很重要。 但是,另一个问题开始不断萦绕自己:你为什么跳这么多次槽?回想自己的每次跳槽,没有答案。于是,我反过来想:公司如何才能留住我? 第一家创业公司7人,我的导师走了,我唯一留在这家公司的理由都没有了。 第二家公司做开源软件,Leader 换成了我不喜欢的人。现在想想真幼稚。现在想想,真没必要。 第三家公司是一家咨询+外包的公司,做了一年多的外包,发现自己想做自己的产品,我留在公司的理由是有产品给我做,询问当时的办公室负责人,并没有产品可以做。 第四家公司是做产品了,组织构架的调整我不满意,产品不再是我,细节不方便说,我就想好好做产品,留下来的理由也没有了。 目前这家公司,进来的初衷是从零建设一个敏捷的团队,后来希望破灭。然后我的希望变成能好好写代码。目前留下来的理由是好好磨炼自己的技术。但有机会会看。因为这里是 code is cheap。 企业应该如何留住员工 我尝试把“我”的私人问题扩大到组织上思考:企业应该如何留住员工? 最近看的《红雀》的台词跳了出来: 给了别人想要的,你就会得到你想要的。 留住员工,靠的不是“留”,而是“给”。当然,前提是这个人值得留。 这时,会有读者想到马斯洛需求层次理论: 这个理论告诉我们如何满足一个人的不同层次的需求。但是,站在公司层面,如何操作呢?毕竟公司里会同时存在不同层次需求的人,而且同一个人不同时期的需求还可能千差万别。 如何能满足所有人的需求(至少是大部分)?我想到了一句话:海纳百川,有容乃大。但是不可能路边随随便便就收纳,而是能帮助公司实现目标的人。这是海纳百川的前提。 所以,公司应该像大海,能满足不同的人不同时期的需求。这是什么意思? 生理需求上,提供上行业内比较有竞争力的薪资,像奈飞。安全需求上,比如提供团体险;社交需求上,让工程师之间有更多的交流的机会,比如谷歌为促进员工的非正式交流,在食堂排队,一般要4分钟。因为时间长了大家会掏出手机来看,时间短了,同事们又聊不起来……等等。 P.S. 公司文化并不是没有理论的发展,而是要根据公司的发展需要进行调整。 我再次强调,上述想法的前提:不可能路边随随便便就收纳,而是能帮助公司实现目标的人。所以,要严进。 同时,上述想法是理想情况,处于企业生命周期不同阶段的公司需要根据自己的具体情况量力而行。 同时,我也提醒读者啊:我没有办过企业,上述想法都个人臆想。 教训 给那些还在路上的新人,不要冲动,不要冲动,不要冲动。不要学我。我是反例。 成本 最后,突然想到,好奇阿里为什么不让HR 先把这些稳定性问题在一面给问了?就可以节约一二面的工程师的时间了。毕竟工程师的时间永远相对 HR 的时间更缺。招工程师比招 HR 更难,如果我没有理解错的话。 小结 听说30到35岁是大多数人职场的转折点。我相信了。想清自己想要的,是做好职业规划的前提。

2018-06-24 · 1 min · 47 words · 翟志军 Jack Zhai

使用Ansible实现自动化运维的一些技巧

提示:本文要求读者有一定的 Ansible 使用经验 最近一年才有机会在生产环境上使用 Ansible。用的过程中,想把一些小技巧记录下来,避免自己忘记。如果能帮助到其他同学就更好了。如果有同学指出有更好的方法,就更更好了。 技巧1:校验你的模板文件是否正确 通常我们会使用template module 来生成应用的配置,比如生成 Nginx 的配置或者 sudoers 配置。而像 sudoers 文件内的配置错误可能直接导致无法登录。所以,我们希望在生成这些配置文件后能校验一下它的正确性。如果校验失败,直接停止,不生成该配置文件。 而 template module 有一个属性 validate 就是为了实现这一需求的: - template: src: "user-sudoers" dest: "/etc/sudoers.d/abc" validate: visudo -cf %s 校验 Nginx 配置文件的文件: - name: Copy the nginx file template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf validate: "/usr/sbin/nginx -t -c %s" notify: - restart nginx 校验 Prometheus 配置文件: - name: Copy Prometheus config template: src: prometheus.yml.j2 dest: "/etc/prometheus.yml" validate: "promtool check config %s" notify: reload prometheus config 校验 Logstash 配置文件: ...

2018-06-22 · 2 min · 273 words · 翟志军 Jack Zhai

一些小团队的自动化运维实践经验

注:本文要求读者对Ansible和 Jenkins有一定的认识。 题记: 幸福的家庭都是相似的 不幸的家庭各有各的不幸 行业内各巨头的自动化运维架构都各种功能各种酷炫,如下图,让人可望不可及。现在最终的样子大家都知道了,但问题是如何根据自己团队当前的情况一步步向那个目标演进? 笔者所在团队,三个半开发,要维护几十台云机器,部署了十来个应用,这些应用90%都是遗留系统。应用系统的编译打包基本在程序员自己的电脑上。分支管理也清一色的 dev 分支开发,测试通过后,再合并到 master 分支。生产环境的应用配置要登录上具体的机器看才知道,更不用说配置中心及配置版本化了。 对了,连基本的机器级别的基础监控都没有。 我平时的工作是 50% 业务开发,50% 运维。面对这么多问题,我就想啊,如何在低成本情况下实现自动化运维。本文就是总结我在这方面一些经验和实践。希望对读者有帮助。 别说话,先上监控和告警 事情有轻重缓急,监控和告警是我觉得一开始就要做的,即使业务开发被拖慢。只有知道了当前的情况,你才好做下一步计划。 现在市面上监控系统很多:Zabbix、Open-Falcon、Prometheus。最终作者选择了 Prometheus。因为: 它是拉模式的 它方便使用文本方式来配置,有利于配置版本化 插件太多了,想要监控什么,基本都会有现成的 以上三者,我基本都要重新学,我为什么不学一个 Google SRE 书上推荐的呢? 之前我们已经介绍过,人少机器多,所以,安装 Prometheus 的过程也必须要自动化,同时版本化。笔者使用的是 Ansible + Git 实现。最终样子如下: 这里需要简单介绍一下: Prometheus Server 负责监控数据收集和存储 Prometheus Alert manager 负责根据告警规则进行告警,可集成很多告警通道 node-exporter 的作用就是从机器读取指标,然后暴露一个 http 服务,Prometheus 就是从这个服务中收集监控指标。当然 Prometheus 官方还有各种各样的 exporter。 使用 Ansible 作为部署工具的一个好处是太多现成的 role 了,安装Prometheus 时,我使用的是现成的:prometheus-ansble 有了监控数据后,我们就可以对数据进行可视化,Grafana 和 Prometheus 集成得非常好,所以,我们又部署了 Grafana: 在 Grafana 上查看 nodex-exporter 收集的数据的效果图大概如下: 可是,我们不可能24小时盯着屏幕看CPU负载有没有超吧?这时候就要上告警了,Promehtues 默认集成了 N 多告警渠道。可惜没有集成钉钉。但也没有关系,有好心的同学开源了钉钉集成 Prometheus 告警的组件:prometheus-webhook-dingtalk。接着,我们告警也上了: ...

2018-06-07 · 3 min · 490 words · 翟志军 Jack Zhai

通俗解释有了 IP 地址,为什么还要用 MAC 地址?

题记:既生亮何生瑜。 摘要:标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西。本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么。 一开始时,网络中的机器并不多。大家都连到同一个集线器就可以了,就可以实现互通。这时,机器 A 发消息到机器 B ,消息头里附上机器 B 的MAC,集线器收到消息后就广播给所有连到集线器的机器。 机器 C 收到消息,发现消息里的 MAC 地址和自己的不一样,就丢弃。机器B发现消息里的 MAC 地址和自己一样,就收到下并解析。 这样机制带来问题很明显:首先每次广播,给所在网络带来不必要的浪费。所以,就出现了交换机。它能识别消息里的目标 MAC 地址后,直接就消息丢到机器 B 所连接的端口中。另一个角度,交换机必须记住所有的 MAC 地址和端口之间的关系。 这样的机制在网络规规模小的时候是高效的。但是当网络规模扩大到全球的时候,不可能让一台交换机记录下全球这么多的网络设备,也不可能让全球的机器连接到一台交换机上。 那如果是多台交换机呢? 想像一下,你是斯坦福的学生,你的电脑 x 的网络直连的是学校的交换机,而学校的交换机又连美国国家网络交换机。而美国国家网络交换机又直接的是中国国家网络交换机,中国服务器 y 直连的是中国国家交换机。 你想访问中国的服务器 y 中的资源。你了解到服务器 y 的 MAC 地址是00:0C:29:01:00:12,所以你在消息里附上这个 MAC 地址。 学校交换机收到消息后,拿到 MAC 地址后就愣了,这是要发给谁啊?因为中国服务器 y 并不是直连学校交换机的。这时,学校交换机有一个选择,就是收到不明的 MAC 地址时,一律转发给默认端口。斯坦福交换机就将消息转给美国国家交换机。 美国国家交换机同样发愣了,因为没有这条 MAC 地址对应的端口。它又直接向默认端口:中国国家网络交换机。 中国国家网络交换机收到消息,发现自己记录了 MAC 地址 对应的是服务器 y。就直接将你这位斯坦福学生的消息转发到服务器 y 所连接的端口。 最终,我们的服务器 y 终于收到来自美国斯坦福学生的资源访问请求。 ...

2018-05-17 · 1 min · 111 words · 翟志军 Jack Zhai

阿里云经典网络下如何节约公网 IP 费用

想法 历史原因,我们一直使用的是阿里云经典网络的 ECS,疲于业务的开发及人力不足,一直没有特别大的动力迁移到 VPC 下。 而经典网络下的 ECS 的公网 IP 是收费的,而且没有公网 IP 有时会不方便。 购买公网 IP 时的费用 未购买公网 IP 时的费用 如果是按月购买,每个月将节约:296 - 273 = 23 元。 而我们的大多服务是内网使用的,所以,公网 IP 的申请完全是浪费。 可是,我们有时,还是需要公网下载一些东西的。这时怎么办呢? 我的方案是:没有公网 IP 的机器,使用 HTTP 代理就可以上网了。 当然,哪些机器需要上网,基于安全上的考虑,需要读者自己决定了。 怎么做? 我的具体实现方便使用 Squid 搭建 http proxy 服务。其他机器通过配置环境变量配置,笔者是通过 Ansible 初始化机器时配置的: - name: use httpproxy lineinfile: path: "/etc/profile" line: "<<item>>" with_items: - "export http_proxy=http://<< httpproxy.host >>:<< httpproxy.port >>/" - "export https_proxy=http://<< httpproxy.host >>:<< httpproxy.port >>/" when: is_use_httpproxy is defined and is_use_httpproxy == 'True' tag: httpproxy 关于 Squid Http Proxy 服务,笔者同样是使用 Ansible 搭建,具体不细表,看官可以自行看代码:Squid-ansible。 ...

2018-05-14 · 1 min · 109 words · 翟志军 Jack Zhai

为什么“分层”给我们带来好处——论软件工程的分层概念

All problems in computer science can be solved by another level of indirection – David Wheeler 计算机科学中的任何问题,都可以通过加上一层逻辑层来解决。– David Wheeler 总之,分层就是有好处 在计算机领域,“分层” 概念无处不在。比如 web 开发时的 MVC ,网络编程时的 OSI 参考模型和 TCP/IP 协议族。 但是为什么要进行分层呢?不同的书有不同的说法。 在《图解TCP/IP》这本书这样说: 在这一模型中,每个分层都接收它下一层所提供的特定服务,并且负责为自己的上一层提供特定的服务。上下层之间进行交互时所遵循的约定叫做“接口”。 在我看来,说了等于白说。:-P 而《企业应用架构模式》开篇第 1 章是这样说的: 在分解复杂的软件系统时,软件设计者用得最多的技术之一就是分层。 当用分层的观点来考虑系统时,可以将各个子系统想像成按照“多层蛋糕”的形式来组织,每一层都依托在其下层之上。在这种组织方式下,上层使用了下层定义的各种服务,而下层对上层一无所知。另外,每一层对自己的上层隐藏其下层的细节。 Marting Fowler在第 1 章后面,又举了一个表现层,领域层,数据源层的例子。但是个人认为依然没有把为什么要分层说透。 对于为什么要分层,我见过的大多数文章说的只是它带来的好处。比如下层修改实现,不影响上层使用;分离关注点等。但是为什么会带来这些好处?看似很傻的一个问题,其实很难回答。 两个例子帮助你认识“分层” 我们先通过两个例子给大家一些感性的认识。 自动驾驶 用分层的思维来看开车这件事情是这样的: 分层 具体内容 人的意图 前行,不上坡,右转弯 人的操作 踩着油门,瞥一眼后视镜,方向盘打右 汽车运行 根据踩下油门的程度,发动机输出动力,而方向盘打右转动转向拉杆 发动机 进气,压缩,点燃,排气 更底层省略…. 更底层省略 ….. 因为有了分层,当我们要实现自动驾驶汽车时,要解决的就只是“人的操作”这一层的问题,而不需要实现“人的操作”以下所有的层,也就是不需要自己从头造汽车(不是绝对,但是绝对不需要从头造所有的部分)。 IoT 云云对接 总要举一个软件开发领域的例子吧。我们举一个 IoT 云云对接的例子。 当第三方云想控制 M云的空调时,系统的外观是这样的: ...

2018-05-01 · 1 min · 92 words · 翟志军 Jack Zhai

出现运维事故后,你会怎么办?

从聊天说起 有一次和朋友聊天,他说他们有一次部署出事了,影响还挺大,那次事故后,他们公司对于部署流程增加了更多的审批。 当朋友说完前半句时,我已经猜到下半句,那是很多公司或个人会做出的反应。至于为什么会做出这样的反应,我也不知道。 我问:为什么那次部署会“出事”? 他说:当时部署的人忘记了那台机器上有一条 Iptable 规则,导致了事故。 我就在想,如果有人审批,那次事故就不会发生吗?审批的人就知道那台机器上有一条规则导致事故的发生?然后驳回这次部署吗?连一线的开发和运维都忘记了的 Iptable 规则,“高高在上的审批领导”就更不知道了。 题外话:增加审批流程并不能避免这次事故,只不过当出现事故时,可以更好的定责。然而我又好奇了,这种“审批”是为了解决问题,解决什么问题?,还是为了逃避责任?谁逃避了责任?谁又有责任? 对于这类问题,我心里已经有数了,但想知道这位朋友的回答,就接着问:那么怎么杜绝这类问题呢? 他说:因为那条 Iptable 规则的设置太久远了,是谁都记不起。如果能把每次部署的步骤记录下来,这样下次部署的时候,过一下以前的部署记录,就会知道那个 Iptable 规则了。(作者:大概原意,已经记不清原话) 这位朋友说的做法,我之前待的一个团队的做法也差不多:会有一个页面专门记录下每次部署的步骤,步骤由开发人员写,然后由运维人员执行。只是我不知道他们会不会回顾之前所有针对这台机器的部署步骤。 这个团队里有某某大型互联网公司来的架构师和某财务软件公司来的运维,所以,我不负责地推测,我们这个行业很多公司对于配置的管理还没有达到足够的重视,也没有正确的看待。 我笑了,接着问朋友:那我要知道当前机器的“最终状态”,是不是要找出所有部署记录,还要过滤出对这次部署有影响的每一个细节?比如那条 Iptable 规则。 接下来的对话细节已经记不清,也不重要了。重要的是找出针对这类运维事故根本原因及解决办法。 我个人认为这类问题的根本原因在于: 配置管理的失控: 已经没有人完整知道线上环境配置是什么了?要了解时,只能一个个查。 测试环境与生产环境的配置不一致: 如果那位倒霉的同学在测试环境部署出现这样的问题,到生产环境部署时,自然就会注意相关配置项了。 以上只是我个人认为的,不一定正确,欢迎各位读者讨论。 那如何杜绝这类问题呢? 这两个原因可以看作一个,也可以看作两个。但方法都是一样的: 使用声明式的配置管理方法,而不是脚本式 版本化这些声明的配置 所有环境使用同一套装配置管理方法 使用声明式的配置管理方法,而不是脚本式的 脚本式的配置管理是这样的: apt-get install build-essential apt-get install libtool cd /usr/local/src wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.37.tar.gz tar -zxvf pcre-8.37.tar.gz cd pcre-8.34 ./configure make make install 而声明式的配置管理是这样的: # ./ansible-nginx/tasks/install_nginx.yml # 使用这个7-0.el7版本的yum包 - name: NGINX | Installing NGINX repo rpm yum: name: http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm # 当前机器的nginx的状态应该是最新版本 - name: NGINX | Installing NGINX yum: name: nginx state: latest # 当前机器的 nginx service 的状态应该是已经启动的。至于如何确保 nginx 这个 service,当前是什么状态的,又是如何启动的,我们不需要关心。 - name: NGINX | Starting NGINX service: name: nginx state: started 声明式的配置里写的是当前环境的“状态”,语意上,声明式的配置不论你执行多少次,你得到最终的“状态”就是你所声明的,这也就实现了《持续交付》里说的: ...

2018-03-30 · 1 min · 135 words · 翟志军 Jack Zhai