继前文

TFS在项目中Devops落地进程(上)

TFS在项目中DevOps落地进程(下)

自从之前将开发环境使用TFS进行了自动化之后,就享受在此成果中,其他后续进度就停顿了好一段时间。

毕竟在我们这对于开发而言,做出代码交出发布包事情就结束了,而我们的TFS已经完美的将这个流程给自动化掉了。

本文将聚焦在TFS发布到线上生产环境中所做的一些工作和实践,如果只是纠结于如何使用TFS可以参考上面的2个链接。

之前的线上发布流程

说下我们大概的背景,我们的程序上线流程目前还是相对传统一些,大体是:

①开发写完代码->②提交发布包->③QA拿包测试->④测试完成提交上线->⑤运维拿包进行发布

根据这个流程,狭义上的开发其实到流程②就已经结束了,因为之后从严格意义上来说都跟开发没有关系了(撇开出bug返工fix的逆向流程来说的话)

但是每次发布的时候,开发又必须要留守下来,虽然并不干什么事情,就干等着,但就要你留下,不然万一出现了问题怎么办。

之前发布都是手工发布,发布的时候每个机器都要人肉将发布包拷贝过去,覆盖,重启下应用程序池。

人工做这些重复而又无聊的事情会发生什么问题就不多说了:容易出错,枯燥,难以标准化。

而且人肉发布的时候经常直接将站点发布,所以有些站点正在处理某个请求中的时候就强行被kill了导致”每逢发布必报错“。

没错,你想知道什么时候发布,你只要看异常量冒上来的那一下就是发布的时间点了。。。

后面运维团队搞了jenkins来做自动化发布。

首先jenkins本身是个优秀的东西,但无赖总感觉我们是没hold住它,首先并没有解决”每逢发布必报错“的问题,另外发布时间看起来没有明显减少,最后觉得独立jenkins感觉就是Dev和Ops之间的那个壁垒(信息分割)。

TFS线上发布流程的准备

后面就计划用tfs来进行自动化的线上发布

首先,我们在原来的Release里,新增了若干个环境映射为线上环境

其中我们有一些是分业务线的(一条业务线内,所有前->中->后台的站点均维持同一个版本避免某些用户终端发布的时机不匹配的问题)就通过Release的Envrionment来进行区分

个别Environment里是有2个相连的情况,是因为某些业务线比较大,机器比较多,将比如10台机器,分成5个一组合计2组,发完第一组之后再发第二组这样的分组发布

然后我们线上机器使用了Nginx来做软负载,所以要进行线上发布的话一个正统的流程应该是

①通知Nginx让这个机器下线,并且可能要等待一段时间(等请求处理完毕)

②更新站点

③通知Nginx让这个机器上线

其中①和③由运维那边准备好了专门的python脚本放在每个机器的指定目录里,只要再发布的时候,远程到被部署的机器里执行下就好了

这里面遇到了2个问题:

问题1:

“远程到被部署的机器”这个问题,首先TFS自身的步骤里没这个玩意,所以自己特地研究了下Powershell研究如何动态的在指定的机器里进行Invoke-Command (不枉当年略微了解过Powershell)

TFS里可以支持调用Powershell

最后搞出通过如下命令即可实现远程到指定机器里调用指定的命令

[sourcecode language='powershell'  padlinenumbers='true']

$username 可以访问机器的账户名
$password可以访问机器的密码
$machine = 你的机器地址
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr Invoke-Command $machine -Credential $cred -ScriptBlock { 你需要在目标机器执行的命令 }
[/sourcecode]

问题2:

每个要发布的机器都要执行这3个步骤,想下一个机器3个Task,10台机器就30个Task,30台机器就90个Task,这还有要针对Task的一些变量配置,这茫茫大的配置量。。。

于是乎我们使用了TFS的任务组功能,所谓任务组,就是可以将若干个Task合并为一个Task,然后在通过变量传参的形式各个Task共享指定的变量

如:

通过任务组将3个Task合并为一个,里面包含”下线->更新->上线”全流程,一个任务组就对应发布指定的一台机器

然后吭哧吭哧的我们将这些问题解决了,就基本上配置出了基础的线上发布方案,然后就开始…..翻车

