自我教练:做一个职业教练的计划

M(Me): 我想做一个职业教练,但是我还不知如何计划。

C(Coach):  先回顾一下,作为一名职业教练,需要什么样的技能的呢?
M: 教练、引导。 主要的实践包括 提问,倾听、反馈、肢体语言,重要的是在教练过程中察觉教练对象的变化,并根据变化,不断激发教练对象的潜能。 另外一项就是引导技能,在团队教练时,引导团队高效的表达观点、讨论、并形成一致的结论和可执行的行动。

C: 其他技能呢?
M: 不断需要训练的通用的能力吧。
 IQ, 通过模式学习,对对方的反应进行察觉,并选择自己需要使用的教练方法。
 EQ, 同理心、正能量、影响等等。
还有一个SQ的概念,灵商。一种寻找生命最终的目的和意义、拥有完美人生的基本愿望。所以,自身的心理承受能力一定要强大到一定等级,才能保持在教练过程中的正能量输出。

C:还有呢?
M: 不确定了,有一些琐碎的细节,应该可以通过再次阅读《高绩效教练》去补充一下知识和技能。不过重点是找到实践机会。

C: 很好。 那么对于上面说到的教练、引导、以及实践,有什么可行动的计划呢?
M: 平常运用。 一天至少进行一次有意识的教练行为。
一方面,包括自我教练,将自己以前拖延的,特别是重要但不紧急的任务目标,通过教练的手段进行一次思考,看看能不能去推动一下;
另一方面,找伙伴们聊聊,特别是在心里有一些动荡的伙伴,正好昨天有同学找我,聊聊他的创业想法。

C:还有呢?
M: 家庭、工作中有一些机会,但是我觉得我还不能很好的掌握。因为在这一个场景中,自己是带有一个很强的目标意愿的,很容易就会将自己所希望的目标通过强势的口吻强输出给对方。这一点,很头痛。

C: 那可以怎么改进呢?
M: 先处理关系吧。以前太强势了。 不过,现在我还不认为是一个缺点。强势的办事效率很高。 我需要学习如何在保证沟通效率的同时,进行更灵活的教练对话方式。
OK。 改进计划不是处理关系,而是改进自己的语言沟通方式。

C: 很好。关系的改进需要双方努力,需要察觉对方的反馈进行调整。所以能将计划聚焦到自己身上,更能保证计划能往前迈进。   改进计划还能更具体一些么? 计划应该准备什么?产生什么结果?
M: 开放式提问。我再去综合地理解、背诵一下这些开放式问题,加强对他们的印象。  
最重要的,就是强化、保持。可能这个教练愿景只能保持很短的一段时间,也可能因为其他的一些重要的事情,忘记了我要成为一个职业教练的任务。

C: 可以用什么来保持任务呢?想想方法。
M: 贴便签纸在明显的位置,将自我激励写在手机屏上,好像很多方面我以前都做过,但并没看到可持续的。很可能某天心情不好,就撕了。 或者想想,反正已经延误这么久了,就继续耽误着吧。好多事情就是这么被拖延的。。。
好吧, 我好像找到方法了。 在我的日记本上,每周都写上一句自我教练作为提醒。 在自我教练中,我会回来看这段对话的。

C:很好,做一个定期的提醒。 那行动之后,可以做一些什么行动,来进行持续改进呢?
M: 记录结果,记录对话,评估影响。可能评估影响并不精准,OK, 换句话说,是记录我能察觉的影响事实吧,还是记录。我可不喜欢去假设别人很喜欢我,更不乐意承认有人很讨厌我。通过记录,反思,强化自己的能力。  
我还得找到一个教练需要的能力雷达图,对记录的内容进行评分,持续的改进这些能力。

C:OK。 对行动总结一下吧。
M: 立即在日记本上的每一周周三,写上自我教练的任务。20周20多遍,不难,嗯哼。  
然后在教练知识中寻找一些具体的雷达图,多角度的,甚至包括单独考察倾听能力、反馈能力、提问能力的。   具体的改进模型我还不知道,先做出来之后再看吧。
下周自我教练之前,完成雷达图。我们再针对这个进行讨论。

C: 好的,看来这周的教练任务已经可以排满了,期待你的实践和改进。
M:谢谢。

部署Linux代理服务器

在DevOps自动初始化服务器时,需要自动安装Linux软件包、Pip依赖包等。但对于一些安全策略,从服务器直接访问外网时不被允许的。

所以,一般企业采用两种方式:

1. 下载依赖包,上传到服务器上后手动安装。 该方法非常冗余,而且依赖包可能会形成好几层依赖。依赖包的抓取和更新都是一件很耗时和无趣的事情;

2. 做一个软件库镜像。这种方式通过Docker的方式,比以前要容易的多了,软件上试行很简单,硬件上,准备百G左右的硬盘就好了。 还有,镜像更新需要你的网络足够好。

