Tips:同上《进击的 Ansible(一):Ansible 快速入门》,本文使用Ansible2.5.4版本,项目演示环境为MacOS。由于Ansible项目的活跃版本更新较快,很多API接口不向后兼容,所以练习本文时请确保使用的版本一致。学完上一篇《进击的 Ansible(一):Ansible 快速入门》,发布单个项目绰绰有余。然而在实际生产环境中,一个服务往往有多个组件。比如在部署大数据服务的时候,往往需要部署一个“大数据全家桶”:Hadoop、Zookeeper、Hive、Mysql、Flink等,这时候依赖其中的知识就有点捉襟见肘了上一篇文章。yaml文件等配置文件较多,依赖关系复杂。如果不能正确划分目录组织项目结构,对于后期的维护是非常不利的。那么今天的文章就着重解决这个问题:如何科学正确的划分Ansible应用的目录结构?将Ansible视为一种编程语言,首先要确立一个概念:“将Ansible视为一种编程语言”。我们可以将Ansible理解为专门用来管理自动化发布的DSL。其基本语法规则约等于yaml语言规则,如synchronize、pip、template等,同时Ansible模块可以等同于语言的内置函数或内置包,即写剧本正在编写Ansible语言的代码块。这样,只要我们沿着编程语言的思路去理解Ansible,很多疑惑就会迎刃而解:比如Ansible支持变量,模块when是编程语言if的流程控制语句,模块循环orwith_*是编程语言中for或while的循环迭代语句。我们如何在使用编程语言进行项目开发的过程中降低项目的复杂度?当然是“模块化”。不同的功能被打包成不同的包或文件,构成业务功能的最小单元称为“模块”。在项目的入口文件中,我们使用import(Python、Golang等语言使用此关键字)或require(Node.js等语言使用此关键字)等关键字来加载需要的模块,然后我们就可以进行业务逻辑的编排了。https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...https://zhuanlan.zhihu.com/p/...这样做的好处是显而易见的。模块是业务功能的具体实现。后面需要修改的时候,只需要修改相关的模块即可。这正是SOLID原则中的“SRP”(单一职责原则)所提倡的。此外,模块化还支持像“搭积木”一样根据业务需求灵活组织业务流程,使现有模块得到最大程度的复用,这也符合“DRY”(Don'tRepeat你自己)在编程原理中。因此,既然我们把Ansible看成一种编程语言(DSL),我们可以发现在Ansible的文档中,“模块”的概念是用Roles来表示的,导入的概念是用import_tasks、include_tasks等来表示的。让我在这里题外话。不知道有没有人觉得Ansible中发明的“playbook”和“roles”这些直译为“脚本”和“角色”的概念是混淆的?关键概念:角色现在我们已经建立了“角色=模块”的概念。让我们看一下文档中Roles的定义并丰富细节:Roles让您可以根据已知的文件结构自动加载相关的变量、文件、任务、处理程序和其他Ansible工件。将内容按角色分组后,您可以轻松地重用它们并与其他用户共享。角色允许您根据已知文件结构自动加载相关变量、文件、任务、处理程序和其他Ansible工件。对内容分组后通过角色,它们可以很容易地被重用并与其他用户共享。”Roles说白了就是对变量、文件、任务等的封装,目的是为了模块复用。Roles如何使用?在软件设计范式的最佳实践中,有一种叫做“约定大于配置”。简单地说,“软件做了一些先决条件假设。这些假设是软件开发人员和软件用户之间的协议。作为软件用户,你遵守这些约定就够了,没有必要(也不支持)去配置这些约定。”——某种程度上可以理解为软件中的默认配置。Ansible在使用Roles时也存在“约定大于配置”的情况,这些约定是死板的(即不支持在配置文件中自定义)。首先,Role的目录结构是固定的。Ansible角色具有定义的目录结构,其中包含八个主要标准目录。您必须在每个角色中至少包含这些目录之一。您可以省略该角色不使用的任何目录。Ansible角色具有定义的目录结构,其中包含八个主要标准目录。八个主要标准目录。指定的目录结构如下:├──defaults│└──main.yml├──files├──handlers│└──main.yml├──meta│└──main.yml├──tasks│└──main.yml├──templates├──tests│├──inventory│└──test.yml└──vars└──main.yml默认情况下,Ansible会在角色中的每个目录中查找一个main.yml文件获取相关内容。这八个目录的作用是:tasks/main.yml:放置role执行任务时使用的文件。handlers/main.yml:处理程序,可以在角色内部或外部使用library/my_module.py:模块,可以在角色中使用(有关更多信息,请参阅在角色中嵌入模块和插件)。defaults/main.yml:角色的默认变量(有关更多信息,请参阅使用变量)。这些变量在所有可用变量中的优先级最低,可以很容易地被任何其他变量(包括库存变量)覆盖。vars/main.yml:作用中的其他变量。(vars在Ansible模块中的作用是一样的,只是这里的vars代表一个目录。)files/main.yml:用于角色部署的文件。templates/main.yml:用于角色部署的模板。与Ansible模块中的模板功能相同,只是这里的模板代表的是目录。)meta/main.yml:角色使用的元数据。每个角色必须至少包含一个这样的目录。当然我们可以省略任何角色没有用到的目录,但是每个目录下的main.yml文件是该目录的入口文件,Ansible在读取的时候默认会去寻找这个文件。所以这个main.yml文件不能省略。第二,存储和查找角色。上面我们了解了一个角色的内部目录结构,但这远远不能满足实际生产的需要。文章开头我们还以一个大数据项目为例,该项目往往需要部署Flink、Hadoop等多个组件。这些组件中的每一个都可以被视为一个角色。那么Ansible是如何找到角色的呢?默认情况下,有两种方式:在Ansible发布项目中,创建一个名为roles的目录。默认情况下,Ansible会自动在/etc/ansible/roles目录中查找角色。比如我们要使用Ansible创建一个发布大数据“全家桶”的大数据项目。本项目必须包含三个角色:Flink、Mysql、Hive。那么bigdata项目的目录结构大致如下:?bigdatatree-L3.└──roles├──flink│├──defaults│├──files│├──handlers│├──meta│├──任务│├──模板│├──测试│└──vars├──配置单元│├──默认值│├──文件│├──处理程序│├──元│├──任务│├──模板│├──测试│└──vars└──mysql├──defaults├──files├──处理程序├──meta├──tasks├──templates├──tests└──varscanbe明显看到roles下的Flink、hive、Mysql的子目录结构就是上面说的八个目录。Ansible-galaxy快速创建角色。从上面我们可以看出,每个创建的角色都必须至少包含八个主要目录之一。所以Ansible内置了一个命令行工具ansible-galaxy来快速创建角色的八大目录,减少我们的工作量。假设角色名为flink,使用如下命令生成相关目录:ansible-galaxyinitFlink使用tree命令查看ansible-galaxy生成的目录正是角色需要的标准八个目录。?treeflinkflink├──README.md├──defaults│└──main.yml├──files├──handlers│└──main.yml├──meta│└──main.yml├──tasks│└──main.yml├──templates├──tests│├──inventory│└──test.yml└──vars└──main.ymlansible-galaxyinit其他几个有用的参数:ansible-galaxyinit-forcerole_name,如果默认创建的角色与当前工作目录下存在的文件同名,则抛出异常。使用-force选项会强制创建角色目录,并替换角色目录下的同名目录或文件。ansible-galaxyinit--role-skeleton=/path/to/skeletonrole_name,用过Maven的同学应该知道,Maven支持以其他项目为骨架新建项目。ansible-galaxy也支持这个功能,以/path/to/skeleton路径下的角色为骨架,复制所有文件创建新角色。Galaxy:角色在线分享社区此外,与DockerHub、GrafanaDashboards类似,AnsibleGalaxy还有一个在线社区Galaxy[https://galaxy.ansible.com/home],里面有开发者分享的各种开发角色。方便我们搜索现成的角色下载,也可以将自己开发的角色上传到Galaxy。下载或上传角色到Galaxy网站,还需要使用命令行工具ansible-galaxy。默认情况下,ansible-galaxy调用的Galaxy服务器地址为https://galaxy.ansible.com,Galaxy地址可以通过-server选项或在ansible.cfg文件中重新配置。下载角色下载角色的语法模板为:$ansible-galaxyinstallusername.role_nameansible-galaxy默认会将角色下载到环境变量ANSIBLE_ROLES_PATH中,ansible-galaxy提供参数--role_path指定角色下载地址.Ansible-galaxy其他命令一目了然ansible-galaxysearchelasticsearch,在Galaxy官网找到角色elasticsearchansible-galaxyinfousername.role_name,查看username.role_name的详细信息ansible-galaxylist,查看安装的角色ansible-galaxy去掉username.role_name,卸载安装的username.role_nameansible-galaxylogin,登录Galaxy网站整体布局:套装最好如果你坚持看完上面的部分,那你一定知道角色的使用方法了。简单的说就是需要在当前的Ansible应用下存在一个名为roles的目录。接下来说说如何布局Ansible应用下roles目录以外的其他目录?官方的Ansible最佳实践文档[https://docs.ansible.com/ansi...]建议:您对Ansible的使用应该符合您的需要,但不符合我们的需要,因此请随意修改此方法并根据您的需要进行组织觉得合适。组织playbook内容的一种重要方法是Ansible的“角色”组织功能,该功能记录在主要playbook页面中。您应该花时间阅读并理解此处提供的角色文档:Roles.Ansible的整体目录结构没有一定的规则,只要适合您当前的需求即可。但是角色的概念是至关重要的。良心的Ansible官方在Github上开了一个项目ansible-examples[https://github.com/ansible/an...],收集优秀的最佳实践。大家可以根据自己的实际需要借鉴。分享一下我常用的项目布局:.├──Makefile├──README.md├──deploy.retry├──deploy.yml├──files│├──apache-maven-3.8.3-bin.tar.gz│├──apache-zookeeper-3.7.0-bin.tar.gz│├──flink-1.14.0-bin-scala_2.11.tgz│├──hadoop-2.7.5.tar│├──hadoop-3.3.1.tar.gz│├──mysql-connector-java-8.0.26-1.el7.noarch.rpm│├──mysql-connector-java-8.0.26.jar│└──openjdk-11.0.2_linux-x64_bin.tar.gz├──库存│└──主机└──角色├──flink├──hadoop├──hadoop3├──hive├──java├──linux├───mvn├──mysql└──zookeeperMakefile,用于封装Ansible的发布命令deploy.ym,是执行Ansible命令时的入口文件文件,用于存放角色相关的部署包,一般比较大,不用git用于版本管理。库存,用于管理部署机器。角色,用于部署的组件。从上面的目录可以看出,目前主要用于部署大数据相关的组件。
