部署流水线搭建小记:Docker、Jenkins、Java和Couchbase

hqla5155 8年前
   <p>这篇文章讲述了如何用Jenkins和Docker来为一个需要和数据库交互的Java应用创建 <em>部署流水线</em>(deployment pipeline )。</p>    <p>Jenkins支持创建流水线。它使用一种基于Groovy的流水线领域特定语言( <em>Pipeline DSL</em> )的简单脚。</p>    <p>而这些脚本,通常名字叫 Jenkinsfile 。它定义了一些根据指定参数执行简单或复杂的任务的步骤。流水线创建好后,可以用来构建代码,或者编排从代码提交到交付过程中所需的工作。</p>    <p>流水线包括步骤( Step ),节点( Node )和阶段( Stage )。流水线执行在节点上。节点是Jenkins安装的一部分。流水线通常包含多个阶段。一个阶段包含多个步骤。</p>    <p>对于我们本文中的应用,其基本的部署流程是这样的:</p>    <p><img src="https://simg.open-open.com/show/1a837441ff1211dad713ab3ab6b251dd.png"></p>    <ol>     <li>开发者更新工作区</li>     <li>Jenkins收到通知</li>     <li>Jenkins克隆工作区</li>     <li>Jenkins创建一个Docker镜像</li>     <li>Jenkins运行测试</li>     <li>Jenkins将镜像推到Docker Hub</li>    </ol>    <p>应用的完整代码放在了 Github仓库 上。</p>    <p>应用位于仓库中的 webapp 目录。应用会借助 Couchbase的Java SDK ,使用一个到Couchbase数据库的连接,保存一个简单的JSON文档。应用同时包含一个测试,以验证数据库是否包含持久化的文档。</p>    <h2><strong>下载并安装Jenkins</strong></h2>    <p>从jenkins.io下载Jenkins。这里使用的是Jenkins 2.21。</p>    <p>先把Jenkins启动起来:</p>    <pre>  JENKINS_HOME=~/.jenkins java -jar ~/Downloads/jenkins-2.21.war --httpPort=9090  </pre>    <p>这条命令指定了Jenkin家目录的路径。家目录下面存放了所有的配置信息。同时指定了Jenkins的监听端口。这里指定的是9090端口。</p>    <p>启动Jenkins会在中终端中看到如下消息:</p>    <pre>  Jenkins initial setup is required. An admin user has been created and a password generated.    Please use the following password to proceed to installation:        (译文:Jenkins需要初始化的设置。我们已经为你创建好了一个管理员用户生成好了密码。请使用下面密码继续安装。)        3521fbc3d40448efa8942f8e464b2dd9        This may also be found at: /Users/arungupta/.jenkins/secrets/initialAdminPassword        (译文:这个密码的内容同时也可以在`/Users/arungupta/.jenkins/secrets/initialAdminPassword`中找到。)  </pre>    <p>复制一下终端中显示的密码,这个密码会用来解锁Jenkins。</p>    <p>在浏览器中输入 localhost:9090 访问Jenkins,然后粘贴密码:</p>    <p><img src="https://simg.open-open.com/show/77aee8e005006dc4ca6ad453a4d9d376.png"></p>    <p>点击 Next 进入下一步:</p>    <p>创建第一个如图所示的管理员用户:</p>    <p><img src="https://simg.open-open.com/show/731a79988f09bf4c80c39839ee91a099.png"></p>    <p>点击 Save and Finish 继续。</p>    <p>点击 Install suggested plugins :</p>    <p><img src="https://simg.open-open.com/show/923180a8682480645b8170e858617b0a.png"></p>    <p>然后就会安装好一批默认的插件:</p>    <p><img src="https://simg.open-open.com/show/d82a3a8bbc69ea0b64beb2225c7ea980.png"></p>    <p>(很奇怪Ant和Subversion是默认的插件。)</p>    <p>然后会弹出登陆框:</p>    <p><img src="https://simg.open-open.com/show/42e3d20b46717bfd3980e01b47be6ff1.png"></p>    <p>输入之前创建好的用户名和密码。</p>    <p>最后Jenkins就可以使用了。</p>    <p><img src="https://simg.open-open.com/show/4c7a2cdae8c57f2e7cbdd2299e042ce5.png"></p>    <p>不得不说,要安装好一个简单的Jenkins所需要的步骤不少。真的有必要需要这么多步骤才能开始使用Jenkins吗?能不能有一个更简单,更傻瓜,更偷懒的方式来开始使用Jenkins呢?希望能遵守管理优先原则( <em>Convention-over-Configuration</em> )然后提供一个预先配置好的一键安装包。</p>    <h2><strong>创建Jenkins作业</strong></h2>    <p>让我们在Jenkins中创建一个用来运行流水线的作业。</p>    <ol>     <li> <p>在Jenkins重启之后,他会显示一个登陆界面。输入之前创建的用户名和密码。这会把你带回到 Installing Plugins/Upgrade 页面。点击页面左上角的Jenkins图标,可看到主控制面板:<br> <img src="https://simg.open-open.com/show/e49673bd15d56c911b426af3444d8669.png"></p> <p><img src="https://simg.open-open.com/show/e49673bd15d56c911b426af3444d8669.png"></p> </li>     <li> <p>点击 create new job ,作业的名字取做 docker-jenkins-pipeline ,类型选 Pipeline 。</p> </li>    </ol>    <p><img src="https://simg.open-open.com/show/fbc284ea77b84059fffc95fa8f66221a.png"></p>    <p>点击OK按钮。</p>    <ol>     <li> <p>按照如图所示对流水线进行配置:</p> </li>    </ol>    <p><img src="https://simg.open-open.com/show/c504792d1b9bd0e20c07cdc812cd2dba.png"></p>    <p>这里我们使用了本地的仓库。你当然也可以选择托管在Github上的仓库。另外,这个仓库可以配置一个git钩子或者定时的轮询器来触发流水线的运行。点击 Save 按钮来保存配置。</p>    <h2><strong>让Jenkins进行构建</strong></h2>    <p>在启动这个作业之前,Couchbase数据库需要显式地进行启动:</p>    <pre>  docker run -d --name db -p 8091-8093:8091-8093 -p 11210:11210 arungupta/oreilly-couchbase:latest  </pre>    <p>这个问题会在 <a href="/misc/goto?guid=4959719626053680363" rel="nofollow,noindex">编号9的问题</a> 修复之后得以解决。确保你可以使用用户名 Administrator 和密码 password ,通过 <a href="/misc/goto?guid=4959719626142275999" rel="nofollow,noindex">http://localhost:8091</a> 来访问Couchbase。点击 Data Bucket 标签页可以看到创建的名为 books 的Bucket。</p>    <p><img src="https://simg.open-open.com/show/37be4ed633c450054140b9593e46a686.png"></p>    <p>点击 Build Now 你应该看见下图类似的输出:</p>    <p><img src="https://simg.open-open.com/show/37b9207459ccedffb1c712b374db951d.png"></p>    <p>看起来一切正常。</p>    <p>让我们来试着理解下背后发生了什么。</p>    <p>Jenkinsfile描述了流水线是如何构建的。从整体看它有四个阶段 - 打包、创建Docker镜像、运行应用和运行测试。每一个阶段在Jenkins的控制面板都是以一个方框显示的。每一个阶段花费的总体时间显示在每一个方框中间。</p>    <p>然后我们试着理解每一个阶段都做了什么事情。</p>    <p>打包:</p>    <p>应用的的源码位于 webapp 目录下。而这一条Maven命令:</p>    <pre>  mvn clean package -DskipTests  </pre>    <p>用来创建应用的JAR包。注意Maven项目也包含测试,但是这里被故意通过 -DskipTests 忽略了。</p>    <p>通常,测试会 分开放在一个下游的项目中 。Maven项目创建一个应用的Fat JAR(译者注:Fat JAR是把项目所有类文件、资源文件和依赖打包在一起的JAR)文件并且包含所有的依赖。</p>    <p>创建Docker镜像:</p>    <p>应用的Docker镜像是使用 webapp 目录下的Dockerfile来构建的。这个镜像仅仅包含一个Fat JAR,可以通过 java -jar 来运行。</p>    <p>每一个镜像都使用构建编号打上了标签:</p>    <pre>  ${env.BUILD_NUMBER}  </pre>    <p>运行应用:</p>    <p>运行应用需要运行应用的Docker容器。数据库容器的IP地址可以通过下面这条命令来查到:</p>    <pre>  docker inspect  </pre>    <p>数据库容器和应用容器同时运行在默认的 bridge 网络中。这可以让两个容器来互相沟通。也可以在swarm模式的集群中运行流水线,这需要创建并且使用覆盖网络。</p>    <p>运行测试:</p>    <p>测试可以使用如下命令来进行:</p>    <pre>  mvn test  </pre>    <p>如果测试通过,镜像会被推送到Docker Hub。不管测试是否成功,运行结构都能捕获到。同时我们显示了 try/catch/finally 块在Jenkinsfile中的使用。如果测试通过了,那镜像就会推送到Docker Hub中。在我们这个例子中,它被推送到了 <a href="/misc/goto?guid=4959719626225355320" rel="nofollow,noindex">这里</a> 。</p>    <h2><strong>待办事项</strong></h2>    <ul>     <li> <p>把测试移到一个下游的项目中( <a href="/misc/goto?guid=4959719626301063806" rel="nofollow,noindex">#7</a> )</p> </li>     <li> <p>使用Git钩子或者轮询来触发流水线( <a href="/misc/goto?guid=4959719626386893828" rel="nofollow,noindex">#8</a> )</p> </li>     <li> <p>自动化数据库的启动与停止( <a href="/misc/goto?guid=4959719626053680363" rel="nofollow,noindex">#9</a> )</p> </li>     <li> <p>用Swarm模式下的Docker引擎集群来运行流水线( <a href="/misc/goto?guid=4959719626476530598" rel="nofollow,noindex">#10</a> )</p> </li>     <li> <p>增加额外的配置来将镜像推送到bintray( <a href="/misc/goto?guid=4959719626556431517" rel="nofollow,noindex">#11</a> )</p> </li>     <li> <p>另外一个痛点找不到关于全局变量语法的文档。只有在 &lt;JENKINS-HOST>:&lt;JENKINS-PORT>/job/docker-jenkins-pipeline/pipeline-syntax/globals 能找到相关内容。这一点点戳。</p> </li>     <li> <p>“ 不是不可能,只是还没有实现 ” #sadpanda</p> </li>    </ul>    <p> </p>    <p> </p>    <p>来自:http://dockone.io/article/1735</p>    <p> </p>