我偏好的方式,是建立一个代理。在一个有外网网络访问权限的机器上,安装代理服务器,其他不可访问外网的设备,通过代理服务器进行访问。可访问资源的策略通过代理服务器进行控制即可, 比如仅能访问yum源、pip源等。这种方式属于按需访问,简单轻便。

代理服务器比较知名的,是Squid,配置强大。另一个我最爱的小型简约的代理服务器是tinyproxy。

  1. 在可访问公网的机器上安装tinyproxy:
yum install tinyproxy

如果yum repo里面没有tinyproxy,可以去rpmfind寻找,并安装远程文件:

yum install https://rpmfind.net/linux/epel/7/x86_64/Packages/t/tinyproxy-1.8.3-2.el7.x86_64.rpm

2. 配置

vi /etc/tinyproxy/tinyproxy.conf
#Add below line, according your server ip configuration
Allow 172.16.0.0/12
Allow 192.168.0.0/12

3. 启动

service tinyproxy restart

4. 在其他机器上验证代理

ssh a-internal-server
export http_proxy=192.168.6.200:8888
curl http://www.luochunhui.com/

完成,就这么简单。

接下来在后文,我将通过配置,把这个Proxy,用到DevOps的自动化软件安装中去,解决yum、pip的安装问题。

给产品负责人进行干系人管理的10条建议

原文:10 Tips for Product Owners on Stakeholder Management

干系人管理

作为一个产品负责人,对干系人进行管理是其重要的一项工作职责。你需要了解干系人的关注点,你和你的产品能给他们带来什么样的需求,以及他们能如何帮助到你。干系人的种类很多,包括客户、用户、管理层、合作伙伴等等。作为产品负责人你需要对他们进行有效管理、并促使他们能够有效的协作,以便于最大化你的产品价值。本文将为产品负责人提供10条关于干系人管理的建议,文章最后还有在其他方面给予产品负责人的建议,希望你能喜欢。

管理干系人的10条建议

1.对干系人说”不”

作为产品负责人,你的工作是保证产品的价值最大化。因此,做好一小部分事情,远比将大量的事情做的虎头蛇尾要好的多。这不是一件易事!这意味着你将无法取悦所有人。举个例子,现在你拿起一款每天都会使用的产品,思考一下,它是不是有大量功能?还是说它只是一个简单功能的产品,而正是由于这一个简单功能,使得你每天都在使用它。

为了实现产品的价值最大化,作为产品负责人必须做出需求优先级的排序决定,也包括对一些需求说”不”。开始学习如何对干系人说”不”!有很多种说”不”的方法,事实上,我的同事为此专门写了一本书,对产品负责人有很好的帮助。你需要专门花一些时间去学习。

