跳至内容

Ansible 基础

在本章中,您将学习如何使用 Ansible。


**目标**: 在本章中,您将学习如何

✔ 实施 Ansible;
✔ 在服务器上应用配置更改;
✔ 创建第一个 Ansible 剧本;

🏁 **ansible**、**模块**、**剧本**。

**知识**: ⭐ ⭐ ⭐
**复杂度**: ⭐ ⭐

**阅读时间**: 30 分钟


Ansible 集中和自动化管理任务。它是

  • **无代理**(它不需要在客户端上进行特定部署),
  • **幂等**(每次运行都具有相同的效果)。

它使用 **SSH** 协议远程配置 Linux 客户端,或使用 **WinRM** 协议与 Windows 客户端协作。如果这些协议都不可用,Ansible 始终可以使用 API,这使得 Ansible 成为配置服务器、工作站、Docker 服务、网络设备等的真正瑞士军刀(实际上几乎所有东西)。

警告

从 Ansible 服务器到所有客户端打开 SSH 或 WinRM 流,使其成为架构中的关键元素,必须对其进行仔细监控。

由于 Ansible 主要基于推送,因此它不会在每次执行之间保留其目标服务器的状态。相反,它将在每次执行时执行新的状态检查。它被认为是无状态的。

它将帮助您进行

  • 供应(部署新 VM),
  • 应用程序部署,
  • 配置管理,
  • 自动化,
  • 编排(当使用多个目标时)。

注意

Ansible 最初由 Michael DeHaan 编写,他是其他工具(如 Cobbler)的创始人。

Michael DeHaan

最早的第一个版本是 0.0.1,于 2012 年 3 月 9 日发布。

2015 年 10 月 17 日,AnsibleWorks(Ansible 背后的公司)被 Red Hat 以 1.5 亿美元收购。

The features of Ansible

为了在您日常使用 Ansible 时提供图形界面,您可以安装一些工具,如 Ansible Tower(RedHat),它不是免费的,它的开源对应物 Awx,或者其他项目,如 Jenkins 和优秀的 Rundeck 也可以使用。

摘要

要进行本培训,您至少需要 2 台 Rocky8 服务器

  • 第一台将是**管理机器**,Ansible 将安装在其上。
  • 第二台将是需要配置和管理的服务器(除了 Rocky Linux 之外的其他 Linux 也一样)。

在下面的示例中,管理站的 IP 地址为 172.16.1.10,被管理站为 172.16.1.11。您可以根据自己的 IP 地址方案调整示例。

Ansible 词汇表

  • **管理机器**: 安装 Ansible 的机器。由于 Ansible 是**无代理的**,因此不会在被管理的服务器上部署任何软件。
  • **被管理节点**: Ansible 管理的目标设备也称为“主机”。这些可以是服务器、网络设备或任何其他计算机。
  • **清单**: 包含有关被管理服务器的信息的文件。
  • **任务**: 任务是一个定义要执行的过程的块(例如,创建用户或组、安装软件包等)。
  • **模块**: 模块抽象了任务。Ansible 提供了许多模块。
  • **剧本**: 一个用 yaml 格式编写的简单文件,定义目标服务器和要执行的任务。
  • **角色**: 角色允许您组织剧本和其他所有必要文件(模板、脚本等),以便于共享和重用代码。
  • **集合**: 集合包含剧本、角色、模块和插件的逻辑集合。
  • **事实**: 这些是包含有关系统信息(机器名称、系统版本、网络接口和配置等)的全局变量。
  • 处理程序:这些用于在发生更改时导致服务停止或重新启动。

在管理服务器上安装

Ansible 在EPEL 存储库中可用,但有时可能过于陈旧,无法与当前版本配合使用,因此您可能需要使用更新的版本。

因此我们将考虑两种类型的安装

  • 一种基于 EPEL 存储库
  • 一种基于 pip python 包管理器

两个版本都需要EPEL,因此您可以立即安装它

  • EPEL 安装
sudo dnf install epel-release

从 EPEL 安装

如果我们从EPEL 安装 Ansible,我们可以执行以下操作

sudo dnf install ansible

然后验证安装

