基于SLB的滚动发布脚本示例

更新时间:2018-01-12 16:12:44    滚动发布 滚动发布(rolling update)是最常见的一种发布模式。比如我有10台机器,一台一台的进行部署。每台机器进行部署时,需要保证没有请求会派发到该机器,否则用户就会看到502的错误。所以需要有一个“下线”的操作,把当前机器从负载均衡中摘除,然后在部署完成之后,再把自己挂回到负载均衡中,这个过程称为“上线”。接下来会讲解,配合阿里云SLB如何做上线/下线操作。 基于阿里云SLB的滚动发布 在SLB中进行如下配置: 图中的关键点: 健康检查路径,需要由实例上的web服务器提供,在本例中是/nginx-status 。 健康检查间隔,配置为2S。 健康阈值,配置为2,也就说2次健康检查失败,则认为该后端服务器不可用。同样的,两次连续的健康检查成功,就会认为该后端服务器可用。 按照这个配置,如果/nginx-status这个URL不可用超过4S,则SLB会把该服务器摘除。在这4S内,应用服务仍需要是可用的,因为还会有请求派发过来。可以通过如下方式达到这个效果。 配置nginx 将/nginx-status这个URL派发到一个本地文件,使用如下配置文件: server { location ~ ^/(nginx-status) { root /home/admin/status; } } 并在机器上放置文件:/home/admin/status/nginx-status。当该文件被删除时候,/nginx-status这个请求会返回404,4S之后,该实例就会被从SLB中摘除。这个过程也就是“下线”的过程。 与之对应,touch /home/admin/status/nginx-status这个操作就是上线的过程,也是4S之后生效。 上/下线脚本 所以对应的,应用启停的脚本就是这样样子: #下线 rm /home/admin/status/nginx-status sleep 6 #按理说是4S,留一些buffer #重启应用 #上线 touch /home/admin/status/nginx-status sleep 6 #按理说是4S,留一些buffer 前面的sleep保证,下线完成了再进行重启;后面的sleep,保证上线完成了再进行下一台(批)机器的部署。 应用重启脚本 上线和下线之间是重启的脚本。对于tomcat应用来说,典型的启动脚本就是sh catalina.sh start。执行完这一句,命令就退出了。但是事实上应用还没起来,有些比较大的应用可能需要一两分钟才能启动完成。如果在启动完成之前就上线,那么打到这台实例的请求还是有问题。所以需要有一个脚本来判断tomcat是否真的起来了。通常可以判断某个URL是否返回200。比如类似/health这样的URL。 完整示例 下面是是一个完整的例子,您可以以该例子为基础,按照自己项目的实际情况进行修改使用。 SLB与机器实例 SLB的创建与配置此处略,详见SLB的文档。SLB的后端服务器需要加入到云效的管理中,此处也不再赘述。 代码库 本例使用的代码库是https://code.aliyun.com/rdc-demos/springboot-example,其中也包括了构建配置。 部署配置及脚本 … Continue reading 基于SLB的滚动发布脚本示例

