Ansible execution process

Posted by jjk-duffy on Mon, 07 Feb 2022 21:23:41 +0100

Ansible introduction

(1) Ansible does not need to install the client and communicates through sshd (login without key).
(2) Ansible works based on modules, which can be developed in any language.
(3) Ansible can support the use of command line modules and writing
(4) Ansible installation is very simple, and the shadow mask can be installed directly on CentOS.
(5) Ansible provides UI (browser graphical), which is a very popular open source software.


Ansible installation

(1) Environmental preparation
Turn off the firewall and SELinux on both machines and modify the / etc/hosts file.

[root@ansible-01 ~]# systemctl stop firewalld
[root@ansible-01 ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
Removed symlink /etc/systemd/system/basic.target.wants/firewalld.service.
[root@ansible-01 ~]# setenforce 0
[root@ansible-01 ~]# vi /etc/selinux/config 
...
#     disabled - No SELinux policy is loaded.
SELINUX=disabled	//Change this to disabled
# SELINUXTYPE= can take one of three two values:
...

[root@ansible-01 ~]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.200.13 ansible-01    //Add IP and hostname of two hosts
192.168.200.23 ansible-02
~
"/etc/hosts" 4L, 210C written

(2) Install Ansible

Prepare two machines anisble-01 and anisble-02. Only install Ansible on anisble-01 and install epel warehouse first.

[root@ansible-01 ~]# yum install  epel-release -y

[root@ansible-01 ~]# yum install -y ansible

[root@ansible-01 ~]# ansible --version / / view the ansible version number
ansible 2.9.21
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Nov 20 2015, 02:00:19) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)]

(3) ssh key free login configuration (only used at the control end)

Generate the key pair SSH keygen - t RSA on anisble-01, put the public key on anisble-02, and set the key authentication. Use the - t option to specify the type of key to generate

[root@ansible-01 ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.
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:
55:fc:87:9b:2a:a5:73:70:f4:4b:b8:72:34:f7:0f:0a root@ansible-01
The key's randomart image is:
+--[ RSA 2048]----+
|           ..    |
|           ..    |
|          .  . . |
|         .  . o .|
|        S  . o + |
|          . * *  |
|          E* *.o |
|          =.=....|
|           *.   o|
+-----------------+
[root@ansible-01 ~]# SSH copy ID 192.168.200.23 / / copy the public key to the remote machine
The authenticity of host '192.168.200.23 (192.168.200.23)' can't be established.
ECDSA key fingerprint is e8:43:c1:8e:c1:07:7c:4a:99:a5:34:e3:ab:ed:78:15.
Are you sure you want to continue connecting (yes/no)? 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.200.23's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '192.168.200.23'"
and check to make sure that only the key(s) you wanted were added.

[root@ansible-01 ~]# ssh 192.168.200.23
Last login: Tue May 25 01:35:36 2021 from 192.168.200.1

[root@ansible-02 ~]# logout 
Connection to 192.168.200.23 closed.

(4) Host group settings

Add the IP addresses of this machine and another machine in the / etc/ansible/hosts file:

[root@ansible-01 ~]# vi /etc/ansible/hosts

[root@ansible-01 ~]# grep ^[^#] /etc/ansible/hosts
[testhost]
127.0.0.1
192.168.200.23

Note: testhost is the name of the user-defined host group. The following two IPS are the machine IPS in the group, but 127.0.0.1 is not set as password free

[root@ansible-01 ~]# ssh-copy-id 127.0.0.1
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is e8:43:c1:8e:c1:07:7c:4a:99:a5:34:e3:ab:ed:78:15.
Are you sure you want to continue connecting (yes/no)? 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@127.0.0.1's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '127.0.0.1'"
and check to make sure that only the key(s) you wanted were added.

Ansible remote execution command

Batch execute commands: (testhost is the host group name, - m followed by the module name, - a followed by the command, or you can execute commands directly for a machine)

[root@ansible-01 ~]# ansible 127.0.0.1 -m command -a "hostname"
127.0.0.1 | CHANGED | rc=0 >>
ansible-01
[root@ansible-01 ~]# ansible 192.168.200.23 -m command -a "hostname"
192.168.200.23 | CHANGED | rc=0 >>
ansible-02
[root@ansible-01 ~]# ansible testhost -m command -a "hostname"
127.0.0.1 | CHANGED | rc=0 >>
ansible-01
192.168.200.23 | CHANGED | rc=0 >>
ansible-02

One module is also implemented by the shell

[root@ansible-01 ~]# ansible testhost -m shell -a "w"
127.0.0.1 | CHANGED | rc=0 >>
 04:26:12 up  3:26,  3 users,  load average: 0.00, 0.02, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty1                      01:00    3:11m  0.71s  0.71s -bash
root     pts/1    192.168.200.1    03:32    4.00s  1.68s  0.00s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/21f0e6a9ae -tt 127.0.0.1 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1621887971.06-10684-197908214016938/AnsiballZ_command.py && sleep 0'
root     pts/3    localhost        04:26    1.00s  0.29s  0.08s w
192.168.200.23 | CHANGED | rc=0 >>
 04:26:03 up  3:22,  3 users,  load average: 0.08, 0.03, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty1                      01:04    3:05m  0.49s  0.49s -bash
root     pts/0    ansible-01       04:26    1.00s  0.31s  0.09s w
root     pts/1    192.168.200.1    03:31   54:07   0.00s  0.00s -bash

Ansible copy files or directories

Note:

The copy module is used to add the host name, src is the source address, DeST is the destination address, owner is the user and group is the group, mode is permission (the source directory will be placed under the target directory. If the directory specified by the target does not exist, it will be created automatically. If the file is copied, the name specified by DeST is different from the source, and it is not an existing directory, which is equivalent to renaming it after copying. On the contrary, if dest is an existing directory on the target machine, the file will be copied directly to the directory.) (below directory)

If the specified directory of the target exists (if the directory / tmp/123 already exists on the target machine, the contents of the test.txt file will be created under the directory / tmp/123)

[root@ansible-01 ~]# vi test.txt 
[root@ansible-01 ~]# cat test.txt 
aaabbb
[root@ansible-01 ~]# ansible 192.168.200.23 -m copy -a "src=test.txt dest=/tmp/123"
192.168.200.23 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "checksum": "ecfbc47dc36487bbf3bd5212745d2a9f9deefb0d", 
    "dest": "/tmp/123", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/tmp/123", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 7, 
    "state": "file", 
    "uid": 0
}
[root@ansible-02 ~]# ls /tmp/
123
[root@ansible-02 ~]# cat /tmp/123
aaabbb

