面向初学者的 Ansible 教程:Playbook、命令和示例
什么是 Ansible?
Ansible 是一种开源的自动化和编排工具,用于软件供应、配置管理和软件部署。Ansible 可以轻松地运行和配置类 Unix 系统以及 Windows 系统,以提供基础设施即代码。它包含自己的声明式编程语言,用于系统配置和管理。
Ansible 以其安装简单、使用方便(关于客户端连接)、没有 Ansible 客户端代理以及众多的技能而闻名。它通过 SSH 连接到客户端,因此不需要在客户端安装特殊的代理,并且通过将模块推送到客户端,模块在客户端本地执行,然后将输出推回 Ansible 服务器。
由于它使用 SSH,因此可以非常轻松地使用 SSH 密钥连接到客户端,从而简化了整个过程。客户端详细信息,如主机名或 IP 地址和 SSH 端口,存储在称为清单文件的文件中。一旦创建了清单文件并填充了内容,ansible 就可以使用它。
为什么使用 Ansible?
以下是使用 Ansible 的一些重要优点/好处
- Ansible 最显著的优势之一是它对所有人免费使用。
- 安装和使用 Ansible 不需要任何特殊的系统管理员技能,并且官方文档非常全面。
- 它在插件、模块、清单和剧本方面的模块化使其成为编排大型环境的理想伴侣。
- Ansible 非常轻量级且一致,并且在操作系统或底层硬件方面没有限制。
- 由于其无代理功能以及使用 OpenSSH 安全功能,它也非常安全。
- 鼓励采用 Ansible 的另一个优势是其平稳的学习曲线,这得益于全面的文档和易于学习的结构和配置。
Ansible 历史
以下是 Ansible 历史上的重要里程碑
- 2012 年 2 月,Ansible 项目开始。它最初由 Michael DeHaan 开发,他是 Cobbler 和 Func(Fedora Unified Network Controller)的创建者。
- 该公司最初名为 AnsibleWorks Inc,为 ansible 工具提供资金,于 2015 年被 RedHat 收购,后来与 RedHat 一起被纳入 IBM 旗下。
- 目前,Ansible 已包含在 Fedora Linux、RHEL、Centos 和 Oracle Linux 等发行版中。
Ansible 中使用的重要术语
-
Ansible 服务器
安装 Ansible 并从中运行所有任务和剧本的机器
-
模块
基本上,模块是在客户端执行的命令或一组类似的 Ansible 命令
-
任务
任务是包含单个要完成的程序的节
-
角色
一种组织任务和相关文件的方式,以便稍后在剧本中调用
-
事实
通过 gather-facts 操作从全局变量中获取的客户端系统信息
-
清单
包含有关 ansible 客户端服务器数据的文件。在后面的示例中定义为 hosts 文件
-
剧
执行剧本
-
处理程序
仅当存在通知器时才调用的任务
-
通知器
分配给任务的部分,如果输出已更改,则会调用处理程序
-
标签
为任务设置的名称,以后可用于仅发布该特定任务或任务组。
Ansible 在 Linux 上的安装
在您比较和权衡选项并决定使用 Ansible 后,下一步是在您的系统上安装它。在下一个小型教程中,我们将介绍在不同的 Linux 发行版上安装的步骤,其中最受欢迎的。
在 Centos/RedHat 系统上安装 Ansible
第 1 步) 安装 EPEL 存储库
[root@ansible-server ~]# sudo yum install epel-release
第 2 步) 安装 ansible 包
[root@ansible-server ~]# sudo yum install -y ansible
在 Ubuntu/Debian 系统上安装 Ansible
第 1 步) 更新包
$ sudo apt update
第 2 步) 安装 software-properties-common 包
$ sudo apt install software-properties-common
第 3 步) 安装 ansible 个人包存档
$ sudo apt-add-repository ppa:ansible/ansible
第 4 步) 安装 ansible
$ sudo apt update $ sudo apt install ansible
Ansible 临时命令
Ansible 最简单的用法之一是使用临时命令。当您想在服务器或一组服务器上发出某些命令时,可以使用这些命令。临时命令不为将来的使用而存储,而是代表与所需服务器交互的快速方式。
对于这个 Ansible 教程,将配置一个简单的两台服务器 hosts 文件,其中包含 host1 和 host2。
您可以通过在所有主机上发出 ping 命令来确保从 ansible 服务器可访问主机。
[root@ansible-server test_ansible]# ansible -i hosts all -m ping host1 | SUCCESS => { "changed": false, "ping": "pong" } host2 | SUCCESS => { "changed": false, "ping": "pong" }
解释
- 命令的状态,在这种情况下是成功
- 运行命令的主机
- 通过 -m 参数发出的命令,在这种情况下是 ping
- 使用 -i 参数,您可以指向 hosts 文件。
如果需要,您可以在特定主机上发出相同的命令。
[root@ansible-server test_ansible]# ansible -i hosts all -m ping --limit host2 host2 | SUCCESS => { "changed": false, "ping": "pong" }
解释
- 可以使用 limit 参数仅在 hosts 文件中的特定主机上发出命令
- 主机名称,如清单文件中定义的
如果您需要快速将文件复制到多个目标,您可以使用 ansible 中的 copy 模块,它使用 SCP。所以命令及其输出如下所示
[root@ansible-server test_ansible]# ansible -i hosts all -m copy -a "src=/root/test_ansible/testfile dest=/tmp/testfile" host1 | SUCCESS => { "changed": true, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "dest": "/tmp/testfile", "gid": 0, "group": "root", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "root", "size": 0, "src": "/root/.ansible/tmp/ansible-tmp-1562216392.43-256741011164877/source", "state": "file", "uid": 0 } host2 | SUCCESS => { "changed": true, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "dest": "/tmp/testfile", "gid": 0, "group": "root", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "root", "size": 0, "src": "/root/.ansible/tmp/ansible-tmp-1562216392.6-280302911361278/source", "state": "file", "uid": 0 }
解释
- 定义的 copy 模块
- 模块参数,在这种情况下,是源绝对路径和目标绝对路径。
- Ansible 命令输出反映了 copy 命令的成功以及其他详细信息,如用于文件完整性检查的 sha1 或 md5 校验和以及元数据,如所有者、大小或权限。在许多服务器上安装软件包非常容易。Ansible 有几个模块可以与使用的安装程序交互,例如 yum、apt、dnf 等。
在下一个示例中,您将了解如何通过 yum 模块在两个 Centos 主机上安装软件包。
[root@ansible-server test_ansible]# ansible -i hosts all -m yum -a 'name=ncdu state=present' host1 | SUCCESS => { "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirror.netsite.dk\n * elrepo: mirrors.xservers.ro\n * epel: fedora.mirrors.telekom.ro\n * extras: centos.mirrors.telekom.ro\n * remi-php70: remi.schlundtech.de\n * remi-safe: remi.schlundtech.de\n * updates: centos.mirror.iphh.net\nResolving Dependencies\n--> Running transaction check\n---> Package ncdu.x86_64 0:1.14-1.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n ncdu x86_64 1.14-1.el7 epel 51 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 51 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : ncdu-1.14-1.el7.x86_64 1/1 \n Verifying : ncdu-1.14-1.el7.x86_64 1/1 \n\nInstalled:\n ncdu.x86_64 0:1.14-1.el7 \n\nComplete!\n" ] } host2 | SUCCESS => { "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirror.netsite.dk\n * elrepo: mirrors.leadhosts.com\n * epel: mirrors.nav.ro\n * extras: centos.mirrors.telekom.ro\n * remi-php70: mirrors.uni-ruse.bg\n * remi-safe: mirrors.uni-ruse.bg\n * updates: centos.mirror.iphh.net\nResolving Dependencies\n--> Running transaction check\n---> Package ncdu.x86_64 0:1.14-1.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n ncdu x86_64 1.14-1.el7 epel 51 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 51 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : ncdu-1.14-1.el7.x86_64 1/1 \n Verifying : ncdu-1.14-1.el7.x86_64 1/1 \n\nInstalled:\n ncdu.x86_64 0:1.14-1.el7 \n\nComplete!\n" ] }
解释
- 此示例中使用 yum 模块
- 它定义了模块参数,在这种情况下,您将选择软件包的名称及其状态。如果状态是 absent,例如,将搜索软件包,如果找到,则将其删除
- 当显示为黄色时,您将看到 ansible 命令的输出,其中状态已更改,在这种情况下,表示软件包已找到并安装。
- 通过 ansible 发出的 yum install 命令的状态。在这种情况下,安装了包 ncdu.x86_64 0:1.14-1.el7。
当然,所有 yum 安装程序选项都可以通过 ansible 使用,包括 update、install、latest version 或 remove。
在下面的示例中,发出相同的命令来删除之前安装的 ncdu 包。
[root@ansible-server test_ansible]# ansible -i hosts all -m yum -a 'name=ncdu state=absent' host1 | SUCCESS => { "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nResolving Dependencies\n--> Running transaction check\n---> Package ncdu.x86_64 0:1.14-1.el7 will be erased\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nRemoving:\n ncdu x86_64 1.14-1.el7 @epel 87 k\n\nTransaction Summary\n================================================================================\nRemove 1 Package\n\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Erasing : ncdu-1.14-1.el7.x86_64 1/1 \n Verifying : ncdu-1.14-1.el7.x86_64 1/1 \n\nRemoved:\n ncdu.x86_64 0:1.14-1.el7 \n\nComplete!\n" ] } host2 | SUCCESS => { "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nResolving Dependencies\n--> Running transaction check\n---> Package ncdu.x86_64 0:1.14-1.el7 will be erased\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nRemoving:\n ncdu x86_64 1.14-1.el7 @epel 87 k\n\nTransaction Summary\n================================================================================\nRemove 1 Package\n\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Erasing : ncdu-1.14-1.el7.x86_64 1/1 \n Verifying : ncdu-1.14-1.el7.x86_64 1/1 \n\nRemoved:\n ncdu.x86_64 0:1.14-1.el7 \n\nComplete!\n" ] }
解释
- yum 命令的输出显示包已被删除。
Ansible 用于与客户端服务器交互的另一个有用且重要的功能是收集系统的一些事实。因此,它从系统中获取硬件、软件和版本信息,并将每个值存储在一个稍后可以使用的变量中。
如果您需要有关将通过 ansible 修改的系统的详细信息,可以使用以下命令。setup 模块从系统变量收集事实。
Ansible Playbooks
Ansible Playbooks 是通过脚本向远程系统发送命令的方式。Ansible Playbooks 用于配置复杂的系统环境,通过执行脚本到一台或多台系统上来提高灵活性。Ansible Playbooks 更倾向于一种配置语言,而不是一种编程语言。
Ansible 剧本命令使用 YAML 格式,因此不需要太多语法,但必须遵守缩进。顾名思义,剧本是剧集的集合。通过剧本,您可以为某些主机指定特定的角色,为其他主机指定其他角色。通过这样做,您可以在一个剧本中编排多个服务器,适用于各种场景。
为了在继续进行 Ansible 剧本示例之前获得所有详细信息,我们必须首先定义一个任务。这些是 Ansible 模块与角色和剧本的接口。
现在,让我们通过一个示例来学习 Ansible 剧本,其中包含一个具有多个任务的剧本,如下所示
--- - hosts: group1 tasks: - name: Install lldpad package yum: name: lldpad state: latest - name: check lldpad service status service: name: lldpad state: started
在上面的 Ansible 剧本示例中,host 文件中的 group1 主机组通过 yum 模块针对 lldpad 包安装,之后,安装后创建的 lldpad 服务通过 service 模块启动,该模块主要用于与 systemd 集成。
解释
- 剧本将运行的主机组
- 此任务使用 yum 模块进行 lldpad 安装
- 服务模块用于在安装后检查服务是否已启动并正在运行
每个 ansible 剧本都使用清单文件。清单文件包含按组划分的服务器列表,以便更好地控制每个主机的 IP 地址和 SSH 端口等详细信息。
此 Ansible 剧本示例中可以使用清单文件,如下所示。有两个组,分别名为 group1 和 group2,分别包含 host1 和 host2。
[group1] host1 ansible_host=192.168.100.2 ansible_ssh_port=22 [group2] host2 ansible_host=192.168.100.3 ansible_ssh_port=22
解释
- 组名
- 主机名,以及 IP 地址和 ssh 端口,在这种情况下,默认端口为 22。
另一个有用的 Ansible 剧本示例,这次包含两个主机有两个剧集,是下一个。对于第一组主机 group1,将启用 selinux。如果已启用,则主机屏幕上将出现一条消息。
对于第二组主机,仅当 ansible_os_family 为 RedHat 且 ansible_system_vendor 为 HP 时,才会安装 httpd 包。
Ansible_os_family 和 ansible_system_vendor 是通过 gather_facts 选项收集的变量,可以像在此条件示例中使用一样使用。
--- - hosts: group1 tasks: - name: Enable SELinux selinux: state: enabled when: ansible_os_family == 'Debian' register: enable_selinux - debug: Imsg: "Selinux Enabled. Please restart the server to apply changes." when: enable_selinux.changed == true - hosts: group2 tasks: - name: Install apache yum: name: httpd state: present when: ansible_system_vendor == 'HP' and ansible_os_family == 'RedHat'
解释
- when 子句的示例,在这种情况下,当 OS 类型为 Debian 时。ansible_os_family 变量通过 gather_facts 功能收集。
- 任务输出被注册以供将来使用,其名称为 enable_selinux
- when 子句的另一个示例。在这种情况下,如果 SELinux 之前确实已启用,则会为主机用户显示一条消息。
- when 子句的另一个示例,包含两个规则
除了任务,还有一些特殊的任务称为处理程序。处理程序在整个剧本中必须具有唯一的名称。它们的工作方式与常规任务相同,但可以由通知器通知处理程序。
如果在运行剧本期间没有通知处理程序,它将不会运行。但是,如果多个任务通知同一个处理程序,它将在所有任务完成后只运行一次。
在下面显示的示例中,您可以看到特定任务如何具有调用另一个任务的 notify 部分。如果第一个任务的输出已更改,则将调用处理程序任务。最好的例子是更改配置文件,然后重新启动该特定服务。
--- - hosts: group2 tasks: - name: sshd config file modify port lineinfile: path: /etc/ssh/sshd_config regexp: 'Port 28675' line: '#Port 22' notify: - restart sshd handlers - name: restart sshd service: sshd name: sshd state: restarted
在这种情况下,如果第一个任务“sshd config file modify port”已更改,也就是说,如果端口首先不是 28675,那么它将被修改,并且任务将通知具有相同名称的处理程序运行,然后它将重新启动 sshd 服务。
解释
- 通知器示例
- 处理程序示例
Ansible Roles
当处理大型剧本时,将任务分解到角色中会更容易。这也有助于将来重用角色。角色是任务的集合,可以从一个剧本移动到另一个剧本,可以独立运行,但只能通过剧本文件运行。
角色存储在单独的目录中,并具有特定的目录结构。
[root@ansible-server test2]# tree . `-- role1 |-- defaults | `-- main.yml |-- handlers | `-- main.yml |-- meta | `-- main.yml |-- README.md |-- tasks | `-- main.yml |-- tests | |-- inventory | `-- test.yml `-- vars `-- main.yml 7 directories, 8 files
defaults 目录中的 yaml 文件包含一个默认变量列表,将与剧本一起使用。handlers 目录用于存储处理程序。meta 目录应该包含有关作者和角色依赖项的信息。在 tasks 目录中,有一个用于角色的主要 yaml 文件。
tests 目录包含一个示例 yaml 剧本文件和一个示例清单文件,在创建实际角色之前主要用于测试目的。
vars 目录包含 yaml 文件,其中将定义角色使用的所有变量。templates 目录和 files 目录应包含将由角色中的任务使用的文件和模板。
要为角色创建目录树,您应该使用带有最后一个参数(角色名称)的以下命令
[root@ansible-server test2]# ansible-galaxy init role1
Ansible 也与模板配合得很好。作为模板语言,它使用 Jinja2。
在下一个示例中,您将了解一个基本的 jinja2 模板是什么样的,并在角色中使用它。
在运行时,根据您所在的机房,您可以从多个名称服务器中选择,每个服务器对应一个机房,使用变量“resolver_ip_addresses”。
{% for resolver in resolver_ip_addresses %} nameserver {{ resolver }} {% endfor %} options timeout:1 options attempts:5 options rotate
在此示例中,在剧本目录中,定义了一些变量,包括一个名为 resolver_ip_addresses 的变量,该变量根据机房具有不同的值。
- name: Set resolver for server template: src: dns.j2 dest: /etc/resolv.conf group: root owner: root mode: "0644" tag: resolver
解释
- 要使用的模板名称。模板位于角色路径的 templates 目录中
- 要在客户端上替换模板的文件的目标路径。
- 目标文件的权限
角色的任务也可以有一个 tag 字段,该字段有一个名称。多个任务可以共享相同的 tag。在运行 ansible 剧本时,您也可以指定 tag,以便执行这些任务。
Ansible 案例研究
在本节中,我们将分析一个重要的 ansible 剧本的案例研究,该剧本包含三个角色。其目的是提供我们之前讨论过的实际示例。此 Ansible playbook 教程中使用的某些示例将在此 playbook 中进行调整和使用。
以下是剧本的目录结构。将使用的 Yaml 文件是 p4.yml。
[root@ansible-server test_ansible]# ls -lrth total 16K -rw-r--r--. 1 root root 0 Jul 3 10:13 testfile -rw-r--r--. 1 root root 203 Jul 3 13:30 p1.yml -rw-r--r--. 1 root root 125 Jul 3 15:00 hosts -rw-r--r--. 1 root root 488 Jul 3 16:40 p2.yml -rw-r--r--. 1 root root 188 Jul 4 17:33 p4.yml drwxr-xr-x. 5 root root 47 Jul 4 17:35 roles [root@ansible-server test_ansible]# cd roles [root@ansible-server roles]# ls -lrth total 12K drwxr-xr-x. 9 root root 4.0K Jul 4 12:52 httpd drwxr-xr-x. 9 root root 4.0K Jul 4 13:55 selinux drwxr-xr-x. 9 root root 4.0K Jul 4 16:54 resolver
该剧本有三个角色,一个称为 resolver,它通过将文件从服务器复制到 /etc/resolv.conf 目标来设置服务器上的特定名称服务器。另一个称为 httpd,它使用 yum 模块安装 httpd 包,第三个启用 SELinux 并通知登录用户重新启动系统。每个角色都是使用 ansible-galaxy 命令创建的。
Resolver 角色,main.yml 任务
Httpd 角色,main.yml 任务
Selinux 角色,main.yml 任务
下面定义了 p4.yml 剧本。如果未在命令行中另行指定,它将在所有主机上运行,它将以 root 用户在端口 22 (SSH) 上运行,它将在运行角色之前收集事实,并且它将运行上面提到的所有三个角色。可以通过使用 –t 参数在 ansible-playbook 命令中指定 tag 来独立运行每个角色。
--- - hosts: all user: root port: 22 gather_facts: True roles: - { role: selinux, tags: selinux } - { role: httpd, tags: httpd } - { role: resolver, tags: resolver }
在两台主机上运行 p4.yml 剧本并解释输出。可以使用 –check 参数运行相同的命令进行试运行。如果您想使用密码身份验证,请使用 -k 参数。
解释
- 运行 p4.yml 的 Ansible-playbook 命令
- Playbook 跳过 SELinux 角色,因为它已启用。
- Ansible 发现 httpd 包已安装,因此返回 ok。
- Resolver 已设置,角色 resolver 状态已更改。
Ansible 命令备忘单
在 Centos/RHEL 系统上安装 EPEL 存储库
[root@ansible-server ~]# sudo yum install epel-release
在 Centos/RHEL 系统上安装 ansible 包
[root@ansible-server ~]# sudo yum install -y ansible
在 Debian/Ubuntu 系统上更新包
$ sudo apt update
在 Debian/Ubuntu 系统上安装 software-properties-common 包
$ sudo apt install software-properties-common
在 Debian/Ubuntu 系统上安装 ansible 个人包存档
$ sudo apt-add-repository ppa:ansible/ansible
在 Debian/Ubuntu 系统上安装 ansible
$ sudo apt update $ sudo apt install ansible
在清单文件中定义的所有服务器上发出 ping 命令
[root@ansible-server test_ansible]# ansible -i hosts all -m ping
仅在 host2 上发出 ping 命令
[root@ansible-server test_ansible]# ansible -i hosts all -m ping --limit host2
将文件“testfile”复制到清单文件中的所有主机
[root@ansible-server test_ansible]# ansible -i hosts all -m copy -a "src=/root/test_ansible/testfile dest=/tmp/testfile"
在所有主机上安装 ncdu 包
[root@ansible-server test_ansible]# ansible -i hosts all -m yum -a 'name=ncdu state=present'
在所有主机上删除 ncdu 包
[root@ansible-server test_ansible]# ansible -i hosts all -m yum -a 'name=ncdu state=absent'
为名为 role1 的角色构建目录结构。
[root@ansible-server test2]# ansible-galaxy init role1
试运行 p4.yml 剧本
[root@ansible-server test_ansible]# ansible-playbook -i hosts p4.yml --check
使用密码身份验证运行 p4.yml 剧本以获取所有主机
[root@ansible-server test_ansible]# ansible-playbook -i hosts p4.yml -k
摘要
在一个技术飞速发展且同时增长得令人难以置信的世界里,系统管理员和 DevOps 工程师必须考虑各种方法来自动化例行任务和编排大型服务器池。
虽然市面上有许多 Ansible 的替代品(Chef、Puppet)可以完成相同的事情,但 Ansible 凭借其简洁性、改进的安全性以及最重要的平稳学习曲线而脱颖而出。由于这些优点以及 Ansible 的快速普及,我们创建了一个充满示例的教程,以便您能够获得更顺畅的 Ansible 初体验。
在本 Ansible 基础教程中,我们描述了 ansible 并谈论了它的历史。我们提到了 Ansible 的优势以及 ansible 在自动化和编排不同规模基础设施方面带来的好处。我们定义了 essential ansible 使用的术语,并定义了 Ansible playbooks 的结构。所有信息都附有详细解释的实践示例。