前言关于Docker的文章很多,但大部分优质文章都是翻译过来的。都说Docker天生适合持续集成/持续部署,但同样的,能落地并真正可操作的文章也很少见。基于这些情况,虽然我们的专栏定位为运维管理文,但本文属于特例,实战案例讲解——如何通过Docker实现JAVA项目的持续部署(只需要简单的四个步骤),即:gitpush上传代码,通过Git和Jenkins的配合,自动完成程序的部署和发布,无需运维人员参与。这是一个真正的容器级实现。这样做带来的好处不仅仅是效率的提升,更是一种改变:开发者第一次真正为自己的代码负责——他们终于可以跳过运维和测试部门,独立维护运行环境(the首先是测试/开发环境)。本文为cSphereDocker实战视频第二讲的文字版。本文合著者@张春源学生(就职于cSphere)为视频主讲人。更多系列视频见https://csphere.cn/training。福利:点击“这里”,手机端即可欣赏本文对应的实战视频。难者不会,会者不难。通过四个简单的配置就可以优雅的实现持续部署。本文照例放入目录,敬请欣赏:持续部署的技术思路效果展示配置Git与Jenkins联动配置Jenkins自动更新代码详细效果图文FAQ好了,开始吧。1.持续部署的技术思想在这个例子中,假设我们的JAVA项目的名字是hello。简要的技术思路如下。在这种情况下,假设代码托管在git.oschina.com上,并且Jenkins和DockerRegistry(类似于yum源)各自运行在一个Docker容器中。JAVA项目本身也单独运行在一个名为hello的容器中。本文采用的持续部署方案是从私有的DockerRegistry中拉取代码,然后通过重建镜像的方式实现。在这里,詹金斯处于中心位置。就像长臂猿一样,在收到Git的请求后,通过远程调用服务器的Shell脚本来完成几乎所有的功能。此外,还有一些变通方法,将代码放在宿主机上,通过卷组映射让容器读取。不推荐这种方式的原因是将代码拆分出容器违反了Docker的容器原则:还会导致加载和卸载的复杂度增加。从货运工人的角度来看,整体是最经济的。只有这样,才能实现真正的容器级别的迁移。也就是说,在容器时代,摒弃过去的文件分发思路才是正道。本文末尾的问答部分对此有更多介绍。容器是进程。这也是采用上述方案进行Docker持续部署的原因和意义。容器的生命周期应该比虚拟机短很多。如果容器出现问题,应该立即杀死它而不是试图恢复。#p#2。效果展示了本文***实现的效果,有多神奇?并查看下面的演示。2.1程序代码更新前的效果我们使用时间戳来简明扼要地表达程序更新情况。2.2提交程序代码更新本例中,我们将首页的时间戳从201506181750修改为201506191410(见下图)。2.3上传新代码到Git依次执行以下操作,并输入正确的git账号密码。然后呢?然后无事可做。拿杯茶(如果你不喜欢喝咖啡),静静地等待自动部署发生,看着一系列的流程被自动触发,机器人像机器人一样运行(稍后描述)。为什么需要3~5分钟?只是因为本案例中的JAVA项目需要从国外下载Maven包供Jenkins调用编译JAVA。在正式的应用环境中,Maven源可以放在国内也可以放在机房。如果只需要做PHP项目的持续部署,会更快。2.4查看代码更新效果等待几分钟后,新代码确实已经自动部署完成。那么这一切是如何运作的呢?复杂吗?否则。只需按照以下步骤快速完成即可。#p#3。配置Git和Jenkins联动的过程主要分为以下三个步骤。3.1Jenkins配置Git源Jenkins新建项目java-app,并配置从Git中拉取的程序代码。具体如下:3.2Jenkins配置远程构建在Jenkins中配置token,供远程调用git时使用。3.3Git在收到用户更新的代码后如何打开钩子让Git将消息和任务传递给Jenkins?借助Git的钩子功能,配置也很简单,如下。4.配置Jenkins自动更新代码。Jenkins的主要工作是配置“远程构建”。收到Git的消息后,根据预定义的任务列表,触发远程构建(到目标服务器),执行一系列任务,重建容器等。详情见下文:#p#我们提取了最关键的Shell脚本内容。这些Docker相关的操作在第1部分“技术思路”中已经提到,这里不再赘述。5、效果图详解在2.3章节中,我们当时的操作是这样的。这样做的目的是将更新后的代码提交给Git。当时,我没有详细说明接下来发生了什么。上面已经解释了原理,接下来我们就来说说实际发生的事情。5.1上传代码到Git看来整个过程已经完成,顺利退出。事实上,后台工作才刚刚开始。此时会触发Git服务器向对应的Jenkins服务器发送操作请求。这个工作太快了,没啥好说的。让我们看看詹金斯接下来会做什么。5.2Jenkins的精彩交互如下。这个自动运行的过程让我们有点小成就感。值得端着一杯咖啡(如果你不喜欢喝茶)静静地观看。1)Jenkins会自动“弹出”一个构建任务。2)我们点进去看看具体的操作日志。是的,接受来自Git的任务。3)下载Maven相关软件包(这个过程比较慢)。#p#4)下载完成后开始使用mavenBUILD新建的hello工程包。5)然后重建Maven容器,构建一个新的Image并推送到Docker私有库中。6)***,再次拉起Docker容器。就这样,它重生了。呵呵6.FAQ问题一:是不是因为项目是基于JAVA的所以采用了这么复杂的方法(而不是把update代码放在host上再进行volumegroupmapping);PHP项目是否可以使用更新代码放在主机上然后卷组映射这种方式?答1:将代码拆分出容器违反了容器原则。导致装卸复杂性增加。从货运工人的角度来看,整体是最经济的。一切都是版本化的。抛弃过去的文件分发。这就是方法。至于文件大小,大war包只有50M或者100M,现网下不是问题,性能问题最好优化一下。另外推荐关注docker2docker,p2p传输。问题2:如果整体代码超过500m或者超过1g,是不是整体容器坏了?容器和代码分离的话,镜像大小在100m左右(2层,base+service),代码放在共享存储中。每个代码都会更新。比如svn代码可以在共享存储中直接svnupdate。你可以控制版本答案2:如果你的代码是500M,那只能说明业务开发要放到板子上。问题三:如果测试环境使用你提供的完整的容器服务,还可以,但是在生产环境中,将docker作为一个应用运行在集群中。如果每个容器都有完整的代码,是不是有点臃肿?为什么不在每个集群节点中使用它呢?运行基础服务镜像,通过卷组功能绑定共享存储中的代码,添加Crontab、Python、Shell脚本,让每次代码更新只有一次。回答3:环境一致性在过去一直没有很好的解决。10年前我们做paas的时候,也是类似这种做法。也不是不好,时代变了,毕竟有脚本很难有好的系统。不能只考虑一时的方便。如果将容器技术与vm进行比较,我想会让你在做决定的时候纠结。补充3:脚本一般是典型的运维工程师思维,quick&dirty。做一个产品或系统一般是很难的。总体考虑和可扩展性考虑较少。现在做docker的难点在于怎么看。是调度的基本单位还是部署的基本单位?想清楚了,再说方案。备注:以上问题的回答主要由王立军@cSphere和陈尔冬@HUAWEI完成。作者简介肖天国,男,硕士毕业于北京科技大学,触控技术运维负责人。拥有十余年运维及团队管理经验。曾就职于联想集团、搜狐畅游、知行通、21世纪互联。曾经是云计算行业的从业者,现在喜欢思考云计算和测评、云数据库、新技术在运维方面的应用。倡导管理学科与运维体系融合,人性化运维管理,打造高效专业的运维团队。张春元,目前就职于cSphere。国内最早的Docker从业者,有一年多生产环境Docker容器管理经验。深刻理解Docker对开发、测试、运维的价值。擅长使用Docker构建整个DevOps自动化平台。喜欢研究Dockerfile的艺术,对CoreOS有深入的研究。欢迎关注“cSphere”微信公众号,第一时间获取本系列视频最新内容,获取第一手Docker容器管理方案。如何愉快地开发一系列高效的运维微信群,是国内高端运维圈和运维行业垂直社交的典范。现有会员1000余人,其中运维总监及以上级别会员300余人。《高效运维》公众号值得您关注。作为高效运维系列微信群唯一官方公众号,每周发布多篇干货满满的原创文章:系列群讨论精华、运维论坛精彩分享线上/线下活动和原创一些小组成员。《高效运维》也是互联网专栏《高效运维***实践》,也是运维2.0的官方公众号。提示:目前,高效运维两大微信群仅提供少量珍贵席位,资深运维专家。如果您愿意,可以添加小天国的个人微信号xiaotianguo为好友申请;也可以加入我们的聊天群(主要是技术讨论,规则少,气氛热烈)。重要提示:除非事先获得授权,否则请在本文公众号发表2天后转载本文。尊重知识,转载请转载全文,包括我行及下方二维码。题图来自:blog.nicescale.com如果您对“这里”弹出的实用视频有任何疑问,欢迎通过https://csphere.cn/training进行互动讨论。谢谢!