5个小时写一个扑克牌游戏——金钩钓鱼

  罗大佑有歌云:“无聊的日子总是会写点无聊的歌曲......”,我不是歌手,我是程序员,于是无聊的日子总是会写点无聊的程序。程序不能太大,不然没有时间完成;程序应该有趣,不然就达不到消磨时间的目的;程序应该有那么一点挑战性,不然即使写完了也没有进步。 金钩钓鱼游戏是我儿时经常玩的一种扑克牌游戏,规则非常简单,两个玩家,一旦牌发到手里之后,接下来每个人出什么牌基本上已经就定了,玩家没有自己做决策的机会,所以这个游戏很容易用程序自动模拟出来。   (一)关于金钩钓鱼游戏 基本规则(简化版):两个玩家(Player),一副扑克(Deck),大小王(Joker)可要可不要,我们的游戏假定包含大小王,洗牌(Shuffle)之后,每个玩家得到同样数目的牌(27张),玩家任何时候不能看自己手里的牌,玩家依次出牌,每次出一张,轮到自己出牌时,抽出自己手中最底下的一张牌放到牌桌(Board)上,牌桌上的牌按照玩家出牌的顺序摆成一条长链。J(钩)是最特殊的一张牌,当某个玩家出到J时,便将牌桌上的所有牌都归为己有,并放到自己牌池的最上面(与出牌时恰恰相反),此即所谓“金钩钓鱼”,此时牌桌清空,再由此玩家重新出牌。另外,当自己出的牌与牌桌上的某张牌点数相同时,便将牌桌中那张牌及其之后的牌都归为己有(包含自己刚出的那张),再由此玩家重新出牌,比如牌桌上的牌为3,7,8,4,9,当某个玩家出了8,便将牌桌上的8,4,9连同自己刚出的8一并收回,派桌上剩下3,7。最后,谁手中的牌最先出完,谁就输了。   (二)对于一副牌的建模 由于花色(Suit)对于此游戏并不重要,所以对扑克牌建模时省略了对花色的建模,同样,由于不需要比较大小,牌的点数(Rank)可以用String来表示(其中王用"W"表示)。 package com.thoughtworks.davenkin.simplefishinggame; public class Card { private String rank; public Card(String rank) { this.rank = rank; } public String getRank() { return rank; } } 一副扑克(Deck)由54张牌组成: package com.thoughtworks.davenkin.simplefishinggame; import java.util.ArrayList; import java.util.Collections; public class Deck { ArrayList<Card> cards = new ArrayList<Card>(); public Deck() { buildDeck(); } private … Continue reading 5个小时写一个扑克牌游戏——金钩钓鱼

重温大师经典:Martin Fowler的持续集成

持续集成 作者:Martin Fowler     译者:滕云 原文发布时间:2006年5月1日     翻译时间:2012年2月25日 原文链接:http://www.martinfowler.com/articles/continuousIntegration.html (此翻译已获原作者同意)   持续集成(Continuous Integration, CI)是一种软件开发实践,在实践中项目成员频繁地进行集成,通常每个成员每天都会做集成工作,如此,每天整个项目将会有多次集成。每次集成后都会通过自动化构建(包括测试)来尽快发现其中的错误。许多团队都发现这种方法大大地减少了集成问题并且能够快速地开发出高内聚性的软件。本文简要地总结了持续集成技术及其现状。 我还清楚地记得我刚加入一个大型软件项目时的情形,那时我正在英国一个电子公司做暑期实习。我的经理(属于QA部门)领我参观了一个巨大并很压抑的房间,里面全是格子间。经理告诉我这个项目已经开发了有些年头,现在正在做集成,并且已经集成了好几个月了。经理还告诉我说,没有人真正知道完成集成工作需要多少时间。由此我学到了软件项目的一个通病:软件集成是一个漫长并且无法预测的过程。     然而,软件集成不必像这样的。在ThoughtWorks的大多数项目还有世界上许多其它组织的软件项目中,软件集成并不是什么难事。每个开发人员离共享的工程状态只有咫尺之遥,并且可以在几分钟之内将自己的代码集成进去。任何集成错误都能被快速地发现并得到快速的修正。 这种鲜明的对比并不是源自于后者有多么昂贵或复杂的工具,而关键在于每人都频繁集成这种简单实践,通常是每天向一个被管控的代码库集成。 当我向人们阐述这种实践时,通常得到两种反应:“(在我们这里)行不通”和“无关紧要”。当人们尝试了这种实践之后,他们发现其实做起来比说起来简单,而且这样的实践对于开发“至关重要”。因此有了第三种反应:“是的,我们就是这么做的,不然该怎么活啊?” “持续集成”源自于极限编程(XP),并且是XP最初的12种实践之一。当我以咨询师的角色加入ThoughtWorks时,我鼓励我的团队使用这种技术。Matthew Foemmel将我的建议变成了实实在在的行动,由此软件集成从少有发生并且复杂的状态变成了一桩易事。Matthew和我将我们的经验写在了本文的第一版中,而本文也是我的个人网站上最受欢迎的文章之一。 虽然持续集成并不需要使用特别的工具来部署,但是我们发现拥有一台持续集成服务器将大有益处,其中最著名的有开源的CruiseControl,该软件最初由ThoughtWorks的几个员工开发,现在由一个很大的社区维护着。后来几款其它的持续集成服务器也相继出现了,有开源的,也有商业化的,包括ThoughtWorks Studios的Cruise。     在开发中使用持续集成 对于我来说,解释持续集成及其工作原理最简单的方法便是以一个小的软件功能的开发为例来进行演示。假设我们需要向软件添加一点功能,至于是什么样的功能并不重要,我们假定它很小并且可以在几个小时内完成。 首先我们需要在本地机器上保留一份当前已经处于集成状态的代码的拷贝。我通过代码管理系统在代码库的主线(mainline)上拉下(check out)一份工作代码拷贝。 上一段文字主要针对使用代码控制系统的人,对于不使用代码控制系统的人来说便是胡言乱语了。因此,我将向后者解释一下。代码控制系统用于将项目所有的代码保存在一个代码库(repository)中,项目当前的状态通常被称为主线。任何时候开发人员都可以从主线上获得一份拷贝到本地机器,这被称为“checking out”。本地机器上的代码拷贝称为“working copy”。(多数时候,实际上你是在更新(update)本地代码到主线状态,实践中它们是一样的效果。) 现在,为了完成软件的功能添加,我对本地代码进行修改,其中既包括修改产品代码,也包括添加自动化测试。持续集成非常看重测试,并且在软件代码本身中达到了测试自动化——我将其称为自测试代码,通常使用流行的XUnit测试框架的一个版本。 当我完成了功能开发(或者在我开发过程的不同阶段),我将在本地开发机上完成自动化构建。构建过程将编译并链接本地代码,然后跑自动化测试。只有当构建和测试都没有错误时,该次构建才能算是好的构建。 有了本地的成功构建,我便可以考虑将我修改的代码提交到代码库了。但是,在我提交之前,其他开发人员可能已经向主线提交了他们的修改,所以首先我需要将他们的修改更新到我本地并且重新构建。如果他人的修改与我的修改有冲突,那么在本地编译或者测试阶段将会发生错误,这种情况下,我需要负责修改本地代码直到与主线代码保持适当同步为止。 当本地代码与主线代码同步之后,我便可以向主线提交自己的修改了,代码库也得以更新。 然而,单是提交了修改并不表示我的工作就完成了。我需要再次构建,但这次是在一台拥有主线代码的集成机器上进行。只有这次构建成功了才表示我的任务完成。通常会出现这样的情况:我忘了提交本地机器上的一些东西,因此代码库并没有得到适当的更新。只有我提交的修改在集成机器上成功构建之后,我的工作才算完成。这样的集成构建可以由我手动完成,也可以由Cruise自动完成。 当两个开发者的代码有冲突时,通常会在第二个开发者更新本地代码时捕获到,否则,集成构建应该会失败。在这两种途径中,错误都可以被快速地发现。在持续集成环境中,你决不应该使失败的集成构建保留太长时间。一个好的团队每天都应该有许多成功的构建。当然,失败的构建也会时常发生,但需要尽快的修复。 这样做的结果是,我们总会得到一个稳定并且工作正常的软件。每个人都围绕着一个共享并稳定的基础代码库工作,绝不离基础代码库太远以至于需要很长的时间将自己的修改集成到基础代码库中。如此这般,我们花在找bug上的时间减少了,因为bug在频繁的集成中经常出现。     持续集成实践 上文只是关于持续集成的一个概要和它在日常开发中的工作原理。让所有这些都能很好的运作显然不止于此。现在,就让我们来看看有效持续集成所需的关键实践。   维护一个单一的代码库 软件项目需要大量的文件协同工作来构建出最终的产品。跟踪所有的文件需要大量的工作,尤其是在多个开发者参与的项目中。因此,我们可以并不惊奇的看到,不同的软件开发团队都在开发用于管理这些文件的工具——源代码管理工具,也叫配置管理,版本控制系统,代码库等。这些工具是多数软件项目不可分的组成部分。然而,令人伤心并吃惊的是,并不是所有的项目都使用了这样的工具。我的确见到(虽然很少)不使用这些工具的项目,它们使用本地和共享磁盘这种混乱的结合来共同工作。 因此,做为最基本的持续集成实践,请保证你使用一款体面的代码管理系统。成本不是问题,有许多高质量的开源代码管理工具存在。当前的选择为Subversion(译者注:现在有了更新的hg和git)。(更老的开源工具CVS如今仍然被大量使用,虽然比没有强,但是Subversion是更现代的选择。)有趣的是,当我和一些开发者聊天时,我发现相比起多数商业化的代码管理系统,他们更喜欢Subversion。据我所知,唯一值得花钱买的只有Perforce。 当你有了代码管理系统之后,确保每个开发者都能方便的获得到源代码。不应该有人还在问:“foo-whiffle 文件在哪儿?”所有东西都必须在代码库里。 虽然许多团队都在使用代码库,但是我经常发现,他们并不把所有东西都放在里面。如果大家需要使用一个文件,他们知道该文件放到代码库中,但是,构建所需的所有都应该包含在代码库里,包括测试脚本,属性文件,数据库模式文件,安装脚本和第三方库等。我所知道的有项目将编译器加到代码库中的(对于早期脆弱的C++编译器来说非常重要)。基本原则是:在一台新机器上check out代码后构建也能构建成功。新机器上的东西应该尽量的少,通常包括很大的,难于安装的,并且稳定的软件,比如操作系统,Java开发环境或者数据库管理系统等。 你需要将构建所需的所有东西都加到代码管理系统中,同时也需要将大家经常操作的东西方进去,IDE配置便是一个很好的例子,这样便于大家共享IDE配置。 版本控制系统的一大功能是它允许你创建多个分支,以此来处理不同的“开发流”。这种功能很有用,但却经常被过度使用以至给开发者带来了不少麻烦。所以,你需要将分支的使用最小化,特别建议使用主线,即项目中只有单一的开发分支,并且每人在多数时间里都在“离线”工作。 总之,你应该将构建所需的所有东西都放在代码管理系统中,而不应该将构建的输出放进去。有些朋友确实将构建输出放在代码管理系统中,但我认为这是一个坏味道,可能导致更深的问题——通常是你无法完成重新构建。   … Continue reading 重温大师经典:Martin Fowler的持续集成

深圳地区可参与的中继台网时间表201607

*下差-5MHz/亚音88.5Hz 439.180 周一?南山 438.525 周二?梅林 438.025 周三 科技园 国语YY+ECHOLINK 438.275 周四 罗湖 国语 439.460 周五 罗湖 粤语 439.550 周五 东莞 粤语 439.850 周六?宝安? 439.250 周日 广州南沙 其它: 438.875 深圳公明 46楼 438.660 惠州罗浮山 700米 439.075 中山 ? 439.350 广州1 439.930 广州2 VHF: 145.300 -0.6/88.5 深圳VHF 144.640 全国APRS专用 数字DMR 439.790 -8/88.5 深圳DMR 数字C4FM: 筹备中…相应频率的QQ群,请添加微信公众号 bi7jta73 索取   增加:河源 439.625 -5 … Continue reading 深圳地区可参与的中继台网时间表201607

十步搭建 OpenVPN

摘要: 十步搭建 OpenVPN,享受你的隐私生活 我们支持保护隐私,不为我们有自己的秘密需要保护,只是我们认为保护隐私应该成为一项基本人权。所以我们坚信无论谁在什么时候行使这项权利,都应该不受拘束的获取必须的工具和服务。 十步搭建 OpenVPN,享受你的隐私生活 我们支持保护隐私,不为我们有自己的秘密需要保护,只是我们认为保护隐私应该成为一项基本人权。所以我们坚信无论谁在什么时候行使这项权利,都应该不受拘束的获取必须的工具和服务。OpenVPN就是这样一种服务并且有多种工具(客户端) 来让我们利用并享受这种服务。 通过与一个OpenVPN服务器建立连接,我们基本上在我们的设备和远端运行OpenVPN的主机之间建立了一个安全的通信通道。尽管在两个端点之间的通信可能被截获,但是信息是经过高强度加密的所以实际上它对于攻击者没什么用。OpenVPN除了扮演加密通信通道的调解人,我们也可以通过设置使服务器扮演互联网网关的角色。通过这种方式,我们可以连接任何不安全的Wifi,然后迅速的链接到远程的OpenVPN服务器,然后在不需要考虑偷窥的人或者无聊的管理员的情况下运行需要上网的程序。(注意:OpenVPN服务器旁还是需要信任的管理员的。) 这篇文章将一步一步的教会你如何在Ubuntu Server 14.04 LTS上安装OpenVPN。OpenVPN所在的主机可能是云上的一台VPS,一台在我们家里某台电脑上运行的虚拟机,或者是一个老到你都快忘了的设备。 第一步 准备系统 我们需要Ubuntu Server主机的一个命令行终端,比如通过SSH从远程访问它。首先需要更新它的本地仓库数据: sub0@delta:~$ sudo apt-get update 进行操作系统和已安装的包的升级,输入: sub0@delta:~$ sudo apt-get dist-upgrade 如果升级了新内核,那就需要重启。当更新完成后,就该安装OpenVPN了: sub0@delta:~$ sudo apt-get -y install openvpn easy-rsa dnsmasq 注意,我们用apt-get安装了三个包: openvpn提供了OpenVPN的核心 easy-rsa包含了一些有用的密钥管理脚本 dnsmasq是当我们的OpenVPN所在的主机将扮演客户端的路由器时会用到的域名服务器 第二步 生成证书和私钥 这是安装OpenVPN中最重要和最关键的一步,目的是建立公钥基础设施(PKI)。包括如下内容: 为OpenVPN服务器创建一个证书(公钥)和一个私钥 为每个OpenVPN客户端创建证书和私钥 建立一个证书颁发机构(CA)并创建证书和私钥。这个私钥用来给OpenVPN服务器和客户端的证书签名 从最后一个做起,我们先建立一个目录: sub0@delta:~$ sudo mkdir /etc/openvpn/easy-rsa 然后把easy-rsa的文件拷过去: sub0@delta:~$ sudo cp -r … Continue reading 十步搭建 OpenVPN