<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DevOps技术分享 &#187; Jenkins</title>
	<atom:link href="http://www.showerlee.com/archives/category/ci-cd/jenkins/feed" rel="self" type="application/rss+xml" />
	<link>http://www.showerlee.com</link>
	<description>与你共同学习运维开发</description>
	<lastBuildDate>Mon, 19 Oct 2020 05:51:41 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6</generator>
		<item>
		<title>Jenkins构建github webhook</title>
		<link>http://www.showerlee.com/archives/2893</link>
		<comments>http://www.showerlee.com/archives/2893#comments</comments>
		<pubDate>Mon, 19 Oct 2020 04:06:45 +0000</pubDate>
		<dc:creator>showerlee</dc:creator>
				<category><![CDATA[DevTools]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[jenkins webhook]]></category>

		<guid isPermaLink="false">http://www.showerlee.com/?p=2893</guid>
		<description><![CDATA[如何构建Jenkins github webhook, 这个一直在网上没有一个非常系统的解决方案, 官方给的文 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	<span style="background-color:#FFFFFF;font-size:14px;font-family:Helvetica;"><span style="font-size:16px;">如何构建Jenkins github webhook, 这个一直在网上没有一个非常系统的解决方案, 官方给的</span><a href="https://plugins.jenkins.io/github/" target="_blank"><span style="font-size:16px;">文档</span></a><span style="font-size:16px;">也相对比较晦涩</span></span>
</p>
<p>
	
</p>
<p>
	<span style="font-size:16px;"><span style="font-size:16px;background-color:#FFFFFF;">刚好最近闲下来想在把之前的CICD项目搞的更加完备, 这里就结合这块顺带把Jenkins github webhook给大家整理一个文档, 帮助有需求的小伙伴针对如何使用Jenkins插件仓库下的github plugin与我们常用的github代码进行webhook集成.</span></span>
</p>
<p>
	<span style="font-size:16px;"><span style="font-size:16px;background-color:#FFFFFF;">DEMO:&nbsp;<span style="font-size:16px;background-color:#FFFFFF;"><a href="https://github.com/showerlee/gradle-demo-with-docker" rel="nofollow">https://github.com/showerlee/gradle-demo-with-docker</a></span></span></span>
</p>
<p>
	
</p>
<p>
	<span style="font-size:16px;color:#E53333;"><span style="font-size:16px;background-color:#FFFFFF;color:#E53333;">什么是Github Webhook?</span></span>
</p>
<p>
	<span><span style="font-size:14px;background-color:#FFFFFF;"><span style="font-size:16px;">顾名思义, 也就是Github项目下Webhook允许使用者触发一个CI系统(例如Jenkins)的URL，这个URL通常由github plugin提供，这个Webhook会侦听特定事件，如推送master push, PR或merge请求。</span><span style="font-size:16px;background-color:#FFFFFF;">如果项目推送了新代码,&nbsp;&nbsp;</span><span style="font-size:16px;">Github会向这个Webhook URL发送包含此次commit的相关POST请求, 并通过Jenkins相关配置触发相应的jenkins job, 实现我们每次的代码提交都能够自动触发一次Jenkins代码构建, 真正打通了我们代码仓库与CI系统的壁垒, 使我们开发人员能够快速进行CICD自动化集成构建部署, 并且在后期的审计过程中, 能够通过每次commit追溯每一次构建内容. 实现commit与构建一一对应.</span></span></span>
</p>
<p>
	<span><span style="font-size:14px;background-color:#FFFFFF;"><br />
</span></span>
</p>
<p>
	<span style="font-size:16px;"><span style="font-size:16px;background-color:#FFFFFF;">这里开始我们的具体配置:</span></span>
</p>
<p>
	<span style="font-size:16px;"><span style="font-size:16px;background-color:#FFFFFF;"><br />
</span></span>
</p>
<p>
	<span style="color:#337FE5;font-size:18px;"><span style="font-size:18px;background-color:#FFFFFF;color:#337FE5;">1.在Github下添加Jenkins github plungin webhook URL</span></span>
</p>
<p>
	<span style="font-size:16px;background-color:#FFFFFF;">访问你的代码仓库如下路径</span>
</p>
<p>
	<span style="font-size:14px;background-color:#FFFFFF;"><span style="font-size:16px;"><a href="https://github.com/&lt;org&gt;/&lt;repo&gt;/settings/hooks/" rel="nofollow">https://github.com/&lt;org&gt;/&lt;repo&gt;/settings/hooks/</a></span><br />
</span>
</p>
<p>
	<span style="font-size:16px;background-color:#FFFFFF;">点击右上角的Add webhook</span>
</p>
<p>
	<span style="font-size:14px;background-color:#FFFFFF;"><a href="http://www.showerlee.com/archives/2893/1-50"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/1.png" alt="" width="800" height="164" class="alignnone size-full wp-image-2900" title="" align="" /></a><br />
</span>
</p>
<p>
	<span style="font-size:16px;">按照如图添加我们的Jenkins URL地址, 假设你的Jenkins主页是jenkins.example.com, 这里URL即为如下地址(如有非80端口, 这里也要添加)</span>
</p>
<p>
	<span style="font-size:16px;">这里需要保证jenkins.example.com为可以访问的公网域名且对应的IP地址可公网解析.</span>
</p>
<p>
	<span style="color:#E53333;font-size:16px;">本地虚拟机用户</span><span style="color:#E53333;font-size:16px;">不适合此次webhook的教程, 因为github需要与你的jenkins主机通信, 这里本地虚拟机通常都在一个内网, 无法实现公网互通</span>
</p>
<p>
	<span style="color:#E53333;font-size:14px;"><a href="http://www.showerlee.com/archives/2893/2-35"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/2-1024x699.png" alt="" width="800" height="546" class="alignnone size-large wp-image-2901" title="" align="" /></a><br />
</span>
</p>
<p>
	
</p>
<p>
	<span style="font-size:16px;">配置好点击Add webhook保存</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:18px;background-color:#FFFFFF;">2.在Github下创建Personal access token</span>
</p>
<p>
	<span style="color:#000000;font-size:16px;background-color:#FFFFFF;"><span style="font-size:16px;background-color:#FFFFFF;color:#000000;">访问你的代码仓库如下路径</span></span>
</p>
<p>
	<span style="color:#000000;font-size:16px;background-color:#FFFFFF;"><span style="font-size:16px;background-color:#FFFFFF;color:#000000;"><span style="font-size:16px;"><a href="https://github.com/settings/tokens" rel="nofollow">https://github.com/settings/tokens</a></span><br />
</span></span>
</p>
<p>
	<span style="color:#337FE5;font-size:16px;background-color:#FFFFFF;"><span style="color:#000000;font-size:16px;">按照如图配置你的token, 创建好后保存token内容</span><br />
</span>
</p>
<p>
	<span style="color:#337FE5;font-size:16px;background-color:#FFFFFF;"><span style="color:#000000;"><a href="http://www.showerlee.com/archives/2893/3-26"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/3-545x1024.png" alt="" width="600" height="1128" class="alignnone size-large wp-image-2902" title="" align="" /></a><br />
</span></span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:18px;"><span style="font-size:18px;background-color:#FFFFFF;color:#337FE5;">3. 安装配置Jenkins github plugin</span></span>
</p>
<p>
	<span style="font-size:16px;">访问</span><span style="font-size:16px;"><a href="http://jenkins.example.com/pluginManager/available" rel="nofollow">http://jenkins.example.com/pluginManager/available</a> 找到github plugin, 并进行安装.</span>
</p>
<p>
	<span style="font-size:16px;"><a href="http://www.showerlee.com/archives/2893/4-22"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/4.png" alt="" width="800" height="107" class="alignnone size-large wp-image-2903" title="" align="" /></a><br />
</span>
</p>
<p>
	<span style="font-size:16px;">进入http://jenkins.example.com/configure</span>
</p>
<p>
	<span style="font-size:16px;">找到github plugin区域, 按照如图进行配置</span>
</p>
<p>
	<span><span style="font-size:14px;background-color:#FFFFFF;"></span></span>
</p>
<p>
	<a href="http://www.showerlee.com/archives/2893/5-17"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/51.png" alt="" width="1000" height="227" class="alignnone size-full wp-image-2907" title="" align="" /></a>
</p>
<p>
	<span style="font-size:16px;">这里需要在Credentials下添加之前创建的Personal access token作为我们Github项目向Jenkins webhook URL发送POST请求的凭证.</span>
</p>
<p>
	<a href="http://www.showerlee.com/archives/2893/6-16"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/6.png" alt="" width="1000" height="329" class="alignnone size-full wp-image-2908" title="" align="" /></a>
</p>
<p>
	<span style="font-size:16px;">点击Test connection确认连接正常</span>
</p>
<p>
	<a href="http://www.showerlee.com/archives/2893/7-14"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/7.png" alt="" width="1000" height="239" class="alignnone size-full wp-image-2910" title="" align="" /></a>
</p>
<p>
	<span style="font-size:16px;">点击左下角Save保存Github</span><span style="font-size:16px;">配置</span>
</p>
<p>
	<span style="font-size:16px;"><br />
</span>
</p>
<p>
	<span style="font-size:18px;color:#337FE5;">4.激活Jenkins job使用该插件触发webhook</span>
</p>
<p>
	<span style="font-size:16px;">这里我进入我的一个jenkins pipeline item, 按照如图激活github webhook.</span>
</p>
<p>
	<a href="http://www.showerlee.com/archives/2893/8-13"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2020/10/8.png" alt="" width="1000" height="207" class="alignnone size-full wp-image-2913" title="" align="" /></a>
</p>
<p>
	
</p>
<p>
	<span style="font-size:16px;">这样子我们就成功的配置了Github到Jenkins的webhook.</span>
</p>
<p>
	<span style="font-size:16px;">这里我提供一个demo项目, 大家可以参考这个项目进行此次的配置.</span>
</p>
<p>
	<span style="font-size:16px;"><span style="font-size:16px;"><a href="https://github.com/showerlee/gradle-demo-with-docker" rel="nofollow">https://github.com/showerlee/gradle-demo-with-docker</a></span><span style="font-size:16px;"></span><br />
</span></p>
<div>声明: 本文采用 <a rel="external" href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" title="署名-非商业性使用-相同方式共享 3.0 Unported">CC BY-NC-SA 3.0</a> 协议进行授权</div><div>转载请注明来源：<a rel="external" title="DevOps技术分享" href="http://www.showerlee.com/archives/2893">DevOps技术分享</a></div><div>本文链接地址：<a rel="external" title="Jenkins构建github webhook" href="http://www.showerlee.com/archives/2893">http://www.showerlee.com/archives/2893</a></div>]]></content:encoded>
			<wfw:commentRss>http://www.showerlee.com/archives/2893/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes自动化流水线</title>
		<link>http://www.showerlee.com/archives/2661</link>
		<comments>http://www.showerlee.com/archives/2661#comments</comments>
		<pubDate>Thu, 06 Sep 2018 03:40:13 +0000</pubDate>
		<dc:creator>showerlee</dc:creator>
				<category><![CDATA[DevTools]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Kubernetes]]></category>

		<guid isPermaLink="false">http://www.showerlee.com/?p=2661</guid>
		<description><![CDATA[因为忙于家里事情, 很久没有更新我的博客, 这里我将这半年多对Jenkins pipeline集成k8s实现自 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	因为忙于家里事情, 很久没有更新我的博客, 这里我将这半年多对Jenkins pipeline集成k8s实现自动化部署流水线的心得在这里分享给大家, 有不足之处, 还请大家多多指正.
</p>
<p>
	
</p>
<p>
	这里简单的介绍一下我们这个自动化流水线所使用到的工具:
</p>
<p>
	Jenkins Pipeline: 目前国内外DevOps, CI/CD比较主流的一种将我们软件开发周期所涉及到的环节通过pipeline流水线完美的串联在一起的自动化部署框架. 它提出了一种pipeline as a code的概念, 意在将我们的所有软件开发周期中涉及到的所有步骤(版本控制 - 代码检查 - 编译 - 单元测试 - 打包 - 测试环境部署 -&nbsp;集成测试 - 功能测试 - 生产环境部署)通过代码的方式推送给我们的Jenkins进行pipeline自动化部署, 实现将我们的自动化流水线的配置代码化, 并同样实现版本控制.&nbsp;
</p>
<p>
	目前Jenkins官方有两种pipeline的写法, 一种叫做Declarative Pipeline, 另外一种叫做Scripted Pipeline. 前者较为方便阅读, 适合初学者入门, 但相对对集成模块的兼容性以及pipeline逻辑编写的功能性较后者相对弱一些, 后者较为专业, 可以实现逻辑编写, 并支持很多主流集成模块, 推荐具有groovy脚本编写经验的人员使用.
</p>
<p>
	具体内容详见: <a href="http://www.showerlee.com/archives/1972" rel="nofollow">http://www.showerlee.com/archives/1972</a>
</p>
<p>
	
</p>
<p>
	Kubernetes: 目前这几年流行的一种容器化管理系统,&nbsp;<span style="color:#111111;font-family:Helvetica;font-size:13px;background-color:#FFFFFF;">用于自动部署、扩展和管理容器化（containerized）应用程序的开源系统。它旨在提供“跨主机集群的自动部署、扩展以及运行应用程序容器的平台”。它支持一系列容器工具, 目前主流会使用Docker作为他的主流配置容器.使用它的原因也在于它将是目前DevOps领域的一个主流的Docker容器管理系统, 目前国内外很多公司都即将或者已经把自己的传统的虚拟机架构转向为Docker微服务架构, 这里我们非常有必要去学习如何基于k8s下去做自动化部署.</span>
</p>
<p>
	<span style="color:#111111;font-family:Helvetica;font-size:13px;background-color:#FFFFFF;">具体内容详见:&nbsp;<a href="http://www.showerlee.com/archives/2200" rel="nofollow">http://www.showerlee.com/archives/2200</a></span>
</p>
<p>
	
</p>
<p>
	<span style="color:#111111;font-family:Helvetica;font-size:13px;background-color:#FFFFFF;">Helm: 这个应该算作k8s的一个功能性的工具, 它作为k8s的包管理工具, 非常方便的帮助我们整合k8s下零散的部署脚本为一个具体的项目包,&nbsp;<span style="font-family:Helvetica;font-size:13px;vertical-align:baseline;color:#111111;background-color:#FFFFFF;">最终</span><span style="color:#111111;font-family:Helvetica;font-size:13px;background-color:#FFFFFF;">简化了Kubernetes部署应用的版本控制、打包、发布、删除、更新等操作</span>.</span>
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;">具体内容详见:&nbsp;<a href="http://www.showerlee.com/archives/2455" rel="nofollow">http://www.showerlee.com/archives/2455</a></span></span>
</p>
<p>
	
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;">这里本次自动化流水线实现的部署内容就是通过编写pipeline脚本, 将一个从Docker官方拿到的centos docker镜像容器, 进行二次安装配置, 打包为一个nignx静态网站容器, 发布到我们k8s下, 期间我们会对这个容器进行一些常规的功能测试, 从而模拟我们在k8s下实现自动化流水线交付的完整架构.</span></span>
</p>
<p>
	
</p>
<p>
	<span style="font-size:13px;background-color:#FFFFFF;">本次内容涉及到的代码可以参考我的github仓库:</span>
</p>
<p>
	<span style="font-size:13px;background-color:#FFFFFF;"><a href="https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes" rel="nofollow">https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes</a><br />
</span>
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;"><br />
</span></span>
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;">Okay, Let's roll out...</span></span>
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;"><br />
</span></span>
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;"> </span></span>
</p>
<p>
	<span style="color:#337FE5;font-size:16px;"><span style="font-family:Helvetica;background-color:#FFFFFF;"><strong>安装环境</strong></span></span>
</p>
<p>
	Local Desktop: MacOS
</p>
<p>
	Virtual Machine: Virtual Box
</p>
<p>
	Virtual System: CentOS 7.4
</p>
<p>
	Jenkins: Jenkins 2.138
</p>
<p>
	Kubernetes: Kubernetes 1.9
</p>
<p>
	Docker:&nbsp;17.03.2-ce
</p>
<p>
	Helm:&nbsp;helm-v2.7.0
</p>
<p>
	kube-master 10.110.16.14
</p>
<p>
	kube-node-1 10.110.16.15
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-family:Helvetica;font-size:16px;background-color:#FFFFFF;"><strong>一. 系统环境配置</strong></span>
</p>
<p>
	<span style="color:#337FE5;">1.</span><span style="color:#337FE5;">关闭SELINUX和firewall</span>
</p>
<p>
	# vi /etc/sysconfig/selinux
</p>
<pre class="prettyprint lang-bsh">...
SELINUX=disabled 
...</pre>
<p><span># setenforce 0</span></p>
<p>
	# systemctl stop firewalld&nbsp; &amp;&amp; systemctl disable firewalld
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">2</span><span style="color:#337FE5;">.安装k8s环境.</span>
</p>
<p><a href="http://www.showerlee.com/archives/2200" rel="nofollow">http://www.showerlee.com/archives/2200</a></p>
<div>
	
</div>
<p><span style="background-color:#FFFFFF;color:#337FE5;">3.安装helm环境.</span> </p>
<p><a href="http://www.showerlee.com/archives/2455" rel="nofollow">http://www.showerlee.com/archives/2455</a></p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">4.安装Jenkins环境.</span>
</p>
<p><a href="http://www.showerlee.com/archives/1880" rel="nofollow">http://www.showerlee.com/archives/1880</a></p>
<p>
	
</p>
<p>
	<strong><span style="font-size:18px;color:#337FE5;">二. Jenkins Pipeline配置</span></strong><span style="font-size:16px;color:#337FE5;"></span>
</p>
<p>
	<span style="color:#337FE5;">1.将jenkins用户添加到默认docker用户组下, 从而保证jenkins可以直接访问</span><span style="color:#337FE5;">/var/run/docker.sock</span>
</p>
<p>
	# usermod -a -G docker jenkins
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">2.更改全局安全配置, 保证pipeline可以直接调用helm</span>
</p>
<p>
	进入Jenkins --&gt; Manage Jenkins --&gt; Configure Global Security<br />
在<span>Authorization下选择</span>Project-based Matrix Authorization Strategy
</p>
<p>
	配置<span>Anonymous User具有Read Jenkins Jobs的权限</span>
</p>
<p>
	如图:
</p>
<p>
	<span><span style="font-size:13px;background-color:#FFFFFF;"></span></span>
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=2680"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2018/09/permision.png" alt="" width="700" height="326" class="alignnone size-full wp-image-2680" title="" align="" /></a>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">3.配置jenkins用户加载kubectl环境变量.</span>
</p>
<p>
	#&nbsp;mkdir -p /home/jenkins/.kube
</p>
<p>
	# cp -i /etc/kubernetes/admin.conf /home/jenkins/.kube/config
</p>
<p>
	# chown jenkins:jenkins /home/jenkins/.kube/config
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">4.配置github与dockerhub的Jenkins账户凭证, 后面pipeline对应模块需要调用.</span>
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=2687"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2018/09/credential.png" alt="" width="700" height="326" class="alignnone size-full wp-image-2687" title="" align="" /></a><span></span><a href="http://www.showerlee.com/?attachment_id=2688"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2018/09/credential1.png" alt="" width="700" height="289" class="alignnone size-large wp-image-2688" title="" align="" /></a>
</p>
<p>
	
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">5.创建pipeline任务</span>
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=2683"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2018/09/pipeline1.png" alt="" width="800" height="441" class="alignnone size-full wp-image-2683" title="" align="" /></a>
</p>
<pre class="prettyprint">#!groovy

def kubectlTest() {
    // Test that kubectl can correctly communication with the Kubernetes API
    echo "running kubectl test"
    sh "kubectl get nodes"

}

def helmLint(String chart_dir) {
    // lint helm chart
    sh "/usr/local/bin/helm lint ${chart_dir}"

}

def helmDeploy(Map args) {
    //configure helm client and confirm tiller process is installed

    if (args.dry_run) {
        println "Running dry-run deployment"

        sh "/usr/local/bin/helm upgrade --dry-run --debug --install ${args.name} ${args.chart_dir} --set ImageTag=${args.tag},Replicas=${args.replicas},Cpu=${args.cpu},Memory=${args.memory},DomainName=${args.name} --namespace=${args.name}"
    } else {
        println "Running deployment"
        sh "/usr/local/bin/helm upgrade --install ${args.name} ${args.chart_dir} --set ImageTag=${args.tag},Replicas=${args.replicas},Cpu=${args.cpu},Memory=${args.memory},DomainName=${args.name} --namespace=${args.name}"

        echo "Application ${args.name} successfully deployed. Use helm status ${args.name} to check"
    }
}



timeout(time: 2000, unit: 'SECONDS') {
    node {
        println "----------------------------------------------------------------------------"
        stage 'Check out pipeline from GitHub Repo'
        //git url: 'https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git'
        git branch: 'master',
            credentialsId: 'showerlee-github',
            url: 'https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git'

        // Setup the Docker Registry (Docker Hub) + Credentials 
        registry_url = "https://index.docker.io/v1/" // Docker Hub
        docker_creds_id = "showerlee-dockerhub" // name of the Jenkins Credentials ID

        def pwd = pwd()
        def chart_dir = "${pwd}/charts/newegg-nginx"

        // Add build tag version
        Properties props = new Properties()
        File propsFile = new File("${pwd}/promote.properties")
        props.load(propsFile.newDataInputStream())
        def build_tag_raw = props.getProperty('BUILD_TAG')
        float build_tag = Float.parseFloat(build_tag_raw)+0.1;
        println("Set current build_tag="+build_tag+" temporarily")

        //Set build_tag to index.html
        sh """
        echo "&lt;h1&gt;Welcome Newegg Nginx Test Version: ${build_tag}&lt;/h1&gt;" &gt; index.html
        """

        def inputFile = readFile('config.json')
        def config = new groovy.json.JsonSlurperClassic().parseText(inputFile)
        println "pipeline config ==&gt; ${config}"
        println "----------------------------------------------------------------------------"
        
        stage 'Register DockerHub'
        echo "[INFO] Register Dockerhub"
        docker.withRegistry("${registry_url}", "${docker_creds_id}") {
        
            // Set up the container to build 
            maintainer_name = "showerlee"
            container_name = "nginx-test"
            println "----------------------------------------------------------------------------"

            stage "Build Nginx Container"
            echo "[INFO] Building Nginx with docker.build(${maintainer_name}/${container_name}:${build_tag})"
            container = docker.build("${maintainer_name}/${container_name}:${build_tag}", '.')
            println "----------------------------------------------------------------------------"
            try {
                
                // Start Testing
                stage "Spin up Nginx Container"
                echo "[INFO] Spin up Nginx Container"
                
                // Run the container with the env file, mounted volumes and the ports:
                docker.image("${maintainer_name}/${container_name}:${build_tag}").withRun("--name=${container_name}  -p 80:80 ")  { c -&gt;
                       
                    // wait for the django server to be ready for testing
                    // the 'waitUntil' block needs to return true to stop waiting
                    // in the future this will be handy to specify waiting for a max interval: 
                    // <a href="https://issues.jenkins-ci.org/browse/JENKINS-29037" rel="nofollow">https://issues.jenkins-ci.org/browse/JENKINS-29037</a>
                    //
                    waitUntil {
                        sh """
                        set +x
                        ss -antup | grep :::80[^0-9] | grep LISTEN | wc -l | tr -d '\n' &gt; /tmp/wait_results
                        set -x
                        """
                        wait_results = readFile '/tmp/wait_results'

                        echo "[INFO] Wait Results(${wait_results})"
                        if ("${wait_results}" == "1")
                        {
                            echo "[INFO] Nginx is listening on port 80"
                            sh "rm -f /tmp/wait_results"
                            return true
                        }
                        else
                        {
                            echo "[INFO] Nginx is not listening on port 80 yet"
                            return false
                        }
                    } // end of waitUntil
                    
                    // At this point Nginx is running
                    echo "[INFO] Docker Container is running"
                    input 'You can check the running container on docker build server now! Click Proceed to next stage...'    
                    // this pipeline is using 3 tests 
                    // by setting it to more than 3 you can test the error handling and see the pipeline Stage View error message
                    MAX_TESTS = 3
                    for (test_num = 1; test_num &lt;= MAX_TESTS; test_num++) {     
                        println "----------------------------------------------------------------------------"   
                        echo "Running Test(${test_num})"
                    
                        expected_results = 0
                        if (test_num == 1 ) 
                        {
                            // Test we can download the home page from the running docker container
                            echo "[INFO] Check validation of home page"
                            sh """
                            set +x
                            docker exec -t ${container_name} curl -s <a href="http://localhost" rel="nofollow">http://localhost</a> | grep Welcome | wc -l | tr -d '\n' &gt; /tmp/test_results
                            set -x
                            """
                            expected_results = 1
                        }
                        else if (test_num == 2)
                        {
                            // Test if port 80 is exposed
                            echo "[INFO] Check if port 80 is exposed"
                            sh """
                            set +x
                            docker inspect --format '{{ (.NetworkSettings.Ports) }}' ${container_name}
                            docker inspect --format '{{ (.NetworkSettings.Ports) }}' ${container_name} | grep map | grep '80/tcp:' | wc -l | tr -d '\n' &gt; /tmp/test_results
                            set -x
                            """
                            expected_results = 1
                        }
                        else if (test_num == 3)
                        {
                            // Test there's nothing established on the port since nginx is not running:
                            echo "[INFO] Check if nothing established from nginx container"
                            sh """
                            set +x
                            docker exec -t ${container_name} ss -apn | grep 80 | grep ESTABLISHED | wc -l | tr -d '\n' &gt; /tmp/test_results
                            set -x
                            """
                            expected_results = 0
                        }
                        else
                        {
                            err_msg = "Missing Test(${test_num})"
                            echo "[ERROR] ${err_msg}"
                            currentBuild.result = 'FAILURE'
                            error "Failed to finish container testing with Message(${err_msg})"
                        }
                        
                        // Now validate the results match the expected results
                        stage "Test(${test_num}) - Validate Results"
                        test_results = readFile '/tmp/test_results'
                        echo "[INFO] Test(${test_num}) Results($test_results) == Expected(${expected_results})"
                        sh """
                        set +x
                        if [ \"${test_results}\" != \"${expected_results}\" ]; 
                        then 
                            echo \" --------------------- Test(${test_num}) Failed--------------------\"
                            echo \" - Test(${test_num}) Failed\"
                            exit 1
                        else 
                            echo \" - Test(${test_num}) Passed\"
                            exit 0
                        fi
                        set -x
                        """

                        echo "[INFO] Finished Running Test(${test_num})"
                    
                        // cleanup after the test run
                        sh "rm -f /tmp/test_results"
                        currentBuild.result = 'SUCCESS'
                    }
                }
                
            } catch (Exception err) {
                err_msg = "Test had Exception(${err})"
                currentBuild.result = 'FAILURE'
                error "FAILED - Stopping build for Error(${err_msg})"
            }
            println "----------------------------------------------------------------------------"
            stage "Push to DockerHub"
            input 'Do you approve to push?'
            container.push()
            currentBuild.result = 'SUCCESS'
            println "----------------------------------------------------------------------------"
            stage "Push properties to git repo"
            echo "Push current build_tag="+build_tag+" to git repo"
            withCredentials([usernamePassword(credentialsId: 'showerlee-github', passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
                sh """
                set +x
                git --version
                echo 'BUILD_TAG=${build_tag}' &gt; ${pwd}/promote.properties
                git config --global user.email "showerlee@vip.qq.com"
                git config --global user.name "showerlee"
                git add ${pwd}/promote.properties ${pwd}/index.html
                git commit -m"Update docker tag to ${build_tag}"
                git push --set-upstream <a href="https://$" rel="nofollow">https://$</a>{GIT_USERNAME}:${GIT_PASSWORD}@github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git master
                set -x
                """
            }
            println "----------------------------------------------------------------------------"
            
        }
        
        stage ('helm test') { 
            echo "[INFO] Start helm test"   
            // run helm chart linter
            echo "[INFO] Run helm chart linter"
            helmLint(chart_dir)

            // dry-run helm chart installation
            echo "[INFO] Dry-run helm chart installation"
            helmDeploy(
                dry_run       : true,
                name          : config.app.name,
                chart_dir     : chart_dir,
                tag           : build_tag,
                replicas      : config.app.replicas,
                cpu           : config.app.cpu,
                memory        : config.app.memory
            )
            println "----------------------------------------------------------------------------"
        }
        
        stage ('helm deploy') {
            input 'Do you approve to deploy?'
            echo "[INFO] Start helm deployment"
            // Deploy using Helm chart
            helmDeploy(
                dry_run       : false,
                name          : config.app.name,
                chart_dir     : chart_dir,
                tag           : build_tag,
                replicas      : config.app.replicas,
                cpu           : config.app.cpu,
                memory        : config.app.memory
            )
            echo "[INFO] Deployment Finished..."
        }
        
        ///////////////////////////////////////
        //
        // Coming Soon Feature Enhancements
        //
        // 1. Add Docker Compose testing as a new Pipeline item that is initiated after this one for "Integration" testing
        // 2. Make sure to set the Pipeline's "Throttle builds" to 1 because the docker containers will collide on resources like ports and names
        // 3. Should be able to parallelize the docker.withRegistry() methods to ensure the container is running on the slave
        // 4. After the tests finish (and before they start), clean up container images to prevent stale docker image builds from affecting the current test run
    }
}</pre>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">6.执行pipeline任务构建</span>
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=2690"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2018/09/pipeline3.png" alt="" width="800" height="329" class="alignnone size-full wp-image-2690" title="" align="" /></a>
</p>
<pre class="prettyprint">Started by user admin
Obtained Jenkinsfile from git <a href="https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git" rel="nofollow">https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git</a>
[Pipeline] timeout
Timeout set to expire in 33 min
[Pipeline] {
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/kube-helm-pipeline@2
[Pipeline] {
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] stage (Check out pipeline from GitHub Repo)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Check out pipeline from GitHub Repo
Proceeding
[Pipeline] git
 &gt; git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
 &gt; git config remote.origin.url <a href="https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git" rel="nofollow">https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git</a> # timeout=10
Fetching upstream changes from <a href="https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git" rel="nofollow">https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git</a>
 &gt; git --version # timeout=10
using GIT_ASKPASS to set credentials github credential
 &gt; git fetch --tags --progress <a href="https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git" rel="nofollow">https://github.com/showerlee/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git</a> +refs/heads/*:refs/remotes/origin/*
 &gt; git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 &gt; git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision ce4fc2593333f3ed89cd5654966919b0aa97628d (refs/remotes/origin/master)
 &gt; git config core.sparsecheckout # timeout=10
 &gt; git checkout -f ce4fc2593333f3ed89cd5654966919b0aa97628d
 &gt; git branch -a -v --no-abbrev # timeout=10
 &gt; git branch -D master # timeout=10
 &gt; git checkout -b master ce4fc2593333f3ed89cd5654966919b0aa97628d
Commit message: "Update docker tag to 1.5"
 &gt; git rev-list --no-walk ce4fc2593333f3ed89cd5654966919b0aa97628d # timeout=10
[Pipeline] pwd
[Pipeline] echo
Set current build_tag=1.6 temporarily
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ echo '&lt;h1&gt;Welcome Newegg Nginx Test Version: 1.6&lt;/h1&gt;'
[Pipeline] readFile
[Pipeline] echo
pipeline config ==&gt; [app:[memory:128Mi, replicas:3, name:newegg-nginx, cpu:10m], pipeline:[library:[branch:master], enabled:true]]
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] stage (Register DockerHub)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Register DockerHub
Proceeding
[Pipeline] echo
[INFO] Register Dockerhub
[Pipeline] withEnv
[Pipeline] {
[Pipeline] withDockerRegistry
$ docker login -u showerlee -p ******** <a href="https://index.docker.io/v1/" rel="nofollow">https://index.docker.io/v1/</a>
Login Succeeded
[Pipeline] {
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] stage (Build Nginx Container)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Build Nginx Container
Proceeding
[Pipeline] echo
[INFO] Building Nginx with docker.build(showerlee/nginx-test:1.6)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ docker build -t showerlee/nginx-test:1.6 .
Sending build context to Docker daemon 2.164 MB

Step 1/6 : FROM centos:centos7
 ---&gt; 5182e96772bf
Step 2/6 : MAINTAINER showerlee
 ---&gt; Using cache
 ---&gt; cc77ae5c175a
Step 3/6 : RUN yum -y update         &amp;&amp; yum clean all         &amp;&amp; yum install -y epel-release         &amp;&amp; yum install -y nginx iproute
 ---&gt; Using cache
 ---&gt; 2c718c146ba5
Step 4/6 : EXPOSE 80
 ---&gt; Using cache
 ---&gt; 829b29a719e6
Step 5/6 : COPY index.html /usr/share/nginx/html/
 ---&gt; Using cache
 ---&gt; 22e805b84cee
Step 6/6 : CMD nginx -g daemon off;
 ---&gt; Using cache
 ---&gt; de02105d9033
Successfully built de02105d9033
[Pipeline] dockerFingerprintFrom
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] stage (Spin up Nginx Container)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Spin up Nginx Container
Proceeding
[Pipeline] echo
[INFO] Spin up Nginx Container
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ docker run -d --name=nginx-test -p 80:80 showerlee/nginx-test:1.6
[Pipeline] dockerFingerprintRun
[Pipeline] waitUntil
[Pipeline] {
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
[Pipeline] readFile
[Pipeline] echo
[INFO] Wait Results(1)
[Pipeline] echo
[INFO] Nginx is listening on port 80
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ rm -f /tmp/wait_results
[Pipeline] }
[Pipeline] // waitUntil
[Pipeline] echo
[INFO] Docker Container is running
[Pipeline] input
You can check the running container on docker build server now! Click Proceed to next stage...
Proceed or Abort
Approved by admin
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] echo
Running Test(1)
[Pipeline] echo
[INFO] Check validation of home page
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
[Pipeline] stage (Test(1) - Validate Results)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Test(1) - Validate Results
Proceeding
[Pipeline] readFile
[Pipeline] echo
[INFO] Test(1) Results(1) == Expected(1)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
 - Test(1) Passed
[Pipeline] echo
[INFO] Finished Running Test(1)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ rm -f /tmp/test_results
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] echo
Running Test(2)
[Pipeline] echo
[INFO] Check if port 80 is exposed
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
map[80/tcp:[{0.0.0.0 80}]]
[Pipeline] stage (Test(2) - Validate Results)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Test(2) - Validate Results
Proceeding
[Pipeline] readFile
[Pipeline] echo
[INFO] Test(2) Results(1) == Expected(1)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
 - Test(2) Passed
[Pipeline] echo
[INFO] Finished Running Test(2)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ rm -f /tmp/test_results
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] echo
Running Test(3)
[Pipeline] echo
[INFO] Check if nothing established from nginx container
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
[Pipeline] stage (Test(3) - Validate Results)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Test(3) - Validate Results
Proceeding
[Pipeline] readFile
[Pipeline] echo
[INFO] Test(3) Results(0) == Expected(0)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
 - Test(3) Passed
[Pipeline] echo
[INFO] Finished Running Test(3)
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ rm -f /tmp/test_results
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ docker stop 05a19a7c8519a04cc03029d7273a8e2ae3363e74a03b6d4167dfbec0bf6ee978
05a19a7c8519a04cc03029d7273a8e2ae3363e74a03b6d4167dfbec0bf6ee978
+ docker rm -f 05a19a7c8519a04cc03029d7273a8e2ae3363e74a03b6d4167dfbec0bf6ee978
05a19a7c8519a04cc03029d7273a8e2ae3363e74a03b6d4167dfbec0bf6ee978
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] stage (Push to DockerHub)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Push to DockerHub
Proceeding
[Pipeline] input
Do you approve to push?
Proceed or Abort
Approved by admin
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ docker tag showerlee/nginx-test:1.6 index.docker.io/showerlee/nginx-test:1.6
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ docker push index.docker.io/showerlee/nginx-test:1.6
The push refers to a repository [docker.io/showerlee/nginx-test]
aedd55edeb74: Preparing
85e9d4859663: Preparing
1d31b5806ba4: Preparing
85e9d4859663: Layer already exists
1d31b5806ba4: Layer already exists
aedd55edeb74: Retrying in 5 seconds
aedd55edeb74: Retrying in 4 seconds
aedd55edeb74: Retrying in 3 seconds
aedd55edeb74: Retrying in 2 seconds
aedd55edeb74: Retrying in 1 second
aedd55edeb74: Pushed
1.6: digest: sha256:8ee214129c880a0d759837daf30c31772797fa6709f11edd9e30db6891710de4 size: 948
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] stage (Push properties to git repo)
Using the ‘stage’ step without a block argument is deprecated
Entering stage Push properties to git repo
Proceeding
[Pipeline] echo
Push current build_tag=1.6 to git repo
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ set +x
git version 1.8.3.1
[master cdbb62c] Update docker tag to 1.6
 2 files changed, 2 insertions(+), 2 deletions(-)