The directory specified by the destination does not exist (it will be created automatically)

[root@ansible-01 ~]# mkdir test1
[root@ansible-01 ~]# ls
anaconda-ks.cfg  test1  test.txt
[root@ansible-01 ~]# mv test.txt test1
[root@ansible-01 ~]# ls
anaconda-ks.cfg  test1
[root@ansible-01 ~]# cd test1/
[root@ansible-01 test1]# ll
total 4
-rw-r--r--. 1 root root 10 May 28 19:47 test.txt

[root@ansible-01 ~]# ansible 192.168.200.23 -m copy -a "src=test1 dest=/tmp/test1"
192.168.200.23 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "ecfbc47dc36487bbf3bd5212745d2a9f9deefb0d", 
    "dest": "/tmp/test1/test1/test.txt", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "8b51426ccbcbda446d4321fce54cc940", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 7, 
    "src": "/root/.ansible/tmp/ansible-tmp-1621890125.71-10864-147793543610172/source", 
    "state": "file", 
    "uid": 0
}
[root@ansible-02 tmp]# ll
total 4
-rw-r--r--. 1 root root 10 May 28 19:58 123
drwxr-xr-x. 3 root root 18 May 28 20:20 test1
[root@ansible-02 tmp]# cd test1 / / automatically created test1
[root@ansible-02 test1]# ll
total 0
drwxr-xr-x. 2 root root 21 May 28 20:20 test1   //test1 of source address file
[root@ansible-02 test1]# cd test1/
[root@ansible-02 test1]# ll
total 4
-rw-r--r--. 1 root root 10 May 28 20:20 test.txt

If you copy a file (the name specified by dest is different from the source, and it is not an existing directory, it is equivalent to copying it and renaming it):

[root@ansible-01 ~]# touch test1.txt
[root@ansible-01 ~]# ansible 192.168.200.23 -m copy -a "src=test1.txt dest=/tmp/test2.txt"
192.168.200.23 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", 
    "dest": "/tmp/test2.txt", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 0, 
    "src": "/root/.ansible/tmp/ansible-tmp-1621890611.66-10898-233886045095341/source", 
    "state": "file", 
    "uid": 0
}

