Ansible 常用模块
Ansible模块的使用
文件模块
Files文件模块库包含的模块可以对Linux文件进行管理,如创建、删除、编辑和修改文件的权限与属性等。
模块 | 说明 |
---|---|
blockinfile | 插入、更新或删除由可定义标记线包围的多行文本块 |
lineinfile | 确保特定行位于某个文件中,或使用反向引用正则表达式来替换现有行。此模块可以在想要更改某一个行的文本时使用 |
copy | 将文件从本地或远程计算机复制到目标主机的某个位置。类似于file模块,copy模块还可以设置文件属性,包括SELinux上下文 |
fetch | 该模块和copy类似,但以相反的方式工作。fetch用来从目标主机获取文件到本机控制节点上 |
file | 设置权限、所有权、SELinux上下文以及常规文件、符号链接、硬连接、目录时间戳等。此模块还可以创建或删除常规文件、符号链接、硬连接和目录。其他过个与文件相关的模块支持与file模块相同的属性设置选项,包括copy模块 |
stat | 检索文件的状态信息,与Linux stat命令相似 |
synchronize | 对rsync命令的打包 |
文件模块使用示例
确保目标主机上存在文件
1 | - name: Touch a file and set permissions |
如果目标主机已存在该文件,则会进行touch操作。上面的task除了确保文件存在以外,还会保证文件的权限为设定值。
1 | File: touch.me |
修改文件属性
使用file模块,确保新的或现有文件具有正确的文件属性和SELinux类型。
1 | - name: SELinux type is set to samba_share_t |
修改前touch.me文件的setype属性是user_home_t
,使用file模块处理后setype属性已经改变为samba_share_t
。
1 | $ ls -lZ |
永久更改SELinux文件上下文属性
设置上下文属性时,file模块的行为和chcon类似。通过运行restorecon可能会意外的撤销使用该模块对文件上下文所做的更改。当使用file设置上下文后,可以使用System模块集合中的sefcontext来更新SELinux策略,如semanage fcontext
。
1 | - name: SELinux type is persistently set to samba_share_t |
可以看得到在SELinux上下文策略中目标的默认上下文已经更改为samba_share_t
。
1 | # semanage fcontext -l | grep touch.me |
注意:sefcontext模块只更新SELinux策略中目标的默认上下文,并不更改当前现有文件的上下文。
在目标主机上复制和编辑文件
使用copy模块时,模块假定设置了force: yes
。这会强制copy模块覆盖远程文件(如果存在并且包含于与当前要发送的文件内容不同)。如果手动设置force: no
,则它仅会在目标主机不存在要复制的这个文件时才会进行复制。
1 | - name: Copy a file to managed hosts |
如果要从目标主机上拉取文件到本机,则使用fetch模块。
1 | - name: Retrieve SSH key from reference host |
要确保现有文件中存在某行文本,可以使用lineinfile模块。
1 | - name: Add a line of text to file |
如果要将文本块插入到文档中,应使用blockinfile模块。
1 | - name: Add additional lines to a file |
使用blockinfile模块时,注释块标记插入到块的开头和结尾,用来让Ansible识别和保持幂等性。
1
2
3 # BEGIN ANSIBLE MANAGED BLOCK
This is the first line.
# END ANSIBLE MANAGED BLOCK
在目标主机上删除文件
在大多数情况下,如果控制目标主机文件的删除使用file模块的state: absent
参数来控制。
1 | - name: Removed file in the server |
检索文件的详细信息
使用stat模块可以查看文件的详细信息,并返回文件的事实。你可以利用这些Facts对文件进行检索和校验。stat模块类似于Linux系统中的stat
命令。
1 | - name: Check all stat of /etc/passwd |
同步控制节点和受控节点之间的文件
使用synchronize模块来操作同步主机间的文件。synchronize对rsync工具进行打包,它简化了playbook中常见文件管理任务。使用该模块要求双方主机安装rsync工具。
1 | - name: synchronize local file to server file |
使用Jinja2模版部署自定义文件
可以利用Jinja2模版语法通过和变量与事实相配合,对固定地方的值进行覆盖和编辑。来实现定制化修改配置文件。
1 | 使用`{% EXPR %}`用于表达式或逻辑(循环、判断) |
构建Jinja2模版
Jinja2模版由多个元素组成:数据、变量和表达式。在呈现Jinja2模版时,这些变量和表达式被替换为对应的值。模版中使用的变量可以在playbook的vars部分中指定。可以将目标主机的事实作为模版中使用的变量。
可以使用
ansible all -m setup
来查看目标主机中全部的Fact事实。模版文件没有固定的文件拓展名,只要是文本文件即可,但是为了方便记忆理解,通常使用.j2
来代表文本文件是Jinja2的模版文件。
部署Jinja2模板
我们刚刚创建好了Jinja2模版,现在要利用这些模版。我们需要使用template
模块。src参数指的是模版文件在控制节点中的路径,dest的值是在目标主机的指定目录生成文件。
1 | tasks: |
template和file模块一样支持对文件权限进行设置。
标示配置文件由Ansible管理
我们使用模版生成文件后,为了避免管理员用户手动的修改这些配置文件,我们最好在模版的开头写上声明。虽然template不会自动地帮我们完成,但是我们可以在模版文件的开头手动引入设定好的提醒文本,使用Jinja2语法将变量的内容填写到配置文件中。
可以使用ansible_managed
指令中默认设置的 Ansible managed
字符串来执行此操作。这不是一个正常的变量,但是可以在模版中用作一个变量。ansible_managed
指令在ansible.cfg
文件中的设置:
ansible_managed = Ansible managed: modified on %Y-%m-%d %H:%M:%S
要将在ansible.cfg
文件中配置的ansible_managed
字符串包含在Jinja2模版内,使用下面的引用变量语法即可。
1 | {{ ansible_managed }} |
通过模版生成的配置文件开头存在了Ansible managed: modified on 2020-06-10 15:55:29
。这样就能对修改此文件的人有一个提示的作用。
控制结构
可以在Jinja2模版中使用控制结构,以减少重复的输入。为Play中每个主机能够动态的生成条目,或者有条件的将文本插入到文件中。
循环
Jinja2使用for
语句来提供循环功能。
1 | {% for user in users %} |
下面的示例模版使用for逐一遍历users变量中的所有值,将myuser替换为各个值,但值为root时除外。
1 | {# for statement #} |
loop.index变量是循环到当前处的索引号。他在循环第一次执行时的值为1,每一次迭代递增1。
下面的例子是生成hosts文件。
1 | {% for host in groups['all'] %} |
1 |
|
条件语句
Jinja2使用if语句来提供条件控制。如果满足某些条件,则会按照语句块内的规则继续生成。
1 | {% if finished %} |
Jinja2仅能用于模版,不能用于Playbook。条件语句和循环语句可以相互嵌套。
变量过滤器
可以使用Jinja2提供的过滤器改变原有变量输出的格式,例如将字符串转换为JSON或YAML。
如果要转换为json格式时,使用to_json过滤器进行输出。
如果要转换为yaml格式时,使用to_yaml过滤器进行输出。
1 | {{ output | to_json }} |
如果要使结构更适于人类阅读,可以使用下面的过滤器来输出人类可读格式。
1 | {{ output | to_nice_json }} |
变量测试
在Ansible Playbook中与when子句一同使用的表达式是Jinja2表达式。用于测试返回值的内置Ansible测试failed、changed、succeeded、skipped四种。
1 | tasks: |
软件包管理
使用dnf的Ansible模块可以在受控主机上控制dnf软件包管理器。dnf是RHEL8使用的默认包管理器用于替代yum。不过也可以使用yum模块来对RHEL8进行操作。
下面示例中使用task任务来代替原有的dnf包管理器指令:
dnf install httpd -y
1 | - name: Install the httpd packages |
state关键字有如下参数:
- present 如果软件包不存在,则安装软件包
- absent 如果已安装,则删除软件包
- latest 如果软件包不是最新版本,则会对软件包进行更新。要是没有安装则会安装最新版本的软件包
name关键字有以下使用方式:
- 直接填写某一个或以列表的形式填写多个软件包名称
- 使用
'*'
配合latest可以进行更新系统全部软件包 - 若要管理模块或组需要使用
@
符号
安装Development Tools
软件组的示例:
1 | - name: Install the Development Tools group |
安装postgresql
数据库模块:
1 | - name: Install the postgresql module |
如果包管理器不是yum或者dnf。可以使用package
模块替代yum/dnf
模块。package
模块可以自动检测并使用受控主机的包管理器去安装配置的软件包。
1 | - name: Install httpd |
收集已安装的软件包信息
使用package_facts
模块就能获取到受控主机中已经安装的软件包。它会将获取到的全部软件包信息存入ansible_facts.packages
变量中。
使用package_facts
模块并进行输出的示例:
1 |
|
package_facts
模块有两个选项:
- manager 选择软件包管理器。默认auto自动识别
- strategy 策略
返回prod主机组中已安装的httpd软件包信息。
1 | ok: [serverc] => { |
配置yum仓库
添加yum仓库
使用yum_repository
模块来控制第三方yum仓库。在添加仓库时即可配置GPG密钥。
1 |
|
可以直接使用gpgkey选项而不需要使用其他模块进行配置。
用户管理和身份认证
如何管理用户和用户组,以及配置ssh-key。
用户模块
使用user
模块可以管理主机上的用户以及它们的许多参数。也可以删除用户、设置主目录、设置UID、关联的用户组等很多参数。
如果需要创建可以登录的计算机用户,需要使用password参数和password_hash('sha512')
搭配生成Hash后的密码才可以登陆系统。
1 |
|
组模块
group
模块可以管理受控主机中的用户组。
1 |
|
group
模块参数: gid,local,name,state,system(如果设置为yes,则表示创建的组是系统组)
系统调度
at一次性任务
使用at
模块来创建一个一次性任务。可以安排任务在未来的某一个时间点执行一次。
at
模块参数:
参数 | 选项 | 说明 |
---|---|---|
command | - | 计划要运行的命令 |
count | - | 单位数字。必须和units一同使用 |
script_file | - | 计划要执行的现有脚本文件 |
state | absent/present | 添加或删除命令或脚本的状态 |
unique | yes/no | 如果任务已在运行,则不会再次执行 |
units | minutes/hours/days/weeks | 时间单位 |
at
模块使用示例:
1 |
|
目前使用at
模块总会在文件名末尾拼接上marcinDELIMITERxxxx
字符串,经过Google发现这一串文本是用来在at pool中用来标示任务的。可是在这里为什么将他们输出了出来目前还不得而知。
cron计划任务
要完成重复性的任务,也可以使用cron
模块来创建计划任务。
1 | - name: Ensure a job that runs at 2 and 5 exists. Creates an entry like "0 5,2 * * ls -alh > /dev/null" |
想要在特殊时间点,比如系统重启后运行一个任务,可以使用special_time
参数来配置cron计划任务。
1 | - name: Ensure a job that runs at system reboot. Creates an entry like "@reboot ls -alh > /dev/null" |
reboot模块
使用reboot模块重新启动比直接用shell模块发起关机更安全,使用shell模块关闭受控主机后,它会等待再次开机恢复运行,才会继续向下执行其他任务和Play。
对受控主机重启后并持续等待180s。如果受控主机恢复运行则继续执行接下来的任务。
1 | - name: Reboot a slow machine that might have lots of updates to apply |
如果超出运行时间,则执行出错。接下来的task和play都不会继续执行。
fatal: [servera]: FAILED! => {"changed": false, "elapsed": 19, "msg": "Timed out waiting for last boot time check (timeout=18)", "rebooted": true}