To <a href="https://****:****@github.com/****/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git" rel="nofollow">https://****:****@github.com/****/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git</a>
   ce4fc25..cdbb62c  master -&gt; master
Branch master set up to track remote branch master from <a href="https://****:****@github.com/****/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git" rel="nofollow">https://****:****@github.com/****/Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes.git</a>.
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] }
[Pipeline] // withDockerRegistry
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] stage
[Pipeline] { (helm test)
[Pipeline] echo
[INFO] Start helm test
[Pipeline] echo
[INFO] Run helm chart linter
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ /usr/local/bin/helm lint /var/jenkins_home/workspace/kube-helm-pipeline@2/charts/newegg-nginx
==&gt; Linting /var/jenkins_home/workspace/kube-helm-pipeline@2/charts/newegg-nginx
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, no failures
[Pipeline] echo
[INFO] Dry-run helm chart installation
[Pipeline] echo
Running dry-run deployment
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ /usr/local/bin/helm upgrade --dry-run --debug --install newegg-nginx /var/jenkins_home/workspace/kube-helm-pipeline@2/charts/newegg-nginx --set ImageTag=1.6,Replicas=3,Cpu=10m,Memory=128Mi,DomainName=newegg-nginx --namespace=newegg-nginx
[debug] Created tunnel using local port: '39460'

[debug] SERVER: "localhost:39460"

Release "newegg-nginx" does not exist. Installing it now.
[debug] CHART PATH: /var/jenkins_home/workspace/kube-helm-pipeline@2/charts/newegg-nginx

NAME:   newegg-nginx
REVISION: 1
RELEASED: Sun Aug 26 01:38:02 2018
CHART: newegg-nginx-1.0.0
USER-SUPPLIED VALUES:
Cpu: 10m
DomainName: newegg-nginx
ImageTag: "1.6"
Memory: 128Mi
Replicas: 3

COMPUTED VALUES:
ContainerPort: 80
Cpu: 10m
DomainName: newegg-nginx
Image: showerlee/nginx-test
ImagePullPolicy: Always
ImageTag: "1.6"
Imagetag: latest
Memory: 128Mi
Replicas: 3
ServicePort: 80
ServiceType: NodePort

HOOKS:
MANIFEST:

---
# Source: newegg-nginx/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: newegg-nginx-newegg-nginx
  labels:    
    app: newegg-nginx-newegg-nginx
    version: 1.0.0
    release: newegg-nginx
spec:
  type: "NodePort"
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: newegg-nginx-newegg-nginx
---
# Source: newegg-nginx/templates/deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: newegg-nginx-newegg-nginx
  labels:    
    app: newegg-nginx-newegg-nginx
    version: 1.0.0
    release: newegg-nginx
spec:
  replicas: 3
  template:
    metadata:
      labels:        
        app: newegg-nginx-newegg-nginx
        version: 1.0.0
        release: newegg-nginx
    spec:
      containers:
        - name: newegg-nginx
          image: "showerlee/nginx-test:1.6"
          imagePullPolicy: "Always"
          ports:
            - containerPort: 80
              protocol: TCP
          resources:
            requests:
              cpu: "10m"
              memory: "128Mi"
---
# Source: newegg-nginx/templates/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: newegg-nginx-newegg-nginx
  labels:    
    app: newegg-nginx-newegg-nginx
    version: 1.0.0
    release: newegg-nginx
spec:
  rules:
  - host: newegg-nginx.buyabs.corp
    http:
      paths:
      - path: /
        backend:
          serviceName: newegg-nginx-newegg-nginx
          servicePort: 80
[Pipeline] echo
----------------------------------------------------------------------------
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (helm deploy)
[Pipeline] input
Do you approve to deploy?
Proceed or Abort
Approved by admin
[Pipeline] echo
[INFO] Start helm deployment
[Pipeline] echo
Running deployment
[Pipeline] sh
[kube-helm-pipeline@2] Running shell script
+ /usr/local/bin/helm upgrade --install newegg-nginx /var/jenkins_home/workspace/kube-helm-pipeline@2/charts/newegg-nginx --set ImageTag=1.6,Replicas=3,Cpu=10m,Memory=128Mi,DomainName=newegg-nginx --namespace=newegg-nginx
Release "newegg-nginx" does not exist. Installing it now.
NAME:   newegg-nginx
LAST DEPLOYED: Sun Aug 26 01:38:24 2018
NAMESPACE: newegg-nginx
STATUS: DEPLOYED

RESOURCES:
==&gt; v1beta1/Ingress
NAME                       HOSTS                     ADDRESS  PORTS  AGE
newegg-nginx-newegg-nginx  newegg-nginx.buyabs.corp  80       1m

==&gt; v1/Pod(related)
NAME                                        READY  STATUS             RESTARTS  AGE
newegg-nginx-newegg-nginx-56c478c888-6n6rt  0/1    ContainerCreating  0         1m
newegg-nginx-newegg-nginx-56c478c888-hsbcp  0/1    ContainerCreating  0         1m
newegg-nginx-newegg-nginx-56c478c888-vdfgb  0/1    ContainerCreating  0         1m

==&gt; v1/Service
NAME                       TYPE      CLUSTER-IP     EXTERNAL-IP  PORT(S)       AGE
newegg-nginx-newegg-nginx  NodePort  10.97.200.124  &lt;none&gt;       80:32239/TCP  1m

==&gt; v1beta1/Deployment
NAME                       DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
newegg-nginx-newegg-nginx  3        3        3           0          1m


[Pipeline] echo
Application newegg-nginx successfully deployed. Use helm status newegg-nginx to check
[Pipeline] echo
[INFO] Deployment Finished...
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // timeout
[Pipeline] End of Pipeline
Finished: SUCCESS</pre>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">7.验证结果</span>
</p>
<pre id="out" class="console-output">
<p>
	<a href="http://www.showerlee.com/archives/2661/web"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2018/09/web.png" alt="" width="500" height="93" class="alignnone size-full wp-image-2692" title="" align="" /></a> 
</p>
</pre>
<p>
	这样我们就成功的利用Jenkins集成k8s+helm实现将我们的静态网站部署到我们的kubernetes集群中.
</p>
<p>
	
</p>
<p>
	大功告成...
</p>
<p>
	
</p>
<p>
	</p>
<div>声明: 本文采用 <a rel="external" href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" title="署名-非商业性使用-相同方式共享 3.0 Unported">CC BY-NC-SA 3.0</a> 协议进行授权</div><div>转载请注明来源：<a rel="external" title="DevOps技术分享" href="http://www.showerlee.com/archives/2661">DevOps技术分享</a></div><div>本文链接地址：<a rel="external" title="Jenkins-Pipeline-CI-CD-with-Helm-on-Kubernetes自动化流水线" href="http://www.showerlee.com/archives/2661">http://www.showerlee.com/archives/2661</a></div>]]></content:encoded>
			<wfw:commentRss>http://www.showerlee.com/archives/2661/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>浅谈Jenkins Pipeline</title>
		<link>http://www.showerlee.com/archives/1972</link>
		<comments>http://www.showerlee.com/archives/1972#comments</comments>
		<pubDate>Wed, 19 Jul 2017 09:34:35 +0000</pubDate>
		<dc:creator>showerlee</dc:creator>
				<category><![CDATA[DevTools]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Jenkins Pipeline]]></category>

		<guid isPermaLink="false">http://www.showerlee.com/?p=1972</guid>
		<description><![CDATA[已经很久很久没有更新我的空间了, 最近刚好工作上的变动让我有时间去静下心来去整理一下这一年来学到的东西. 谈到 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	已经很久很久没有更新我的空间了, 最近刚好工作上的变动让我有时间去静下心来去整理一下这一年来学到的东西.
</p>
<p>
	谈到Jenkins, 大家肯定耳熟能详, 持续集成/持续交付, 自动化部署工具, 测试工具, 配合目前我们绝大多说开发工具, 简直是万能的瑞士军刀.
</p>
<p>
	接触Devops这个概念两年有余, 使用了很多开发工具诸如JIRA, Gitlab, Ansible, SVN, NEXUS, CHEF, FISHEYE, Confluence等等, 唯独Jenkins让我印象最为深刻.
</p>
<p>
	为什么呢?
</p>
<p>
	还记得我之前写过几篇文章, 介绍了Jenkins配合ansible, gitlab实现持续集成自动化部署. Jenkins作为核心的部署工具将原来只能通过命令行或者二次开发才能实现部署方式搬到前台, 将更多的GUI可操作空间交给DevOps和开发, 加之完善的权限分配规范, 让运维与开发能够和谐的在这个系统间协同工作.&nbsp;
</p>
<p>
	<a href="http://www.showerlee.com/archives/tag/jenkins-pipeline" title="查看Jenkins Pipeline中的全部文章" class="tag_link">Jenkins Pipeline</a>, 我觉得是Jenkins2.0以后一个革命性的更新, 那就是用一种全新的Pipeline code方式, 将我们原来意义上的手动配置每一个Jenkins Job的具体配置项变成将所有配置代码化, 并再次配合Gitlab等版本控制系统去保存我们的代码配置, 这样子无论Job在未来需要更新, 或者需要回滚到之前的某一个配置, 又或者一个新的Job需要参考之前的老Job的配置并直接套用, 又或者我们需要去批量生成若干个Job配置, 我们都可以像管理软件代码的方式去管理我们的Jenkins Job配置. 这样就极大的简化我们自动化部署的结构, 将以前需要手动配置Job的这个步骤, 直接代码化. 最终体现出我们DevOps的最终目标.&nbsp;
</p>
<p>
	<a href="http://www.showerlee.com/archives/1972/realworld-pipeline-flow-2"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2017/07/realworld-pipeline-flow1.png" alt="realworld-pipeline-flow" width="1024" height="387" class="alignnone size-full wp-image-2016" /></a>
</p>
<p>
	目前来说Jenkins pipeline应该算上是一个出生不久但我觉得比较成熟的概念, 如果你要认真去了解他, 我觉得会给你带来意想不到的收获.
</p>
<p>
	
</p>
<p>
	Jenkinsfile (Declarative Pipeline)
</p>
<pre class="prettyprint">Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any 

    stages {
        stage('Build') { 
            steps { 
                sh 'make' 
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh 'make publish'
            }
        }
    }
}</pre>
<p>
	这是一个比较简单JenkinsFile(pipeline code), 简单来说包含了三块我们日常基本的自动化部署步骤, 之所以会命名Pipeline, 可以说是因为我们可以在不同的stage下去编写我们的具体部署需求, 然后通过Pipeline将这些stage块连接起来, 不仅能够将我们的部署结构分割成块状并可以直接通过查询这个块的的日志来定位/排错我们的部署内容, 而且将一个块状内的代码方法化, 实现不同块之间的相互调用, 这样就在原有的Jenkins平行逻辑配置的基础上, 加入逻辑化的功能, 而且本身配置代码化又便于我们去做版本控制, 可以说是在原有Jenkins下做出的重大的变革.&nbsp;
</p>
<p>
	接下来我将利用上述代码编写一个Jenkins pipeline示例:
</p>
<p>
	首先我们将上面的代码写入一个我们新建好的pipeline job
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=1991"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2017/07/pipe21.jpg" alt="pipe2" width="1024" height="321" class="alignnone size-full wp-image-1991" /></a>
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=1993"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2017/07/pipe31.jpg" alt="pipe3" width="1024" height="475" class="alignnone size-full wp-image-1993" /></a>
</p>
<p>
	
</p>
<p>
	这里我们可以清晰的看到每一个stage的名字, 是否执行成功, 涉及到的版本控制commit变更, 以及所用到的平均时间.
</p>
<p></p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=1988"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2017/07/pipeline11.jpg" alt="pipeline1" width="1024" height="352" class="alignnone size-full wp-image-1988" /></a>
</p>
<p>
	我们也可以通过Pipeline script from SCM - Git的方式实现我刚才所说的将我们具体的pipeline code保存到git上, 利用Jenkins git将代码抓取到该job实现JenkinsFile版本控制.
</p>
<p>
	<a href="http://www.showerlee.com/?attachment_id=1996"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2017/07/pipe5.jpg" alt="pipe5" width="1024" height="721" class="alignnone size-full wp-image-1996" /></a>
</p>
<p>
	
</p>
<p>
	最后, 无论是我们DevOps去编写/排错job code还是开发去测试代码质量, 都可以将我们在执行这个job过程中出现的任何问题精确的定位到每一个块状stage下, 从而提高我们工作效率.
</p>
<p>
	接下来我会在空间陆续更新Pipeline的一些语法及常见编写规范.
</p>
<p>
	希望大家有兴趣可以尝试一下Jenkins这个新功能, 下面是具体的Pipeline语法及编写文档.
</p>
<p>
	Pipeline Guide:
</p>
<p><a href="https://jenkins.io/doc/book/pipeline" rel="nofollow">https://jenkins.io/doc/book/pipeline</a></p>
<p><a href="https://jenkins.io/doc/book/pipeline/syntax" rel="nofollow">https://jenkins.io/doc/book/pipeline/syntax</a></p>
<p></p>
<div>声明: 本文采用 <a rel="external" href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" title="署名-非商业性使用-相同方式共享 3.0 Unported">CC BY-NC-SA 3.0</a> 协议进行授权</div><div>转载请注明来源：<a rel="external" title="DevOps技术分享" href="http://www.showerlee.com/archives/1972">DevOps技术分享</a></div><div>本文链接地址：<a rel="external" title="浅谈Jenkins Pipeline" href="http://www.showerlee.com/archives/1972">http://www.showerlee.com/archives/1972</a></div>]]></content:encoded>
			<wfw:commentRss>http://www.showerlee.com/archives/1972/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Jenkins+Ansible+Gitlab自动化部署三剑客</title>
		<link>http://www.showerlee.com/archives/1880</link>
		<comments>http://www.showerlee.com/archives/1880#comments</comments>
		<pubDate>Fri, 11 Mar 2016 05:00:47 +0000</pubDate>
		<dc:creator>showerlee</dc:creator>
				<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[gitlab]]></category>

		<guid isPermaLink="false">http://www.showerlee.com/?p=1880</guid>
		<description><![CDATA[最近一直在学习Ansible的一些playbook的写法, 所以一直没有怎么更新, 想到目前大家对诸如salt [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	
</p>
<p>
	最近一直在学习<a href="http://www.showerlee.com/archives/tag/ansible" title="查看Ansible中的全部文章" class="tag_link">Ansible</a>的一些playbook的写法, 所以一直没有怎么更新, 想到目前大家对诸如saltstack, docker, <a href="http://www.showerlee.com/archives/tag/ansible" title="查看Ansible中的全部文章" class="tag_link">Ansible</a>等自动化部署相关的工具很感兴趣, 但又苦于没有可学习的中文实例, 这里我就把我这几个月所接触到目前国外比较流行的部署经验给大家分享一下.
</p>
<p>
	<span style="line-height:1.5;">首先给大家介绍的是<a href="http://www.showerlee.com/archives/tag/ansible" title="查看Ansible中的全部文章" class="tag_link">Ansible</a>, 恩, 重要的问题说三遍, 不是Saltstack, Ansible作为一个python写的自动化部署工具, 确实较之前我所接触的Chef, saltstack, puppet更有自己的一些优势, 首先就是agentless, 无需在Linux client安装任何服务即可无缝连接Linux default ssh端口进行部署(windows需要安装winrm 开启ssh服务), 这点其实我觉得非常重要, 可以想象很多公司本身是对network管理非常严格的, 在部署一个产品的同时你需要考虑很多时间成本, 使用其他部署工具本身非常棘手的问题就是去申请开端口, client量少的话, 我们可以去等, 多的话本身你去request, waiting, unblock port等等long long process.... 最后会耗费很长时间. 这个对很多产品本身就是很致命的. 不推荐Saltstack的原因也是因为其需要在每台agent逐一去安装client service并测试, 这本身就会耗费一些时间成本.</span>
</p>
<p>
	<span style="line-height:1.5;">其他呢? 其实我觉得就是容易上手, 语法简单, 有现成模板让你去学习, 加之是我们非常喜爱的python语法, why not?</span>
</p>
<p>
	<span style="line-height:1.5;">Jenkins不用我多说, 估计懂行的人都在用它, 开源, 轻量级, 兼容性和扩展性强, 直观的GUI管理这都是它的优势, 配合Ansible我觉得用起来会非常easy going.</span>
</p>
<p>
	<span style="line-height:1.5;">最后提一下Gitlab, 为什么要用Gitlab? 他作为一个代码版本控制系统和部署有什么关系呢? 其实这里就涉及一个我们Ansible playbook管理问题, 试想我们需要维护一个公司庞大的server集群, 我们所有需要部署的机器或者产品会对应我们相对的部署脚本, 我们使用的Ansible playbook如果只是保存在Ansible Server的具体某个目录, 这本身就不便于我们进行编写维护更新(想想每次都跑到远程去编写playbook或者每次在本地编写好后再upload到远程我都会脑补数以万计的草泥马从我眼前呼啸而来).</span>
</p>
<p>
	<span style="line-height:1.5;">这里Gitlab就给我们提供一个非常方便以及直观的Playbook management. 我们需要做的其实就是在Gitlab去建立一个对应产品或者server的playbook仓库, 然后我们在本地写好后直接commit到这个仓库, 最后在部署的时候, 去让Jenkins pull这个playbook到其workspace, 并作为一个Job去run这个playbook, 这样是不是很规范, 而且便于管理?</span>
</p>
<p>
	<span style="line-height:1.5;">当然Ansible本身企业版Tower也会提供一个类似管理并维护playbook以及监控ansible本身running process的GUI管理系统, 用起来也很不错, 但作为收费版本, 我们在这里就不做过多阐述了.</span>
</p>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;">这里我推荐Jenkins和Ansible可以安装到同一个环境作为部署server, Gitlab作为版本控制系统可单独部署在另一台server.</span>
</p>
<p>
	<span style="color:#E53333;">总结:</span>
</p>
<p>
	<span style="color:#E53333;">Jenkins首先从Gitlab去抓取我们写好的具体产品的playbook, 并使用virtualenv下的Ansible相关命令, 保证我们在一个clean的环境下使用stable version去批量部署我们的产品到远程client.</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#E53333;font-size:16px;">Let's go.....</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:16px;">一. 安装环境</span>
</p>
<p>
	System: CentOS 6.7 x64 (deploy.example.com)
</p>
<p>
	Jenkins:&nbsp;Jenkins ver. 1.650
</p>
<p>
	Ansible: Ansible 2.1.0
</p>
<p>
	Gitlab:&nbsp;GitLab 7.14.3
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:16px;">二. Jenkins配置</span>
</p>
<p>
	我们创建deploy用户作为jenkins_user, workspace为deploy家目录下的jenkins目录.
</p>
<p>
	# su - root
</p>
<p>
	# adduser deploy
</p>
<p>
	# wget -O /etc/yum.repos.d/jenkins.repo <a href="http://pkg.jenkins-ci.org/redhat/jenkins.repo" rel="nofollow">http://pkg.jenkins-ci.org/redhat/jenkins.repo</a>
</p>
<p>
	<span style="line-height:1.5;"># rpm --import <a href="https://jenkins-ci.org/redhat/jenkins-ci.org.key" rel="nofollow">https://jenkins-ci.org/redhat/jenkins-ci.org.key</a></span>
</p>
<p>
	<span style="line-height:1.5;"># yum install jenkins -y</span>
</p>
<p>
	<span style="line-height:1.5;"># vi&nbsp;/etc/sysconfig/jenkins</span>
</p>
<p>
	<span style="line-height:1.5;"> </span>
</p>
<pre class="prettyprint lang-bsh">...
JENKINS_HOME="/home/deploy/jenkins"
JENKINS_USER="deploy"
...</pre>
<p>
	# service jenkins start
</p>
<p>
	浏览器访问Jenkins页面
</p>
<p><a href="http://deploy.example.com:8080" rel="nofollow">http://deploy.example.com:8080</a></p>
<p>
	安装完成, 以下是我已经配置好的一些Jenkins&nbsp;Job.
</p>
<p>
	<span style="line-height:1.5;"></span>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-0.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-0-1024x338.png" alt="QQ20160311-0" width="1024" height="338" class="alignnone size-large wp-image-1884" /></a>
</p>
<p>
	这里我们使用一个国内PHP网站模板phpcms作为我们需要部署的产品进行本次范例演示, 在进行最终的Build前我们需要做一些准备工作, 稍后我们会回到这个界面.
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:16px;">三. Ansible配置</span>
</p>
<p>
	这里我们需要配置virtualenv去隔离我们ansible的发行版本为最新版本2.1.0, 默认pip或者yum安装的1.9版本因为BUG以及对windows不兼容的原因, 这里不推荐使用.
</p>
<p>
	配置步骤传送门:&nbsp;<a href="http://www.showerlee.com/archives/1862" target="_blank">http://www.showerlee.com/archives/1862</a>
</p>
<p>
	Ansible-playbook范例传送门:&nbsp;<a href="http://www.showerlee.com/archives/1649" target="_blank">http://www.showerlee.com/archives/1649</a>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:16px;">四. Gitlab配置</span>
</p>
<p>
	部署并使用传送门:&nbsp;<a href="http://www.showerlee.com/archives/1285" target="_blank">http://www.showerlee.com/archives/1285</a>
</p>
<p>
	我们最终会创建一个ansible playbook仓库&nbsp;git@git.example.cn:showerlee/Ansible-showerlee.git, 并在本地编写好我们的规则, 最终commit到这个仓库, 以便Jenkins去调用我们的部署<span style="line-height:1.5;">规则.</span>
</p>
<p>
	<span style="color:#E53333;">这里博主单独clone出来一份部署phpcms的playbook仓库</span><span style="color:#E53333;">, 算是给大家的福利:</span>
</p>
<p>
	<a href="https://git.showerlee.com/showerlee/leon-playbook-phpcms1.1" target="_blank"><span style="color:#E53333;"><a href="https://git.showerlee.com/showerlee/leon-playbook-phpcms1.1" rel="nofollow">https://git.showerlee.com/showerlee/leon-playbook-phpcms1.1</a></span><span style="color:#E53333;"></span></a>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-2.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-2-1024x500.png" alt="" width="800" height="391" class="alignnone size-large wp-image-1885" title="" align="" /></a>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-3.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-3-1024x250.png" alt="" width="800" height="195" class="alignnone size-large wp-image-1886" title="" align="" /></a>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-4.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-4-1024x274.png" alt="" width="800" height="214" class="alignnone size-large wp-image-1887" title="" align="" /></a>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;font-size:16px;">五.最终部署</span>
</p>
<p>
	<span style="color:#337FE5;font-size:14px;">准备工作完毕, 我们接下来给大家介绍Jenkins Job配置.</span>
</p>
<p>
	<span style="color:#337FE5;font-size:14px;">1.创建一个new item</span>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-5.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-5.png" alt="QQ20160311-5" width="354" height="313" class="alignnone size-full wp-image-1888" /></a>
</p>
<p>
	<span style="color:#337FE5;font-size:14px;">2. 创建一个freestyle Job, 命名规则"产品名-环境", 这里我们为Phpcms-Dev</span>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-6.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-6-1024x306.png" alt="" width="800" height="239" class="alignnone size-large wp-image-1889" title="" align="" /></a>
</p>
<p>
	<span style="color:#337FE5;font-size:14px;">3. Job配置</span>
</p>
<p>
	<span style="color:#337FE5;">1). 定制Build参数.</span>
</p>
<p>
	这里Dynamic Choice Parameter用来通过Groovy脚本来抓取这个git仓库的所有branch, 并作为一个多选项, 方便我们在最终Build前去选择我们需要的这个产品Branch分支.
</p>
<p>
	Groovy抓取Git branch代码:
</p>
<p>
	
</p>
<pre class="prettyprint lang-bsh">def gettags = ("git ls-remote -h <a href="mailto:git@git.showerlee.com">git@git.showerlee.com</a>:showerlee/phpcms.git").execute()  
gettags.text.readLines().collect { it.split()[1].replaceAll('refs/heads/', '')  }.unique() </pre>
<p>
	
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-11.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-11-1024x425.png" alt="" width="800" height="332" class="alignnone size-large wp-image-1895" title="" align="" /></a>
</p>
<p>
	Choice Parameter也是用来给我们Job定制Build前的可选参数, 不过这里的参数可以直接写死
</p>
<p>
	deploy_environment为我们的参数名, 定义我们的部署环境名,&nbsp;prod, qa为我们具体的可选项, 定义我们产品的两个环境.
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-8.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-8-1024x427.png" alt="" width="800" height="334" class="alignnone size-large wp-image-1892" title="" align="" /></a><span style="color:#337FE5;">2). 源代码管理</span>
</p>
<p>
	我们可以利用Jenkins内置的Source Code Management工具去抓取远程Git或者SVN仓库的代码到本地, 这里我们抓取存放在我们Gitlab上的Playbook到Jenkins的workspace目录, 用来进行后续部署工作, 这个仓库如需认证,&nbsp;我们可以在Credentials add这个仓库的用户账号密码, 其余均保持默认即可(默认Jenkins default不支持Git, 需要到其后台安装Git插件)
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-9.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-9-1024x557.png" alt="" width="800" height="435" class="alignnone size-large wp-image-1894" title="" align="" /></a>
</p>
<p>
	<span style="color:#337FE5;">3). Execute shell进行最终的CLI部署.</span>
</p>
<p>
	这个Build模块下的Execute shell方法是Jenkins比较常用并非常核心的功能, 用来执行我们部署过程中核心的命令.
</p>
<p>
	开头和结尾的set +x,&nbsp;set&nbsp;-x用来关闭和打开该部分的扩展参数及命令
</p>
<p>
	<span>开启virtualenv和加载ansible环境变量</span>
</p>
<pre class="prettyprint"># source /home/deploy/.virtualenv/bin/activate
# . /home/deploy/.virtualenv/ansible/hacking/env-setup -q</pre>
<p>
	<span>进入该Job的workspace目录下保存该playbook的仓库子目录下, 检查ansible版本, 并执行最终的部署命令.</span>
</p>
<pre class="prettyprint lang-bsh">cd $WORKSPACE/leon-playbook-phpcms1.1
ansible --version
ansible-playbook -i inventory/$deploy_environment ./deploy.yml -e project=phpcms -e branch=$branch_selector -e env=$deploy_environment</pre>
<p><span style="color:#E53333;">注: -i&nbsp;用来自定义ansible host文件路径, ./deploy.yml为ansible-playbook入口文件, -e 后可跟给当前session添加的环境变量.</span> </p>
<p>
	<span style="color:#E53333;">这里</span><span style="color:#E53333;">$deploy_environment</span> <span style="color:#E53333;">$branch_selector 为该Job定义好的可选参数, 详见3-1)</span>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-10.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-10-1024x266.png" alt="" width="800" height="208" class="alignnone size-large wp-image-1891" title="" align="" /></a>