[root@ansible-02 tmp]# ll
total 4
-rw-r--r--. 1 root root  7 May 25 04:53 123
drwxr-xr-x. 3 root root 18 May 25 05:01 test1
-rw-r--r--. 1 root root  0 May 25 05:10 test2.txt

desc is a directory that already exists on the target machine, and the file will be copied directly to the directory

[root@ansible-01 ~]# ansible 192.168.200.23 -m copy -a "src=test1.txt dest=/tmp/test1.txt"
192.168.200.23 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", 
    "dest": "/tmp/test1.txt/test1.txt", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 0, 
    "src": "/root/.ansible/tmp/ansible-tmp-1621891559.15-10931-150950126324872/source", 
    "state": "file", 
    "uid": 0
}

[root@ansible-02 tmp]# mkdir test1.txt
[root@ansible-02 tmp]# ls
123  test1  test1.txt  test2.txt
[root@ansible-02 tmp]# cd test1
test1/     test1.txt/ 
[root@ansible-02 tmp]# cd test1.txt/
[root@ansible-02 test1.txt]# ll
total 0
-rw-r--r--. 1 root root 0 May 25 05:25 test1.txt

/tmp/123 is the same as / etc/passwd on the source machine, but if the target machine already has / tmp/123 directory, a passwd file will be created under / tmp/123 directory, and the contents in the previous 123 have been replaced.

[root@ansible-01 ~]# ansible testhost -m copy -a "src=/etc/passwd dest=/tmp/123 "
127.0.0.1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "8f3ebea24b1558e6207af80195aa12931d96345f", 
    "dest": "/tmp/123", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "ca8f3327c9a73cb6fd96ba88ec4d18ee", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 1040, 
    "src": "/root/.ansible/tmp/ansible-tmp-1621892103.0-10968-210043315330026/source", 
    "state": "file", 
    "uid": 0
}
192.168.200.23 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "8f3ebea24b1558e6207af80195aa12931d96345f", 
    "dest": "/tmp/123", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "ca8f3327c9a73cb6fd96ba88ec4d18ee", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 1040, 
    "src": "/root/.ansible/tmp/ansible-tmp-1621892103.03-10970-31205733278544/source", 
    "state": "file", 
    "uid": 0
}

[root@ansible-02 tmp]# ls
123  test1  test1.txt  test2.txt
[root@ansible-02 tmp]# cat 123
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

Ansible remote execution script

Create a shell script

[root@ansible-01 ~]# vim /tmp/test.sh
#!/bin/bash
echo `date` > /tmp/ansible_test.txt

Scripts are distributed to each machine

[root@ansible-01 ~]# ansible testhost -m copy 
-a "src=/tmp/test.sh dest=/tmp/test.sh mode=0755"

Execute the shell script in batch

[root@ansible-01 ~]# ansible testhost -m shell -a "/tmp/test.sh" 
127.0.0.1 | CHANGED | rc=0 >>

192.168.200.23 | CHANGED | rc=0 >>

shell module, which also supports remote command execution with pipeline

[root@ansible-01 ~]# ansible testhost -m shell -a "cat /etc/passwd |wc -l "
127.0.0.1 | CHANGED | rc=0 >>
21
192.168.200.23 | CHANGED | rc=0 >>

Finally, check whether it runs successfully

[root@ansible-01 ~]# cat /tmp/ansible_test.txt
Tue May 25 06:06:40 CST 2021

Ansible management task plan

Add scheduled task

testhost: Specifies the remote client
-m cron: Specifies the cron module to use
Name = 'test cron': Specifies the name of the task plan, which can be seen when the client executes crontab -l
job=’/bin/touch /tmp/1212.txt ': specify the task to be executed
weekday=6: specify to execute on Saturday. If not specified, the default is *, and the time-sharing day, month and week are minute, hour, day, month and weekday respectively

[root@ansible-01 ~]# ansible testhost -m cron -a "name='test cron' job='/bin/touch /tmp/1212.txt' weekday=6"
127.0.0.1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "test cron"
    ]
}
192.168.200.23 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "test cron"
    ]
}

verification:

[root@ansible-01 ~]# crontab -e

#Ansible: test cron
* * * * 6 /bin/touch /tmp/1212.txt

[root@ansible-02 ~]# crontab -e