$ ansible --version
ansible [core 2.14.2]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/rocky/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible  ansible collection location = /home/rocky/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.2 (main, Jun 22 2023, 04:35:24) [GCC 8.5.0 20210514 
(Red Hat 8.5.0-18)] (/usr/bin/python3.11)
  jinja version = 3.1.2
  libyaml = True

$ python3 --version
Python 3.6.8

请注意,ansible 自带其自身的 python 版本,不同于系统版本的 python(此处为 3.11.2 与 3.6.8)。您在使用 pip 安装安装所需的 python 模块时(例如,pip3.11 install PyVMomi)需要牢记这一点。

从 python pip 安装

由于我们想要使用更新版本的 Ansible,因此我们将从 python3-pip 安装它

注意

如果您之前已从EPEL 安装了 Ansible,请将其删除。

在此阶段,我们可以选择使用我们想要的 python 版本安装 ansible。

sudo dnf install python38 python38-pip python38-wheel python3-argcomplete rust cargo curl

注意

python3-argcompleteEPEL 提供。如果您尚未完成,请安装 epel-release。此软件包将帮助您完成 Ansible 命令。

现在我们可以安装 Ansible

pip3.8 install --user ansible
activate-global-python-argcomplete --user

检查您的 Ansible 版本

$ ansible --version
ansible [core 2.13.11]
  config file = None
  configured module search path = ['/home/rocky/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/rocky/.local/lib/python3.8/site-packages/ansible
  ansible collection location = /home/rocky/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/rocky/.local/bin/ansible
  python version = 3.8.16 (default, Jun 25 2023, 05:53:51) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)]
  jinja version = 3.1.2
  libyaml = True

注意

在本例中,手动安装的版本比 RPM 打包的版本旧,因为我们使用的是旧版本的 python。当然,此观察结果会随着时间的推移以及发行版的年代和 python 版本而有所不同。

配置文件

服务器配置位于 /etc/ansible 下。

有两个主要的配置文件

  • 主要配置文件 ansible.cfg,其中包含命令、模块、插件和 SSH 配置;
  • 客户端机器管理清单文件 hosts,其中声明了客户端和客户端组。

如果 Ansible 是使用其 RPM 包安装的,配置文件将自动创建。使用 pip 安装时,此文件不存在。我们将不得不使用 ansible-config 命令手动创建它

$ ansible-config -h
usage: ansible-config [-h] [--version] [-v] {list,dump,view,init} ...

View ansible configuration.

positional arguments:
  {list,dump,view,init}
    list                Print all config options
    dump                Dump configuration
    view                View configuration file
    init                Create initial configuration

示例

ansible-config init --disabled > /etc/ansible/ansible.cfg

--disabled 选项允许您通过在选项前面添加 ; 来注释掉一组选项。

注意

您也可以选择将 ansible 配置嵌入到您的代码库中,让 Ansible 以以下顺序加载它找到的配置文件(处理它遇到的第一个文件并忽略其余文件)

  • 如果环境变量 $ANSIBLE_CONFIG 已设置,则加载指定文件。
  • 如果当前目录中存在 ansible.cfg,则加载该文件。
  • 如果用户的主目录中存在 ~/.ansible.cfg,则加载该文件。

如果没有找到这三个文件中的任何一个,则加载默认文件。

清单文件 /etc/ansible/hosts

由于 Ansible 将必须处理所有要配置的设备,因此为其提供一个(或多个)与您的组织完美匹配的结构良好的清单文件至关重要。

有时需要仔细考虑如何构建此文件。

转到默认清单文件,该文件位于 /etc/ansible/hosts 下。提供了一些示例并进行了注释

# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
#   - Comments begin with the '#' character
#   - Blank lines are ignored
#   - Groups of hosts are delimited by [header] elements
#   - You can enter hostnames or ip addresses
#   - A hostname/ip can be a member of multiple groups

# Ex 1: Ungrouped hosts, specify before any group headers:

## green.example.com
## blue.example.com
## 192.168.100.1
## 192.168.100.10

# Ex 2: A collection of hosts belonging to the 'webservers' group:

## [webservers]
## alpha.example.org
## beta.example.org
## 192.168.1.100
## 192.168.1.110

