请选择 进入手机版 | 继续访问电脑版

ITIL,DevOps,ITSS,ITSM,IT运维管理-ITIL先锋论坛

 找回密码
 立即注册

扫描二维码登录本站

QQ登录

只需一步,快速开始

查看: 1039|回复: 0

你会写DevOps的文档吗?

[复制链接]
发表于 2018-8-23 14:53:32 | 显示全部楼层 |阅读模式
本帖最后由 monicazhang 于 2018-8-23 14:53 编辑 0 c& c4 B7 \+ @  [$ x. D5 ~
5 d! s+ K  r  P3 g/ ^$ z
每个ITILxf.com" target="_blank" class="relatedlink">DevOps都一个百宝箱,里面放着各种命令行脚本,可以用来自动化各式任务。但若文档不全,即便是脚本的作者,时间一久也不敢随便乱用,毕竟运维的大部分工作是管理生产环境,要是出了错,不是轻描淡写就可以蒙混过关的。写好 DevOps 的文档其实也是一门技术活儿,这里给大家分享一些组织运维脚本及其文档的经验。
/ }& m! ~2 g; c: \
1.png

- e/ J$ u  z) ~$ v
Fabric的任务管理与文档
" ]1 A, W8 d! \  [$ ]; Z
在以前的文章中,我们曾经介绍过Glow使用了fabric来执行各种日常管理的任务。Fabric提供了非常好用的任务组织以及查阅任务文档的功能。
2 N0 x4 W' L/ B
Fabric的主文件一般命名为fabfile.py,但任务多了,都写在一个文件里显然很难维护。Fabric有一个很实用的特性,就是当fabfile.py里导入其他模块时,会自动发现里面的fabric任务。利用这个特性,可以把各种任务分类写在不同的模块中,然后在fabfile.py中统一导入。比如 Glow 的 DevOps 代码库的结构大概长这个样子:

0 W# e, j) Y, F4 ?
$ tree
- P5 U1 J9 t* O6 F- D7 s4 i0 B├── __init__.py# H/ e/ M$ O5 W
├── fabfile.py, J+ }: c* a4 N: T1 _7 o
├── fab_scripts
  R, e$ p! i3 w" ~) \│   ├── __init__.py" M  [$ s2 h1 u
│   ├── monitors.py
' e3 [9 D# N0 I! i3 H6 ~│   ├── mysql.py4 S' u9 X+ c$ k9 `" Y
│   ├── nginx.py
  a1 S7 ~: A" y# `8 s│   ├── redis.py* W& d7 z  j8 M4 b, t$ b
│   ├── scaling.py
5 L' y# m5 c8 x: g│   ├── services.py

( `$ _* t. B; ^, N! E) [
在fabfile.py里除了一些最核心的任务脚本外,主要就是一些import语句
9 n" ?. n# T* e" B
# fabfile.pyfrom fab_scripts import monitors  
% ]0 y3 K! d' ?6 Y( Nfrom fab_scripts import mysql  
5 V3 {& x' Y% e. U$ Q* j3 k5 r4 Bfrom fab_scripts import nginx  
3 i6 J7 \; D( l9 |from fab_scripts import redis  
* \+ ]: v# I7 w( mfrom fab_scripts import scaling  
, s& @2 C7 L* x3 }from fab_scripts import services  

5 O$ s6 Q3 q1 `; p% L$ }+ k
这样我们就把散落在多个文件里的任务聚集到了一起,我们可以用fab -l来列出所有可执行的任务及其描述,其中任务描述来自于对应任务的第一行docstring。例如,
/ p& s, c" f; w  G# z; ]# i
+ h) A" \% H$ s/ ?/ c3 u# }$ [
$ fab -lAvailable commands:   monitors.get                Get YAML definition of monitors   monitors.list               List names of all monitors   monitors.mute               Mute specific groups of monitors   monitors.mute_all           Mute all monitors globally   monitors.unmute             Unmute specific groups of monitors   monitors.unmute_all         Unmute all monitors globally   mysql.connection_list       Show number of DB connections group by host   mysql.connection_sources    Show number of DB connections group by process   nginx.turn_off_maintenance  Turn off site maintenance mode.   nginx.turn_on_maintenance   Turn on site maintenance mode. Return 503.   redis.auto_save             Update saving settings for redis instances   redis.start_slave           Set master and start replication.   redis.stop_slave            Stop replication and set its master to none.   scaling.add_servers         Launch more instances in specific server group   scaling.create_image        Create an image for provisioning new instances   scaling.get_latest_tag      Get latest tag of deployed code   services.cycle              Restart application services.   services.start              Start application services.   services.stop               Stop application services.
9 B& E" \# k( u  p
这里可以看到,将任务分写在不同的模块,模块名就起到了Namespace的作用。在显示命令列表时,在同一个Namespace下的命令被聚集到了一起,很好地起到了任务分类的作用。使用fab -d [task_name]可以显示该任务完整的docstring。规整的docstring可以让执行任务的用户清楚地理解其作用及参数用法。我们在写fabric任务的docstring时,一般分为三个部分2 V$ \' Y" q& v, B8 L