#Ansible: test cron
* * * * 6 /bin/touch /tmp/1212.txt

Delete scheduled task

[root@ansible-01 ~]# ansible testhost -m cron -a "name='test cron' state=absent"
127.0.0.1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": []
}
192.168.200.23 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": []
}

Validation: (empty)
[root@ansible-01 ~]# crontab -e

[root@ansible-02 ~]# crontab -e

Ansible install rpm package / management service

Batch remote installation rpm package

[root@ansible-01 ~]# ansible testhost -m yum -a "name=httpd"



Open service:

[root@ansible-01 ~]# ansible testhost -m service -a "name=httpd state=starte
d enabled=yes"

View service status:

13 ports:

[root@ansible-01 ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2021-05-25 07:10:31 CST; 1min 42s ago
     Docs: man:httpd(8)
           man:apachectl(8)
 Main PID: 12534 (httpd)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─12534 /usr/sbin/httpd -DFOREGROUND
           ├─12535 /usr/sbin/httpd -DFOREGROUND
           ├─12536 /usr/sbin/httpd -DFOREGROUND
           ├─12537 /usr/sbin/httpd -DFOREGROUND
           ├─12538 /usr/sbin/httpd -DFOREGROUND
           └─12539 /usr/sbin/httpd -DFOREGROUND

May 25 07:10:31 ansible-01 systemd[1]: Starting The Apache HTTP Server...
May 25 07:10:31 ansible-01 httpd[12534]: AH00558: httpd: Could not relia...e
May 25 07:10:31 ansible-01 systemd[1]: Started The Apache HTTP Server.
Hint: Some lines were ellipsized, use -l to show in full.

23 port:

[root@ansible-02 ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2021-05-25 07:10:26 CST; 2min 39s ago
     Docs: man:httpd(8)
           man:apachectl(8)
 Main PID: 11645 (httpd)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─11645 /usr/sbin/httpd -DFOREGROUND
           ├─11646 /usr/sbin/httpd -DFOREGROUND
           ├─11647 /usr/sbin/httpd -DFOREGROUND
           ├─11648 /usr/sbin/httpd -DFOREGROUND
           ├─11649 /usr/sbin/httpd -DFOREGROUND
           └─11650 /usr/sbin/httpd -DFOREGROUND

May 25 07:10:26 ansible-02 systemd[1]: Starting The Apache HTTP Server...
May 25 07:10:26 ansible-02 httpd[11645]: AH00558: httpd: Could not relia...e
May 25 07:10:26 ansible-02 systemd[1]: Started The Apache HTTP Server.
Hint: Some lines were ellipsized, use -l to show in full.

[ root@ansible-01 ~]# chkconfig --list (this command cannot be queried, but it needs to be queried with the prompted command)

[root@ansible-01 ~]# systemctl list-unit-filesclear

Use of Ansible documents

List all modules:
[root@ansible-01 ~]# ansible-doc -l
fortios_router_community_list                                 Configure com.
azure_rm_devtestlab_info                                      Get Azure Dev.
ecs_taskdefinition                                            register a ta.
avi_alertscriptconfig                                         Module for se.
tower_receive                                                 Receive asset.
netapp_e_iscsi_target                                         NetApp E-Seri.
azure_rm_acs                                                  Manage an Azu.
fortios_log_syslogd2_filter                                   Filters For the river 
junos_rpc Run arbitration.
na_elementsw_vlan NetApp Element.```


View the documentation for the specified module

[root@ansible-01 ~]# Ansible doc Yum / / view the documentation of the specified module

> YUM    (/usr/lib/python2.7/site-packages/ansible/modules/packaging/os/yum.py)

        Installs, upgrade, downgrades, removes, and lists packages and groups with the `yum'
        package manager. This module only works on Python 2. If you require Python 3 support
        see the [dnf] module.

  * This module is maintained by The Ansible Core Team
  * note: This module has a corresponding action plugin.

OPTIONS (= is mandatory):

- allow_downgrade
        Specify if the named package and version is allowed to downgrade a maybe already
        installed higher version of that package. Note that setting allow_downgrade=True can
        make this module behave in a non-idempotent way. The task could end up with a set of
        packages that does not match the complete list of specified packages to install
        (because dependencies between the downgraded package and others can cause changes to
        the packages which were in the earlier transaction).
        [Default: no]
        type: bool
        version_added: 2.4