# If you have multiple hosts following a pattern, you can specify
# them like this:

## www[001:006].example.com

# Ex 3: A collection of database servers in the 'dbservers' group:

## [dbservers]
##
## db01.intranet.mydomain.net
## db02.intranet.mydomain.net
## 10.25.1.56
## 10.25.1.57

# Here's another example of host ranges, this time there are no
# leading 0s:

## db-[99:101]-node.example.com

如您所见,提供的示例文件使用 INI 格式,此格式为系统管理员所熟知。请注意,您可以选择其他文件格式(例如 yaml),但对于第一次测试,INI 格式非常适合我们未来的示例。

清单可以在生产中自动生成,尤其是在您拥有 VMware VSphere 之类的虚拟化环境或云环境(Aws、OpenStack 或其他)的情况下。

  • /etc/ansible/hosts 中创建主机组

您可能已经注意到,组是在方括号中声明的。然后是属于组的元素。例如,您可以通过将以下代码块插入此文件来创建一个 rocky8

[rocky8]
172.16.1.10
172.16.1.11

组可以在其他组中使用。在这种情况下,必须指定父组由具有 :children 属性的子组组成,如下所示

[linux:children]
rocky8
debian9

[ansible:children]
ansible_management
ansible_clients

[ansible_management]
172.16.1.10

[ansible_clients]
172.16.1.10

我们不会深入探讨清单,但如果您有兴趣,请查看 此链接

现在我们的管理服务器已经安装好,我们的清单也准备好了,是时候运行我们的第一个 ansible 命令了。

ansible 命令行使用

ansible 命令在 一个或多个目标主机上启动任务。

ansible <host-pattern> [-m module_name] [-a args] [options]

示例

警告

由于我们尚未在 2 台测试服务器上配置身份验证,因此以下并非所有示例都能正常工作。它们作为示例提供,以方便理解,并在本章的后面完全起作用。

  • 列出属于 rocky8 组的主机
ansible rocky8 --list-hosts
  • 使用 ping 模块 ping 主机组
ansible rocky8 -m ping
  • 使用 setup 模块从主机组显示事实
ansible rocky8 -m setup
  • 通过使用带参数的 command 模块,在主机组上运行命令
ansible rocky8 -m command -a 'uptime'
  • 以管理员权限运行命令
ansible ansible_clients --become -m command -a 'reboot'
  • 使用自定义清单文件运行命令
ansible rocky8 -i ./local-inventory -m command -a 'date'

注意

与本例一样,有时将受管理设备的声明分成多个文件(例如,按云项目划分)并向 Ansible 提供这些文件的路径,比维护一个很长的清单文件更简单。

选项信息
-a 'arguments'要传递给模块的参数。
-b -K请求密码并以更高权限运行命令。
--user=username使用此用户连接到目标主机,而不是当前用户。
--become-user=username以此用户身份执行操作(默认:root)。
-C模拟。不会对目标进行任何更改,但会对其进行测试,以查看应该更改哪些内容。
-m module运行名为

准备客户端

在管理机器和客户端上,我们将创建一个名为 ansible 的用户,专门用于 Ansible 执行的操作。此用户必须使用 sudo 权限,因此必须将其添加到 wheel 组中。

此用户将用于

  • 在管理站一侧:运行 ansible 命令并 SSH 到受管理的客户端。
  • 在受管理的站(此处用作您的管理站的服务器也用作客户端,因此它本身受管理)上执行从管理站启动的命令:因此它必须具有 sudo 权限。

在两台机器上,创建一个名为 ansible 的用户,专门用于 ansible

sudo useradd ansible
sudo usermod -aG wheel ansible

为此用户设置密码

sudo passwd ansible

修改 sudoers 配置,以允许 wheel 组的成员在不输入密码的情况下使用 sudo

sudo visudo

我们的目标是注释掉默认值,并取消注释 NOPASSWD 选项,以便在完成操作后,这些行看起来像这样

## Allows people in group wheel to run all commands
# %wheel  ALL=(ALL)       ALL

## Same thing without a password
%wheel        ALL=(ALL)       NOPASSWD: ALL

警告

