1Ansible common module details
1.1 module introduction
- Modules are tools for temporary commands to complete tasks. Ansible provides hundreds of modules that can complete different tasks. Usually, we can find a tested special module to complete the required tasks as part of the standard installation
- The ansible doc - L command can list all modules installed on the system. You can use ansible doc to view the help document of a specific module by name, and then find information about what parameters the module will take as options
- Most modules take parameters. A list of parameters available for the module can be found in the module's documentation. You can pass parameters to the module with the - a option. When no parameters are required, the - a option can be omitted from the. If you need to specify more than one parameter, provide it as a space delimited list enclosed in quotation marks
1.2 module classification
Module type | modular |
---|---|
File module | Copy: copy the local file to the managed host file: set the permissions and other properties of the file lineinfile: ensure that a specific line is synchronized in the file synchronize: synchronize content using rsync |
Software package module | Package: manage packages using the automatic detection package manager native to the operating system yum: manage packages using yum APT: manage packages using APT dnf: manage packages using dnf gem: manage Ruby gempip: manage Python packages from PyPI |
System module | Firewalld: use firewalld to manage firewall reboot: restart the computer service: manage service user: add, delete and manage user accounts |
Net Tools module | get_url: download files via HTTP, HTTPS or FTP nmcli: manage network uri: interact with Web Services |
Other modules
- Cloud module
- Command module
- Database module
- Asset module
- Message module
- Monitoring module
- Network module
- Notification module
- Source control module
- Unit module
- web Facility module
- windows module
1.3 ansible common modules
- ping
- yum
- template
- copy
- user
- group
- service
- raw
- command
- shell
- script
1.4 differences between common modules raw, command and shell of ansible
command, shell module:
- python is required to be installed on the managed host. command can execute shell commands on the managed host, but environment variables and operators are not supported (such as' | '.' < ',' > ',' & ')
- The / bin/sh instruction called by the shell module executes
raw module:
- Instead of installing python on the managed host, run the command directly using the remote shell
- Typically used on systems where python cannot be installed (such as network devices)
2Ansible common modules
2.1 Ping module
The ping module is used to check whether the specified node machine is connected. The usage is very simple and does not involve parameters. If the host is online, it will reply to pong
[root@localhost ansible]# ansible all -m ping 192.168.25.130 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" }
2.2command module
The command module is used to execute commands on the remote host. ansible uses the command module by default. (that is, the command module is used by default without specifying the module)
[root@localhost ansible]# ansible all -m command -a 'ls /opt' 192.168.25.130 | CHANGED | rc=0 >> abc
[root@localhost ansible]# ansible all -a 'ls /opt' 192.168.25.130 | CHANGED | rc=0 >> abc
command module parameters
- Chdir specifies a directory. Before executing the command, you will enter the directory specified by chdir
[root@localhost ansible]# ansible all -m command -a "chdir=/opt/ ls" 192.168.25.130 | CHANGED | rc=0 >> abc
- creates creates does not help us create files. Its purpose is that when the specified file exists, the command will not be executed. For example, when the / opt/abc file exists, the specified command will not be executed
[root@node1 ~]# cd /opt/ [root@node1 opt]# ls abc [root@localhost ansible]# ansible all -m command -a "creates=/opt/abc echo redhat-test" 192.168.25.130 | SUCCESS | rc=0 >> skipped, since /opt/abc exists
- When / opt/abc does not exist, execute the RedHat test command
[root@node1 ~]# cd /opt/ [root@node1 opt]# ls [root@node1 opt]# [root@localhost ansible]# ansible all -m command -a "creates=/opt/abc echo redhat-test" 192.168.25.130 | CHANGED | rc=0 >> redhat-test
- Remove when the specified file does not exist, the command will not be executed
[root@node1 ~]# cd /opt/ [root@node1 opt]# ls [root@node1 opt]# [root@localhost ansible]# ansible all -m command -a "removes=/opt/abc echo redhat-test" 192.168.25.130 | SUCCESS | rc=0 >> skipped, since /opt/abc does not exist
- When / opt/abc exists, execute the redha test command
[root@node1 ~]# cd /opt/ [root@node1 opt]# ls abc [root@localhost ansible]# ansible all -m command -a "removes=/opt/abc echo redhat-test" 192.168.25.130 | CHANGED | rc=0 >> redhat-test
- touch create file
[root@localhost ansible]# ansible all -m command -a 'touch /opt/ll' [WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. 192.168.25.130 | CHANGED | rc=0 >> [root@localhost ansible]# ansible all -m command -a 'chdir=/opt/ ls' 192.168.25.130 | CHANGED | rc=0 >> abc ll
One drawback of the command module is that it cannot use pipeline characters and redirection functions
[root@localhost ansible]# ansible all -m command -a "echo 'hello world' > /opt/ll" 192.168.25.130 | CHANGED | rc=0 >> hello world > /opt/ll [root@localhost ansible]# ansible all -m command -a 'cat /opt/ll' 192.168.25.130 | CHANGED | rc=0 >> [root@localhost ansible]# ansible all -m command -a 'ps -ef|grep vsftpd' 192.168.25.130 | FAILED | rc=1 >> error: unsupported SysV option Usage: ps [options] Try 'ps --help <simple|list|output|threads|misc|all>' or 'ps --help <s|l|o|t|m|a>' for additional help text. For more details see ps(1).non-zero return code
2.3raw module
The raw module is used to execute commands on a remote host and supports pipeline characters and redirection
//Support redirection [root@localhost ansible]# ansible all -m raw -a 'echo "hell word" > /opt/ll' 192.168.25.130 | CHANGED | rc=0 >> Shared connection to 192.168.25.130 closed. [root@localhost ansible]# ansible all -m raw -a 'cat /opt/ll' 192.168.25.130 | CHANGED | rc=0 >> hell word Shared connection to 192.168.25.130 closed.
//Supports pipe characters [root@localhost ansible]# ansible all -m raw -a 'ss -antl' 192.168.25.130 | CHANGED | rc=0 >> State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 0.0.0.0:111 0.0.0.0:* LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 5 127.0.0.1:631 0.0.0.0:* LISTEN 0 128 127.0.0.1:6010 0.0.0.0:* LISTEN 0 128 127.0.0.1:6011 0.0.0.0:* LISTEN 0 128 [::]:111 [::]:* LISTEN 0 128 [::]:22 [::]:* LISTEN 0 5 [::1]:631 [::]:* LISTEN 0 128 [::1]:6010 [::]:* LISTEN 0 128 [::1]:6011 [::]:* Shared connection to 192.168.25.130 closed. [root@localhost ansible]# ansible all -m raw -a 'ss -antl|grep 22' 192.168.25.130 | CHANGED | rc=0 >> LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 128 [::]:22 [::]:* Shared connection to 192.168.25.130 closed.
2.4 shell module
- The shell module is used to execute scripts on the controlled machine, or directly execute commands on the controlled machine, and the shell module also supports pipeline and redirection
- When the shell module executes commands in the remote host, it will be processed by the / bin/sh program on the remote host
//Script file [root@node1 ~]# vim test.sh [root@node1 ~]# cat test.sh #!/bin/bash echo "hello word" [root@node1 ~]# chmod +x test.sh [root@node1 ~]# ll Total consumption 12 drwxr-xr-x. 2 root root 6 11 February 2020 public drwxr-xr-x. 2 root root 6 11 February 2020 template drwxr-xr-x. 2 root root 6 11 February 2020 video drwxr-xr-x. 2 root root 6 11 February 2020 picture drwxr-xr-x. 2 root root 6 11 February 2020 document drwxr-xr-x. 2 root root 6 11 February 2020 Download drwxr-xr-x. 2 root root 6 11 February 2020 music drwxr-xr-x. 2 root root 6 11 February 2020 desktop -rw-------. 1 root root 1230 11 February 2020 anaconda-ks.cfg -rw-r--r--. 1 root root 1385 11 February 2020 initial-setup-ks.cfg -rwxr-xr-x. 1 root root 31 7 March 17:49 test.sh //Viewing script files for controlled hosts [root@localhost ansible]# ansible all -m command -a 'cat test.sh' 192.168.25.130 | CHANGED | rc=0 >> #!/bin/bash echo "hello word" //Use the shell module to execute the script on the controlled machine on the controlled machine [root@localhost ansible]# ansible all -m shell -a '/bin/bash /root/test.sh &> /opt/test.log' 192.168.25.130 | CHANGED | rc=0 >> [root@localhost ansible]# ansible all -m command -a 'cat /opt/test.log' 192.168.25.130 | CHANGED | rc=0 >> hello word
2.5 script module
The script module executes the script on the ansible management host on the controlled host. The script exists on the ansible management host and does not need to be copied to the controlled host before execution (that is, the script module is used to execute the script on the master on the controlled host)
//Script file [root@localhost ansible]# ls ansible.cfg hosts inventory roles [root@localhost ansible]# mkdir scripts [root@localhost ansible]# cd scripts/ [root@localhost scripts]# vim test.sh [root@localhost scripts]# cat test.sh #!/bin/bash useradd tom echo "redhat" | passwd --stdin tom echo "hello word" > ~tom/abc //Execute the script file on the host computer [root@localhost ansible]# ansible all -m script -a 'scripts/test.sh' 192.168.25.130 | CHANGED => { "changed": true, "rc": 0, "stderr": "Shared connection to 192.168.25.130 closed.\r\n", "stderr_lines": [ "Shared connection to 192.168.25.130 closed." ], "stdout": "Change user tom Your password.\r\npasswd: All authentication tokens have been successfully updated.\r\n", "stdout_lines": [ "Change user tom Your password.", "passwd: All authentication tokens have been successfully updated." ] } //View the content on the controlled machine [root@node1 ~]# id tom uid=1001(tom) gid=1002(tom) group=1002(tom) [root@node1 ~]# cd /home/tom/ [root@node1 tom]# ls abc [root@node1 tom]# cat abc hello word
2.6 template module
- The template module can transfer the configuration file with parameters to the target address, and modify and backup the parameters of the file
- The template module is used to generate a template and transfer it to a remote host
//transfer files [root@localhost ansible]# ansible all -m template -a 'src=~/anaconda-ks.cfg dest=/opt/hehe' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "checksum": "4e0b9a45ca5724c0e46a70d56213e1d90f2f0595", "dest": "/opt/hehe/anaconda-ks.cfg", "gid": 0, "group": "root", "md5sum": "a840aed2908e3fca668c10f7face84cc", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:usr_t:s0", "size": 1230, "src": "/root/.ansible/tmp/ansible-tmp-1626510875.6001868-10108-259486274186289/source", "state": "file", "uid": 0 } [root@node1 ~]# head -3 /opt/hehe #version=RHEL8 ignoredisk --only-use=nvme0n1 autopart --type=lvm
2.7yum module
- The yum module helps us manage the package through Yum source on the managed host
main parameter
name specifies the package to be managed
State specifies the state of the package
statec common values
present ensure that the software package is installed [installed]
Latest means install the latest version from yum
removed means to delete the corresponding software package [absent]
//Query whether vsftpd software is installed on the controlled machine [root@node1 ~]# rpm -qa|grep vsftpd [root@node1 ~]# //On the management host, install vsftpd on the controlled machine through the yum module [root@localhost ansible]# ansible all -m yum -a 'name=vsftpd state=present' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: vsftpd-3.0.3-31.el8.x86_64" ] } //Query whether the controlled machine is installed with vsftpd on the management host [root@localhost ansible]# ansible all -m shell -a 'rpm -qa | grep vsftpd' [WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command because yum, dnf or zypper is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. 192.168.25.130 | CHANGED | rc=0 >> vsftpd-3.0.3-31.el8.x86_64 //Uninstall vsftpd on the controlled machine through yum module on the management host [root@localhost ansible]# ansible all -m yum -a 'name=vsftpd state=absent' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Removed: vsftpd-3.0.3-31.el8.x86_64" ] } //Query whether vsftpd on the controlled machine is uninstalled on the management host [root@localhost ansible]# ansible all -m shell -a 'rpm -qa | grep vsftpd' [WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command because yum, dnf or zypper is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. 192.168.25.130 | FAILED | rc=1 >> non-zero return code
2.8 copy module
The copy module copies files from the ansible management host to the managed host
Common parameters
- src [source] specifies the file or directory to copy
- dest [destination] specifies the directory where the file will be copied to the controlled host
- Content when you do not use src to specify the copied file, you can use content to specify the file content directly
//Copy the inventory on the management host to the control host [root@localhost ansible]# ansible all -m copy -a 'src=/etc/ansible/inventory dest=/opt/inventory' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "checksum": "895cbc69037e6266a4cc5ac0b702ecbc6e5f93c9", "dest": "/opt/inventory", "gid": 0, "group": "root", "md5sum": "fb1a9c0d2acdde2788955941206a48f8", "mode": "0644", "owner": "root", "secontext": "system_u:object_r:usr_t:s0", "size": 67, "src": "/root/.ansible/tmp/ansible-tmp-1626513540.3747706-10780-226187928193702/source", "state": "file", "uid": 0 } [root@node1 ~]# cd /opt/ [root@node1 opt]# ls abc hehe inventory ll test.log [root@node1 opt]# cat inventory [webservers] 192.168.25.130 ansible_user=root ansible_password=1
2.9 group module
The group module helps us manage groups on controlled hosts
Common parameters
Name specifies the name of the group to operate on
sate specifies the status of the Group [present creates a group, absent deletes a group]
gid specifies the gid of the group
Change system to system group (yes/no)
//Add a system group on the controlled machine with gid 306 and group name mysql [root@localhost ansible]# ansible all -m group -a 'name=mysql gid=306 state=present' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "gid": 306, "name": "mysql", "state": "present", "system": false } //See if a group is created on the controlled host [root@localhost ansible]# ansible all -m shell -a 'grep mysql /etc/group' 192.168.25.130 | CHANGED | rc=0 >> mysql:x:306: //Change mysql group to system group [root@localhost ansible]# ansible all -m group -a 'name=mysql gid=306 system=yes' 192.168.25.130 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "gid": 306, "name": "mysql", "state": "present", "system": true } //Change the gid of mysql group [root@localhost ansible]# ansible all -m group -a 'name=mysql gid=600 ' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "gid": 600, "name": "mysql", "state": "present", "system": false } [root@localhost ansible]# ansible all -m shell -a 'grep mysql /etc/group' 192.168.25.130 | CHANGED | rc=0 >> mysql:x:600: //Delete mysql group [root@localhost ansible]# ansible all -m group -a 'name=mysql state=absent ' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "name": "mysql", "state": "absent" } [root@localhost ansible]# ansible all -m shell -a 'grep mysql /etc/group' 192.168.25.130 | FAILED | rc=1 >> non-zero return code
2.10user module
The user module is used to manage users on the controlled host, such as creating users, deleting users, modifying users, deleting users, creating keys for users, etc
Common parameters
Name specifies the name of the user
Group specifies the base group of the user
groups specifies the additional group that the user is in
Shell specifies the default shell for the user
Uid specifies the uid of the user
create_home creates a home for a user when the user is created or when the home directory does not exist
System specifies whether the user is a system user
//Add a system user on the controlled machine, whose user name is mysql, uid is 306, and its shell is set to / sbin/nologin. There is no home directory [root@localhost ansible]# ansible all -m user -a 'name=mysql uid=306 shell=/sbin/nologin system=yes create_home=no' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "comment": "", "create_home": false, "group": 306, "home": "/home/mysql", "name": "mysql", "shell": "/sbin/nologin", "state": "present", "system": true, "uid": 306 } [root@localhost ansible]# ansible all -m shell -a 'grep mysql /etc/passwd' 192.168.25.130 | CHANGED | rc=0 >> mysql:x:306:306::/home/mysql:/sbin/nologin [root@localhost ansible]# ansible all -m shell -a 'ls /home' 192.168.25.130 | CHANGED | rc=0 >> ii runtime tom //Modify user's uid [root@localhost ansible]# ansible all -m user -a 'name=mysql uid=360' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "append": false, "changed": true, "comment": "", "group": 306, "home": "/home/mysql", "move_home": false, "name": "mysql", "shell": "/sbin/nologin", "state": "present", "uid": 360 } [root@localhost ansible]# ansible all -m shell -a 'grep mysql /etc/passwd' 192.168.25.130 | CHANGED | rc=0 >> mysql:x:360:306::/home/mysql:/sbin/nologin //Delete the mysql user on the controlled host [root@localhost ansible]# ansible all -m user -a 'name=mysql state=absent' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "force": false, "name": "mysql", "remove": false, "state": "absent" } [root@localhost ansible]# ansible all -m shell -a 'grep mysql /etc/passwd' 192.168.25.130 | FAILED | rc=1 >> non-zero return code
2.11 service module
The service module helps us manage the services on the controlled host
Common parameters
Name specifies the name of the service to be operated
state specifies the status of the service [started, stopped]
enabled specifies whether the service is set to start automatically (yes/no)
//Check whether vsftpd service is installed on the controlled machine [root@localhost ansible]# ansible all -m shell -a 'rpm -qa |grep vsftpd' [WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command because yum, dnf or zypper is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. 192.168.25.130 | FAILED | rc=1 >> non-zero return code //Install the vsftpd service on the controlled host [root@localhost ansible]# ansible all -m yum -a 'name=vsftpd state=present' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: vsftpd-3.0.3-31.el8.x86_64" ] } [root@localhost ansible]# ansible all -m shell -a 'rpm -qa |grep vsftpd' [WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command because yum, dnf or zypper is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. 192.168.25.130 | CHANGED | rc=0 >> vsftpd-3.0.3-31.el8.x86_64 //Check whether the vsftpd service on the controlled machine is started [root@localhost ansible]# ansible all -m shell -a 'systemctl is-active vsftpd' 192.168.25.130 | FAILED | rc=3 >> inactivenon-zero return code //Start the vsftpd service on the controlled machine [root@localhost ansible]# ansible all -m service -a 'name=vsftpd state=started' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "name": "vsftpd", "state": "started", "status": { "ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "systemd-journald.socket basic.target system.slice sysinit.target network.target", "AllowIsolate": "no", "AllowedCPUs": "", ...... //Check whether the vsftpd service on the controlled machine is started [root@localhost ansible]# ansible all -m shell -a 'systemctl is-active vsftpd' 192.168.25.130 | CHANGED | rc=0 >> active //Check whether the vsftpd service on the controlled machine starts automatically [root@localhost ansible]# ansible all -m shell -a 'systemctl is-enabled vsftpd' 192.168.25.130 | FAILED | rc=1 >> disablednon-zero return code //Set the vsftpd service on the controlled machine to start automatically [root@localhost ansible]# ansible all -m service -a 'name=vsftpd enabled=yes' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "enabled": true, "name": "vsftpd", "status": { "ActiveEnterTimestamp": "Sat 2021-07-17 06:15:20 EDT", "ActiveEnterTimestampMonotonic": "34314422767", "ActiveExitTimestampMonotonic": "0", "ActiveState": "active", "After": "network.target systemd-journald.socket basic.target sysinit.target system.slice", ...... //Check whether the vsftpd service on the controlled machine starts automatically [root@localhost ansible]# ansible all -m shell -a 'systemctl is-enabled vsftpd' 192.168.25.130 | CHANGED | rc=0 >> enabled //Stop the vsftpd service on the controlled machine [root@localhost ansible]# ansible all -m service -a 'name=vsftpd state=stopped' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "name": "vsftpd", "state": "stopped", "status": { "ActiveEnterTimestamp": "Sat 2021-07-17 06:15:20 EDT", "ActiveEnterTimestampMonotonic": "34314422767", "ActiveExitTimestampMonotonic": "0", "ActiveState": "active", "After": "system.slice network.target sysinit.target systemd-journald.socket basic.target", ...... [root@localhost ansible]# ansible all -m shell -a 'systemctl is-active vsftpd' 192.168.25.130 | FAILED | rc=3 >> inactivenon-zero return code
2.12 lineinfile module
- The lineinfile module is used to ensure that a specific line is in a file, or to ensure that the specified text is deleted from the file (j that is, to ensure that the specified text does not exist in the file), and to replace "the text of a line" with a regular expression
Common parameters
- path specifies the file to operate on
- line specifies the text content
- State setting status [when you want to delete the corresponding text, you need to set the state parameter to absent. The default value of state is present]
- regexp uses regular expressions to match the corresponding lines [when replacing text, if multiple lines are matched, only the last matched line of text will be replaced; when deleting text, if multiple lines are matched, all lines will be deleted]
- insertafter enables you to insert text after a "specified line"
//Change SELINUX=enforcing and in / etc/selinx/config to disabled [root@localhost ansible]# ansible all -m lineinfile -a 'path=/etc/selinux/config regexp="^SELINUX=" line="SELINUX=disabled"' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "backup": "", "changed": true, "msg": "line replaced" } [root@localhost ansible]# ansible all -m shell -a 'cat /etc/selinux/config' 192.168.25.130 | CHANGED | rc=0 >> # 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 # 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 //Insert hehe,xixi in managed host / opt/ll [root@localhost ansible]# ansible all -m lineinfile -a 'path=/opt/ll line="hehe\nxixi"' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "backup": "", "changed": true, "msg": "line added" } [root@localhost ansible]# ansible all -m shell -a 'cat /opt/ll' 192.168.25.130 | CHANGED | rc=0 >> hell word hehe xixi //Delete the line hehe in / opt/ll [root@localhost ansible]# ansible all -m lineinfile -a 'path=/opt/ll state=absent regexp="hehe"' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "backup": "", "changed": true, "found": 1, "msg": "1 line(s) removed" } [root@localhost ansible]# ansible all -m shell -a 'cat /opt/ll' 192.168.25.130 | CHANGED | rc=0 >> hell word xixi //Change owner and group [root@node1 opt]# ll ll -rw-r--r--. 1 root root 15 7 August 17:45 ll [root@localhost ansible]# ansible all -m lineinfile -a 'path=/opt/ll owner=zhao group=zhao line=xix state=present' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "backup": "", "changed": true, "msg": "ownership, perms or SE linux context changed" } [root@node1 ~]# cd /opt/ [root@node1 opt]# ll ll -rw-r--r--. 1 zhao zhao 19 7 August 17:52 ll //Insert a row in / opt/ll on the managed host [root@node1 opt]# cat ll #Listen=80 hell word xixi [root@localhost ansible]# ansible all -m lineinfile -a 'path=/opt/ll regexp="^Listen" insertafter="#Listen" line=Listen=80' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "backup": "", "changed": true, "msg": "line added" } [root@localhost ansible]# ansible all -m shell -a 'cat /opt/ll' 192.168.25.130 | CHANGED | rc=0 >> #Listen=80 Listen=80 hell word xixi
2.13 firewalld module
Firewalld specifies the released service, which must be queried on firewalld CMD -- get service
//Load the vsftpd service on the managed host into the firewall rules [root@localhost ansible]# ansible all -m firewalld -a 'service=ftp permanent=yes state=enabled immediate=yes' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "Permanent and Non-Permanent(immediate) operation, Changed service ftp to enabled" } [root@node1 opt]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: ens160 sources: services: cockpit dhcpv6-client ftp ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
3LAMP separation deployment
First, write the IP addresses of the other three hosts into the manifest file of the management host
[root@localhost ansible]# vim inventory [root@localhost ansible]# cat inventory [webservers] 192.168.25.130 ansible_user=root ansible_password=1 192.168.25.140 ansible_user=root ansible_password=1 192.168.25.142 ansible_user=root ansibel_password=1
Do password free login for the other three hosts and test whether they can ping
[root@localhost 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:vwTYVhpdEagFVrTJFdeIqwoKH/x3bzzGR1/xl6gS/Fc root@localhost The key's randomart image is: +---[RSA 3072]----+ | o+o.*=.o | | . oo=... .| | .o* . | | o.+ . . | | . . S . . +| | . o .. =. ..E+| | o + . .=o....o| | o . oo.+*.. .| | . .o+oo | +----[SHA256]-----+ [root@localhost ansible]# ssh-copy-id 192.168.25.140 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" The authenticity of host '192.168.25.140 (192.168.25.140)' can't be established. ECDSA key fingerprint is SHA256:/SJbOLoOuH3estBrdxUtlQ56iKPhVSYumEVNVXmOye0. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes /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@192.168.25.140's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '192.168.25.140'" and check to make sure that only the key(s) you wanted were added. [root@localhost ansible]# ansible 192.168.25.140 -m ping 192.168.25.140 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" } [root@localhost ansible]# ssh-copy-id 192.168.25.142 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" The authenticity of host '192.168.25.142 (192.168.25.142)' can't be established. ECDSA key fingerprint is SHA256:/SJbOLoOuH3estBrdxUtlQ56iKPhVSYumEVNVXmOye0. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes /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@192.168.25.142's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '192.168.25.142'" and check to make sure that only the key(s) you wanted were added. [root@localhost ansible]# ansible 192.168.25.142 -m ping 192.168.25.142 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" }
3.1 installing apache
Install apache
[root@localhost ansible]# ansible 192.168.25.130 -m yum -a 'name=httpd state=present' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: httpd-tools-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64", "Installed: mod_http2-1.11.3-3.module+el8.2.0+4377+dc421495.x86_64", "Installed: apr-util-openssl-1.6.1-6.el8.x86_64", "Installed: httpd-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64", "Installed: apr-1.6.3-9.el8.x86_64", "Installed: apr-util-1.6.1-6.el8.x86_64", "Installed: redhat-logos-httpd-81.1-1.el8.noarch", "Installed: apr-util-bdb-1.6.1-6.el8.x86_64", "Installed: httpd-filesystem-2.4.37-21.module+el8.2.0+5008+cca404a3.noarch" ] } [root@localhost ansible]# ansible 192.168.25.130 -m yum -a 'name=httpd-devel state=present' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: apr-devel-1.6.3-9.el8.x86_64", "Installed: httpd-devel-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64", "Installed: libdb-devel-5.3.28-37.el8.x86_64", "Installed: apr-util-devel-1.6.1-6.el8.x86_64", "Installed: expat-devel-2.2.5-3.el8.x86_64", "Installed: cyrus-sasl-devel-2.1.27-1.el8.x86_64", "Installed: openldap-devel-2.4.46-11.el8.x86_64" ] }
Start apache
[root@localhost ansible]# ansible 192.168.25.130 -m service -a 'name=httpd state=started' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "name": "httpd", "state": "started", "status": { "ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "-.mount sysinit.target network.target systemd-tmpfiles-setup.service nss-lookup.target remote-fs.target systemd-journald.socket system.slice tmp.mount httpd-init.service basic.target", ...... [root@localhost ansible]# ansible 192.168.25.130 -m shell -a 'systemctl is-active httpd' 192.168.25.130 | CHANGED | rc=0 >> active
Set the httpd service to start automatically
[root@localhost ansible]# ansible 192.168.25.130 -m service -a 'name=httpd enabled=yes' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "enabled": true, "name": "httpd", "status": { "ActiveEnterTimestamp": "Sun 2021-07-18 03:38:14 EDT", "ActiveEnterTimestampMonotonic": "50817852436", "ActiveExitTimestampMonotonic": "0", "ActiveState": "active", "After": "httpd-init.service network.target systemd-journald.socket systemd-tmpfiles-setup.service nss-lookup.target tmp.mount basic.target -.mount sysinit.target system.slice remote-fs.target", ...... [root@localhost ansible]# ansible 192.168.25.130 -m shell -a 'systemctl is-enabled httpd' 192.168.25.130 | CHANGED | rc=0 >> enabled
View service status
[root@localhost ansible]# ansible 192.168.25.130 -m shell -a 'systemctl status httpd' 192.168.25.130 | CHANGED | rc=0 >> ● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) Active: active (running) since Sun 2021-07-18 03:38:14 EDT; 5min ago Docs: man:httpd.service(8) Main PID: 62606 (httpd) Status: "Running, listening on: port 80" Tasks: 213 (limit: 11152) Memory: 23.7M CGroup: /system.slice/httpd.service ├─62606 /usr/sbin/httpd -DFOREGROUND ├─62628 /usr/sbin/httpd -DFOREGROUND ├─62629 /usr/sbin/httpd -DFOREGROUND ├─62630 /usr/sbin/httpd -DFOREGROUND └─62631 /usr/sbin/httpd -DFOREGROUND 7 March 18:37:58 node1 systemd[1]: Starting The Apache HTTP Server... 7 March 18:38:14 node1 httpd[62606]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::df4e:bd67:1a8c:e302. Set the 'ServerName' directive globally to suppress this message 7 March 18:38:14 node1 systemd[1]: Started The Apache HTTP Server. 7 March 18:38:24 node1 httpd[62606]: Server configured, listening on: port 80
View httpd port number 80
[root@localhost ansible]# ansible 192.168.25.130 -m raw -a 'ss -antl' 192.168.25.130 | CHANGED | rc=0 >> State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 0.0.0.0:111 0.0.0.0:* LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 5 127.0.0.1:631 0.0.0.0:* LISTEN 0 128 127.0.0.1:6010 0.0.0.0:* LISTEN 0 128 127.0.0.1:6011 0.0.0.0:* LISTEN 0 128 [::]:111 [::]:* LISTEN 0 128 *:80 *:* LISTEN 0 128 [::]:22 [::]:* LISTEN 0 5 [::1]:631 [::]:* LISTEN 0 128 [::1]:6010 [::]:* LISTEN 0 128 [::1]:6011 [::]:* Shared connection to 192.168.25.130 closed.
Set http80 port for firewall release
[root@localhost ansible]# ansible 192.168.25.130 -m firewalld -a 'service=http permanent=yes state=enabled immediate=yes' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "Permanent and Non-Permanent(immediate) operation, Changed service http to enabled" } [root@localhost ansible]# ansible 192.168.25.130 -m firewalld -a 'service=https permanent=yes state=enabled immediate=yes' 192.168.25.130 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "Permanent and Non-Permanent(immediate) operation, Changed service https to enabled" } [root@node1 ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: ens160 sources: services: cockpit dhcpv6-client ftp http https ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
Browser login
3.2 installing mysql
Install mysql
[root@localhost ansible]# ansible 192.168.25.140 -m yum -a 'name=mariadb state=present' 192.168.25.140 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: mariadb-connector-c-3.0.7-1.el8.x86_64", "Installed: mariadb-connector-c-config-3.0.7-1.el8.noarch", "Installed: mariadb-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64", "Installed: mariadb-common-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.140 -m yum -a 'name=mariadb-server state=present' 192.168.25.140 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: mariadb-backup-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64", "Installed: mariadb-errmsg-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64", "Installed: mariadb-gssapi-server-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64", "Installed: mariadb-server-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64", "Installed: mariadb-server-utils-3:10.3.17-1.module+el8.1.0+3974+90eded84.x86_64", "Installed: perl-DBD-MySQL-4.046-3.module+el8.1.0+2938+301254e2.x86_64" ] }
Start the mysql service and set the startup self startup
[root@localhost ansible]# ansible 192.168.25.140 -m service -a 'service=mariadb state=started' 192.168.25.140 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "name": "mariadb", "state": "started", "status": { "ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "system.slice network.target systemd-tmpfiles-setup.service sysinit.target tmp.mount -.mount basic.target systemd-journald.socket", ...... [root@localhost ansible]# ansible 192.168.25.140 -m shell -a 'systemctl is-active mariadb' 192.168.25.140 | CHANGED | rc=0 >> active [root@localhost ansible]# ansible 192.168.25.140 -m service -a 'name=mariadb enabled=yes' 192.168.25.140 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "enabled": true, "name": "mariadb", "status": { "ActiveEnterTimestamp": "Sun 2021-07-18 04:08:13 EDT", "ActiveEnterTimestampMonotonic": "4287861883", "ActiveExitTimestampMonotonic": "0", "ActiveState": "active", "After": "basic.target tmp.mount system.slice network.target -.mount sysinit.target systemd-journald.socket systemd-tmpfiles-setup.service", ...... [root@localhost ansible]# ansible 192.168.25.140 -m shell -a 'systemctl is-enabled mariadb' 192.168.25.140 | CHANGED | rc=0 >> enabled
View mysql service status
[root@localhost ansible]# ansible 192.168.25.140 -m shell -a 'netstat -tulp' 192.168.25.140 | CHANGED | rc=0 >> Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN 1159/sshd tcp 0 0 localhost:ipp 0.0.0.0:* LISTEN 1161/cupsd tcp 0 0 localhos:x11-ssh-offset 0.0.0.0:* LISTEN 2832/sshd: root@pts tcp 0 0 0.0.0.0:sunrpc 0.0.0.0:* LISTEN 1/systemd tcp 0 0 node2:domain 0.0.0.0:* LISTEN 2085/dnsmasq tcp6 0 0 [::]:ssh [::]:* LISTEN 1159/sshd tcp6 0 0 localhost:ipp [::]:* LISTEN 1161/cupsd tcp6 0 0 localhos:x11-ssh-offset [::]:* LISTEN 2832/sshd: root@pts tcp6 0 0 [::]:mysql [::]:* LISTEN 34191/mysqld tcp6 0 0 [::]:sunrpc [::]:* LISTEN 1/systemd udp 0 0 0.0.0.0:58227 0.0.0.0:* 995/avahi-daemon: r udp 0 0 node2:domain 0.0.0.0:* 2085/dnsmasq udp 0 0 0.0.0.0:bootps 0.0.0.0:* 2085/dnsmasq udp 0 0 0.0.0.0:sunrpc 0.0.0.0:* 1/systemd udp 0 0 0.0.0.0:mdns 0.0.0.0:* 995/avahi-daemon: r udp 0 0 localhost:323 0.0.0.0:* 999/chronyd udp6 0 0 [::]:48692 [::]:* 995/avahi-daemon: r udp6 0 0 [::]:sunrpc [::]:* 1/systemd udp6 0 0 [::]:mdns [::]:* 995/avahi-daemon: r udp6 0 0 localhost:323 [::]:* 999/chronyd
Database security settings
[root@node2 ~]# mysql_secure_installation NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MariaDB to secure it, we'll need the current password for the root user. If you've just installed MariaDB, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] y New password: Re-enter new password: Password updated successfully! Reloading privilege tables.. ... Success! By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] n ... skipping. By default, MariaDB comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up... All done! If you've completed all of the above steps, your MariaDB installation should now be secure. Thanks for using MariaDB! [root@node2 ~]#
Login database test
[root@node2 ~]# mysql -uroot -p1 Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 15 Server version: 10.3.17-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | +--------------------+ 3 rows in set (0.000 sec) MariaDB [(none)]>
3.3 installing PHP
Install PHP
[root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: nginx-filesystem-1:1.14.1-9.module+el8.0.0+4108+af250afe.noarch", "Installed: apr-util-openssl-1.6.1-6.el8.x86_64", "Installed: php-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: php-cli-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: httpd-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64", "Installed: php-common-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: mod_http2-1.11.3-3.module+el8.2.0+4377+dc421495.x86_64", "Installed: apr-1.6.3-9.el8.x86_64", "Installed: httpd-filesystem-2.4.37-21.module+el8.2.0+5008+cca404a3.noarch", "Installed: apr-util-1.6.1-6.el8.x86_64", "Installed: redhat-logos-httpd-81.1-1.el8.noarch", "Installed: apr-util-bdb-1.6.1-6.el8.x86_64", "Installed: php-fpm-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: httpd-tools-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64" ] }
Install common PHP modules
[root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-gd state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-gd-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-ldap state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-ldap-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-odbc state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-pdo-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: php-odbc-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: unixODBC-2.3.7-1.el8.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-pear state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-process-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: php-xml-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: php-pear-1:1.10.5-9.module+el8.1.0+3202+af5476b9.noarch" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-xml state=present' 192.168.25.142 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "msg": "Nothing to do", "rc": 0, "results": [] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-xmlrpc state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-xmlrpc-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-mbstring state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-mbstring-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-snmp state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: net-snmp-1:5.8-14.el8.x86_64", "Installed: net-snmp-agent-libs-1:5.8-14.el8.x86_64", "Installed: lm_sensors-libs-3.4.0-21.20180522git70f7e08.el8.x86_64", "Installed: php-snmp-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64", "Installed: mariadb-connector-c-3.0.7-1.el8.x86_64", "Installed: mariadb-connector-c-config-3.0.7-1.el8.noarch" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-soap state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-soap-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=php-bcmath state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: php-bcmath-7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64" ] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=curl state=present' 192.168.25.142 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "msg": "Nothing to do", "rc": 0, "results": [] } [root@localhost ansible]# ansible 192.168.25.142 -m yum -a 'name=curl-devel state=present' 192.168.25.142 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: libcurl-devel-7.61.1-12.el8.x86_64" ] } [root@node3 etc]# cd [root@node3 ~]# mkdir -p /var/www/html [root@node3 ~]# cd /var/www/html [root@node3 html]# vim info.php [root@node3 html]# cat info.php <?php phpinfo(); ?>