V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Glowapp
V2EX  ›  DevOps

写好 DevOps 的文档 by Glow CTO Ryan YE

  •  
  •   Glowapp · 2015-11-16 12:13:07 +08:00 · 4071 次点击
    这是一个创建于 3293 天前的主题,其中的信息可能已经有所发展或是发生改变。
    每个 DevOps 都一个百宝箱,里面放着各种命令行脚本,可以用来自动化各式任务。但若文档不全,即便是脚本的作者,时间一久也不敢随便乱用,毕竟运维的大部分工作是管理生产环境,要是出了错,不是轻描淡写就可以蒙混过关的。写好 DevOps 的文档其实也是一门技术活儿,这里给大家分享一些组织运维脚本及其文档的经验。


    因为行文里有一些附图,我就统一更新在评论上。
    原文地址 http://tech.glowing.com/cn/better-documentation-for-devops/
    Ryan 个人博客 http://yejianye.com/
    我司官网 glowing.com
    我司微信 Glow_Inc
    4 条回复    2015-11-16 15:53:12 +08:00
    Glowapp
        1
    Glowapp  
    OP
       2015-11-16 12:13:50 +08:00
    Fabric 的任务管理与文档
    在以前的文章中,我们曾经介绍过 Glow 使用了 fabric 来执行各种日常管理的任务。 Fabric 提供了非常好用的任务组织以及查阅任务文档的功能。
    Fabric 的主文件一般命名为 fabfile.py ,但任务多了,都写在一个文件里显然很难维护。 Fabric 有一个很实用的特性,就是当 fabfile.py 里导入其他模块时,会自动发现里面的 fabric 任务。利用这个特性,可以把各种任务分类写在不同的模块中,然后在 fabfile.py 中统一导入。比如 Glow 的 DevOps 代码库的结构大概长这个样子


    fabfile.py 里除了一些最核心的任务脚本外,主要就是一些 import 语句



    这样我们就把散落在多个文件里的任务聚集到了一起,我们可以用 fab -l 来列出所有可执行的任务及其描述,其中任务描述来自于对应任务的第一行 docstring 。例如,



    这里可以看到,将任务分写在不同的模块,模块名就起到了 Namespace 的作用。在显示命令列表时,在同一个 Namespace 下的命令被聚集到了一起,很好地起到了任务分类的作用。使用 fab -d [task_name]可以显示该任务完整的 docstring 。规整的 docstring 可以让执行任务的用户清楚地理解其作用及参数用法。我们在写 fabric 任务的 docstring 时,一般分为三个部分
    • 任务的简单介绍
    • 任务的参数
    • 具体用例

    最后一点由为重要,有些任务参数众多,即使读了参数说明,仍会让人有些云里雾里。但几个典型的实际用例,对于用户了解任务的用法会起到至关重要的作用。在下面的例子中,我们展示了 deploy 任务(代码部署)的说明文档



    动态 Docstring

    在 Python 中, docstring 其实就是函数的__doc__的属性,所以我们可以像修改普通变量那样动态修改 docstring ,这给我们生成动态文档或是重用公共的文档提供了可能。例如,我们的 services 模块下有 cycle,start,stop 三个任务,分别用来重启,开始,停止我们的 microservice 。我们当然希望在用 fab -d 来查看任务的文档说明时,同时可以显示所有可用的 microservice 。但 hard-coded 现有的 microservice 是一个愚蠢的做法,这样我们不但需要把同一段文档复制三份,并且每次新增一个 microservice 时还要记得来更新文档。这里我们用 Python 的 decorator 来动态地把可用服务的信息添加到 docstring 中。比如 cycle 任务的定义是这样的



    注意到这里用了 @service_doc 这个 decorator ,它的定义如下



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



    动态外部文档

    除了 docstring ,我们也经常需要写独立的外部文档。在 Glow ,这些文档绝大部分都是用 Markdown 来写的。例如,我们需要写一个介绍生产环境架构的文档,其中肯定会加入生产环境中有哪些服务器,每个服务器的功能描述以及它们的 hostname 。我们可以用手动的方式来写,但每当为生产环境添加新服务器时,我们必须记得更新这份文档。而实际情况是,我们从来不在 AWS 的控制台手动创建服务器,所有的服务器都是由 Ansible 来创建与维护的。也就是说,所有的服务器配置信息及其功能描述都已经存在于 Ansible 的 playbook 中。当我们写外部文档时,应该去引用 Ansible 中的信息,而不是重写手写一遍。
    所以在我们的生产环境文档中会利用 HTML 注释来指定需要外部引用的部分,然后通过执行脚本将这些引用的内容填充至文档里。例如,在我们的生产环境文档中有这样一段



    这里<!-- BEGIN EC2-SERVER-LIST -->和<!-- END EC2-SERVER-LIST -->之间的表格就是一个外部引用,每次 Ansible 更新服务器配置时,会执行一个脚本,它会自动在文档中查找这对标签,并更新其中的内容。这是一个很简单的技术,但对于保持文档与实际环境同步很有帮助。

    小结

    几乎所有人都承认文档的重要性,但真正愿意在文档上花费精力的团队却十分有限。写这篇文章是希望大家能意识到,文档其实也是代码的一部分,也应该遵循 DRY 原则,也可以通过编程的手段来动态生成与自动更新。
    如果各位对这种文档与代码结合的概念有兴趣,你也许听过 Literate programming ,( https://en.wikipedia.org/wiki/Literate_programming )那 Literate programming 与 DevOps 结合会是什么样子,有兴趣的可以看看这个视频(
    oclock
        2
    oclock  
       2015-11-16 13:55:25 +08:00
    All due respect 技术布道和招聘广告还是应该分开
    dreampuf
        3
    dreampuf  
       2015-11-16 14:24:35 +08:00
    更常见的做法是将 fabfile 作为一个文件夹,在其中__init__.py 文件加载相关的 scripts
    adoyle
        4
    adoyle  
       2015-11-16 15:53:12 +08:00
    写得真棒!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5722 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:43 · PVG 09:43 · LAX 17:43 · JFK 20:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.