; W3 v) B; F8 N5 ^, U
  • 任务的简单介绍
  • 任务的参数
  • 具体用例
    / k/ H6 q) [6 {/ B! X$ z% k7 ?
最后一点由为重要,有些任务参数众多,即使读了参数说明,仍会让人有些云里雾里。但几个典型的实际用例,对于用户了解任务的用法会起到至关重要的作用。在下面的例子中,我们展示了deploy任务(代码部署)的说明文档

, y3 u4 Z( Z0 |) Q  e1 u% i
$ fab -d deploy" _) K3 j! B' ?  J# y7 ~
Displaying detailed information for task 'deploy':
# D0 }. }( u* A2 R  t% v" I1 n+ x! S8 }; L9 D! c4 Y
   Deploy code to targeted server_group.1 b9 D$ n7 c; X# }) V
   You need put ansible vault password at ~/.ansible_vault_passwd directory,
; T1 M1 e0 m5 n/ ~& J) M   otherwise you would be prompt to enter vault password.: V0 g4 d) G. u' E8 f

" I% k3 Y! w& C1 z0 h+ _   Args:
6 Q* X% _) S8 N8 H/ d: z- |5 y       server_group: Possible values include prod, stage
5 \9 B3 |$ Q6 }* g! l. }( N       release_tags: A list of release tags to be pushed
' w2 E) D8 D5 U+ N4 D: y) @! ~; ^
, [' E- R' z4 u+ F7 x" s/ {9 O  [   Examples:        # Deploy to stage) b' `8 I6 O5 h3 R6 O' h; N8 f+ o
       fab deploy:stage,glow_stage_1446102452        # Deploy to production
" |$ j; x4 h! a9 Z2 s       fab deploy:prod,glow_prod_1446102452        # Deploy multiple repo at once, |- c7 z* r- {1 |' J
       fab deploy:prod,glow_prod_1446102452,nurture_prod_1445102467
; U. v& }& z* A1 U3 I% G
动态Docstring
- \+ }, d& w. s' E
在Python中,docstring其实就是函数的__doc__的属性,所以我们可以像修改普通变量那样动态修改docstring,这给我们生成动态文档或是重用公共的文档提供了可能。例如,我们的services模块下有cycle,start,stop三个任务,分别用来重启,开始,停止我们的microservice。我们当然希望在用fab -d来查看任务的文档说明时,同时可以显示所有可用的microservice。但hard-coded现有的microservice是一个愚蠢的做法,这样我们不但需要把同一段文档复制三份,并且每次新增一个microservice时还要记得来更新文档。这里我们用Python的decorator来动态地把可用服务的信息添加到docstring中。比如cycle任务的定义是这样的:

