Ansible 学习总结中,有哪些关键点或技巧容易被忽视?

摘要:世事洞明皆学问,人情练达即文章。 导航 1 工具介绍 1.1 Ansible 简介 1.2 Ansible 概念 1.3 工作原理 1.4 作用范围 2 配套命令 2.1 ansible 2.2 ansible-playbook 2.3 a
世事洞明皆学问,人情练达即文章。 导航 1 工具介绍 1.1 Ansible 简介 1.2 Ansible 概念 1.3 工作原理 1.4 作用范围 2 配套命令 2.1 ansible 2.2 ansible-playbook 2.3 ansible-doc 2.4 ansible-vault 2.5 ansible-galaxy 2.6 ansible-console 3 Inventory - 主机清单 4 Playbook - 任务清单 4.1 Keywords - 关键词 4.2 Vars - 变量 4.2.1 变量优先级 4.2.2 文件变量 4.2.3 特殊变量 4.2.4 调用变量 4.3 Tasks - 任务 4.3.1 Tasks 4.3.2 Roles 4.3.3 Handlers 4.4 其它技巧 4.4.1 When - 判断 4.4.2 Loop - 循环 5 常用模块 6 常用插件 7 杂七杂八 1、工具介绍 1.1、Ansible 简介 Ansible 是一款开源的自动化运维工具,主要用于服务器批量管理、应用部署和任务自动化。它主要的特点有:(1)无客户端的架构,免去了安装客户端的困扰。(2)基于 YAML 的语法配置,使得 Playbook 配置很容易阅读。(3)采用了 模块化的设计,使得其灵活度较高。(4)幂等性。 注:什么是幂等性? 当系统处于您的任务所描述的状态时,即使多次运行同一任务,Ansible 也不会更改任何内容。【例如:通过 lineinfile 模块去为 test 文件中以 a 开头的行的前面添加一行字串 test123,当多次执行同一任务 ansible localhost -m lineinfile -a "path=test state=present line=test123 insertbefore='^a'" 时,会发现 test 文件并没有随着任务的重复执行而重复添加多行 test123 字串,这便是幂等性。】 1.2、Ansible 概念 管理节点:运行 Ansible CLI 工具(ansible、ansible-playbook、ansible-vault 等)的机器。 被管节点:用 Ansible 管理的目标设备(服务器、网络设备或任何计算机)。 ==== 清单-inventory:被管节点的 主机列表,也被叫做“主机文件”。 剧本-playbook:用 YAML 编写的,用来描述自动化任务(指定哪些主机运行哪些命令任务)的文件。 剧集-play:一个剧本可以包含多个剧集,而一个剧集可以理解为:针对一组主机的一次完整执行任务的计划。【注:一个 Play 是由 关键词、变量、任务 组成,其中任务又分为以下三种。】 任务-task:用于定义执行的命令操作,相当于执行 单条命令。 角色-role:多个任务集中整合在了一起,相当于执行 一个 Bash 脚本。【注:Ansible 内置角色、第三方角色】 处理器-handler:可触发式的任务,相当于 Bash 脚本中定义的 Bash 函数。 ==== 模块:一个模块相当于一条 Linux 命令。【注:Ansible 内置模块】 插件:用于 扩展 Ansible 的功能。默认情况下,Ansible 远程目标只支持 ssh 的连接协议,但通过连接插件,它还可以支持 winrm、netconf 协议。【注:Ansible 内置插件】 集合:Ansible 内容的分发格式,可以包含剧本、角色、模块和插件。默认情况下,我们所使用的模块、插件 都是来自 Ansible.Builtin 集合。如果你想管控 windows 设备,那我们一定要使用 Ansible.Windows 集合中的模块。【注:Ansible 内置集合、第三方集合】 Playbook 用法汇总示例: #本配置中的所有内容即代表一个剧本 #剧集一 - hosts: linux tasks: ##任务1 - name: install nginx yum: #yum 模块 name: nginx state: present ##任务2 - name: update nginx config template: #template 模块 src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx #调用处理器 handlers: #定义处理器 - name: restart nginx service: name: nginx state: restarted #剧集二 - hosts: windows collections: #声明集合,不声明调用集合模块需带集合名称,如 ansible.windows.win_file。 - ansible.windows tasks: - name: Remove a file, if present win_file: #调用 windows 集合中的模块 path: C:\Temp\foo.conf state: absent #剧集三 - hosts: web roles: #角色 - nginx 1.3、工作原理 Ansible 管理节点(1)首先与被管节点 Agent 建立远程连接,并检查当前系统的模块脚本执行环境。(2)接着管理端将任务模块对应的模块脚本传输至 Agent 端并执行,模块脚本执行时会先进行“状态检测判断”,然后将结果以 json 格式返回。(3)最后删除 Agent 处的临时模块脚本文件并关闭连接。 注:(1)状态检测判断流程:① 获取当前状态。② 与 Playbook 期望状态对比。③ 决定是否执行修改。【注:以上述修改 test 文件为例。当第二次执行任务时,发现文件中已在 a 行的前面添加了 test123,这正符合 Playbook 的期望,于是本次任务并不会做出任何修改。】(2)Ansible 中的 模块其实是用 Python/Powershell 脚本实现的,它具有和 Linux 命令相类似的功能。 因此,这也就说明了为什么 Ansible 要求被管节点需要具备 Python 或 Powershell 的执行环境。 1.4、作用范围 Ansible 拥有丰富的插件和功能模块。而借助其 连接插件,理论上可对大多数设备(Linxu、Windows、网络设备)进行远程管理。但实际上,它只是对 Linux 设备支持度较好(注:大多数功能模块都只对 Linux 有效),对 Windows 和网络设备的管理效果一般。 注:Ansible 对不同设备能否被管理的要求如下: 对 Linux 设备的要求:(1)开启 SSH 服务。(2)安装 Python 2.7 或更高版本。 对 Windows 设备的要求:(1)开启 WinRM 服务。(2)安装 PowerShell 3.0 或更高版本,以及至少 .NET 4.0。(3)PowerShell 脚本执行策略设置为 Restricted。 对网络设备(交换机/路由器)的要求:开启 NETCONF 服务。【注:由于是新协议,因此老旧网络设备可能并不支持该功能。】 2、配套工具 2.1、ansible ansible 是用于临时 执行单一命令任务 的工具,不用写 playbook 即可执行任务。 #对所有主机执行 id 命令,并查看输出结果。 ansible all -i hosts -m command -a "id" -v 2.2、ansible-playbook ansible-playbook 是用于 执行复杂命令任务 的工具,必须依赖 playbook 文件才能运行。 #执行 task.yml 任务集。 ansible-playbook -i hosts task.yml cat task.yml ###文本内容### - hosts: linux tasks: - name: install nginx yum: name: nginx state: present ###### 2.3、ansible-doc ansible-doc 是用于 查看模块/插件使用说明 的工具,相当于是 Ansible 的“man 手册”。 #查看 ping 模块的参数介绍。 ansible-doc -s ping #查看 ping 模块的参数介绍。 ansible-doc -t module -s ping 2.4、ansible-vault ansible-vault 是用于 加密 playbook 配置 的工具,防止剧本中的密码信息泄露。 #加密 playbook 任务文件 ansible-vault encrypt task.yml #执行被加密的 playbook 任务文件 ansible-playbook task.yml --ask-vault-pass 2.5、ansible-galaxy ansible-galaxy 是用于 下载管理角色/集合 的工具,相当于是 Ansible 的“任务/模块应用商店”或是类似 pip 的“包管理器”。 角色/集合的官网地址:https://galaxy.ansible.com/ui/standalone/roles/、https://galaxy.ansible.com/ui/collections/。 #下载用于自动化部署 nginx 任务的角色 ansible-galaxy role install geerlingguy.nginx #角色的使用类似 task 一样,具体操作见本文 Playbook 小节。 2.6、ansible-console ansible-console 是用于 与 Ansible 进行命令交互 的工具,相当于是面向 Ansible 的 Shell。 ansible-console > hosts web > ping > shell uptime 3、Inventory - 主机清单 在主机清单中支持定义:主机、主机组、主机变量、主机组变量,但一般不建议在主机清单中定义变量,变量都是定义在单独的 主机/组文件 中。主机清单支持多种格式去书写,但最常用的格式是 ini 格式。以下是一个主机清单的示例: # hosts.ini [windows] # windows 组定义了5个主机 www.test-[01:05].com [linux] # linux 组定义了2个主机,其中一个主机自带登录变量。 192.168.1.1 ansible_user=kali ansible_password=kali www.test-06.com ansible_host=192.168.1.2 [windows:vars] # windows 组变量 ansible_connection=winrm ansible_user=administrator ansible_password=password123 [hosts:children] # 基于组创建的 hosts 组 windows linux 注:Ansible 默认预定义了两个主机组:all 分组(所有主机)、ungrouped 分组(不在分组内的主机)。需要注意的是,这两个组都不包括 localhost(管理节点本机) 这个特殊的节点。【注:命令 ansible windows --list-hosts 可列出 windows 组中的所有主机。】 4、Playbook - 任务清单 Playbook 是 Ansible 中最重要的一个概念,它定义了批量的主机任务应该如何去执行。而一个 Playbook 则是由一个或多个 Play 构成的,因此,只要了解了 Play 的构成也就了解了 Playbook。 一个 Play 主要是由以下三部分构成: Keywords:指定主机组、远程连接的方式、是否提权等全局参数。其中主机组必须被指定。【注:可用参数参考】 Vars:定义 playbook 在运行时需要使用的变量。【非必须】 Tasks:指定要执行的任务。 4.1、Keywords - 关键词 Play 中的关键词有点像是 C 语言中的全局变量,在一个 Play 中,hosts 和 tasks/roles 是必不可少的,其余参数则可有可无。Play 常用关键词如下: hosts:指定要执行任务的主机组。 connection:使用指定的协议,连接需要执行该任务的主机。默认是 ssh。 port:指定连接协议对应的端口。默认是指定协议对应的默认端口。 ==== become:开启提权功能,使用提权之后的身份执行任务。 become_method:提权支持 sudo、su 这两种方法,默认是使用 sudo 进行提权。 become_user:指定提权之后获得的用户身份,默认是 root 用户。 collections:全局声明集合名称,这样在调用此集合的模块时不需要携带集合的前缀名称。 ==== vars、vars_files:定义变量。【注:这些关键词指的便是下面的小节。】 tasks、roles、handlers:定义任务。【注:这些关键词指的便是下面的小节。】 注意:并不只是在 Play 中存在关键词的说法,Task、Role 中也依然存在。虽然三者之间的关键词各有差异(关键词 when 在 Play 中没有,但在 Task、Role 中是有的。),但相似的地方有很多,像如关键词 become、vars 等。 4.2、Vars - 变量 4.2.1、变量优先级 Ansible 中支持自定义变量的地方有很多,以下我将按照优先级的顺序依次列出: 命令行变量:通过命令行参数带入,优先级最高。如:ansible-playbook -i hosts -v main.yml --extra-vars "v1=a v2=b"。 playbook 变量:通过关键词 vars 带入。 Inventory 主机变量:通过主机 ip 带入。如:1.1.1.1 v1=a v2=b host_vars 主机变量:不可描述。 group_vars 主机组变量:不可描述。 Inventory 主机组变量:不可描述。 4.2.2、文件变量 在上述变量中,关于文件变量 host_vars、group_vars 的构成不太好理解,故以一个 ansible 项目示例做说明: (1)首先,按照如下项目的目录结构制作相应的文件。 nginx_install ├── inventory │ ├── group_vars │ │ └── lin.yml │ ├── hosts │ └── host_vars │ └── 192.168.56.20.yml └── main.yml 其中,hosts 文本内容如下: [lin] 192.168.56.20 (2)然后,以 YAML 的语法格式去编写文件中的变量。lin.yml 文本内容如下: --- v1: a v2: b (3)最后,在工作目录 nginx_install 下执行命令 ansible-playbook -i inventory -v main.yml 即可。【注:参数 i 的值不仅可以是文件也可以是目录。】 4.2.3、特殊变量 Facts 变量 为了让 Ansible 更了解目标节点,可以让它去收集目标节点的信息,比如获取目标节点的:主机名、系统版本、IP 地址、分区挂载信息等。这些节点信息被称为 Facts,可通过命令 ansible localhost -m gather_facts 去查看。有了这些信息,我们便可以更灵活的管理节点了,比如当 IP 地址为 xxx 时就怎样,当系统是 CentOS 6 时怎样,等等这些。 这些变量中以 ansible_ 开头的变量默认都被 Ansible 注入到了其自身维护的变量表 hostvars 中了。因此,我们可以直接去访问变量本身,而无需以访问“组变量或字典变量”的方式去访问它们。 注:这些变量只能通过 Playbook 去调用,使用命令 ansible localhost -m debug -a "var=ansible_facts.ansible_interfaces" 并不能够查看,应该是 ansible 在执行任务时默认并不会收集 Facts 所导致,但 ansible-playbook 默认是会收集的。 变量 Facts 和 Hostvars 的值还可通过以下 Play 去查看。 - name: playbooks hosts: lin tasks: - name: info in ansible_facts debug: var: ansible_facts - name: info in hostvars debug: var: hostvars register 变量 有时候,可能需要将某一条任务执行的结果保存下来,以便在接下的任务中调用或者做些判断。这时就可以通过 register 关键字来将某一任务结果保存为一个变量。【注:这个变量的结构类似于 上面的 hostvars 变量,因此在调用的时候需要注意。】 - name: register variables hosts: lin tasks: - name: capture output of whoami command command: whoami register: login - name: get var debug: msg: "login user is {{ login.stdout }}" 4.2.4、调用变量 构造的变量最终都是为了使用,而变量的类型又多种多样,如:整数、字串、数组、字典 等类型,那么面对这些类型的变量该如何使用呢?以下以一个示例的两种用法去调用它们。 以上面测试 register 变量的示例为例,假设输出的复杂变量 login 的值如下: "login": { "changed": true, "cmd": [ "whoami" ], "delta": "0:00:00.011976", "end": "2025-12-31 05:27:48.401127", "failed": false, "msg": "", "rc": 0, "start": "2025-12-31 05:27:48.389151", "stderr": "", "stderr_lines": [], "stdout": "kali", "stdout_lines": [ "kali" ] } 那么在 Play 中调用其中值的方法如下: - name: register variables hosts: lin tasks: - name: capture output of whoami command command: whoami register: login - name: get var debug: msg: "login user1 is {{ login.stdout_lines[0] }}" - name: get var debug: msg: "login user2 is {{ login['stdout_lines'][0] }}" 4.3、Tasks - 任务 在 Play 中用来执行任务的方式有三种,分别是:tasks(常规任务)、roles(任务组织化)、handlers(可复用任务),三者虽各有各的用法,但本质上都是一样的:执行任务。 4.3.1、Tasks 任务列表中的各任务按次序逐个在 hosts 中指定的所有主机上执行,在所有主机上先完成第一个任务后再开始第二个。 在自上而下运行某 playbook 时,如果中途发生错误,则整个 playbook 会停止执行,而由于 playbook 的幂等性,playbook 可以被反复执行,所以即使发生了错误,在修复错误后,再执行一次即可。 - name: task test hosts: linux tasks: - name: make sure apache is running service: name: httpd state: started - name: run this command and ignore the result command: /usr/bin/somecommand ignore_errors: True #若命令会返回错误信息,但这个错误对后续任务的执行影响不大时,可使用此关键词忽略错误,让任务继续顺利执行。 4.3.2、Roles Roles 的出现完美解决了在复杂任务下 playbook 篇幅过长、过于臃肿、缺乏灵活性、维护成本巨大等问题。 Roles 的构建严重依赖目录命名规则和目录摆放,所以目录的命名和摆放非常重要。【注:但此处不会详述 Roles 的构建过程。】 由于运维中的很多业务场景都是一样的,因此可以将一些业务的 Playbook 转换为 Role 格式以供其他人复用。为此,官方提供了一个可托管 Role 的平台,让 Role 角色可以像 APT 软件包一样随下随用。【注:官方地址】 (1)Role 角色的管理: #列出已安装的 Role ansible-galaxy role list #安装找到的 Role ansible-galaxy role install geerlingguy.nginx #删除指定的 Role ansible-galaxy role remove geerlingguy.nginx (2)Role 角色的应用: - name: install nginx hosts: linux roles: - role: geerlingguy.nginx vars: v1: a v2: b (3)Role 角色的结构: #ansible-galaxy init role_name #tree role_name/ role_name/ \\ 角色名称 ├── defaults \\ 为当前角色设定默认变量时使用此目录,应当包含一个main.yml文件; │ └── main.yml ├── files \\ 存放有copy或script等模块调用的文件 ├── handlers \\ 此目录应当包含一个main.yml文件,用于定义各角色用到的各handler │ └── main.yml ├── meta \\ 应当包含一个main.yml,用于定义角色的特殊设定及其依赖关系;1.3及以后版本支持 │ └── main.yml ├── README.md ├── tasks \\ 至少包含一个名为main.yml的文件,定义了此角色的任务列表 │ └── main.yml ├── templates \\ template模块会自动在此目录中寻找Jinja2模板文件 ├── tests │ ├── inventory │ └── test.yml └── vars \\ 应当包含一个main.yml,用于定义此角色用到的变量 └── main.yml 4.3.3、Handlers Handler 通过任务关键词 notify 来监视某个 task,一旦 task 的执行结果发生变化,则触发 Handler 任务。 Handler 任务并不是被 notify 后立刻执行的。默认情况下,是在 “当前 Play 的所有 tasks 执行完之后” 才执行。 默认情况下,在一个 Play 中,只要有 task 执行失败,则 play 终止,即使是与 handler 关联的 task 在失败的 task 之前运行成功了,handler 也不会被执行。如果希望在这种情况下 handler 仍然能够执行,可开启 Play 关键词 force_handlers: yes。 - name: handler task test hosts: all force_handlers: yes tasks: - name: a task which always notifies its handler command: /bin/true notify: restart the database - name: a task which fails because the package doesn't exist yum: name: notapkg state: latest handlers: - name: restart the database service: name: mariadb state: restarted 4.4、其它技巧 4.4.1、When - 判断 任务关键词 when 可根据某些条件的是否达成来决定 task 是否应该被执行。 - name: Install vim hosts: all tasks: - name:Install VIM via yum yum: name: vim-enhanced state: installed when: ansible_os_family == "RedHat" # when: some_var | float > 90 # when: result is changed 注:When 的条件判断因为可以配合过滤器插件和测试插件使用,故使其变得很灵活也很复杂,具体可参考第三方手册或官方手册查看。 4.4.2、Loop - 循环 任务关键词 loop 可执行一些重复性的操作。 (1)普通循环 tasks: - name: postfix and httpd are running service: name: "{{ item }}" state: started loop: - postfix - httpd - name: retrieve the list of home directories command: ls /home register: home_dirs - name: add home dirs to the backup spooler file: path: /mnt/{{ item }} src: /home/{{ item }} state: link loop: "{{ home_dirs.stdout_lines }}" (2)高级循环 - name: test loop hosts: test tasks: - name: add several users user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" loop: - { name: 'user1', groups: 'wheel' } - { name: 'user2', groups: 'sudo' } 注:loop 循环的用法多种多样,具体可参考第三方手册或官方手册查看。 5、常用模块 以下模块均来自默认集合 ansible.builtin(面向 linux 系统)。此外,还有两个集合也值得关注,分别是:ansible.windows(面向 windows 系统)、ansible.netcommon(面向网络设备)。 ping 模块 – 对目标节点进行连通性测试。【示例:ansible localhost -m ping】 debug 模块 – Playbook 配置调试。【示例:ansible localhost -m debug -e "str=123" -a "var=str"】 copy 模块 – 将本地文件复制到目标节点。【示例:ansible localhost -m copy -a "src=/etc/hosts dest=/tmp/hosts mode=0777"】 file 模块 – 管理文件和文件属性。【示例:ansible localhost -m file -a "path=/tmp/hosts state=directory" - 新建目录】 lineinfile 模块 – 类似 sed 的文本编辑器。【示例:ansible localhost -m lineinfile -a "path=test state=present line=c=345 regexp='^a'" - 将 a 开头的整行替换为 c=345】 template 模块 – 将模板文件输出到目标节点。【示例:ansible localhost -m template -a "src=/root/test.sh.j2 dest=/tmp/test.sh" -e "arg=id" - 将 test.sh.j2 文件中的 arg 变量替换之后,将文件传输到目标节点。】 # test.sh.j2 文本内容 #!/bin/sh {{ arg }} >> /tmp/id.txt package 模块 – 通用软件包管理器。【示例:ansible localhost -m package -a "name=hello state=present" - 安装 hello 软件包】 service/systemd 模块 – 管理系统服务。【示例:ansible localhost -m service -a "name=apache2 state=stopped" - 关闭 apache2 服务】 command 模块 – 在目标节点上执行命令,但该模块不支持像如 通配符、管道符 这类特殊符号。【示例:ansible localhost -m command -a "id"】 shell 模块 – 在目标节点上启动一个 shell 然后在其中执行命令。【示例:ansible localhost -m shell -a "id"】 raw 模块 – 目标节点即便不具备 python 环境,依然能够执行命令,就像是通过 ssh 连接之后执行命令一样,此时将失去 ansible 的幂等性特点。【示例:ansible localhost -m raw -a "id"】 script 模块 –- 将本地脚本传输到目标节点并执行,执行之后脚本被删除。【示例:ansible localhost -m script -a "/root/test.sh --somearg"】 注:通过 ansible 命令使用 command、shell、raw 这三个模块执行命令时,参数不可以以 ansible localhost -m shell -a "cmd=id" 这样的方式使用,只能以 ansible localhost -m shell -a "id" 这样的方式使用。 这是因为:只有这三个模块的“核心参数”不是普通 key = value,而是 _raw_params(裸参数),其余大多模块都是以键值对的方式传递参数的。 6、常用插件 过滤器插件 主要配合 when 对一些变量做一些类型转换,之后再进行判断。 查找插件 主要配合插件 lookup 从各种类型的文件中读取文本内容。 测试插件 主要配合 when 对变量做一些条件的判断。 7、杂七杂八 (1)学习参考集合。 Playbook 参考手册:官方/第三方。 Inventory 参考手册:官方/第三方。 Ansible 模块列表:官方。 Ansible 集合列表:官方。 Ansible 角色商店:官方。 Playbook 关键词:官方。 视频教程:B 站。 (2)命令技巧。 #对主机清单和 playbook 进行语法检查。 ansible-playbook -i hosts --syntax-check playbook #在开始批量执行任务之前,最好先对所有的目标主机进行通性测试。 ansible all -i hosts -m ping #查看 web 组有哪些主机 ansible web --list #以 kali 用户的身份去远程目标,同时再进行 sudo 提权,并打开 5 个并发连接。 ansible lin -i hosts -u kali -k -b -K -f 5 -m command -a "whoami" (3)Playbook 示例。 #本配置中的所有内容即代表一个剧本 #剧集一 - hosts: linux tasks: ##任务1 - name: install nginx yum: #yum 模块 name: nginx state: present ##任务2 - name: update nginx config template: #template 模块 src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx #调用处理器 handlers: #定义处理器 - name: restart nginx service: name: nginx state: restarted #剧集二 - hosts: windows collections: #声明集合,不声明调用集合模块需带集合名称,如 ansible.windows.win_file。 - ansible.windows tasks: - name: Remove a file, if present win_file: #调用 windows 集合中的模块 path: C:\Temp\foo.conf state: absent #剧集三 - hosts: web roles: #角色 - nginx