如果您在输入 Ansible 命令时收到以下错误消息,则可能意味着您在某台客户端上忘记了此步骤:"msg": "Missing sudo password

从现在开始使用管理时,请使用此新用户开始工作

sudo su - ansible

使用 ping 模块进行测试

默认情况下,Ansible 不允许密码登录。

/etc/ansible/ansible.cfg 配置文件中的 [defaults] 部分取消注释以下行,并将其设置为 True

ask_pass      = True

在 rocky8 组的每台服务器上运行 ping

# ansible rocky8 -m ping
SSH password:
172.16.1.10 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
172.16.1.11 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

注意

系统会要求您输入远程服务器的 ansible 密码,这是一个安全问题...

提示

如果您遇到以下错误 "msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program",您只需在管理站上安装 sshpass 即可

$ sudo dnf install sshpass

摘要

现在,您可以测试本章中之前无法正常工作的命令。

密钥身份验证

密码身份验证将被更安全的私钥/公钥身份验证取代。

创建 SSH 密钥

双密钥将使用 ssh-keygen 命令在管理站上的 ansible 用户生成

[ansible]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ansible/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ansible/.ssh/id_rsa.
Your public key has been saved in /home/ansible/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Oa1d2hYzzdO0e/K10XPad25TA1nrSVRPIuS4fnmKr9g ansible@localhost.localdomain
The key's randomart image is:
+---[RSA 3072]----+
|           .o . +|
|           o . =.|
|          . . + +|
|         o . = =.|
|        S o = B.o|
|         = + = =+|
|        . + = o+B|
|         o + o *@|
|        . Eoo .+B|
+----[SHA256]-----+

公钥可以复制到服务器

# ssh-copy-id ansible@172.16.1.10
# ssh-copy-id ansible@172.16.1.11

/etc/ansible/ansible.cfg 配置文件中的 [defaults] 部分重新注释以下行,以防止密码身份验证

#ask_pass      = True

私钥身份验证测试

对于下一个测试,将使用 shell 模块,该模块允许执行远程命令

# ansible rocky8 -m shell -a "uptime"
172.16.1.10 | SUCCESS | rc=0 >>
 12:36:18 up 57 min,  1 user,  load average: 0.00, 0.00, 0.00

172.16.1.11 | SUCCESS | rc=0 >>
 12:37:07 up 57 min,  1 user,  load average: 0.00, 0.00, 0.00

不需要密码,私钥/公钥身份验证有效!

注意

在生产环境中,您现在应该删除之前设置的 ansible 密码,以加强您的安全性(因为现在不需要身份验证密码)。

使用 Ansible

Ansible 可以从 shell 或通过 playbook 使用。

模块

按类别分类的模块列表可以 在此处找到。Ansible 提供了超过 750 个模块!

模块现在分组到模块集合中,可以 在此处找到 集合列表。

集合是 Ansible 内容的一种分发格式,可以包含 playbook、角色、模块和插件。

使用 ansible 命令的 -m 选项调用模块

ansible <host-pattern> [-m module_name] [-a args] [options]

几乎每个需求都有一个模块!因此,建议您不要使用 shell 模块,而是寻找适合需求的模块。

每个需求类别都有自己的模块。以下是一个不完整的列表

类型示例
系统管理user(用户管理)、group(组管理)等。
软件管理dnfyumaptpipnpm
文件管理copyfetchlineinfiletemplatearchive
数据库管理mysqlpostgresqlredis
云管理amazon S3cloudstackopenstack
集群管理consulzookeeper
发送命令shellscriptexpect
下载get_url
源管理gitgitlab

软件安装示例

dnf 模块允许在目标客户端上安装软件

# ansible rocky8 --become -m dnf -a name="httpd"
172.16.1.10 | SUCCESS => {
    "changed": true,
    "msg": "",
    "rc": 0,
    "results": [
      ...
      \n\nComplete!\n"
    ]
}
172.16.1.11 | SUCCESS => {
    "changed": true,
    "msg": "",
    "rc": 0,
    "results": [
      ...
    \n\nComplete!\n"
    ]
}

安装的软件是一个服务,因此现在需要使用 systemd 模块启动它

