-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
545 lines (331 loc) · 35.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>闲庭信步(KISS)</title>
<meta name="description" content="手把青秧插满田,低头便见水中天。身心清净方为道,退步原来是向前。/ 初学者眼中凡事皆有可能,行家心中可行之途无多" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/stylesheets/screen.css" />
<link rel="alternate" href="/atom.xml" type="application/atom+xml" />
</head>
<body>
<!--[if IE]>
html,body{height:100%;overflow:hidden}
<div class="ie-go-away">My blog does not support the IE!</div>
<![endif]-->
<!-- 黑长直 -->
<nav class="black-long-straight">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/archives">Archives</a></li>
<li><a href="/atom.xml">RSS</a></li>
<li><a href="http://switchable.mrzhang.me/" class="switchable" target="_blank">jQuery.Switchable</a></li>
<li>
<form action="http://google.com/search" method="get" target="_blank">
<input type="hidden" name="q" value="site:qiaoliang.github.com" />
<input type="text" name="q" class="search" placeholder="Search" x-webkit-speech />
</form>
</li>
</ul>
</nav>
<header class="my-nickname"><em title="Programmer">闲庭信步</em></header>
<section class="main-wrap clearfix">
<article>
<header>
<h1 class="entry-title"><a href="/blog/estimation.html">使用排序法对User Story进行相对估算</a></h1>
<p class="meta">
<time datetime="2011-11-22T10:43:00+08:00" pubdate="pubdate" data-updated="true">2011-11-22 Tue</time>
<span class="tags">
Tags:
<a href='/blog/tags/yong-hu-gu-shi/'>用户故事</a>, <a href='/blog/tags/min-jie/'>敏捷</a>, <a href='/blog/tags/gu-suan/'>估算</a>
</span>
<span class="share-to-weibo">
<a href="javascript:void(0)" onclick="window.open('http://service.weibo.com/share/share.php?appkey=3197495784&ralateUid=2036045341&title=使用排序法对User Story进行相对估算 - &url=http://qiaoliang.github.com/blog/estimation.html', null, 'width=615,height=505,toolbar=0,status=0')" class="sina-weibo" title="分享到新浪微博"></a>
<a href="javascript:void(0)" onclick="window.open('http://share.v.t.qq.com/index.php?c=share&a=index&appkey=&title=使用排序法对User Story进行相对估算 - &url=http://qiaoliang.github.com/blog/estimation.html', null, 'width=700,height=680,toolbar=0,status=0')" class="tencent-weibo" title="分享到腾讯微博"></a>
<a href="javascript:void(0)" onclick="window.open('https://twitter.com/intent/tweet?text=使用排序法对User Story进行相对估算 - http://qiaoliang.github.com/blog/estimation.html', null, 'width=600,height=300,toolbar=0,status=0')" class="twitter" title="分享到Twitter"></a>
</span>
</p>
</header>
<div class="entry-content typo"><p>本文是王晓明同学在InfoQ发表的文章《<a href='http://www.infoq.com/cn/articles/wxm-agile-estimation'>关于项目估算的微博讨论</a>》中提到的排序法详解。</p>
<h1 id='id6'>一、引言</h1>
<p>软件项目的估算历来是一个难题。由于软件开发活动还无法实现土建工程那种成熟度,所以也无法像做土建工程那样通过预算速查手册来评估。但是,对于一项投资来说,总要说出要投资多少吧,软件开发也要给出投资额,这就需要做估算了。 本文主要讨论敏捷软件开发中的用户故事(User Story)估算。估算方法有很多,但大体上分为绝对估算和相对估算。在本文中,“绝对估算”就是指以绝对时间(如小时或天)为单位进行估算。而“相对估算”就是通过用户故事之间的大小对比进行估算,估算后的结果没有时间单位(它们之间的差异,不在本文讨论范围之内)。在相对估算方法中,也有很多种不同方式。而相对估算的过程中常常会出现下面的现象,尤其是对那些第一次使用相对估算的团队: - 当确定相对估算的基准单位“1”时,开发人员很难找到一个合适的用户故事做基准; - 开发人员更关注于讨论单个用户故事的点数是多少,而不是关注与其它用户故事比较的相对大小; - 估算所花费的总时间比较长(常常是整个下午,甚至一天)。 本文所述的估算方法仅是作者在指导工作中曾经使用过且收效不错的经验总结,但并不确保任何情况下都有效。</p>
<h1 id='id7'>二、排序估算法</h1>
<h2 id='1'>1、使用目标</h2>
<p>制定发布计划,通常有一定数量的故事卡。</p>
<h2 id='2'>2、曾使用过的场景</h2>
<p>项目规模较大(一到三个月的周期),已根据用户故事的拆分原则(INVEST原则)得到一个用户故事列表,该列表由各角色共同讨论过,且对每个用户故事的内容已达成共识。同时,团队基本上可以保证,每个卡片都会有两个或两个以上的开发人员了解,并有能力开发。</p>
<h2 id='3'>3、基本依据或假设</h2>
<p>1. 用户故事的客观规模不会因为具体开发人员的差异而不同(尽管人员不同,花费的时间可能不同)。 2. 开发人员基本了解每个用户故事的工作内容。 3. 由于用户故事有一定的数量(从统计学的角度看),所以客观规模不会偏差太多。 4. 开发人员是整个交付过程的瓶颈,所以仅由开发人员估算其开发规模,不包括用户故事的测试规模。</p>
<h2 id='4'>4、估算过程</h2>
<p>* 将待估算的所有用户故事写在卡片上,并分发给每个参与项目的开发人员(均分即可); * 先让一个开发人员取一张卡片A,贴到墙上(随便哪张都可以); * 然后让每个开发人员按以下规则将手中的卡片贴在墙上: 1. 从自己手中取出一张卡片B,与墙上已有的那些卡片进行对比(开始时仅有一张卡片,即A)。 2. 如果手中的卡片B与墙上A的大小相当,就将其贴在卡片A的下方;如图1所示。 <pre>
 <img alt='图1' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image1.png ' />
 </pre></p>
