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