# ansible rocky8 --become  -m systemd -a "name=httpd state=started"
172.16.1.10 | SUCCESS => {
    "changed": true,
    "name": "httpd",
    "state": "started"
}
172.16.1.11 | SUCCESS => {
    "changed": true,
    "name": "httpd",
    "state": "started"
}

提示

尝试两次运行最后两个命令。你会观察到,第一次 Ansible 将采取行动以达到命令设置的状态。第二次,它将不做任何事情,因为它会检测到状态已经达到!

练习

为了帮助你更多地了解 Ansible 以及习惯于搜索 Ansible 文档,以下是一些你在继续之前可以做的练习

  • 创建组 Paris、Tokio、NewYork
  • 创建用户 supervisor
  • 将用户的 uid 改为 10000
  • 将用户更改为属于 Paris 组
  • 安装 tree 软件
  • 停止 crond 服务
  • 使用 644 权限创建一个空文件
  • 更新你的客户端发行版
  • 重启你的客户端

警告

不要使用 shell 模块。在文档中查找合适的模块!

setup 模块:事实介绍

系统事实是 Ansible 通过其 setup 模块检索的变量。

查看你的客户端的不同事实,以了解通过简单命令可以轻松检索的的信息量。

我们将在后面看到如何在我们的剧本中使用事实以及如何创建我们自己的事实。