发布中遇到的一些问题

发布缓慢

先说下我们实际发线上的一个流程

我们以前(TFS以前)是QA将程序包一直测试到预发布(预生产环境)后,然后运维将预发布的包同步到线上

用TFS自然而然也顺着这个流程来,发布预发布的时候将包copy到某个共享目录下,然后线上的发布都通过去这个共享目录里拿

但是默认tfs的每一个Release它都会将发布包下载到发布的代理agent里,这个过程比较缓慢,拖慢整体速度

于是乎我们就发布的时候跳过项目下载,实践证明这个操作能大幅提升发布的效率

发布的时候站点的文件被占用导致发布失败

这个特别是在Asp.Net Core里几乎一定会发生,.Net Framework看具体情况但也很可能会遇到

一般而言的解决方案可以通过勾选IIS发布的时候Task App Offline解决(我们通过这个解决了99%的问题)

但实际上我们遇到了更变态的情况(剩下的1%),有一个站点使用了别人家的COM组件导致用这招依然会有文件占用的问题,这个可以通过发布的时候通过停止应用程序池搞定

折腾后的效果

通过上述修改,我们基本线上的发布透过TFS能跑的相对稳一点了

目前发布的效果是:发布期间站点性能有所下降,但是报错量总体不会发生太大变化

起码脱离了每逢发布必报错的时候了

由于最近一直在测试线上TFS发布(折腾了蛮久了)之前发布的数据没有了,不过看最近的一次发布结果,基本没发生报错

有箭头的位置就是发布的时候(这个稍后会说是如何实现的)

红色的是异常的数量

可以看到最近的发布里,基本没有红色的了

附加值:与Dev的相关整合

由于现在发布使用上了TFS,而我们Dev也是在TFS上的,所以现在我们大家都在同一个工具平台下了。

起码能带来一个显而易见的效果是,有没有发布,和发布完了没,我们大家直接透过TFS的面板就能看到了而不用跑过去问运维了。

另外说2个由于发布走TFS后跟我们Dev整合的一些附加值

①自动拉备份分支

以前我们已经就有这个机制,不过因为以前发布不是走TFS,所以我们是在发布到预发布的时候(预发布归QA管,之前做自动发布流程时候就将预发布以前全部搞好了)就自动拉

但是预发布毕竟不是线上,到了预发布也可能fix bug,所以很多时候备份分支特别多特别乱

而现在就是真正发布到线上的时候才会去拉备份分支,备份分支的备份就显得更加的“真”了

②发布的时候给监控系统打标记

上面异常量的那个图里看到的那几个小箭头

是每次自动发布到线上的时候,TFS会跟Application Insights(我们用的监控产品)说,我现在对某站点进行代号为XXX(TFS内的发布编号)发布拉,给我打个标记)

Application Insights就会说,好的,收到了,箭头已经打上,关联上你给我的信息了

一切通过插件 Release Annotations for Azure Application Insights 来实现即可

然后我就能通过我们的Application Insights的监控里看到什么时候发生了什么样的版本变动

这个信息有什么用呢?

比如你看到如下的图的时候会联想到什么?(某接口的响应时间)

是不是瞬间就能看出来,是因为某次发布导致某个接口的效率急剧变慢,不用猜,不用想,看图说话。