<pre><code> 图1. A与B的大小相当</code></pre>
<p>3. 如果手中的卡片B比卡片A大,就将其贴在A的右侧,如图2所示。 <img alt='图2' src='HTTP://WWW.INFOQ.COM/RESOURCE/ARTICLES/QL-USING-SORT-METHOD-TO-ESTIMATE-USER-STORY/ZH/RESOURCES/IMAGE2.PNG' /> 图 2 B大于A</p>
<p>4. 如果手中的卡片B比卡片A小,就将其贴在A的左侧。 5. 继续再拿出一张卡片C,与墙上的卡片相比,如果比墙上所有卡片都小,则放在左侧;如果比它们大,放在右侧;与墙上某张卡片差不多大小,就放在其下方。 6. 如果C的大小在A和B之间,就把它放在A 和B 之间,如图3所示。以此类推。在这个过程中,可以让所有开发人员同时贴卡片,只要彼此不干涉,保持独立判断即可。 <img alt='图3' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image3.png' /></p>
<p>图3 C介于A和B之间</p>
<p>7. 当全部卡片贴完以后,再请全体开发人员重新看一看,是不是每个卡片的位置都很适当。如图4所示。 <img alt='图4' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image4.png' /> 图 4 排好序的卡片墙</p>
<p>8. 如果对某个卡片的位置有异议,请拿出来讨论。这也许是因为大家对它的内容和理解不一致造成的。因此需要对其进行深入讨论,直至一致认为它应该在哪一列为止。 9. 使用数字 1,2,3,5,8,13或 1,2,4,8,16按顺序将其放在有对比关系的列上,如图5所示。注意,这时团队成员间还会发生对一些卡片的大小进行讨论,有可能也进行位置调整。图5中,列在“2”的每个故事卡片,其大小应该是“1”列的一倍左右。由于是估算,所以并不需要精确,只要相当即可,以此类推。 <img alt='图5' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image5.png' /> 图 5 已设定好每列大小的卡片墙</p>
<p>10. 对于那些列头上还没有数字标识的列(如图5中“L”列、“A”列和“K”列),请开发人员根据其规模的接近程度将其放到相邻的列中。 如图6所示。 <img alt='图6' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image6.png' /> 图6 已估算好的卡片墙</p>
<p>最后,将每列的用户故事数与列头的数字相乘,得到的数字再相加以后,就得到该项目的总体规模。</p>
<h1 id='id8'>三、注意事项</h1>
<p>1. 在估算之前,应该确保所有用户故事之间的规模差异不要过大。例如,某个用户故事大约需要一个小时完成,而另一个用户故事则需要两周。此时说明,用户故事的粒度不合理,不符合INVEST原则中的S原则,需进行合并或分拆。 2. 如果各列卡片的数量不符合正态分布,而是两头的卡片多,中间的卡片少,也说明用户故事粒度可能有问题,需要重新审视一下。在这种情况下,会为后续的迭代计划带来困难。 3. 如果在一列中有数个相关联且同样大小的故事(比如支持银联卡、支持MasterCard、支持VISA卡),且先做完一个卡片,其它两个工作量会减少的情况下,可以将任意一个放在当前列,其它两个可以考虑放在比较小的一列中。但是,具体情况还是要具体分析,因为实际情况较复杂。但在整体审视环节中,这类的分析和验证工作不可缺少。 4. 在讨论和移动卡片时,应该更多地与其它卡片进行对比,而不是直接说某个卡片属于哪一数字列。因为列头的数字都是相对值,没有其它卡片的对比,这些数字没有意义。 5. 在讨论的过程中,会捕捉到一些之前没有发现的问题或信息,此时一定要及时记录下来。对于不清楚的问题,应该当场由业务人员给出结论。 6. 这种方法在那些没有尝试过相对估算的团队中首次使用时,最好能有一定经验的人加以引导,对已排定的顺序进行适当验证。</p>
<h1 id='id9'>四、实际应用的一个案例</h1>
<p>这种方法比较快捷。作者已做过数次实践,所带团队各不相同,但结果比较满意。在最近一次实践中,一共有40多张用户故事,用时大约1.5小时,就完成了规模估算和发布计划的制定。下面两张照片就是当时估算的情景。由于该团队一直使用传统的瀑布开发方式,首次尝试使用敏捷开发方法,所以在这次估算中,作者并没有要求团队一定使用仅包含1,2,3,5的数字序列,而是使用是1,2,3,5,8,13的数字序列。但在开发后期,团队已经有能力将较大的用户故事(8和13)进行拆分,使其变成由1,2,3,5组成的多个用户故事。另外,值得注意的是,如图8所示,本次估算中,在大小为“1”的这一列上,并没有任何用户故事。这也是正常现象,从侧面反映了,并不是所有的估算都需要基准“1”。</p>
<p>图7 开发人员正在向墙上贴用户故事卡片,尚未决定每列的数字。</p>
<p><img alt='图7' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image7.png' /></p>
<p>图8 开发人员正在讨论将一个没有数值的用户故事放在哪个数值列下</p>
<p><img alt='图8' src='http://www.infoq.com/resource/articles/ql-using-sort-method-to-estimate-user-story/zh/resources/image8.png' /></p>
<h1 id='id10'>五、小结</h1>
<p>对于刚刚接触敏捷软件开发方法的团队来说,这种规模估算和计划的方法的确不太容易接受,尤其是在那些已习惯于使用WBS分解方式做计划的团队中,他们会纠结于“1”到底代表多长时间,是代表资深开发人员的一天呢,还是新手的一天?因此,如前所述,这种排序法有其前提条件与假设。而且,在进行用户故事拆分时,进行充分的讨论,让团队成员了解每个用户故事,这是该方法成功的前提,当然,也是敏捷软件开发方法成功的前提。 值得再次强调的一点是,该方法只估算开发工作量。其前提假设是测试工作不是整个交付过程的瓶颈。 另外,用户故事的INVEST原则包括:独立性(Independent),可协商性(Negotiable),有价值(Valuable),可以估算性(Estimable),小的(Small and similar size)和可测试性(Testable)。作者认为,其中的“S”有两方面的含义。一是“small”:一个好的故事在规模上要尽量小,至少要确保在一个迭代内能够完成。用户故事越大,在安排计划,工作量估算等方面的风险就会越大。二是“similar size”:所有用户故事规模不应相差太大,不要为了追求“小”而出现半个小时就能完成的用户故事,结果使得最大和最小的用户故事之间相差数十倍(不要笑,现实中的确见过这种情况)。 原文发表于<a href='http://www.infoq.com/cn/articles/ql-using-sort-method-to-estimate-user-story'>InfoQ中文站</a>。原文链接在<a href='http://www.infoq.com/cn/articles/ql-using-sort-method-to-estimate-user-story'>这里</a></p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/veewee-vagrant.html">用veewee创建vagrant的虚拟机:</a></h1>
<p class="meta">
<time datetime="2011-10-30T20:34:00+08:00" pubdate="pubdate" data-updated="true">2011-10-30 Sun</time>
<span class="tags">
Tags:
<a href='/blog/tags/veewee/'>veewee</a>, <a href='/blog/tags/vagrant/'>vagrant</a>, <a href='/blog/tags/jenkins/'>jenkins</a>
</span>
<span class="share-to-weibo">
<a href="javascript:void(0)" onclick="window.open('http://service.weibo.com/share/share.php?appkey=3197495784&ralateUid=2036045341&title=用veewee创建vagrant的虚拟机: - &url=http://qiaoliang.github.com/blog/veewee-vagrant.html', null, 'width=615,height=505,toolbar=0,status=0')" class="sina-weibo" title="分享到新浪微博"></a>
<a href="javascript:void(0)" onclick="window.open('http://share.v.t.qq.com/index.php?c=share&a=index&appkey=&title=用veewee创建vagrant的虚拟机: - &url=http://qiaoliang.github.com/blog/veewee-vagrant.html', null, 'width=700,height=680,toolbar=0,status=0')" class="tencent-weibo" title="分享到腾讯微博"></a>
<a href="javascript:void(0)" onclick="window.open('https://twitter.com/intent/tweet?text=用veewee创建vagrant的虚拟机: - http://qiaoliang.github.com/blog/veewee-vagrant.html', null, 'width=600,height=300,toolbar=0,status=0')" class="twitter" title="分享到Twitter"></a>
</span>
</p>
</header>
<div class="entry-content typo"><a href='http://www.continuousdelivery.info/index.php/2011/11/04/veewee-vargrant/'>
<p>感谢larryCai在持续交付中文站的投稿。</p>
</a>
<h1 id='id1'>简介</h1>
<p>虚拟机有很多好处,不仅仅节省硬件资源,而且还可以快速切换系统环境,显然会在软件开发中起到极大作用。</p>
<p>在<a href='http://www.continuousdelivery.info/index.php/2011/10/27/vagrant_jenkins_vm/'>上一篇vagrant和jenkins的文章</a>中我提到了vagrant这个工具,有点麻烦的是你必须有先要有一个盒子(vagrant box),盒子是vagrant对virtualbox的虚拟机的进一步封装,自己的虚拟机转变成vagrant的盒子有点麻烦,可以参见<a href='http://vagrantup.com/'>vagrant的说明</a>,因此一般都是找一个现成的来用。 但又没有更好的办法呢,现在网络的开放精神真是强大,你想到的一般就存在了,它就是我要介绍的<a href='http://github.com/jedi4ever/veewee'>veewee</a>,它的功能就是从你的ISO光盘从无到有装出需要的vagrant虚拟机(盒子)。</p>
<h1 id='veewee'>veewee使用入门</h1>
<p>这一块有篇英文文章<a href='http://www.ducea.com/2011/08/15/building-vagrant-boxes-with-veewee/'>Building Vagrant boxes with veewee</a>讲的不错,github上的官方网站<a href='http://github.com/jedi4ever/veewee'>veewee</a>也是蛮详尽的,我在这儿快速的重复一下,再加上一些自己的小技巧。</p>
<h2 id='id2'>安装</h2>
<p>首先你当然要安装好vagrant,virtualbox,veewee实际上是vagrant的一个插件,因此也肯定是ruby写的,安装也很方便(象我这种ruby菜鸟也能完成)。</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~ $ sudo gem install veewee</code></pre>
<h2 id='id3'>使用</h2>
<p>如果安装顺利,那么你就可以打个命令试试到底有何奥妙了。</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~ $ vagrant basebox templates
</code><code> The following templates are available:
</code><code> vagrant basebox define '<boxname>' 'Fedora-14-amd64-netboot'
</code><code> vagrant basebox define '<boxname>' 'ubuntu-10.04.2-server-i386-netboot'
</code><code> vagrant basebox define '<boxname>' 'CentOS-6.0-x86_64-netboot'
</code><code> vagrant basebox define '<boxname>' 'CentOS-4.8-i386'
</code><code> vagrant basebox define '<boxname>' 'Debian-5.0.8-amd64-netboot'
</code><code> vagrant basebox define '<boxname>' 'CentOS-5.6-i386'
</code><code> vagrant basebox define '<boxname>' 'CentOS-5.6-i386-netboot'
</code><code> vagrant basebox define '<boxname>' 'freebsd-8.2-experimental'
</code><code> vagrant basebox define '<boxname>' 'Fedora-15-i386-netboot'
</code><code> vagrant basebox define '<boxname>' 'ubuntu-11.04-server-i386'
</code><code> vagrant basebox define '<boxname>' 'ubuntu-8.04.4-server-amd64'
</code><code> vagrant basebox define '<boxname>' 'archlinux-x86_64'
</code><code> ..</code></pre>
<p>basebox就是veewee插件装好后变成的vagrant中的一个任务,从结果中可以看到已经有好多模板了,怎么用呢,先见一个目录如veewee,然后来创一个自己的机器。</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~$ mkdir veewee ; cd veewee
</code><code> rdccaiy@ubuntu:~/veewee$ vagrant basebox define 'ubuntu1104' 'ubuntu-11.04-server-i386'</code></pre>
<p>现在来看看新创了点什么东东。</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~/veewee$ find .
</code><code> ./definitions/ubuntu1104
</code><code> ./definitions/ubuntu1104/postinstall.sh
</code><code> ./definitions/ubuntu1104/preseed.cfg
</code><code> ./definitions/ubuntu1104/definition.rb</code></pre>
<p><code>definition.rb</code>中指定了iso文件</p>
<pre class='sh_lang'><code>Veewee::Session.declare({
</code><code> :cpu_count => '1', :memory_size=> '384',
</code><code> :disk_size => '10140', :disk_format => 'VDI', :hostiocache => 'off',
</code><code> :os_type_id => 'Ubuntu',
</code><code> :iso_file => "ubuntu-11.04-server-i386.iso",
</code><code> :iso_src => "http://releases.ubuntu.com/11.04/ubuntu-11.04-server-i386.iso",</code></pre>
<p>iso文件就是操作系统的安装光盘,建议先从网上下载,veewee要求本地的话就必须放在和`definitions`平级(也就是上面veewee的下面一级)的`iso`目录下。</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~/veewee$ ls iso
</code><code> ubuntu-11.04-server-i386.iso</code></pre>
<p>闲话少说,让veewee工作起来吧</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~/veewee$ vagrant basebox build ubuntu1104</code></pre>
<p>理论上它应该能无图形化执行,不过我的还是需要打开X-Windows,你应该看到virtualbox虚拟机起来,然后自动按键运行,中间还会重启,我蛮顺利的做出了虚拟机,真是很棒,如下图。(不知怎么的,每次看到电脑帮我自动打字,我进很开心)</p>
<img alt='veewee自动安装' src='http://www.continuousdelivery.info/wp-content/uploads/2011/11/veewee.png' title='veewee自动安装' />
<p>可以看到在终端上的漂亮log</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~/veewee$ vagrant basebox build ubuntu1104
</code><code>
</code><code> Verifying the isofile ubuntu-11.04-server-i386.iso is ok.
</code><code> We found no good state so we are destroying the previous machine+disks
</code><code> VBoxManage unregistervm 'ubuntu1104' --delete
</code><code> Deleting vm ubuntu1104
</code><code> Deleting disk /home/rdccaiy/VirtualBox VMs/ubuntu1104/ubuntu1104.vdi
</code><code> VBoxManage closemedium disk '/home/rdccaiy/VirtualBox VMs/ubuntu1104/ubuntu1104.vdi' --delete
</code><code> Creating vm ubuntu1104 : 384M - 1 CPU - Ubuntu
</code><code> Creating new harddrive of size 10140
</code><code> VBoxManage createhd --filename '/home/rdccaiy/VirtualBox VMs/ubuntu1104/ubuntu1104.vdi' --size '10140' --format vdi > /dev/null
</code><code> Attaching disk: /home/rdccaiy/VirtualBox VMs/ubuntu1104/ubuntu1104.vdi
</code><code> Mounting cdrom: /home/rdccaiy/veewee/iso/ubuntu-11.04-server-i386.iso
</code><code> Waiting for the machine to boot
</code><code> ....</code></pre>
<p>时间应该蛮长的,一切的OK的话,你就可以产生出vagrant的虚拟机了。</p>
<pre class='sh_lang'><code>rdccaiy@ubuntu:~/veewee$ vagrant basebox export 'ubuntu1104'</code></pre>
<p>然后就用vagrant的方法去尝试了,如`vagrant box add ‘ubuntu1104’ ubuntu1104.box`。</p>
<p>如果你要的操作系统模板没找到,可以到[veewee的最新代码中的模板库看看][veeweetemplates]</p>
<h1>veewee的原理</h1>
<p>如果你对操作系统安装(如linux)熟悉的话,应该能很快琢磨出道道来,veewee调用了[virtualbox的API-VBoxManage][vboxmanage]来控制虚拟机,如构建裸盘(`VBoxManage createhd`)和加载光盘。</p>
<p>现在再来看看那三个文件是干嘛的。</p>
<ul>
<li><code>definition.rb</code> 中是你的一些基本硬件配置,每个模板都差不多,中间一段定义了机器启动时如何加载,注意不同的操作系统会用不同的方法,redhat是kickstart,ubuntu是preseed</li>
<li><code>preseed.cfg</code>中就是ubuntu自动安装的配置参数,如果是SuSE,那就是<code>autoinst.xml</code>了,它来完成你的初始光盘安装。</li>
<li><code>postinstall.sh</code> 顾名思义就是装完操作系统后的后续工作,这和你想要的配置有关,为了vagrant,要加上相应的包,当然别做复杂了,记住你只是做一个操作系统的初始虚拟机,具体里面的东西可以让vagrant用puppet或chef来完成。</li>
</ul>
<h1 id='id4'>总结</h1>
<p>这篇文章主要简单讲了一下用<a href='http://github.com/jedi4ever/veewee'>veewee</a>这个软件来如何快速创建vagrant虚拟机,有没有体会到持续交付中反复提到的配置管理了,所有的东西都写成配置文件,然后有软件自动生成你要的东西,慢慢试试在体会吧。</p>
<p>下次我该来谈谈<a href='http://puppetlabs.com/'>puppet</a>了,而且是无主机模式的,给些建议鼓励鼓励吧 <a href='http://weibo.com/larrycai'>@larrycai</a>,让我持续交付。</p>
<h1 id='id5'>参考</h1>
<ol>
<li>larry的英文博客:http://codeslife.com/2011/10/25/create-virtualbox-on-fly-using-veewee/</li>
<li>veewee的官网:http://github.com/jedi4ever/veewee</li>
<li>老外介绍的如何用veewee建立vagrant盒子:<a href='http://www.ducea.com/2011/08/15/building-vagrant-boxes-with-veewee/'>Building Vagrant boxes with veewee</a></li>
<li>VirtualBox API - VBoxManage: https://www.virtualbox.org/manual/ch08.html</li>
<li>持续交付:http://www.continuousdelivery.info/</li>
</ol>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/vagrant-jenkins.html">使用vagrant和Jenkins来管理虚拟机的技巧</a></h1>
<p class="meta">
<time datetime="2011-10-27T14:53:00+08:00" pubdate="pubdate" data-updated="true">2011-10-27 Thu</time>
<span class="tags">
Tags:
<a href='/blog/tags/vagrant/'>Vagrant</a>, <a href='/blog/tags/jenkins/'>Jenkins</a>
</span>
<span class="share-to-weibo">
<a href="javascript:void(0)" onclick="window.open('http://service.weibo.com/share/share.php?appkey=3197495784&ralateUid=2036045341&title=使用vagrant和Jenkins来管理虚拟机的技巧 - &url=http://qiaoliang.github.com/blog/vagrant-jenkins.html', null, 'width=615,height=505,toolbar=0,status=0')" class="sina-weibo" title="分享到新浪微博"></a>
<a href="javascript:void(0)" onclick="window.open('http://share.v.t.qq.com/index.php?c=share&a=index&appkey=&title=使用vagrant和Jenkins来管理虚拟机的技巧 - &url=http://qiaoliang.github.com/blog/vagrant-jenkins.html', null, 'width=700,height=680,toolbar=0,status=0')" class="tencent-weibo" title="分享到腾讯微博"></a>
<a href="javascript:void(0)" onclick="window.open('https://twitter.com/intent/tweet?text=使用vagrant和Jenkins来管理虚拟机的技巧 - http://qiaoliang.github.com/blog/vagrant-jenkins.html', null, 'width=600,height=300,toolbar=0,status=0')" class="twitter" title="分享到Twitter"></a>
</span>
</p>
</header>
<div class="entry-content typo"><a href='http://www.continuousdelivery.info/index.php/2011/10/27/vagrant_jenkins_vm/'>
<p>感谢LarryCai在持续交付中文站的投稿。</p>
</a>
<h1>简介</h1>
<p>虚拟机有很多好处,不仅仅节省硬件资源,而且还可以快速切换系统环境,显然会在软件开发中起到极大作用。</p>
<p>在《持续交付》第十一章(11.7.1)中就提到了虚拟机环境的管理。如下图</p>
<img alt='通过虚拟机创建虚拟环境' src='http://www.continuousdelivery.info/wp-content/uploads/2011/10/1.png' />
<p>通过虚拟机创建虚拟环境</p>
<p>它描述的是在你的持续集成的jenkins ci服务器(以下简称jenkins)中,需要各种服务器来测试一个应用。我们可以快速的从虚拟机的vmm模板库中,启动需要的各种类型虚拟机,而不是每个都重新安装(省时),完成测试,产生报告后,也快速消失(省钱)。</p>
<p>让我们一起来看看一种漂亮的实现方案vagrant+jenkins实现技巧。</p>
<h1>基本知识</h1>
<h2>vagrant</h2>
<p>不同的虚拟机技术(virtualbox,vmware,xen\/kvm等等)可能用不同的方法管理,[vagrant][vagrant]是virtualbox的前端,它简化了virtualbox虚拟机的操作,而且增加了对自动化(provisioning)的puppet\/chef的支持,这里就不详细介绍。[vagrant][vagrant]的入门介绍已经很详细了,有一篇[博客][vagrantblog]也可以借鉴一下。</p>
<p>你要知道的就是下面的几个命令</p>
<pre class='sh_lang'><code>$ cd ubuntu1104-vm # 进入已有的 ubuntu 11.04 虚拟机目录
</code><code>$ vagrant up # 启动 ubuntu 虚拟机
</code><code>$ vagrant ssh -c "pwd"
</code><code>/home/vagrant
</code><code>$ vagrant halt # 停止虚拟机</code></pre>
<h2>jenkins ci</h2>
<p>jenkins 是一个最常用的持续集成服务器,可单独运行或者放在web服务器中运行。</p>
<p>直接启动一个任务(jenkins job)去调用vagrant操作虚拟机不是一个很好的方式,因为启动jenkins的用户(如tomcat)的权限都比较小,以防止任务误操作。</p>
<p>幸好jenkins有个超级棒的主从模式(master+slave)来解决。</p>
<h1>方案搭建</h1>
<h2>建立vagrant用户</h2>
<p>最好,先在一个机器上(可以和jenkins主机不在一起)创建一个vagrant用户,建立一套vagrant的用户环境。</p>
<p>因为无密码访问,所以要配好ssh环境,我们可以重用vagrant虚拟机的公私密钥,如下面的 identityfile就是私钥。</p>
<pre class='sh_lang'><code>vagrant@host:~/vm/ubuntu1104$ vagrant ssh_config
</code><code> host default
</code><code> hostname 127.0.0.1
</code><code> user vagrant
</code><code> port 2222
</code><code> userknownhostsfile /dev/null
</code><code> stricthostkeychecking no
</code><code> passwordauthentication no
</code><code> identityfile /var/lib/gems/1.8/gems/vagrant-0.8.7/keys/vagrant
</code><code> identitiesonly yes</code></pre>
<p>把公私密钥拷到vagrant用户的.ssh目录下。</p>
<pre class='sh_lang'><code>vagrant@host:~$ mkdir .ssh
</code><code>vagrant@host:~$ cp /var/lib/gems/1.8/gems/vagrant-0.8.7/keys/vagrant .ssh/id_rsa
</code><code>vagrant@host:~$ chmod 600 .ssh/id_rsa
</code><code>vagrant@host:~$ cat /var/lib/gems/1.8/gems/vagrant-0.8.7/keys/vagrant.pub >> .ssh/authorized_keys</code></pre>
<h2>jenkins slave设置</h2>
<p>然后到jenkins主机的 系统管理->管理节点->新建节点 来增加vagrant虚拟机节点,如下图。</p>
<img alt='配置jenkins虚拟机节点' src='http://www.continuousdelivery.info/wp-content/uploads/2011/10/2.png' />
<p>例子中,vagrant节点和jenkins主机在一台机器上,所以是localhost,配好了私有密钥,并且设置标签为vagrant-vm</p>
<h2>jenkins 任务设置</h2>
<p>现在可以设置新的任务了,选定自由风格(freestyle),如下图</p>
<img alt='配置jenkins任务' src='http://www.continuousdelivery.info/wp-content/uploads/2011/10/3.png' />
<p>限定它去vagrant-vm去执行,到时它就会触发jenkins从机(slave)的启动。</p>
<img alt='配置jenkins任务' src='http://www.continuousdelivery.info/wp-content/uploads/2011/10/4.png' />
<p>然后设置一个构建内容,就是启动虚拟机,执行命令(真实情况会用puppet安装,并进行测试)。</p>
<p>最后就可以让它跑起来。</p>
<h1>总结</h1>
<p>这篇文章主要简单讲了一下在jenkins中管理虚拟机的一种方案,自动化的安装puppet并没提到,可自己尝试。另外vagrant创立虚拟机也没有谈到,一般可以用veewee这个软件来完成,有空下次讲。</p>
<h1>参考</h1>
1. larry的英文博客:http://codeslife.com/2011/10/21/make-ci-easier-with-jenkins-ci-and-vagrant/
2. stackoverflow的问题讨论:http://stackoverflow.com/questions/6941547
3. vagrant: http://vagrantup.com/
4. vagrantblog: http://blog.crowdint.com/2011/06/21/vagrant.html
5. puppet: http://puppetlabs.com/
6. veewee: http://github.com/jedi4ever/veewee
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/CDMM.html">持续交付成熟度模型更新,新版本v1.2发布</a></h1>
<p class="meta">
<time datetime="2011-10-17T22:05:00+08:00" pubdate="pubdate" data-updated="true">2011-10-17 Mon</time>
<span class="tags">
Tags:
<a href='/blog/tags/chi-xu-ji-cheng/'>持续集成</a>, <a href='/blog/tags/chi-xu-jiao-fu/'>持续交付</a>, <a href='/blog/tags/cheng-shou-du/'>成熟度</a>
</span>
<span class="share-to-weibo">
<a href="javascript:void(0)" onclick="window.open('http://service.weibo.com/share/share.php?appkey=3197495784&ralateUid=2036045341&title=持续交付成熟度模型更新,新版本v1.2发布 - &url=http://qiaoliang.github.com/blog/CDMM.html', null, 'width=615,height=505,toolbar=0,status=0')" class="sina-weibo" title="分享到新浪微博"></a>
<a href="javascript:void(0)" onclick="window.open('http://share.v.t.qq.com/index.php?c=share&a=index&appkey=&title=持续交付成熟度模型更新,新版本v1.2发布 - &url=http://qiaoliang.github.com/blog/CDMM.html', null, 'width=700,height=680,toolbar=0,status=0')" class="tencent-weibo" title="分享到腾讯微博"></a>
<a href="javascript:void(0)" onclick="window.open('https://twitter.com/intent/tweet?text=持续交付成熟度模型更新,新版本v1.2发布 - http://qiaoliang.github.com/blog/CDMM.html', null, 'width=600,height=300,toolbar=0,status=0')" class="twitter" title="分享到Twitter"></a>
</span>
</p>
</header>
<div class="entry-content typo"><p>《持续交付》一书中提供的“持续交付成熟度模型”是1.0版本。这是经过再次调整的改进版,更具有指导性和可操作性。</p>
<p>使用说明:建议使用该模型进行现状分析,发现改进点,不建议将其作为绩效衡量的标准。</p>
<p>共有七个维度,它们分别是:</p>
<ol>
<li><em>持续集成</em> (Continuous Integration)</li>
<li><em>环境与部署</em>(Environments and Deployments)</li>
<li><em>可视化与可追踪性</em>(Visibility and Traceability)</li>
<li><em>测试</em>(Testing)</li>
<li><em>数据管理</em>(Data Management)</li>
<li><em>配置管理</em>(Configuration Management)</li>
<li><em>组织协调性</em>(Organisational Alignment)</li>
</ol>
<p>每个维度又分成五个级别,它们分别是:</p>
<ol>
<li><em>退化级</em>(Regressive)</li>
<li><em>可重复级</em>(Repeatable)</li>
<li><em>可定义级</em>(Definable)</li>
<li><em>可定量级</em>(Quantitatively managed)</li>
<li><em>改进级</em>(Optimizing)</li>
</ol>
<br />
<a href='http://www.continuousdelivery.info/index.php/2011/10/17/cd-v12'>更详细内容.</a>
</div>
</article>
</section>
<footer class="footer">
©2012 闲庭信步
-
Powered by <a href="http://octopress.org" target="_blank">Octopress</a>
</footer>
<ul id="social-links">
<!-- Sina Weibo -->
<li>
<a href="http://weibo.com/tony1130" target="_blank">
<svg width="40" height="40" class="sina-weibo" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path fill="#f9f9f9" d="M9.641,17.231c-3.799,0.374-7.079-1.343-7.326-3.838c-0.246-2.494,2.634-4.82,6.434-5.196 c3.798-0.377,7.079,1.34,7.326,3.835C16.32,14.529,13.44,16.855,9.641,17.231 M17.24,8.952c-0.322-0.098-0.544-0.163-0.375-0.587 c0.365-0.921,0.403-1.718,0.007-2.286c-0.745-1.063-2.783-1.005-5.12-0.027c0-0.002-0.734,0.321-0.546-0.261 c0.359-1.156,0.305-2.123-0.254-2.682c-1.267-1.271-4.639,0.047-7.53,2.936C1.257,8.209,0,10.504,0,12.488 c0,3.796,4.866,6.104,9.628,6.104c6.241,0,10.393-3.627,10.393-6.506C20.021,10.347,18.557,9.358,17.24,8.952" />
<path fill="#f9f9f9" d="M21.384,2.005c-1.507-1.671-3.73-2.308-5.782-1.872l0,0c-0.475,0.102-0.778,0.569-0.676,1.043 c0.101,0.473,0.567,0.777,1.043,0.674c1.459-0.31,3.039,0.145,4.111,1.332c1.069,1.188,1.362,2.806,0.902,4.225v0.001 c-0.149,0.462,0.104,0.957,0.566,1.106c0.461,0.149,0.956-0.104,1.105-0.565c0,0,0-0.002,0-0.004 C23.299,5.95,22.894,3.674,21.384,2.005" />
<path fill="#f9f9f9" d="M19.07,4.094c-0.734-0.814-1.817-1.123-2.817-0.912c-0.409,0.088-0.671,0.49-0.581,0.899 c0.088,0.407,0.489,0.67,0.896,0.58v0.001c0.488-0.104,1.019,0.047,1.379,0.445c0.359,0.398,0.455,0.941,0.301,1.416l0,0 c-0.127,0.398,0.09,0.825,0.488,0.954c0.396,0.127,0.824-0.091,0.952-0.488C20,6.017,19.805,4.908,19.07,4.094" />
<path fill="#f9f9f9" d="M9.85,12.713c-0.132,0.229-0.426,0.338-0.656,0.242c-0.227-0.094-0.297-0.348-0.169-0.572 c0.132-0.221,0.416-0.328,0.64-0.239C9.895,12.227,9.978,12.483,9.85,12.713 M8.64,14.268c-0.367,0.586-1.154,0.843-1.747,0.57 c-0.584-0.265-0.756-0.945-0.389-1.518c0.362-0.568,1.124-0.824,1.712-0.574C8.811,12.998,9.001,13.675,8.64,14.268 M10.021,10.118 c-1.808-0.47-3.852,0.431-4.637,2.023c-0.8,1.624-0.026,3.428,1.801,4.017c1.892,0.612,4.122-0.324,4.898-2.078 C12.848,12.367,11.891,10.602,10.021,10.118" />
</svg>
</a>
</li>
</ul>
<script src="/javascripts/application.js"></script>
<iframe src="/offline-cache.html" style="display:none"></iframe>
</body>
</html>