# ansible ansible_clients -m setup | less
192.168.1.11 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.1.11"
        ],
        "ansible_all_ipv6_addresses": [
            "2001:861:3dc3:fcf0:a00:27ff:fef7:28be",
            "fe80::a00:27ff:fef7:28be"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "12/01/2006",
        "ansible_bios_vendor": "innotek GmbH",
        "ansible_bios_version": "VirtualBox",
        "ansible_board_asset_tag": "NA",
        "ansible_board_name": "VirtualBox",
        "ansible_board_serial": "NA",
        "ansible_board_vendor": "Oracle Corporation",
        ...

现在我们已经了解了如何在命令行上使用 Ansible 配置远程服务器,我们将能够介绍剧本的概念。剧本是使用 Ansible 的另一种方式,它并不比命令行复杂多少,但它将使你更容易重用你的代码。

剧本

Ansible 的剧本描述了要应用于远程系统的策略,以强制执行其配置。剧本以易于理解的文本格式编写,将一组任务组合在一起:yaml 格式。

注意

了解更多关于 yaml 的信息

ansible-playbook <file.yml> ... [options]

选项与 ansible 命令相同。

命令返回以下错误代码

代码错误
0OK 或没有匹配的主机
1错误
2一个或多个主机正在失败
3一个或多个主机无法访问
4分析错误
5选项错误或不完整
99用户中断运行
250意外错误

注意

请注意,当没有主机与你的目标匹配时,ansible 将返回 Ok,这可能会误导你!

Apache 和 MySQL 剧本示例

以下剧本允许我们在目标服务器上安装 Apache 和 MariaDB。

使用以下内容创建一个 test.yml 文件

---
- hosts: rocky8 <1>
  become: true <2>
  become_user: root

  tasks:

    - name: ensure apache is at the latest version
      dnf: name=httpd,php,php-mysqli state=latest

    - name: ensure httpd is started
      systemd: name=httpd state=started

    - name: ensure mariadb is at the latest version
      dnf: name=mariadb-server state=latest

    - name: ensure mariadb is started
      systemd: name=mariadb state=started
...
  • <1> 目标组或目标服务器必须存在于清单中
  • <2> 连接后,用户将成为 root(默认情况下通过 sudo

剧本的执行是使用命令 ansible-playbook 完成的

$ ansible-playbook test.yml

PLAY [rocky8] ****************************************************************

TASK [setup] ******************************************************************
ok: [172.16.1.10]
ok: [172.16.1.11]

TASK [ensure apache is at the latest version] *********************************
ok: [172.16.1.10]
ok: [172.16.1.11]

TASK [ensure httpd is started] ************************************************
changed: [172.16.1.10]
changed: [172.16.1.11]

TASK [ensure mariadb is at the latest version] **********************************
changed: [172.16.1.10]
changed: [172.16.1.11]

TASK [ensure mariadb is started] ***********************************************
changed: [172.16.1.10]
changed: [172.16.1.11]

PLAY RECAP *********************************************************************
172.16.1.10             : ok=5    changed=3    unreachable=0    failed=0
172.16.1.11             : ok=5    changed=3    unreachable=0    failed=0

为了更易读,建议以完整的 yaml 格式编写你的剧本。在前面的示例中,参数在与模块相同的行上给出,参数的值在其名称之后使用 = 分隔。查看以完整 yaml 格式编写的相同剧本

---
- hosts: rocky8
  become: true
  become_user: root

  tasks:

    - name: ensure apache is at the latest version
      dnf:
        name: httpd,php,php-mysqli
        state: latest

    - name: ensure httpd is started
      systemd:
        name: httpd
        state: started

    - name: ensure mariadb is at the latest version
      dnf:
        name: mariadb-server
        state: latest

    - name: ensure mariadb is started
      systemd:
        name: mariadb
        state: started
...

提示

dnf 是允许你为其提供列表作为参数的模块之一。

关于集合的说明:Ansible 现在以集合的形式提供模块。一些模块默认情况下在 ansible.builtin 集合中提供,其他模块必须通过以下方式手动安装

ansible-galaxy collection install [collectionname]

其中 [collectionname] 是集合的名称(这里的方括号用于强调需要用实际的集合名称替换它,并且不属于命令的一部分)。

前面的示例应该这样写

---
- hosts: rocky8
  become: true
  become_user: root

  tasks:

    - name: ensure apache is at the latest version
      ansible.builtin.dnf:
        name: httpd,php,php-mysqli
        state: latest

    - name: ensure httpd is started
      ansible.builtin.systemd:
        name: httpd
        state: started

    - name: ensure mariadb is at the latest version
      ansible.builtin.dnf:
        name: mariadb-server
        state: latest

    - name: ensure mariadb is started
      ansible.builtin.systemd:
        name: mariadb
        state: started
...

剧本不限于一个目标

---
- hosts: webservers
  become: true
  become_user: root

  tasks:

    - name: ensure apache is at the latest version
      ansible.builtin.dnf:
        name: httpd,php,php-mysqli
        state: latest

    - name: ensure httpd is started
      ansible.builtin.systemd:
        name: httpd
        state: started

- hosts: databases
  become: true
  become_user: root

    - name: ensure mariadb is at the latest version
      ansible.builtin.dnf:
        name: mariadb-server
        state: latest

    - name: ensure mariadb is started
      ansible.builtin.systemd:
        name: mariadb
        state: started
...

你可以检查你的剧本的语法

ansible-playbook --syntax-check play.yml

你也可以使用 yaml 的“linter”

dnf install -y yamllint

然后检查你的剧本的 yaml 语法

$ yamllint test.yml
test.yml
  8:1       error    syntax error: could not find expected ':' (syntax)

练习结果

  • 创建组 Paris、Tokio、NewYork
  • 创建用户 supervisor
  • 将用户的 uid 改为 10000
  • 将用户更改为属于 Paris 组
  • 安装 tree 软件
  • 停止 crond 服务
  • 使用 0644 权限创建一个空文件
  • 更新你的客户端发行版
  • 重启你的客户端
ansible ansible_clients --become -m group -a "name=Paris"
ansible ansible_clients --become -m group -a "name=Tokio"
ansible ansible_clients --become -m group -a "name=NewYork"
ansible ansible_clients --become -m user -a "name=Supervisor"
ansible ansible_clients --become -m user -a "name=Supervisor uid=10000"
ansible ansible_clients --become -m user -a "name=Supervisor uid=10000 groups=Paris"
ansible ansible_clients --become -m dnf -a "name=tree"
ansible ansible_clients --become -m systemd -a "name=crond state=stopped"
ansible ansible_clients --become -m copy -a "content='' dest=/tmp/test force=no mode=0644"
ansible ansible_clients --become -m dnf -a "name=* state=latest"
ansible ansible_clients --become -m reboot

作者:Antoine Le Morvan

贡献者:Steven Spencer、tianci li、Aditya Putta、Ganna Zhyrnova