</p>
<p>
	
</p>
<p>
	配置完毕后, save保存.
</p>
<p>
	<span style="color:#337FE5;font-size:14px;">4. 执行Job.</span>
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-12.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-12-1024x336.png" alt="" width="800" height="263" class="alignnone size-large wp-image-1897" title="" align="" /></a>
</p>
<p>
	选择master分支和prod环境
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-13.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-13.png" alt="QQ20160311-13" width="859" height="302" class="alignnone size-full wp-image-1898" /></a>
</p>
<p>
	
</p>
<p>
	查看该Job最终的console output, 也就是显示我们实际在CLI下的输出结果.
</p>
<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-14.png"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2016/03/QQ20160311-14.png" alt="QQ20160311-14" width="347" height="684" class="alignnone size-full wp-image-1899" /></a>
</p>
<p>
	
</p>
<h1 class="build-caption page-headline" style="color:#333333;font-family:Helvetica, Arial, sans-serif;">
	Console Output<br />
</h1>
<pre class="prettyprint lang-bsh">Started by user Leon Li
Building in workspace /home/deploy/jenkins/workspace/Phpcms-Dev
 &gt; git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
 &gt; git config remote.origin.url <a href="mailto:git@git.showerlee.com">git@git.showerlee.com</a>:showerlee/Ansible-showerlee.git # timeout=10
