常用的运维自动化工具
常用的运维自动化工具有以下几种,它们分别具有不同的特点:
-
Ansible:
Ansible是一款简单易用的自动化工具,通过SSH协议远程执行命令,无需在目标机器上安装客户端。它采用基于YAML的Playbook语法,具备强大的剧本编排和配置管理能力。Ansible主要用于软件部署、配置管理和任务自动化等场景。 -
Puppet:
Puppet是一种基于模型驱动的自动化工具,可用于配置管理和自动化部署。Puppet使用自定义的领域特定语言来描述系统配置,可以对各种操作系统平台进行管理。它具有强大的扩展性和可定制性,可以实现复杂的自动化流程。 -
Chef:
Chef是一个开源的自动化工具,用于部署、管理和自动化配置服务器。Chef使用领域特定语言(DSL)来描述系统配置,支持多种操作系统平台。它具有强大的可伸缩性和灵活性,适用于大规模分布式系统的配置管理。 -
SaltStack:
SaltStack是一款快速、可扩展的自动化工具,用于服务器配置管理、远程执行命令和任务自动化。SaltStack使用基于Python的DSL来描述系统配置,支持批量操作和事件驱动的自动化。它具有出色的性能和高度可定制的特点。 -
Jenkins:
Jenkins是一款开源的持续集成和持续交付工具,用于自动化软件构建、测试和部署。Jenkins支持各种编程语言和工具,可以与其他自动化工具集成。它具有丰富的插件生态系统和易于扩展的特点。
ansible
ansible简介
什么是ansible
Ansible是一款自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
Ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是Ansible所运行的模块,Ansible只是提供一种框架。主要包括:
(1) 连接插件connection plugins:负责和被监控端实现通信;
(2) host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
(3) 各种模块核心模块、command模块、自定义模块;
(4) 借助于插件完成记录日志邮件等功能;
(5) playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
ansible不需要代理
Ansible 围绕无代理架构构建。通常而言,Ansible 通过 OpenSSH 或 WinRM 连接它所管理的主机并且运行任务,方法通常是将称为 Ansible 模块的小程序推送至这些主机。这些程序用于将系统置于需要的特定状态。在 Ansible 运行完其任务后,推送的所有模块都会被删除。
Ansible 不需要批准使用任何特殊代理,然后再部署到受管主机上。由于没有代理,也不需要额外的自定义安全基础架构,
Ansible 具有多个重要的优点:
跨平台支持:Ansible 提供Linux、Windows、UNIX和网络设备的无代理支持,适用于物理、虚拟、云和容器环境。
人类可读的自动化:Ansible Playbook采用YAML文本文件编写,易于阅读,有助于确保所有人都能理解它们的用途。
完美描述应用:可以通过 Ansible Playbook进行每种更改,并描述和记录应用环境的每一个方面。
轻松管理版本控制:Ansible Playbook和项目是纯文本。它们可以视作源代码,放在现有版本控制系统中。
支持动态清单:可以从外部来源动态更新 Ansible 管理的计算机列表,随时获取所有受管服务器的当前正确列表,不受基础架构或位置的影响。
编排可与其他系统轻松集成:能够利用环境中现有的 HP SA、Puppet、Jenkins、红帽卫星和其他系统,并且集成到 Ansible 工作流中。
ansible方式
Ansible 的设计宗旨是工具易用,自动化易写易读。所以在创建自动化时我们应追求简单化。
Ansible 自动化语言围绕简单易读的声明性文本文件来构建。正确编写的 Ansible Playbook可以清楚地记录你的工作自动化。
Ansible 是一种要求状态引擎。它通过表达你所希望系统处于何种状态来解决如何自动化IT部署的问题。Ansible 的目标是通过仅执行必要的更改,使系统处于所需的状态。试图将 Ansible 视为脚本语言并非正确的做法。
控制主机
Ansible 易于安装。 Ansible 软件只需要安装到要运行它的一个(或多个)控制节点上。由 Ansible管理的主机不需要安装 Ansible。
对控制节点的要求:
- 控制节点应是Linux或UNIX系统。不支持将Windows用作控制节点,但Windows系统可以是受管主机。
- 控制节点需要安装Python3(版本3.5或以上)或Python2(版本2.7或以上)。
如果操作系统是红帽8.0,Ansible 2.9可以自动使用 platform-python 软件包,该软件包支持使用Python的系统实用程序。你不需要从 AppStream安装python37或python27软件包。
[root@ansible ansible]# yum list installed platform-python
Installed Packages
platform-python.x86_64 3.6.8-51.el8 @anaconda
[root@ansible ansible]#
受管主机
Ansible的一大优点是受管主机不需要安装特殊代理。Ansible控制节点使用标准的网络协议连接受管主机,从而确保系统处于指定的状态。
受管主机可能要满足一些要求,具体取决于控制节点连接它们的方式以及它们要运行的模块。
Linux和UNIX受管主机需要安装有Python2(版本2.6或以上)或Python3(版本3.5或以上),这样才能运行大部分的模块。
对于红帽8,可以启用并安装python36应用流(或python27应用流)
基于Windows的受管主机
Ansible有许多专门为Windows系统设计的模块。这些模块列在https://docs.ansible.com/ansible/latest/modules/list_of_windows_modules.html部分中。
大部分专门为Windows受管主机设计的模块需要在受管主机上安装PowerShell 3.0或更高版本,而不是安装Python。此外,受管主机也需要配置PowerShell远程连接。Ansible还要求至少将.NET Framework 4.0或更高版本安装在Windows受管主机上。
受管网络设备
Ansible还可以配置受管网络设备,例如路由器和交换机。Ansible包含大量专门为此目的而设计的模块。其中包括对Cisco IOS、IOS XR和NX-OS的支持;Juniper Junos;Arsta EOS;以及基于VyOS的网络设备等。
我们可以使用为服务器编写playbook时使用的相同基本技术为网络设备编写Ansible Playbook。由于大多数网络设备无法运行Python,因此Ansible在控制节点上运行网络模块,而不是在受管主机上运行。特殊连接方法也用于与网络设备通信,通常使用SSH上的CLI、SSH上的XML或HTTP(S)上的API。
安装ansible
控制节点安装ansible
准备网络源
[root@ansible ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo
[root@ansible ~]# sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo
[root@ansible ~]#
[root@ansible ~]# yum clean all
27 files removed
[root@ansible ~]# yum makecache
下载ansible的源
[root@ansible ~]# yum -y install centos-release-ansible-29.noarch
Last metadata expiration check: 0:00:29 ago on Fri 28 Jul 2023 10:11:09 AM CST.
Dependencies resolved.
=====================================================================
Package Arch Version Repo Size
=====================================================================
Installing:
centos-release-ansible-29 noarch 1-2.el8 extras 8.4 k
Installing dependencies:
centos-release-configmanagement noarch 1-1.el8 extras 8.7 k
Transaction Summary
=====================================================================
Install 2 Packages
(省略)
Verifying : centos-release-configmanagement-1-1.el8.n 2/2
Installed:
centos-release-ansible-29-1-2.el8.noarch
centos-release-configmanagement-1-1.el8.noarch
Complete!
安装ansible
[root@ansible ~]# yum -y install ansible
(省略)
Installed:
ansible-2.9.27-1.el8.noarch
python3-babel-2.5.1-7.el8.noarch
python3-cffi-1.11.5-5.el8.x86_64
python3-cryptography-3.2.1-5.el8.x86_64
python3-jinja2-2.10.1-3.el8.noarch
python3-jmespath-0.9.0-11.el8.noarch
python3-markupsafe-0.23-19.el8.x86_64
python3-ply-3.9-9.el8.noarch
python3-pycparser-2.14-14.el8.noarch
python3-pytz-2017.2-9.el8.noarch
python3-pyyaml-3.12-12.el8.x86_64
sshpass-1.06-8.el8.x86_64
Complete!
查看ansible和Python的版本
[root@ansible ~]# ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Jan 25 2023, 15:03:30) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)]
[root@ansible ~]# ansible -m setup localhost|grep ansible_python_version
"ansible_python_version": "3.6.8",
[root@ansible ~]#
受控节点配置
受控节点上需要安装Python;和配置控制节点可以免密登录受控节点
部署ansible
1.构建ansible清单
什么是清单:
清单定义Ansible将要管理的一批主机。这些主机也可以分配到组中,以进行集中管理。组可以包含子组,主机也可以是多个组的成员。清单还可以设置应用到它所定义的主机和组的变量。
可以通过两种方式定义主机清单。静态主机清单可以通过文本文件定义。动态主机清单可以根据需要使用外部信息提供程序通过脚本或其他程序来生成。
使用静态清单指定受管主机
静态清单文件是指定Ansible目标受管主机的文本文件。可以使用多种不同的格式编写此文件,包括INI样式或YAML。
在最简单的形式中。INI样式的静态清单文件是受管主机的主机名或IP地址的列表,每行一个
但通常而言,可以将受管主机组织为主机组。通过主机组,可以更加有效的对一系列系统运行Ansible。这时,每一部分的开头为以中括号括起来的主机组名称。其后为该组中每一受管主机的主机名或IP地址,每行一个
静态清单默认在hosts文件里面,但是一般都不写在里面,而且创建另一个文件来定义
[root@ansible ansible]# ls
ansible.cfg hosts roles
[root@ansible ansible]#
注意:可以写主机名,也可以写主机的ip地址
单个主机
node001
node002
[root@ansible ansible]#
用主机组管理
//中括号里面的是组名,写在下面的主机都属于这个主机组,可以写多个主机
[test]
node001
[dev]
node002
[root@ansible ansible]#
2.验证清单
可以用ansible命令验证主机是否存在于清单中
目前主机清单(hosts)中的信息
[root@ansible ansible]# vim hosts
[root@ansible ansible]# cat hosts
node001
[dev]
node002
[root@ansible ansible]#
查看主机清单中所有的主机信息
[root@ansible ansible]# ansible all --list-hosts
hosts (2):
node001
node002
[root@ansible ansible]#
查看清单中的某个主机
[root@ansible ansible]# ansible node001 --list-hosts
hosts (1):
node001
[root@ansible ansible]#
查看清单中某个主机组中的主机
[root@ansible ansible]# ansible dev --list-hosts
hosts (1):
node002
[root@ansible ansible]#
如果没有在清单找到主机是这样的
[root@ansible ansible]# ansible kook --list-hosts
[WARNING]: Could not match supplied host pattern, ignoring: kook
[WARNING]: No hosts matched, nothing to do
hosts (0):
[root@ansible ansible]#
查找在清单中,不属于主机组的主机
[root@ansible ansible]# ansible ungrouped --list-hosts
hosts (1):
node001
[root@ansible ansible]#
3.自定义清单
在/etc/ansible/目录中,创建一个名为inventory的自定义静态清单文件。
主机清单里面的主机可以写主机名也可以写ip
主机后面要写登录的用户和密码(为了安全性一般不写)
自定义的清单文件要在配置文件里面指定才会生效
自定义清单
[root@ansible ansible]# vim inventory
[root@ansible ansible]# cat inventory
node001 ansible_user=root ansible_password=1
[dev]
node002 ansible_user=root ansible_password=1
[root@ansible ansible]#
修改配置文件
//把默认的清单文件改为自定义的清单文件
[root@ansible ansible]# cat ansible.cfg | grep /etc/ansible/inventory
inventory = /etc/ansible/inventory
[root@ansible ansible]#
列出所有受管的主机
[root@ansible ansible]# ansible all --list-hosts
hosts (2):
node001
node002
[root@ansible ansible]#
管理Ansible配置文件
配置Ansible
可以通过修改 Ansible 配置文件中的设置来自定义 Ansible安装的行为。Ansible从控制节点上多个可能的位置之一选择其配置文件。
使用/etc/ansible/ansible.cfg
ansible软件包提供一个基本的配置文件,它位于/etc/ansible/ansible.cfg。如果找不到其他配置文件,则使用此文件。使用~/.ansible.cfg
Ansible在用户的家目录中查找.ansible.cfg文件。如果存在此配置文件并且当前工作目录中也没有ansible.cfg文件,则使用此配置取代/etc/ansible/ansible.cfg。使用./ansible.cfg
如果执行ansible命令的目录中存在ansible.cfg文件,则使用它,而不使用全局文件或用户的个人文件。这样,管理员可以创建一种目录结构,将不同的环境或项目存储在单独的目录中,并且每个目录包含为独特的一组设置而定制的配置文件。推荐的做法是在需要运行Ansible命令的目录中创建ansible.cfg文件。此目录中也将包含任何供Ansible项目使用的文件,如清单和playbook。这是用于Ansible配置文件的最常用位置。实践中不常使用~/.ansible.cfg或/etc/ansible/ansible.cfg文件
使用ANSIBLE_CONFIG环境变量
我们可以通过将不同的配置文件放在不同的目录中,然后从适当的目录执行Ansible命令,以此利用配置文件。但是,随着配置文件数量的增加,这种方法存在局限性并且难以管理。有一个更加灵活的选项,即通过ANSIBLE_CONFIG环境变量定义配置文件的位置。定义了此变量时,Ansible将使用变量所指定的配置文件,而不用上面提到的任何配置文件。
配置文件优先级
ANSIBLE_CONFIG环境变量指定的任何文件将覆盖所有其他配置文件。如果没有设置该变量,则接下来检查运行ansible命令的目录中是否有ansible.cfg文件。如果不存在该文件,则检查用户的家目录是否有.ansible.cfg文件。只有在找不到其他配置文件时,才使用全局/etc/ansible/ansible.cfg文件。如果/etc/ansible/ansible.cfg配置文件不存在,Ansible包含它使用的默认值。
由于Ansible配置文件可以放入的位置有多种,因此Ansible当前使用哪一个配置文件可能会令人困惑。我们可以运行以下命令来清楚地确认所安装的Ansible版本以及正在使用的配置文件。
ansible --version
Ansible仅使用具有最高优先级的配置文件中的设置。即使存在优先级较低的其他配置文件,其设置也会被忽略,不会与选定配置文件中的设置结合。因此,如果你选择自行创建配置文件来取代全局/etc/ansible/ansible.cfg配置文件,就需要将该文件中所有需要的设置复制到自己的用户级配置文件中。用户组配置文件中未定义的设置将保持设为内置默认值,即使已在全局配置文件中设为某个其他值也是如此。
[root@ansible ansible]# ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg //此行代表当前所使用的的配置文件
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Jan 25 2023, 15:03:30) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)]
[root@ansible ansible]#
管理配置文件中的设置
Ansible配置文件由几个部分组成,每一部分含有以键值对形式定义的设置。部分的标题以中括号括起来。对于基本操作,请使用以下两部分:
- [defaults]部分设置Ansible操作的默认值
- [privilege_escalation]配置Ansible如何在受管主机上执行特权升级
例如,下面是典型的ansible.cfg文件:
[root@ansible ansible]# vim ansible.cfg
[root@ansible ansible]# cat ansible.cfg
[defaults]
inventory = /etc/ansible/inventory
remote_user = root
ask_pass = false
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[root@ansible ansible]#
下表说明了此文件中的指令:
Ansible配置
指令 | 描述 |
---|---|
inventory | 指定清单文件的路径。 |
remote_user | 要在受管主机上登录的用户名。如果未指定则使用当前用户名 |
ask_pass | 是否提示输入SSH密码。如果使用SSH公钥身份验证则可以是false |
become | 连接后是否自动在受管主机上切换用户(通常切换为root) 这也可以通过play来指定。 |
become_method | 如何切换用户(通常为sudo,这也是默认设置,但可选择su) |
become_user | 要在受管主机上切换到的用户(通常是root,这也是默认值) |
become_ask_pass | 是否需要为become_method提示输入密码。默认为false。 |
配置连接
Ansible需要知道如何与其受管主机通信。更改配置文件的一个最常见原因是为了控制Ansible使用什么方法和用户来管理受管主机。需要的一些信息包括:
- 列出受管主机和主机组的清单的位置
- 要使用哪一种连接协议来与受管主机通信(默认为SSH),以及是否需要非标准网络端口来连接服务器
- 要在受管主机上使用哪一远程用户;这可以是root用户或者某一非特权用户
- 如果远程用户为非特权用户,Ansible需要知道它是否应尝试将特权升级为root以及如何进行升级(例如,通过sudo)
- 是否提示输入SSH密码或sudo密码以进行登录或获取特权
清单位置
在[defaults]部分中,inventory指令可以直接指向某一静态清单文件,或者指向含有多个静态清单文件和动态清单脚本的某一目录。
[defaults]
inventory = ./inventory
连接设置
默认情况下,Ansible使用SSH协议连接受管主机。控制Ansible如何连接受管主机的最重要参数在[defaults]部分中设置。
默认情况下,Ansible尝试连接受管主机时使用的用户名与运行ansible命令的本地用户相同。若要指定不同的远程用户,请将remote_user参数设置为该用户名。
如果为运行Ansible的本地用户配置了SSH私钥,使得它们能够在受管主机上进行远程用户的身份验证,则Ansible将自动登录。如果不是这种情况,可以通过设置指令ask_pass = true,将Ansible配置为提示本地用户输入由远程用户使用的密码。
[defaults]
inventory = ./inventory
remote_user = root
ask_pass = true
假设在使用一个Linux控制节点,并对受管主机使用OpenSSH,如果可以使用密码以远程用户身份登录,那么我们可以设置基于SSH密钥的身份验证,从而能够设置ask_pass = false。
第一步是确保在**~/.ssh中为控制节点上的用户配置了SSH密钥对。并且使用ssh-copy-id**命令将本地的公钥复制到受管主机中。
升级特权
鉴于安全性和审计原因,Ansible可能需要先以非特权用户身份连接远程主机,然后再通过特权升级获得root用户身份的管理权限。这可以在Ansible配置文件的**[privilege_escalation]**部分中设置。
要默认启用特权升级,可以在配置文件中设置指令become = true。即使默认为该设置,也可以在运行临时命令或Ansible Playbook时通过各种方式覆盖它。(例如,有时候可能要运行一些不需要特权升级的任务或play。)
become_method指令指定如何升级特权。有多个选项可用,但默认为使用sudo。类似地,become_user指令指定要升级到的用户,但默认为root。
如果所选的become_method机制要求用户输入密码才能升级特权,可以在配置文件中设置become_ask_pass = true指令。
以下示例ansible.cfg文件假设你可以通过基于SSH密钥的身份验证以someuser用户身份连接受管主机,并且someuser可以使用sudo以root用户身份运行命令而不必输入密码:
[defaults]
inventory = ./inventory
remote_user = someuser
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
非SSH连接
默认情况下,Ansible用于连接受管主机的协议设置为smart,它会确定使用SHH的最高效方式。可以通过多种方式将其设置为其他的值。
例如,默认使用SSH的规则有一个例外。如果目录中没有localhost,Ansible将设置一个隐式localhost条目以便允许运行以localhost为目标的临时命令和playbook。这一特殊清单条目不包括在all或ungrouped主机组中。此外,Ansible不使用smart SSH连接类型,而是利用默认的特殊local连接类型来进行连接。
ansible localhost --list-hosts
local连接类型忽略remote_user设置,并且直接在本地系统上运行命令。如果使用特权升级,它会在运行sudo时使用运行Ansible命令的用户,而不是remote_user。如果这两个用户具有不同的sudo特权,这可能会导致混淆。
如果你要确保像其他受管主机一样使用SSH连接localhost,一种方法是在清单中列出它。但是,这会将它包含在all和ungrouped组中,而你可能不希望如此。
另一种方法是更改用于连接localhost的协议。执行此操作的最好方法是为localhost设置ansible_connection主机变量。为此,你需要在运行Ansible命令的目录中创建host_vars子目录。在该子目录中,创建名为localhost的文件,其应含有ansible_connection: smart这一行。这将确保对localhost使用smart(SSH)连接协议,而非local。
你也可以通过另一种变通办法来使用它。如果清单中列有127.0.0.1,则默认情况下,将会使用smart来连接它。也可以创建一个含有ansible_connection: local这一行的host_vars/127.0.0.1文件,它会改为使用local。
配置文件注释
Ansible配置文件允许使用两种注释字符:井号或分号。
位于行开头的#号会注释掉整行。它不能和指令位于同一行中。
分号字符可以注释掉所在行中其右侧的所有内容。它可以和指令位于同一行中,只要该指令在其左侧。
连接管理
示例一:
需要在清单文件里面写入用户和密码(不安全)
主机清单文件
[root@ansible ansible]# vim inventory
[root@ansible ansible]# cat inventory
node001 ansible_user=root ansible_password=1
[dev]
node002 ansible_user=root ansible_password=1
[root@ansible ansible]#
写hosts文件
[root@ansible ansible]# vim /etc/hosts
[root@ansible ansible]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.179.11 node001
192.168.179.12 node002
[root@ansible ansible]#
控制节点和受管节点都关闭防火墙和selinux
[root@ansible ansible]# systemctl stop firewalld.service
[root@ansible ansible]# systemctl disable --now firewalld.service
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@ansible ansible]# vim /etc/selinux/config
[root@ansible ansible]# cat /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled //此行的enforcing改为disabled
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
[root@ansible ansible]# setenforce 0
//其他主机过程省略
先接受密钥
//不用真正登录进去,只用接受密钥就行
[root@ansible ansible]# ssh node002
The authenticity of host 'node002 (192.168.179.12)' can't be established.
ECDSA key fingerprint is SHA256:dHkJZbhMHbO0KBd96y6HsQETzSx6HOMVO5JFXkSwfYA.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'node002,192.168.179.12' (ECDSA) to the list of known hosts.
root@node002's password:
[root@ansible ansible]# ssh node001
The authenticity of host 'node001 (192.168.179.11)' can't be established.
ECDSA key fingerprint is SHA256:U1hP1QknHUuLXn71NCSh1JVmGkyNy4ZN6YQA4XF/VAw.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'node001,192.168.179.11' (ECDSA) to the list of known hosts.
root@node001's password:
用ping模块
[root@ansible ansible]# ansible all -m ping
node002 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node001 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
ping通
示例二:
主机清单上不用写用户免密,而是配置免密登录
主机清单(没有用户密码)
[root@ansible ansible]# vim inventory
[root@ansible ansible]# cat inventory
node001
[dev]
node002
[root@ansible ansible]#
生成主机密钥
[root@ansible ansible]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:WMill89pdrHqDrWI7flUDVOcxnpy9/SOqCynLIFxVFQ root@ansible
The key's randomart image is:
+---[RSA 3072]----+
| o+.E o.. |
| ..+ . .= |
| .+ + +o |
| . .+ o .o*o o|
| +. S B ++.oo|
| . .o = = o|
| ..+ + . o |
| .o.*. . . .|
| .=**. |
+----[SHA256]-----+
[root@ansible ansible]#
把公钥传输到远程主机上
[root@ansible ansible]# ssh-copy-id root@node001
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@node001's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@node001'"
and check to make sure that only the key(s) you wanted were added.
[root@ansible ansible]# ssh-copy-id root@node002
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@node002's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@node002'"
and check to make sure that only the key(s) you wanted were added.
[root@ansible ansible]#
ping模块
[root@ansible ansible]# ansible all -m ping
node002 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node001 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
ping通
示例三:
受管主机使用受管主机本机上的普通用户执行(该主机上要配置sudo)
受管主机上都有student用户
给两个受管主机的student用户配置sudo借权
[root@node002 ~]# visudo
student ALL=(ALL) NOPASSWD:ALL
修改控制节点的配置文件
//第三行改成student,第6-9行取消注释
[root@ansible ansible]# vim ansible.cfg
[root@ansible ansible]# cat -n ansible.cfg
1 [defaults]
2 inventory = /etc/ansible/inventory
3 remote_user = student
4 ask_pass = false
5 [privilege_escalation]
6 become = true
7 become_method = sudo
8 become_user = root
9 become_ask_pass = false
[root@ansible ansible]#
把控制节点公钥发给受管主机的student用户,配置student用户的免密登录
[root@ansible ansible]# ssh-copy-id student@node001
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
student@node001's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'student@node001'"
and check to make sure that only the key(s) you wanted were added.
[root@ansible ansible]# ssh-copy-id student@node002
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
student@node002's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'student@node002'"
and check to make sure that only the key(s) you wanted were added.
[root@ansible ansible]#
ping模块
[root@ansible ansible]# ansible all -m ping
node002 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node001 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ansible]#
可以ping通
使用临时命令管理
[root@ansible ansible]# ansible node001 -a 'useradd kok'
node001 | CHANGED | rc=0 >>
[root@ansible ansible]# ansible node002 -a 'useradd plp'
node002 | CHANGED | rc=0 >>
[root@ansible ansible]#
分别在node001和node002上查看命令是否执行成功
[root@node001 ~]# id kok
uid=1001(kok) gid=1001(kok) groups=1001(kok)
[root@node001 ~]#
[root@node002 ~]# id plp
uid=1001(plp) gid=1001(plp) groups=1001(plp)
[root@node002 ~]#
执行成功
运行临时命令
Ansible运行临时命令的语法如下:
ansible host-pattern -m module [-a 'module arguments'] [-i inventory]
示例:
[root@ansible ansible]# ansible all -m ping
node002 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node001 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ansible]#
[root@ansible ansible]# ansible all -m user -a 'name=mbm uid=2221 state=present'
node002 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 2221,
"home": "/home/mbm",
"name": "mbm",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 2221
}
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 2221,
"home": "/home/mbm",
"name": "mbm",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 2221
}
[root@ansible ansible]#
在受管主机上运行任意命令
command模块允许管理员在受管主机的命令行中运行任意命令。要运行的命令通过-a选项指定为该模块的参数。
示例:
如果使用command模块的话,可以省略 “-m command”
[root@ansible ansible]# ansible all -m command -a 'hostname'
node002 | CHANGED | rc=0 >>
node002
node001 | CHANGED | rc=0 >>
node001
[root@ansible ansible]#
command模块允许管理员对受管主机快速执行远程命令。这些命令不是由受管主机上的shell加以处理。因此,它们无法访问shell环境变量,也不能执行重定向和管道等shell操作。
在命令需要shell处理的情形中,管理员可以使用shell模块。与command模块类似,可以在临时命令中将要执行的命令作为参数传递给该模块。Ansible随后对受管主机远程执行该命令。与command模块不同的是,这些命令将通过受管主机上的shell进行处理。因此,可以访问shell环境变量,也可以使用重定向和管道等操作
command和shell模块都要求受管主机上安装正常工作的Python。第三个模块是raw,它可以绕过模块子系统,直接使用远程shell运行命令。在管理无法安装Python的系统(如网络路由器)时,可以利用这个模块。它也可以用于将Python安装到主机上。
在大多数情况下,建议避免使用command、shell和raw这三个“运行命令”模块。
其他模块大部分都是幂等的,可以自动进行更改跟踪。它们可以测试系统的状态,在这些系统已处于正确状态时不执行任何操作。相反,以幂等方式使用“运行命令”模块要复杂得多。依靠它们,你更难以确信再次运行临时命令或playbook不会造成意外的失败。当shell或command模块运行时,通常会基于它是否认为影响了计算机状态而报告CHANGED状态。
command模块不支持管道符和重定向
shell模块支持管道符和重定向
raw模块只在路由器和交换机使用
常用模块
常用模块:ping
//ping模块用于检查指定节点机器是否连通,用法很简单,不涉及参数,主机如果在线,则回复pong
[root@ansible ansible]# ansible node001 -m ping
node001 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
[root@ansible ansible]#
//有'pong'回应说明主机在线
常用模块:command
//command模块用于在远程主机上执行命令,ansible默认就是使用command模块。
//command模块有一个缺陷就是不能使用管道符和重定向功能。
[root@ansible ansible]# ansible node001 -m command -a 'ls /home'
node001 | CHANGED | rc=0 >>
kok
mbm
student
[root@ansible ansible]#
常用模块:raw
//多用于控制网络设备:路由器、交换机
//raw模块用于在远程主机上执行命令,其支持管道符与重定向
[root@ansible ansible]# ansible node001 -m raw -a 'echo "hello world" > /tmp/test'
node001 | CHANGED | rc=0 >>
Shared connection to node001 closed.
[root@ansible ansible]# ansible node001 -m raw -a 'cat /tmp/test'
node001 | CHANGED | rc=0 >>
hello world
Shared connection to node001 closed.
[root@ansible ansible]#
常用模块:shell
//shell模块用于在受控机上执行受控机上的脚本,亦可直接在受控机上执行命令。
//shell模块亦支持管道与重定向。
[root@ansible ansible]# ansible node001 -m shell -a 'ls /var/www/html'
node001 | CHANGED | rc=0 >>
index.php
[root@ansible ansible]# ansible node001 -m shell -a 'systemctl status httpd'
node001 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/httpd.service.d
└─php-fpm.conf
Active: active (running) since Fri 2023-07-28 18:35:25 CST; 54min ago
Docs: man:httpd.service(8)
Main PID: 9183 (httpd)
Status: "Total requests: 5; Idle/Busy workers 100/0;Requests/sec: 0.00152; Bytes served/sec: 94 B/sec"
Tasks: 278 (limit: 4479)
Memory: 31.9M
CGroup: /system.slice/httpd.service
├─ 9183 /usr/sbin/httpd -DFOREGROUND
├─ 9212 /usr/sbin/httpd -DFOREGROUND
├─ 9213 /usr/sbin/httpd -DFOREGROUND
├─ 9214 /usr/sbin/httpd -DFOREGROUND
├─ 9215 /usr/sbin/httpd -DFOREGROUND
└─13502 /usr/sbin/httpd -DFOREGROUND
Jul 28 18:35:25 node001 systemd[1]: Starting The Apache HTTP Server...
Jul 28 18:35:25 node001 httpd[9183]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::20c:29ff:fe3f:d582. Set the 'ServerName' directive globally to suppress this message
Jul 28 18:35:25 node001 systemd[1]: Started The Apache HTTP Server.
Jul 28 18:35:25 node001 httpd[9183]: Server configured, listening on: port 80
[root@ansible ansible]#
常用模块:script
//script模块用于在受控机上执行主控机上的脚本
[root@ansible ansible]# cat /opt/test.sh
#!/bin/bash
echo '123456789' > test111
[root@ansible ansible]#
[root@ansible ansible]# ansible node001 -m script -a '/opt/test.sh &> /opt/test111'
node001 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to node001 closed.\r\n",
"stderr_lines": [
"Shared connection to node001 closed."
],
"stdout": "",
"stdout_lines": []
}
[root@ansible ansible]#
[root@ansible ansible]# ansible node001 -m shell -a 'cat /home/student/test111'
node001 | CHANGED | rc=0 >>
123456789
[root@ansible ansible]#
常用模块:template
//template模块用于生成一个模板,并可将其传输至远程主机上。
[root@ansible ansible]# ansible node001 -m template -a 'src=/opt/kook dest=/opt/pllp'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"checksum": "73f2660ec9772b1d70c275f646315bbccaa04905",
"dest": "/opt/pllp",
"gid": 0,
"group": "root",
"md5sum": "59c465185c22229a328065160dcc9260",
"mode": "0644",
"owner": "root",
"size": 12,
"src": "/home/student/.ansible/tmp/ansible-tmp-1690544972.8056114-2562-70075269419973/source",
"state": "file",
"uid": 0
}
[root@ansible ansible]#
[root@ansible ansible]# ansible node001 -m shell -a 'cat /opt/pllp'
node001 | CHANGED | rc=0 >>
888
999
777
[root@ansible ansible]#
常用模块:yum
//yum模块用于在指定节点机器上通过yum管理软件,其支持的参数主要有两个
name:要管理的包名
state:要进行的操作
//state常用的值:
latest:安装软件
installed:安装软件
present:安装软件
removed:卸载软件
absent:卸载软件
//若想使用yum来管理软件,请确保受控机上的yum源无异常。
//安装一个包
[root@ansible ansible]# ansible node001 -m yum -a 'name=zsh state=present'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Installed: zsh-5.5.1-10.el8.x86_64"
]
}
//卸载一个包
[root@ansible ansible]# ansible node001 -m yum -a 'name=zsh state=absent'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Removed: zsh-5.5.1-10.el8.x86_64"
]
}
[root@ansible ansible]#
常用模块:copy
//copy模块用于复制文件至远程受控机。
//传输
[root@ansible ansible]# ansible node001 -m copy -a 'src=/opt/index.php dest=/var/www/html'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"checksum": "9e5d7cd2f45cc3a092a0cb3e68184a5826310a28",
"dest": "/var/www/html/index.php",
"gid": 0,
"group": "root",
"md5sum": "231dda2188079d6e62e88482373b033f",
"mode": "0644",
"owner": "root",
"size": 24,
"src": "/home/student/.ansible/tmp/ansible-tmp-1690541459.4626603-1965-122164141371592/source",
"state": "file",
"uid": 0
}
[root@ansible ansible]#
//查看
[root@ansible ansible]# ansible node001 -m shell -a 'cat /var/www/html/index.php'
node001 | CHANGED | rc=0 >>
<?php
phpinfo();
?>
[root@ansible ansible]#
常用模块:group
//group模块用于在受控机上添加或删除组。
//创建组
[root@ansible ansible]# ansible node001 -m group -a 'name=iiyy gid=1234 state=present'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"gid": 1234,
"name": "iiyy",
"state": "present",
"system": false
}
[root@ansible ansible]#
//删除组
[root@ansible ansible]# ansible node001 -m group -a 'name=iiyy gid=1234 state=absent'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"name": "iiyy",
"state": "absent"
}
[root@ansible ansible]#
常用模块:user
//user模块用于管理受控机的用户帐号。
[root@ansible ansible]# ansible node001 -m user -a 'name=xc uid=4544 state=present'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 4544,
"home": "/home/xc",
"name": "xc",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 4544
}
[root@ansible ansible]#
常用模块:service
//service模块用于管理受控机上的服务。
//启动httpd服务
[root@ansible ansible]# ansible node001 -m service -a 'name=httpd state=started'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
"After": "systemd-tmpfiles-setup.service nss-lookup.target sysinit.target basic.target remote-fs.target network.target httpd-init.service system.slice systemd-journald.socket tmp.mount -.mount",
"AllowIsolate": "no",
"AllowedCPUs": "",
"AllowedMemoryNodes": "",
"AmbientCapabilities": "",
"AssertResult": "no",
"AssertTimestampMonotonic": "0",
"Before": "shutdown.target",
(省略)
//设置httpd服务开机自启动
[root@ansible ansible]# ansible node001 -m service -a 'name=httpd enabled=yes'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"enabled": true,
"name": "httpd",
"status": {
"ActiveEnterTimestamp": "Fri 2023-07-28 18:35:25 CST",
"ActiveEnterTimestampMonotonic": "1004117610",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "active",
"After": "systemd-journald.socket system.slice tmp.mount sysinit.target nss-lookup.target network.target remote-fs.target -.mount basic.target httpd-init.service systemd-tmpfiles-setup.service",
"AllowIsolate": "no",
"AllowedCPUs": "",
"AllowedMemoryNodes": "",
"AmbientCapabilities": "",
"AssertResult": "yes",
"AssertTimestamp": "Fri 2023-07-28 18:35:25 CST",
"AssertTimestampMonotonic": "1003915232",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
"BlockIOWeight": "[not set]",
"CPUAccounting": "no",
"CPUAffinity": "",
"CPUAffinityFromNUMA": "no",
"CPUQuotaPerSecUSec": "infinity",
"CPUQuotaPeriodUSec": "infinity",
"CPUSchedulingPolicy": "0",
"CPUSchedulingPriority": "0",
(省略)
使用ansible部署lamp架构
1.写主机清单
[root@ansible ansible]# vim inventory
[root@ansible ansible]# cat inventory
node001
node002
node003
[root@ansible ansible]#
2.使用ansible关闭firewalld和selinux
//关闭防火墙
[root@ansible ansible]# ansible node001 -m service -a 'name=firewalld state=stopped'
node002 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"name": "firewalld",
"state": "stopped",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
"After": "system.slice dbus.service polkit.service basic.target",
"AllowIsolate": "no",
(省略)
//关闭selinux
[root@ansible ansible]# ansible node001 -m shell -a 'setenforce 0'
node001 | CHANGED | rc=0 >>
[root@ansible ansible]#
3.安装服务
//安装apache
[root@ansible ansible]# ansible node001 -m yum -a 'name=httpd state=present'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Installed: apr-util-1.6.1-9.el8.x86_64",
"Installed: mailcap-2.1.48-3.el8.noarch",
"Installed: apr-util-bdb-1.6.1-9.el8.x86_64",
"Installed: mod_http2-1.15.7-7.module_el8.8.0+1256+e1598b50.x86_64",
"Installed: httpd-tools-2.4.37-54.module_el8.8.0+1256+e1598b50.x86_64",
"Installed: apr-util-openssl-1.6.1-9.el8.x86_64",
"Installed: httpd-2.4.37-54.module_el8.8.0+1256+e1598b50.x86_64",
"Installed: centos-logos-httpd-85.8-2.el8.noarch",
"Installed: apr-1.6.3-12.el8.x86_64",
"Installed: httpd-filesystem-2.4.37-54.module_el8.8.0+1256+e1598b50.noarch"
]
}
[root@ansible ansible]#
//安装mariadb和mariadb-server
[root@ansible ansible]# ansible node001 -m yum -a 'name=mariadb,mariadb-server state=present'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Installed: perl-libs-4:5.26.3-422.el8.x86_64",
"Installed: perl-macros-4:5.26.3-422.el8.x86_64",
(省略)
[root@ansible ansible]#
//安装php
[root@ansible ansible]# ansible node001 -m yum -a 'name=php* state=present'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Installed: libmpc-1.1.0-9.1.el8.x86_64",
"Installed: libzip-1.5.1-2.module_el8.2.0+313+b04d0a66.x86_64",
"Installed: php-ldap-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64",
"Installed: kernel-headers-4.18.0-500.el8.x86_64",
"Installed: php-bcmath-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64",
"Installed: gcc-c++-8.5.0-20.el8.x86_64",
"Installed: libpq-13.5-1.el8.x86_64",
(省略)
[root@ansible ansible]#
4.启动服务
//启动httpd
[root@ansible ansible]# ansible node001 -m service -a 'name=httpd state=started'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
"After": "systemd-tmpfiles-setup.service nss-lookup.target sysinit.target basic.target remote-fs.target network.target httpd-init.service system.slice systemd-journald.socket tmp.mount -.mount",
"AllowIsolate": "no",
"AllowedCPUs": "",
"AllowedMemoryNodes": "",
"AmbientCapabilities": "",
"AssertResult": "no",
"AssertTimestampMonotonic": "0",
"Before": "shutdown.target",
(省略)
//启动mariadb
[root@ansible ansible]# ansible node001 -m service -a 'name=mariadb.service state=started'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"name": "mariadb.service",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
"After": "sysinit.target -.mount tmp.mount basic.target network.target systemd-journald.socket system.slice systemd-tmpfiles-setup.service",
"AllowIsolate": "no",
"AllowedCPUs": "",
"AllowedMemoryNodes": "",
"AmbientCapabilities": "",
"AssertResult": "no",
"AssertTimestampMonotonic": "0",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
(省略)
//启动php
[root@ansible ansible]# ansible node001 -m service -a 'name=php-fpm state=started'
node001 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"name": "php-fpm",
"state": "started",
"status": {
"ActiveEnterTimestamp": "Fri 2023-07-28 18:40:31 CST",
"ActiveEnterTimestampMonotonic": "1310099506",
"ActiveExitTimestamp": "Fri 2023-07-28 18:40:31 CST",
"ActiveExitTimestampMonotonic": "1309783770",
"ActiveState": "active",
"After": "network.target systemd-tmpfiles-setup.service sysinit.target system.slice systemd-journald.socket syslog.target basic.target -.mount tmp.mount",
"AllowIsolate": "no",
"AllowedCPUs": "",
"AllowedMemoryNodes": "",
"AmbientCapabilities": "",
"AssertResult": "yes",
"AssertTimestamp": "Fri 2023-07-28 18:40:31 CST",
"AssertTimestampMonotonic": "1309891212",
"Before": "shutdown.target",
"BlockIOAccounting": "no",
(省略)
5.把控制节点的index.php文件传输到受控制节点中去
[root@ansible ansible]# cat /opt/index.php
<?php
phpinfo();
?>
[root@ansible ansible]#
//传输
[root@ansible ansible]# ansible node001 -m copy -a 'src=/opt/index.php dest=/var/www/html'
node001 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"checksum": "9e5d7cd2f45cc3a092a0cb3e68184a5826310a28",
"dest": "/var/www/html/index.php",
"gid": 0,
"group": "root",
"md5sum": "231dda2188079d6e62e88482373b033f",
"mode": "0644",
"owner": "root",
"size": 24,
"src": "/home/student/.ansible/tmp/ansible-tmp-1690541459.4626603-1965-122164141371592/source",
"state": "file",
"uid": 0
}
[root@ansible ansible]#