TFS线上生成环境发布历程的更多相关文章

  1. 如何利用docker 构建golang线上部署环境

    公司最近开发了一个项目是用golang 写的,现在要部署到线上环境去,又不想在服务器上装单独的golang,决定用docker 封装下,直接打到镜像里面,然后就直接在hub.docker.com上面搜 ...

  2. vue cli3配置开发环境、测试环境、生产(线上)环境

    cli3创建vue项目是精简版的少了build和config这2个文件,所以配置开发环境.测试环境.生产环境的话需要自己创建env文件. 需要注意2点: 1.cli2创建项目生成的config文件里的 ...

  3. VUE项目部署到线上生产环境,Loading chunk xxx failed

    项目部署到生产环境,路由点击无效,报错 Loading chunk chunk-xxxxx failed.(missing xxxx) 加载失败,错误的路径. 话不多说,直接贴代码: vue.conf ...

  4. rsync实现负载均衡集群文件同步,搭建线上测试部署环境

    闲来无事,搭建一个负载均衡集群,至于负载均衡集群搭建过程,找时间写下.这次主要写集群之间的文件同步,以及线上测试环境的搭建. 笔者看过很多公司都没有线上测试环境,真是崩溃了,不造怎么确保线上线下环境一 ...

  5. Springcloud及Git线上配置详解

    SpringCloud 这个阶段该如何学? 三层架构 + MVC 框架: Spring IOC AOP SpringBoot,新一代的JavaEE开发标准,自动装配 模块化~ all in one,代 ...

  6. 线上mysql内存持续增长直至内存溢出被killed分析(已解决)

    来新公司前,领导就说了,线上生产环境Mysql库经常会发生日间内存爆掉被killed的情况,结果来到这第一天,第一件事就是要根据线上服务器配置优化配置,同时必须找出现在mysql内存持续增加爆掉的原因 ...

  7. 记录线上与本地docker镜像一致,但Dockerfile却构建失败的问题

    背景 公司新开了某个项目,我在新的服务器部署了docker环境,本着ctrl+c 和ctrl+v的惯例,直接把以前的php环境的Dockerfile文件直接复制到新项目服务器那里,结果构建失败,失败的 ...

  8. 线上调试bug

    在以往的工作中,线上一有bug,就需要把文件弄到本地来改,但经常会碰见本地环境又和线上不一样,导致调试困难,闭着眼睛改好之后传到线上去看对不对,不对的话又要改,循环往复,要多麻烦就有多麻烦啊. 今天给 ...

  9. 使用Apollo动态修改线上数据源

    前言 最近需要实现一个功能,动态刷新线上数据源环境,下面来使用Apollo配置中心和Spring提供的AbstractRoutingDataSource来实现. 具体实现 Apollo是携程开源的统一 ...

随机推荐

  1. C# 数据库链接字符串加密工具

    有些项目尤其是WinForm或者是WPF项目,针对一些工具形式的小项目,不想软件流出去之后,懂程序的的拿到手之后一看配置文件就知道了我们数据库的用户名和密码,如果外网能访问的话,那就麻烦大了.所以这里 ...

  2. Eclipse下Maven新建Web项目index.jsp报错完美解决(war包)

    Eclipse下Maven新建Web项目步骤 1. 2. 3. 4. 5. 问题描述 最近用eclipse新建了一个maven项目,结果刚新建完成index.jsp页面就报错了,先把错误信息贴出来看看 ...

  3. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  4. Java移位运算符详解实例

    移位运算符它主要包括:左移位运算符(<<).右移位运算符(>>>).带符号的右移位运算符(>>),移位运算符操作的对象就是二进制的位,可以单独用移位运算符来处 ...

  5. String的valueOf()用于将其它类型转换为字符串

    String的valueOf()重载方法可将double类型,int类型,boolean类型以及char数组类型等变量转换为String类变量. 注:String的valueOf()可将char数组转 ...

  6. 二十五、Hadoop学记笔记————Hive复习与深入

    Hive主要为了简化MapReduce流程,使非编程人员也能进行数据的梳理,即直接使用sql语句代替MapReduce程序 Hive建表的时候元数据(表明,字段信息等)存于关系型数据库中,数据存于HD ...

  7. JavaScript 中常见设计模式整理

    开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...

  8. Can I use MyBatis to generate Dynamic SQL without executing it?

    Although MyBatis was designed to execute the query after it builds it, you can make use of it's conf ...

  9. 优雅地实现CSS Animation delay心得

    话不多说直接开讲: 1.需求: 等待元素A的动画加载完,再加载B元素的动画(下图中A为大熊猫,B为下方卡片) 先来看下最后的效果啦: 2.初始思路: 在B元素的动画属性上加上delay(延迟,使得这个 ...

  10. python一行代码就能搞定的事情!

    打印9*9乘法表: >>> print( '\n'.join([' '.join(['%s*%s=%-2s' % (y,x,x*y) for y in range(1,x+1)]) ...