Fetching upstream changes from <a href="mailto:git@git.showerlee.com">git@git.showerlee.com</a>:showerlee/Ansible-showerlee.git
 &gt; git --version # timeout=10
 &gt; git fetch --tags --progress <a href="mailto:git@git.showerlee.com">git@git.showerlee.com</a>:showerlee/Ansible-showerlee.git +refs/heads/*:refs/remotes/origin/*
 &gt; git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 &gt; git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 6bf787dcad68219d8eee09cecb83cbca36edbef1 (refs/remotes/origin/master)
 &gt; git config core.sparsecheckout # timeout=10
 &gt; git checkout -f 6bf787dcad68219d8eee09cecb83cbca36edbef1
 &gt; git rev-list 6bf787dcad68219d8eee09cecb83cbca36edbef1 # timeout=10
[Phpcms-Dev] $ /bin/sh -xe /tmp/hudson7452069223867148990.sh
+ set +x
ansible 2.1.0 (devel 6ddea3e915) last updated 2016/02/16 16:13:32 (GMT +800)
  lib/ansible/modules/core: (detached HEAD 8d126bd877) last updated 2016/02/16 16:19:09 (GMT +800)
  lib/ansible/modules/extras: (detached HEAD f6c5ed987f) last updated 2016/02/16 16:19:40 (GMT +800)
  config file = /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/ansible.cfg
  configured module search path = /home/deploy/active-ansible-modules/

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [deploy : Backup current source code] *************************************
changed: [127.0.0.1]

cmd: mv /data/deploy_dir/phpcms /data/deploy_dir/phpcms_master_1457681152

start: 2016-03-11 15:25:54.774716

end: 2016-03-11 15:25:54.927415

delta: 0:00:00.152699

TASK [deploy : Get new source code] ********************************************
changed: [127.0.0.1]

TASK [deploy : Check if caches/configs/database.php exists] ********************
ok: [127.0.0.1]

TASK [deploy : Check if test_dir exists] ***************************************
ok: [127.0.0.1]

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] =&gt; {
    "msg": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php exists"
}

msg: /data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php exists

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] =&gt; {
    "msg": "/data/deploy_dir/phpcms_master_1457681152/test_dir exists"
}

msg: /data/deploy_dir/phpcms_master_1457681152/test_dir exists

TASK [deploy : Copy remote necessary original config to new release when Product env] ***
changed: [127.0.0.1] =&gt; (item={u'name': u'db_config', u'dir': u'caches/configs/database.php'})
changed: [127.0.0.1] =&gt; (item={u'name': u'version_config', u'dir': u'caches/configs/version.php'})

msg: All items completed

results: [
  {
    "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php", 
    "changed": true, 
    "group": "deploy", 
    "uid": 606, 
    "dest": "/data/deploy_dir/phpcms/caches/configs/database.php", 
    "checksum": "91869c2faa244f8c5de8a586636c6b4f3c0a2817", 
    "md5sum": "fd88a78a4629bca012a79d22fdcecadd", 
    "owner": "deploy", 
    "_ansible_no_log": false, 
    "item": {
      "name": "db_config", 
      "dir": "caches/configs/database.php"
    }, 
    "state": "file", 
    "gid": 608, 
    "mode": "0644", 
    "invocation": {
      "module_args": {
        "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/database.php", 
        "directory_mode": null, 
        "force": true, 
        "remote_src": true, 
        "dest": "/data/deploy_dir/phpcms/caches/configs/database.php", 
        "selevel": null, 
        "seuser": null, 
        "setype": null, 
        "group": null, 
        "content": null, 
        "serole": null, 
        "original_basename": null, 
        "delimiter": null, 
        "mode": "0644", 
        "regexp": null, 
        "owner": null, 
        "follow": false, 
        "validate": null, 
        "backup": false
      }
    }, 
    "size": 302
  }, 
  {
    "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/version.php", 
    "changed": true, 
    "group": "deploy", 
    "uid": 606, 
    "dest": "/data/deploy_dir/phpcms/caches/configs/version.php", 
    "checksum": "d0eaedb46a36303eb3f3e2a77cc2a623062eff3c", 
    "md5sum": "7917d8199b7c6d5bc87ff3035a72670e", 
    "owner": "deploy", 
    "_ansible_no_log": false, 
    "item": {
      "name": "version_config", 
      "dir": "caches/configs/version.php"
    }, 
    "state": "file", 
    "gid": 608, 
    "mode": "0644", 
    "invocation": {
      "module_args": {
        "src": "/data/deploy_dir/phpcms_master_1457681152/caches/configs/version.php", 
        "directory_mode": null, 
        "force": true, 
        "remote_src": true, 
        "dest": "/data/deploy_dir/phpcms/caches/configs/version.php", 
        "selevel": null, 
        "seuser": null, 
        "setype": null, 
        "group": null, 
        "content": null, 
        "serole": null, 
        "original_basename": null, 
        "delimiter": null, 
        "mode": "0644", 
        "regexp": null, 
        "owner": null, 
        "follow": false, 
        "validate": null, 
        "backup": false
      }
    }, 
    "size": 127
  }
]

TASK [deploy : Copy dir test_dir to new release when Product env] **************
changed: [127.0.0.1]

cmd: cp -a /data/deploy_dir/phpcms_master_1457681152/test_dir /data/deploy_dir/phpcms/

start: 2016-03-11 15:26:16.966237

end: 2016-03-11 15:26:17.069705

delta: 0:00:00.103468

TASK [deploy : Get php version] ************************************************
changed: [127.0.0.1 -&gt; localhost]

cmd: python /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/roles/deploy/files/get_php_version.py <a href="http://www.showerlee.com" rel="nofollow">http://www.showerlee.com</a>

start: 2016-03-11 15:26:17.468311

end: 2016-03-11 15:26:51.560313

delta: 0:00:34.092002

stdout: PHP/5.4.13

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] =&gt; {
    "msg": {
        "changed": true, 
        "cmd": "python /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/roles/deploy/files/get_php_version.py <a href="http://www.showerlee.com" rel="nofollow">http://www.showerlee.com</a>", 
        "delta": "0:00:34.092002", 
        "end": "2016-03-11 15:26:51.560313", 
        "rc": 0, 
        "start": "2016-03-11 15:26:17.468311", 
        "stderr": "", 
        "stdout": "PHP/5.4.13", 
        "stdout_lines": [
            "PHP/5.4.13"
        ], 
        "warnings": []
    }
}

msg: {
  "changed": true, 
  "end": "2016-03-11 15:26:51.560313", 
  "stdout": "PHP/5.4.13", 
  "cmd": "python /home/deploy/jenkins/workspace/Phpcms-Dev/leon-playbook-phpcms1.1/roles/deploy/files/get_php_version.py <a href="http://www.showerlee.com" rel="nofollow">http://www.showerlee.com</a>", 
  "start": "2016-03-11 15:26:17.468311", 
  "delta": "0:00:34.092002", 
  "stderr": "", 
  "rc": 0, 
  "stdout_lines": [
    "PHP/5.4.13"
  ], 
  "warnings": []
}

TASK [deploy : debug] **********************************************************
ok: [127.0.0.1] =&gt; {
    "msg": "PHP/5.4.13"
}

msg: PHP/5.4.13

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=12   changed=5    unreachable=0    failed=0   

Finished: SUCCESS</pre>
<p>
	
</p>
<p>
	这样我们就利用Jenkins+Ansible+Gitlab, 成功部署phpcms到远程Client.</p>
<div>声明: 本文采用 <a rel="external" href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" title="署名-非商业性使用-相同方式共享 3.0 Unported">CC BY-NC-SA 3.0</a> 协议进行授权</div><div>转载请注明来源：<a rel="external" title="DevOps技术分享" href="http://www.showerlee.com/archives/1880">DevOps技术分享</a></div><div>本文链接地址：<a rel="external" title="Jenkins+Ansible+Gitlab自动化部署三剑客" href="http://www.showerlee.com/archives/1880">http://www.showerlee.com/archives/1880</a></div>]]></content:encoded>
			<wfw:commentRss>http://www.showerlee.com/archives/1880/feed</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
	</channel>
</rss>