(译者注:原文并没有写这本书的书名,所以,译者只好猜测性的推荐两本:The Art Of Saying NO, SCRUM:用一半的时间做两倍的事

2.对干系人进行区别对待

一些产品负责人总有忙不完的工作,比如需求提炼会议,Sprint检查会,撰写产品故事。干系人管理也会占用产品负责人大量时间。如果你也是一个忙碌的产品负责人,先给你一个建议:对干系人进行区别对待。我遇到过很多产品负责人,他们花费了大量的时间去管理干系人,当然这并不是一件坏事。干系人管理是很重要的,而我说的是将时间花在重要的干系人身上,比如客户和产品的用户。并非所有的干系人都需要被同等对待,有些人对产品的关注度高,有些低;有些人有很大的决定权利,而有些人没有;有些人是你产品成败生死攸关的关联伙伴,有些人则只是看看热闹。所以,你必须对干系人进行分类,哪些是重要的,哪些不那么重要。你可以做一个干系人地图,这种方式可以让你更有效、更聪明地管理你的干系人。

3 停止对干系人进行个别管理

在上一个建议中,一些产品负责人不仅仅花费了大量时间在不重要的干系人身上,他们还为这些干系人进行单独汇报,导致时间完全不够用。在我之前的经历中,我也看到了一些高效的产品负责人,他们将干系人进行分组管理。比如,产品负责人会邀请一群用户参加定期的演示会议,在演示会议中,产品负责人或开发团队演示了新产品功能,有时也包括用户的使用培训。产品负责人会邀请另一群人作为重要干系人,来参与Sprint检查会,并共同讨论决议下一步的产品价值和需求。在产品提炼会议中,产品负责人则会邀请用户、客户或者其他人来描述他们需要的功能,进行头脑风暴,市场数据验证等。通过这些例子的展示,你可以发现,将关联的干系人集合到一个房间进行会议讨论,很节省你很多的时间。

4 客户也是干系人

在一些组织中,”客户”被理解为一类”可怕”的人群。我遇到过大量的产品负责人,他们在产品没有100%完成之前,拒绝将产品展示给客户。为此他们在没有任何产品反馈的情况下,为产品研发花费很长的时间。我真为这种开发方式感到羞愧。更好的方式,应该是让产品走出去,和客户一起协作。实际上很多用户都喜欢进行协作,提供建议,使得这个产品在未来能够更好地满足他们的需求。举个例子,在多年前,荷兰国际商业银行(ING Bank)发布了他们的第一个移动银行APP。在第一个版本中,只有一个查看银行账户信息的功能。除此以外,还有一个反馈按钮。这就是第一个版本的全部功能,并被发布给了银行的真实客户。版本发布后,银行获得了来自用户的成千上万条反馈信息,这些信息被整理后作为了下一个版本的产品需求导向。所以,别惧怕你的客户。将他们拉进来让如到产品的开发流程中,你会在他们身上得到惊喜的。

5 履行负责人的责任,逐渐获得授权

很多产品负责人新人并未获得多少授权。在新手阶段,他们常常做为一个记录员、代理人、或者商务代表。我们见过很多的产品负责人,他们不停的抱怨他们没有得到授权,没有权利进行决定,没有自由。但猜猜看,事实上,很多时候他们都能够做这些。

那么”履行责任人的责任,逐渐获得授权”到底是什么意思呢? 我们常教产品负责人持续地向干系人要求许可和授权,包括要求研发一个新需求,花一些时间进行问题的修复,解决一些技术债务。我并不是说将干系人牵扯进来有错,而是作为一个真正的企业家类型的产品负责人,你不可以只作为一个记录员,而应该成长为一个真正的产品负责人。这样,你才能向干系人表达你自己,表达你的产品,表达你的行为方式,并获得他们进一步的授权。所以,当你开始履行你负责人的身份,承担责任,制定计划,展示你自己对产品的喜爱和关注,你将进一步获得干系人的授权。换言之:”如果你自己不做计划,你将变成别人计划的一部分”。

Product Owner Maturity

6 如果你自己不做计划,你将变成别人计划的一部分

本句是第五个建议的结尾句,也是第六个建议。作为产品负责人,特别是企业家类型的产品负责人,你不会希望自己成为别人计划的一部分。你需要建立自己的计划,建立自己的产品并推进它成功。在组织进行”敏捷”改变时,我常常听到很多人说自己的计划不可能实现敏捷,所以,他们选择什么都不改变。在这种心态下,显然谈敏捷没有任何意义。当然,所有人都期望能在完全敏捷的环境建立计划,但实际情况是渐进的,和理想情况有很多的差别。

按照传统思维,当我们需要建立一个计划时,我们希望能够将进度保持与计划一致,防止偏差,我们将管理问题和风险,使计划回到正规。从敏捷的角度来看,计划是容许偏差的。计划只是对大方向的指示,甚至只是一个预测,用来指导我们在最近一段时间内的工作。不要把计划当成一个万能的”圣杯”,也不要当成刻在石头上的誓言,更不要把它当成是对未来的幻想。虽然计划是难以制定的,变化的,但是我们仍然需要一个计划。缺少计划就缺少行动,缺少下一步的工作目标。首先我们必须确定我们队未来的假设是清晰的,和团队取得一个一致的愿景期望,并共同建立战略、执行方向。其次,我们也需要接受变化的存在。虽然我们很难预测三个月之后的情况,但我们仍需要一个执行计划去渐进地接近它。

7 停止浪费时间在你不重要的干系人身上

这个建议在第二个建议时已经提到了,即队干系人进行区别对待。我见过很多的产品负责人花费了大部分时间在不重要的干系人身上,这些干系人往往拥有很少的权利,甚至对产品本身也没有多大兴趣。他们只是想介入一下,确保产品的开发过程在他们的”掌控”之中,也防止他们仅有的这点权利被取代或者消失。作为产品负责人,你可以给这些干系人发送一些工作简报、内部更新或其他什么东西,千万别花费大量时间在这些干系人身上。在每天的工作中,我发现很多的产品负责人做的并不好,所以,我将此项再次强调,希望对大家有用。

8 用心去理解干系人的诉求

对于产品负责人来说,这可能是一个全新的话题。很多的产品负责人对此从没主动关注过。在前文和提及过类似概念,即产品负责人需要对不同的干系人使用不同的沟通方式。你需要使用他们的思维方式进行沟通。比如,对一个运营部门的干系人,他不太关心产品的新特性,而更关心这些特性是否影响了产品的成单率,是否影响了净值收益、流程处理效率等。如果你用心去了解这些,了解他们真正关心的话题,你会发现在和他们沟通变得更加省心容易。

9 让敏捷教练帮忙,协助干系人管理

有效对干系人进行管理是一项具有挑战性的工作。特别是对”刁难性”的干系人。虽然您作为产品负责人对干系人管理负责,但这并不意味着您必须全部自己承担!您可以让您的敏捷教练为您提供支持!特别是当你面对开发过程、工作方式、使用敏捷管理的原因等问题质疑时,敏捷教练可以完全支持你。干系人(特别是(高级)管理人员)经常习惯于获得’控制权’。这对他们来说很重要,因为他们经常负责管理(部分)业务。控制很重要,在敏捷环境中也是如此!然而,敏捷环境对控制方式的理解有独特之处。我们经常使用更多的实践、工具和技术。例如,在敏捷环境中通常不再需要指导委员会。但是你不能只是移出他们,应当引入其他的方式来替换这个控制机制。因此,请求敏捷教练,为您和干系人提供支持,共同找到一种新的方式来保持控制,同时提高您的敏捷性!

10 不要成为干系人和开发团队的传话筒

在建议9里面,我们提到的”控制”。控制对于产品负责人来说也同样重要。我们也常看到一些产品负责人扮演着干系人和开发团队的传话筒,隔火墙的角色。开发团队和干系人、客户、用户进行直接沟通的行为是不被允许的。所有的沟通都必须通过产品负责人进行中转。这种方式不仅耗费了产品干系人大量的时间,同时缺乏效率和效果。

更高效的产品负责人会鼓励开发团队和干系人之间的直接沟通,这样开发团队可以更直接的获得产品的反馈,也能更清晰的明白用户即业务需求。除此之外,产品负责人也免除了当一只信鸽的传话角色,节省出大量的时间。

在鼓励沟通的情况下,信息的沟通途径会变得更多更复杂,甚至产生一些错误的信息。产品负责人开始担忧这些干扰信息。不要去试图完全的控制他们,那样又会使你成为传话筒的角色。你需要做的是和团队建立清晰的约定,让团队深刻地明白产品的愿景、目标和下一步计划。制定一个清晰的Sprint目标并专注于此。和团队建立约定,在哪些情况下, 开发团队可以自主决定需求细节的变更。假使出现了一些错误,我们也可以在回顾会上去发现并讨论这些错误,以便在未来进行改进。

以上10条,就是为产品负责人提供的管理干系人的建议。希望大家喜欢,并能帮助你成为一个更好的产品负责人。

最后,欢迎你继续阅读给产品负责人的其他方面的建议:

  1. Agile Product Management
  2. (Product) Vision
  3. Value
  4. Stakeholder Management
  5. Scrum Framework
  6. Product Backlog Management
  7. Release Planning

圣杯(Holy Grail):是在耶稣受难前的逾越节晚餐上,耶稣遣走加略人犹大后吩咐11个门徒喝下里面象征他的血的红葡萄酒,借此创立了受难纪念仪式。后来很多传说相信这个杯子具有某种神奇的能力,如果能找到这个圣杯而喝下其盛过的水就将返老还童、死而复生并且获得永生。 — 译者注

项目的环境配置化

发布包往往依赖于一些环境配置,比如项目的数据库连接地址等, 在现在的云方案中,有etcd/condf,Apollo等方案,以相对独立的方式对配置进行管理。但对于传统项目,配置文件经常与Jar、War等文件,或与源代码在同一目录下进行管理。

传统项目的配置文件通常有以下三种。

  1. 编译参数选择,通过编译时指定不同的参数,将源代码中不同的配置文件打包至二进制文件。
  2. 线上文件目录指定。二进制文件固定读取某一指定目录下的配置文件。
  3. 二进制文件替换配置。由于Java工程下的Jar、War实际结构是zip包,而且其配置文件是明文文本文件。所以,对于此类伪二进制目标文件,可以先采用解压包,替换二进制文件,再封装包的方式进行配置更新。该方式即可达到配置文件更新的目的,又可以保证测试环境和生产环境的二进制包的一致性。

建立配置模板文件、配置文件

在config库中,根据项目名称samples,建立 以下文件:

---
# file: projects/samples/vars/main.yml
# configure_files选项,其指定配置文件列表。系统将从main,prod,uat等文件中所获得变量文件,对src模板文件进行替换,生成实际的配置文件,最后替换jar包中的dest文件。

hellowar:
tomcat:
service_name: "tomcat-hellowar"
port: 8080
configurations_files:
- { src: "{{ project_dir }}/hellowar/config.properties.j2", dest: "WEB-INF/classes/config.properties" }
# file: projects/samples/hellowar/config.properties.j2
# 一个测试的配置

config.site.name={{ config.site.name }}
---
# file: projects/samples/vars/prod.yml
# 生产环境的变量值

config:
site:
name: "I am a production site"
---
# file: projects/samples/vars/uat.yml
# UAT环境的变量值

config:
site:
name: "I am a test site"

Ansible文件

---
# 用Ansible文件将上述配置连接起来。注意增加: role: app.config; configurations_files: "{{ hellowar.configurations_files }}" 即可。

- hosts: "&samples:hellowar"
pre_tasks:
- name: include Globals
include: "{{ playbook_dir }}/../includes/global_vars.yml"
tags: "always"
vars:
project_name: "samples"
roles:
- role: app.config
- role: app.war
vars:
type: "tomcat"
vars:
project_name: "samples"
service_name: "{{ hellowar.tomcat.service_name }}"
workspace: "{{ app_root }}/war/{{ service_name }}"
container:
type: "tomcat"
service_name: "{{ service_name }}"
jdk_home: "{{ jdk8_home }}"
warfile: "hello.war"
TARGET_FILE: "hello-0.0.1-SNAPSHOT.war" #this file path will be replace by jenkins
war_unachive: false
target_type: "war"
configurations_files: "{{ hellowar.configurations_files }}"
service:
name: "{{ service_name }}"
port: "{{ hellowar.tomcat.port }}"

详细工作原理可以阅读 app.war 中的源代码。

加密配置管理

基于安全考虑,生产服务器中的数据库密钥、付费业务的Key/Value对,通常应该进行保密处理,不应该将明文暴露在Config代码库中。Ansible的变量文件可以通过Vaults工具进行加密管理。

另一个好的建议是对公用资源的管理,如数据库、缓存等。 运维应按照业务需要、资源配置需求,对公用资源进行分组管理。开发人员无需了解实际的资源连接IP、密码等细节,只需要了解组名、以及该类型资源下存在的键即可。

以MySQL配置为例,说明配置组和加密配置使用:

---
# file: configs/vaults/test.yml

mysql:
group_sample:
host: 192.158.31.100
port: 3306
user: root
password: "password"

文件定义了 mysql 的sample组。 其键包括 host、port,password等。

在应用的配置模板文件中,按照应用的格式要求,填写资源.组.键即可:

server:
sql:
# 开发环境
host: {{ mysql.group_jkt.host }} # 192.158.31.100
port: {{ mysql.group_jkt.port }}
username: {{ mysql.group_jkt.user }}
password: {{ mysql.group_jkt.password }}

建立加密的prod配置文件

$ cd configs/vaults
$ ansible-vault create prod.yml
New Vault password:
Confirm New Vault password:

输入密钥文件,回车之后,会进入vi编辑页面。 填入与test.yml文件相同的结构和正确的密码,保存。 特别注意,在配置文件更新时,要保证prod和test环境的同步,prod环境缺少配置键而到时上线失败。

查看prod.yml应形如如下内容:

$ cat prod.yml
$ANSIBLE_VAULT;1.1;AES256
6466356161366165386166393136336233
3762383566393964366661313962636264

该文件仅能通过ansible-vault edit prod.yml ,并输入密码后再次进行编辑。无密码之人是无法对文件进行查看和修改的。所以,放心的将prod.yml加入到git版本库进行管理。

还有一个步骤,你需要将这个密钥告诉Ansbile发布机。登录到发布机后,修改ansbile.cfg文件,增加行:

vault_password_file = ~/.ansbile/vault_password_file

创建~/.ansbile/vault_password_file文件,并将密钥明文写入到文件中。

DevOps下的角色及工作流

角色说明

角色职能
admin
管理员
对自动化部署系统进行系统管理、插件管理、编译节点建设、用户及权限管理。 对Jenkins使用的密钥进行管理。
sa
发布配置工程师
建立Jenkins编译任务(Build job)、发布任务(Publish Job)
scm
运维配置工程师
建立配置文件模板、配置文件参数,编写自动运维剧本
dev
开发工程师
编写代码、提交至SCM。
test
测试工程师
按顺序进行测试、准生产、生产各环境的发布、测试、审核审批
master
DevOps架构师
设计并实现DevOps的架构、流程、角色、规范,选择并应用各DevOps工具,指导全员融入DevOps体系

角色权限表 – Jenkins

RoleOverallCredentialsManage ownershipAgentJobPipelineRunViewSCM
adminAllAllAllAllAllAllAllAllAll
devNoneNoneNoneBuild, CancelDeploy to test (Automatically)NoneNoneNone
qaNoneNoneNoneBuild, CancelTestPassDeploy to uat&prodNoneNoneNone
scmCreate, Update, ViewALLNoneConfigureand All for test usageAll for test usageAllNoneNone
saCreate, Update, ViewNoneALLNoneNoneNoneNoneNone

启用角色管理插件

进入Jenkins管理页面,配置全局安全配置, 选择 Role-Based Strategy,保存。在保存前,先备份Jenkins Home下面的config.xml文件,当权限配置出错时,会导致管理员登录不进去。此时还原config.xml文件即可解决。

配置全局角色、项目角色

然后开始按上述权限表进行配置,进入Jenkins系统管理 -> Manage and Assign Roles -> Manage Roles, 通过新增,勾选,得到如下图所示的全局角色表、项目角色表。

建立用户,并授权角色

使用OpenLdap,添加用户。

Jenkins开启Role-Based Strategy组件之后,不接受OpenLdap的角色属性,因此,Jenkins内部权限应迁移到Manage and Assign Roles中进行配置。

进入系统管理 -> Manage and Assign Roles -> Global roles -> User/group to add -> 添加用户邮箱 -> 然后勾选对应角色

进入系统管理 -> Manage and Assign Roles -> Item roles -> User/group to add -> 添加用户邮箱 -> 然后勾选对应的项目组

其他与职能角色相关的任务

SA / SCM:

  1. 管理playbooks部署代码,负责项目及工程配置
  2. 管理 configs/prod 的配置代码修订
  3. 在Jenkins中发布playbooks库
  4. 在Jenkins中发布configs生产库
  5. 维护Jenkins的项目、工程文件。[SA/Dev]

Admin:

  1. 管理角色、用户、角色赋权
  2. 管理整体Jenkins配置

Dev:

  1. 维护业务代码
  2. 维护业务Config。由于生产配置库使用加密存储,Configs/Prod的配置,特别是涉及到密码的配置,由SA管理。
  3. 发起Pipeline编译过程,完成从编译、测试环境发布、测试过程,进入UAT发布准备阶段。

Test:

  1. 承接Dev的测试环境,共同完成测试验证工作。
  2. 确认发布UAT环境
  3. 验收UAT环境
  4. 发布PROD环境
  5. 验收PROD环境

新建项目和工程

为了管理方便,在DevOps中将系统分级为两层,项目、工程。 在演示用例中,我们建立一个项目,samples, 里面包含若干工程,hellowar, hellojar, hellohtml等。

以hellowar为例,建立Tomcat项目的自动化部署。

关于hellowar

hellowar是一个简单的tomcat项目,源代码可以在gikoluo/java-tomcat-example-app找到。部署成功后,访问项目首页,会得到一个WEB页面: hello world。

Jenkins项目框架

 HOME  #根
|-- samples #项目名
| |-----builds #这里放置编译任务
| |---- hellowar
| |---- hellojar
| |---- hellowar #这是一个带有pipeline的发布任务
| |---- hellojar
|-- sa #SA项目,用于管理DevOps环境及设备
|---- playbooks 这是一个发布+ant编译的项目。

对于工程,我们把编译和发布分离,一个pipeline中仅关联一次编译,这样有助于减少编译次数,并保证各环境下的部署内容一致。

Playbook项目框架

ROOT
|-- samples #项目名
|-- 22-tomcat8.yml #基础包。用数字作为前缀,表明依赖的先后顺序。
|-- hellowar.yml #工程包。以工程为名。

配置文件结构

ROOT
|-- projects
| |-- samples
| | |-- vars
| | | |-- main.yml #通用配置
| | | |-- uat.yml #环境特殊配置,比如环境IP,数据库IP等
| | |-- hellowar #应用配置模板文件,可以使用vars中的变量
| | | #在发布时进行变量替换。
| | | |-- application.xml

Tomcat基础包部署文件

---
# filename: 22-tomcat8.yml

- hosts: "&samples:hellowar"
become: True
become_user: root
pre_tasks:
- name: include Globals
include: "{{ playbook_dir }}/../includes/global_vars.yml"
vars:
project_name: "samples"
roles:
- app.tomcat
vars:
project_name: "hellowar"
service_name: "{{ hellowar.tomcat.service_name }}"
jdk_home: "{{ jdk8_home }}"
tomcat_version: '8.5.38'
tomcat_env_catalina_home: "{{ opt_root }}/{{ service_name }}/"
tomcat_redis_filename: "apache-tomcat-{{ tomcat_version }}.tar.gz"
tomcat_default_override_uri_encoding: UTF-8
tomcat_service_allow_restart: true
system_type: "systemd"
tomcat_instances:
- name: "{{ service_name }}"
service_name: "{{ service_name }}"
service_file: "{{ service_name }}"
port_ajp: 8009
port_connector: "{{ hellowar.tomcat.port }}"
port_redirect: 8443
port_shutdown: -1
path: "{{ opt_root }}/{{ service_name }}"
tomcat_service_allow_restart: true
tomcat_default_override_uri_encoding: UTF-8

项目部署文件

---
# filename: hellowar.yml

- hosts: &samples:hellowar
pre_tasks:
- name: include Globals
include: "{{ playbook_dir }}/../includes/global_vars.yml"
tags: "always"
roles:
- role: app.config
- role: app.war
vars:
type: "tomcat"
vars:
project_name: "samples"
service_name: "{{ hellowar.tomcat.service_name }}"
workspace: "{{ app_root }}/war/{{ service_name }}"
container:
type: "tomcat"
service_name: "{{ service_name }}"
jdk_home: "{{ jdk8_home }}"
warfile: "hello.war"
TARGET_FILE: "hello-0.0.1-SNAPSHOT.war" #this file path will be replace by jenkins
war_unachive: false
target_type: "war"
configurations_files: "{{ hellowar.configurations_files }}"
service:
name: "{{ service_name }}"
port: "{{ hellowar.tomcat.port }}"

服务器设备配置

#filename: uat/samples

[jdk8]
192.168.10.50 default_link=1

[hellowar]
192.168.10.50

[samples:children]
hellowar

配置文件

---
#repo: configs
#filename: configs/projects/vars/main.yml

hellowar:
tomcat:
service_name: "tomcat-hellowar"
port: 8080
configurations_files: []
log:
home: "{{ log_root }}/tomcat-hellowar"
level: INFO

提交并在Jenkins中发布Playbooks,configs代码

进入发布机,将项目的设备资源及环境进行初始化

ansible-playbook jkt/22-tomcat7.yml -i $INVERNTORY
ansible-playbook jkt/crm.yml -i $INVERNTORY --tags=setup
ansible-playbook jkt/appserver.yml -i $INVERNTORY --tags=setup

配置Jenkins

在Jenkins WEB页面中,如上框所示的目录架构,新建文件夹任务,samples; 再建立文件夹任务builds。

建立hellowar工程,类型为maven项目,配置如下:

源代码: https://github.com/gikoluo/java-tomcat-example-app.git
Build:
ROOT POM: pom.xml
Goals and options: compile war:war
归档成品: target/hellowar.war

保存,编译,等待hellowar.war编译完成

在samples内,建立任务hellowar,类型为 流水线。配置如下:

Prepare an environment for the run: True
Properties Content内填入以下内容:

PROJECT_NAME=samples
SERVICE_NAME=hellowar
BUILD_JOB=${PROJECT_NAME}/builds/hellowar
TARGET_FILE=target/hellowar.war
AUTO_BUILD=true

流水线: Pipeline srcipt from SCM
GIT, Repositories: https://github.com/gikoluo/devops-utils.git
脚本路径: src/jenkinsfile/common/Jenkinsfile.groovy

  • Prepare an environment for the run: 为EnvInject提供的功能,将Properties Content的语法为Key/Value变量,申明内容将注入到全局变量,供Jenkins脚本使用。注意,内容中,不允许有注释。
    • PROJECT_NAME/SERVICE_NAME: 填项目、工程名称。
    • BUILD_JOB: 填上文建立的Maven项目名。形如${PROJECT_NAME}/builds/hellowar。
    • TARGET_FILE: 填BUILD_JOB中编译归档的文件名,注意带上路径。
    • PLAYBOOK: 填写Playbook名称,如不存在则将使用 ${PROJECT_NAME}/${SERVICE_NAME}。
    • AUTO_BUILD: true/false 。 #是否每次发布时都自动执行编译。默认True。
  • 流水线: gikoluo/devops-utils 提供了一些标准通用的流水线文件,可以直接使用,可以获得源代码滞后,将文件内容直接复制到流水线定义里。

保存,构建。顺利的话,你将得到一个如图所示的Pipeline:

确认发布UAT之后,将进入验收阶段。 在浏览器中键入: http://192.168.10.50:8080/hello/ , 得到Hello World。确认UAT验证完成。

接下来继续通过Pipeline,确认Production发布、Production验收阶段,完成上线的全部流程。

新增目标服务器

在完成服务器的上架工作后,对服务器进行初始化配置。

在Ansible发布机配置的章节,已经进行过类似的操作了。 这里作为运维新机器上架的操作,再列一次。

在机器建立之初,首先得通过项目属性,了解机器的用途。获得以下属性:

  • 项目组: samples。 项目组为服务组,或者一个工作组。可以共享部署配置。
  • 服务名:hellowar。 服务名为一个可独立部署的服务。
  • 环境:UAT。
  • 设备IP:192.168.10.50
  • 服务环境: Tomcat8
  • JAVA环境:JDK8
  • 服务类型:放置在Tomcat下的War服务包

建立机器配置

$ cd playbooks
$ vi uat/samples
[jdk8]
192.168.33.100 default_link=1

[hellowar]
192.168.33.100

[samples:children]
hellowar

提交代码到GIT,然后在Jenkins WEB界面中执行SA/playbooks发布操作,将更新推送到发布机。

进入到发布机中进行目标的Ansible推送操作。

ssh ANSIBLE-UAT

export IP=192.168.33.100
export INVERNTORY=uat
export KEY_PATH=~/.ssh/agent/id_rsa
#注入公钥
ansible-playbook setups/10-installkey.yml -i $INVERNTORY -l "$IP" --private-key=$KEY_PATH
#建立统一的初始化环境
ansible-playbook setups/00-setup.yml -i $INVERNTORY -l "$IP"
#安装JDK8
ansible-playbook setups/01-oracle-jdk8.yml -i $INVERNTORY -l "$IP"
#安装Tomcat
ansible-playbook samples/22-tomcat8.yml -i $INVERNTORY
#初始化项目框架
ansible-playbook samples/23-hellowar.yml -i $INVERNTORY --tags=setup

关于如何写sample/*.yml, 在下一篇文章中会介绍。

Ansible发布机

上接Jenkins部署,现在分别在三个环境下,构建三台Ansible发布机器,机器将作为Jenkins的部署节点。
现在将Jenkins机器作为临时的Ansible节点,分别推送三个环境的Ansible部署机器的安装工作。
以UAT环境为例,操作如下

建立Playbook发布项目

进入Jenkins:
新建任务,添加文件夹,任务名: SA;
进入SA目录,新建任务,添加自由风格的软件项目,任务名: playbook,配置如下:

项目类型: 自由风格的软件项目
描述: 将Absible Playbooks 发布到 发布机
源码管理: git, Repository URL: https://github.com/gikoluo/playbooks2.git
构建:Invoke Ant
Ant version: ant or default
Target: build
构建后操作:
Send build artifacts over SSH
SSH Server: 192.168.10.45
Transfers Set:
Source file: dist/playbooks.tar.gz
Remote directory: playbooks/
Exec command: cd /data/playbooks && tar zxvf playbooks.tar.gz && rm playbooks.tar.gz
Flatten files: TRUE

SSH Server: 192.168.33.10
Transfers Set:
THE SAME AS BELOW.

SSH Server: 10.0.1.12
Transfers Set:
THE SAME AS BELOW.

归档成品:
用于存档的文件: dist/playbooks.tar.gz

保存,然后发布, 检查日志输出、目标文件夹代码是否正常。

安装Ansible

#进入Jenkins机器
$ ssh jenkins
#安装pip & ansbile。 通过pip安装可以保证ansible的版本较新。
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python get-pip.py
$ pip install ansible
#克隆ansible剧本
$ cd /data
$ git clone https://github.com/gikoluo/playbooks2.git playbook
$ git clone https://github.com/gikoluo/ansible-config.git configs
#配置IP
$ cd playbooks
$ vi uat/sa

[ansible]
192.168.10.45
[jdk8]
192.168.10.45 default_link=1

#将Jenkins登录公钥注入部署机器
$ export IP=192.168.10.45
$ export INVERNTORY=uat
$ export KEY_PATH=~/.ssh/agent/id_rsa
$ ansible-playbook setups/10-installkey.yml -i $INVERNTORY -l "$IP" --private-key=$KEY_PATH #如果使用证书登录,使用本行
$ ansible-playbook setups/10-installkey.yml -i $INVERNTORY -l "$IP" -kK #如果使用密码登录,可以使用本行,输入密码和SUDO密码
$ ssh $IP ip a #测试是否可直接登录成功,如果返回正常,则说明安装密钥正常。
#将Jenkins登录公约注入部署机器
$ ansible-playbook setups/00-setup.yml -i $INVERNTORY -l "$IP" #初始化机器环境
$ ansible-playbook provo/01-ansible.yml -i $INVERNTORY -l "$IP" #安装Ansible
$ ansible-playbook setups/01-oracle-jdk8.yml -i $INVERNTORY -l "$IP" #安装JDK环境,将Ansible机器作为Jenkins节点时需要
$ ansible-playbook setups/01-open-jdk8.yml -i $INVERNTORY -l "$IP" #或安装openJDK环境,将Ansible机器作为Jenkins节点时需要

将发布机器配置为Jenkins节点

进入Jenkins -> 系统管理 -> 节点管理 -> 新建节点 -> 填写下方配置后保存。

节点名称:ansible-uat
节点类型:固定节点
远程工作目录: /data/playbooks
主机: 192.168.10.45
Credentials: 自行配置私钥

保存后,Jenkins会自动启动节点服务。如启动失败,可根据日志检查问题。

部署其他节点

与上方操作相同,完成三台发布机初始化工作,在JENKINS节点中分别命名为ANSIBLE-TEST,ANSIBLE-UAT,ANSIBLE-PROD。

Jenkins部署

使用Docker部署

$ git clone https://github.com/gikoluo/devops-jenkins.git
$ cd devops-jenkins
$ docker-compose up

使用K8S部署

$ git clone https://github.com/gikoluo/devops-jenkins.git
$ cd devops-jenkins
$ kubectl apply -f jenkins-home-pvc.yaml
$ kubectl apply -f jenkins-deployment.yaml
$ kubectl apply -f jenkins-service.yaml

传统部署

$ yum install jenkins

安装组件

微服务部署时,组件已经完成部署。传统部署模式下,需要手动运行以下脚本安装组件。

 
$ export JENKINS_USER_ID=luochunhui
$ export JENKINS_API_TOKEN=123456
$ export JENKINS_SERVER=http://192.168.30.200:8080/
$ cd devops-jenkins
$ wget "${JENKINS_SERVER}jnlpJars/jenkins-cli.jar"
$ xargs java -jar jenkins-cli.jar -s $JENKINS_SERVER install-plugin $i < plugins.txt