% \. `, f, K8 z* V
@task@services_docdef cycle(*services, **kwargs):  
0 \$ O* W# F, t1 c: z   """Restart application services.+ Y; }2 \1 l8 q. W- d' I. H
& t  `9 U& [% ^
   Args:" ]& e3 b& s+ s- A0 j- |9 i
       services: list of services need cycle (separate by comma)% F& `- B0 z! ], R0 s; @3 V

$ Z' }& d! L# Z6 p4 [0 ]   Examples:7 h0 O7 R5 F; A* a
       fab services.cycle:glow-www,glow-forum" e$ V* M7 b4 \* ?- U- J3 ?1 Q5 S
   """
9 l2 ~( y! f4 L, k0 ~5 Y+ l
注意到这里用了@service_doc这个decorator,它的定义如下:
7 Z8 g. j9 o+ h8 P; R- d5 V2 y5 \
def services_doc(func):  . W9 y  t& U' G% _3 Z/ w
   services = get_available_services()9 T# I4 a9 z( E2 t2 f4 f
   doc = """
/ s7 x/ ~0 X% M7 w% d2 k- n- i5 g' x! G   Possible values for services:& l( j$ T3 ~' `* P
{}
/ }6 h8 W9 p  C5 r* R" J6 W6 U   """.format(" ".join(" " * 8 + x for x in services))
% a* ^  `* v( F  w2 W+ C3 X: A   func.__doc__ += doc    return func

* I4 H+ g( W( [' p; {
我们通过get_available_services来动态取得当前环境下可用的microservice(这里我们不关心get_available_service是如何实现的),并将其添加到函数的docstring之后。这样,当我们查看cycle的方法时,所有可用的microservice也会显示出来。

2 M, _3 I: C% ^/ z4 D
! R2 }, x' v$ K( p, v6 Q: m. S; d. b" }$ fab -d services.cycleDisplaying detailed information for task 'services.cycle':   Restart application services   Args:       services: list of services need cycle (separate by comma)   Examples:       fab services.cycle:glow-www,glow-forum   Possible values for services:       glow-www       glow-user       glow-forum       ...! \! S) N* e2 a6 p

5 V6 _& z1 [, z
动态外部文档
: ], Y" }% }0 @1 c% |
除了docstring,我们也经常需要写独立的外部文档。在Glow,这些文档绝大部分都是用Markdown来写的。例如,我们需要写一个介绍生产环境架构的文档,其中肯定会加入生产环境中有哪些服务器,每个服务器的功能描述以及它们的hostname。我们可以用手动的方式来写,但每当为生产环境添加新服务器时,我们必须记得更新这份文档。
/ D. x; h) U3 K. C; f1 p
+ H3 s4 }4 i+ Y
而实际情况是,我们从来不在AWS的控制台手动创建服务器,所有的服务器都是由Ansible来创建与维护的。也就是说,所有的服务器配置信息及其功能描述都已经存在于Ansible的playbook中。当我们写外部文档时,应该去引用Ansible中的信息,而不是重写手写一遍。
% y8 d. L$ }0 L) n+ c
2.png
) v% J+ P5 E4 H8 n: b) ?
1 N' Q7 ?9 i, F/ j, u
所以在我们的生产环境文档中会利用HTML注释来指定需要外部引用的部分,然后通过执行脚本将这些引用的内容填充至文档里。例如,在我们的生产环境文档中有这样一段:
8 q$ [& j9 h- Z
## EC2 servers<!-- BEGIN EC2-SERVER-LIST -->  | Server group | Instance type | Count | Description           |
0 `0 f. }4 i9 n4 e  w# K# i( T6 e|:-------------|:--------------|------:|:----------------------|. S1 H0 v8 t, u+ ?/ Q, m2 s) z
| bastion      | t2.small      |     1 | Bastion/Jumper server |
) A# u, S6 H1 I1 A| www          | c3.large      |     4 | Web servers           |
4 [* f+ v* Q& p* ^...<!-- END EC2-SERVER-LIST -->  
& m6 y( e4 G) p" k, S' i2 B! }
$ I9 ]; F3 I! q! d; z
这里<!-- BEGIN EC2-SERVER-LIST -->和<!-- END EC2-SERVER-LIST -->之间的表格就是一个外部引用,每次Ansible更新服务器配置时,会执行一个脚本,它会自动在文档中查找这对标签,并更新其中的内容。这是一个很简单的技术,但对于保持文档与实际环境同步很有帮助。

' n+ L7 ^' j* \/ O4 W
原创:叶剑烨
& D8 V: g+ V& h/ E- A

. ^2 ~2 ]4 ?1 b/ c# n, \* \7 ~, L; s5 U0 t/ C
# J1 n: i# O- a4 Z  Y




上一篇:DevOps未来趋势和展望
下一篇:DevOps平台实践落地-构建管理详解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

参加 ITIL 4 基础和专家认证、长河ITIL实战沙盘、DevOps基础级认证、ITSS服务经理认证报名
本站关键字: ITIL| ITSM| ISO20000| ITIL培训| ITIL认证| ITIL考试| ITSS| ITSS培训| ITSS认证| IT运维管理| DevOps| DevOps培训| DevOps认证| itop| itil4| sre| 开源ITSM软件

QQ|ITIL先锋论坛 ( 粤ICP备11099876号 )|appname

Baidu

GMT+8, 2022-5-23 04:40 , Processed in 0.109865 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表