python -- automatic operation and maintenance tool ansible (Daquan)

Posted by smilepak on Tue, 08 Feb 2022 21:10:47 +0100

1, Know ansible

  • ansible is a powerful configuration management tool designed to help system administrators efficiently manage hundreds of hosts
  • Ansible HD hoc mode: one naming is executed at a time, and batch execution is performed on the remote host
  • ansible playbook mode: execute multiple commands at one time, and different hosts execute different commands, which is more flexible.

2, Installation and use of ansible

1. Install ansible

Method 1:
pip install ansible

Method 2:
yum -y install ansible

Method 3:
git clone git://github.com/ansible/ansible.git
cd ./ansible
source ./hacking/env-setup

2. ansible configuration

The ansible configuration file has multiple locations: look in the following order
1. Environment variable ansible_ Position pointed by config
2. Ansible. In the current directory cfg
3. Configuration file ~ /. In HOME directory ansible.cfg
4,/etc/ansible/ansible.cfg

Common configuration parameters of ansible are as follows:
● inventory=~/ansible_hosts: indicates the location of the inventory file of the host list
● forks = 5: number of concurrent connections. The default value is 5
● sudo_user = root: sets the default user who executes the command
● remote_port = 22: Specifies the connection port of the managed node. The default is 22,. It is recommended to repair it to make it safer
● host_ key_ Check whether the security key of the host is set to True/False, ssh = false. After closing, the first connection will not prompt to configure the instance
● timeout = 60: sets the timeout of SSH connection, in seconds
● log_path = /var/log/ansible.log: specifies a file that stores ansible logs (no logs are recorded by default)

3. inventory file

  • ansible can operate multiple hosts at the same time, which is realized through the inventory file configuration. The relationship between groups and hosts is also defined through the inventory file.
  • The default inventory file location is / etc/ansible/hosts

3.1. Group hosts
The string in [] represents the group name, which is convenient for grouping management of hosts

[group01]
192.168.0.11
192.168.1.20
foo.example.com
bar.example.com

3.2. Assign variables to the host
Assign variables to different hosts, which will be used later in using palybook
Format: host address variable name = variable value (multiple variables are separated by spaces)

[group02]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=999

3.3. Define group variables
Group variables can define variables that belong to the entire group

[group03:vars]
ntp_server=ntp.example.com
proxy=proxy.example.com

3.4. Make a group a sub member of another group
You can define a group as a child member of another group and assign variables to the whole group. These variables can be used by / usr/bin/ansible playbook, but not / usr/bin/ansible

[root@localhost ~]# vim /etc/ansible/hosts
[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
some_server= foo.southeast.example.com
halon_system_timeout = 30
self_destruct_countdown = 60
escape_pods = 2

[usa:children]
southeast
northeast
southwest
northwest

3.5. Select the connection type and connection user name for each host

[targets]
localhost                ansible_connection=local
other.example.com        other.example.com=ssh      ansible_ssh_user=test
other2.example.com        other2.example.com=ssh      ansible_ssh_user=test2

3.6. Set inventory parameters
By setting the inventory parameter, you can control the interaction mode between Ansible and the remote host

ansible_ssh_host   # If the remote host name to be connected is different from the alias of the host you want to set, it can be controlled through this variable

ansible_ssh_port   # ssh port number. If it is not the default port number, it can be set through this variable

ansible_ssh_user   # Default ssh user name

ansible_pass       # ssh password (this method is not recommended and is very unsafe. It is recommended to use a secret key)

ansible_sudo_pass  # Sudo password (it is recommended to use -- ask sudo pass)

ansible_sudo_exe   # Command path of sudo

ansible_connection # The type of connection to the host. For example: local, ssh or parmaiko

ansible_ssh_private_key_file  # The private key file used by ssh is applicable to the case where there are multiple keys and you don't want to use ssh proxy

ansible_shell_type            # The shell type of the target system. By default, "sh" is used. It can also be set to "csh" or "fish"

ansible_python_interpreter    # Path and usage of target host Python: there are multiple Python in the system, or the path is not / usr/bin/python, etc

# -------------------------The following is an example of a host file-----------------------
some_host  absible_ssh_port=2222   ansible_ssh_user=test1
one_host  absible_ssh_port=2222   ansible_ssh_user=test2

3, Upload secret key

Before uploading the secret key

  • The returned information is false, and the ping test is unsuccessful
[root@localhost ~]# ansible master -m  ping
192.168.10.10 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", 
    "unreachable": true
}

You can add – ask pass to enter the password manually

  • ping succeeded at this time, but it was troublesome
[root@localhost ~]# ansible master -m "ping" --ask-pass
SSH password:                        # Input password
192.168.10.10 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

Upload secret key

# Generate secret key
[root@localhost ~]# ssh-keygen -t rsa
......Omitted part
+---[RSA 2048]----+
| ++=Eo           |
|oo..=            |
|  o.. . .        |
|   o * = .       |
|  = + * S        |
| . * .           |
|. +.*..  .       |
| =*=+= o. o      |
| .=@=o=..o       |
+----[SHA256]-----+

# View public key file
[root@localhost ~]# ls -ltr /root/.ssh/       
Total consumption 12
-rw-r--r--. 1 root root  396 5 September 23-19:23 id_rsa.pub
-rw-------. 1 root root 1679 5 September 23-19:23 id_rsa
-rw-r--r--. 1 root root  175 5 September 23-19:24 known_hosts

# Upload public key
[root@localhost ~]# ansible all -m authorized_key -a "user=root key='{{lookup('file', '/root/.ssh/id_rsa.pub')}}' path=/root/.ssh/id_rsa.pub manage_dir=yes" --ask-pass
SSH password: 
192.168.10.10 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "comment": null, 
    "exclusive": false, 
    "follow": false, 
    "gid": 0, 
    "group": "root", 
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmZ3VmXIZRL2W2INKz8iZV/DBLcfyoPhciAQKJJKLNdpKDcHwsT33WgDioVunk1qgwPVi79PZZtl/4sSmo1ZJt1sQ4W37Y9a8ad4jMuQW2JhD/TWfYFKsQgisgSE9YgdTkEZv7T5/Fuqpa0RgblLnqZ0pv3Kb/OweHZIWsieVGZ9pom+MQ3f06mngPRpQIxCDiUHdoAvCRCvk3TXMbggOhg2R8BpZLmPzbu8rR9UOEezT03+nS3gQGuhtJvz3iOBEqLgN80FtsLBm812Vbxjj97ZCu+Dc8kMhtwaOs/GZtH3IMACmAd5chj4ZJomV1EY22eWPslRuceIGOv9QovALT root@localhost", 
    "key_options": null, 
    "keyfile": "/root/.ssh/id_rsa.pub", 
    "manage_dir": true, 
    "mode": "0600", 
    "owner": "root", 
    "path": "/root/.ssh/id_rsa.pub", 
    "size": 396, 
    "state": "file", 
    "uid": 0, 
    "user": "root", 
    "validate_certs": true
}


# Test whether it has achieved confidentiality free
[root@localhost ~]# ansible all -m ping
192.168.10.10 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

4, ansible ad-hoc mode

1. View the list of grouped hosts

[root@localhost ~]# ansible Group name --list-hosts  ##View the list of hosts in the group
[root@localhost ~]# ansible work --list-host
  hosts (40):
    192.168.2.115
    192.168.2.116
    192.168.2.202
    192.168.2.204
    192.168.2.207
......

2. Generate secret key proxy

[root@localhost ~]# ssh-keygen -t rsa                                          ##Generate secret key
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):                  ##Direct enter
Enter passphrase (empty for no passphrase):                                ##Enter password 123123
Enter same passphrase again:                                                         ##Enter the password again
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.

[root@localhost ~]# ssh-copy-id root@192.168.10.30

[root@localhost ~]# ssh-copy-id  root@192.168.10.170 //Configure key pair authentication
------------Interactive agent free--------------(Setting up a proxy allows the host to stop entering passwords)
ssh-agent bash                ## Enable agent function
ssh-add                       ## Add secret key to agent

3. ansible command template

ansible-doc -l                      # List all installed modules note: press q to exit
ansible-doc -s yum                  #-s lists the description information and operation actions of yum module
## -m: Specify the module- a: Specify parameters (for example, - m command: specify the command module; - a date: the command module parameter is date, which is equivalent to executing the date command on the other side)
------------------ ansible appoint ip Execute command ----------------
Method 1:
[root@localhost ~]# ansible all -i "IP address," - m shell -a "free -m"

Method 2:
[root@localhost ~]# ansible ip address - m command -a 'date'

----------------- ansible Specify group batch execution command -----------
[root@localhost ~]# ansible group name - m command -a 'date'

3.1. Command module (execute command, which is the default module)

Command format: ansible [host] [- m module] [- a args]

ansible mysql -m command -a 'date'
ansible all -m command -a 'date'                                        //All hosts execute the date command
ansible all -a 'ls /'                      ##If the - m module is not added, the command module will be run by default. All: indicates all categories

## Error message:"changed": false, ##########################################################
[root@localhost ~]# ansible all -a 'ls /'
192.168.10.30 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", 
    "unreachable": true
}
192.168.10.170 | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", 
    "unreachable": true
}
    Error reporting reason: ssh Secret key error
                   ssh-keygen -t rsa                                          ##Generate secret key
	   ssh-copy-id root@192.168.10.30
	   ssh-copy-id root@192.168.10.170                                    //Configure key pair authentication
	   ssh-agent bash           ##Enable agent function
	   ssh-add                       ##Add secret key to agent
########################################################################

3.2 cron module (setting scheduled tasks)

Two states( state): present Indicates addition (can be omitted), absent Indicates removal
[root@localhost ~]# ansible-doc -s cron            # View cron module information and help documents

[root@localhost ~]# ansible webserver -m cron -a 'minute="*/1" job="/usr/bin/echo heihei" name="test cron job"'
# Option explanation:
# -m: Specify the module;
# -a: Specify parameters; minute="*/1": indicates that the planned task is executed every minute;
# job="/bin/echo heihei": indicates the action of executing echo;
# Finally, name indicates the name of the defined scheduled task (custom)

[root@localhost ~]# ansible webserver -a 'crontab -l'     # View scheduled tasks set
192.168.10.30 | CHANGED | rc=0 >>
#Ansible: test cron job
*/1 * * * * /usr/bin/echo heihei

[root@localhost ~]# crontab -l                            # Go to 192.168.10.30 (i.e. webserver) to view the scheduled tasks
#Ansible: test cron job
*/1 * * * * /usr/bin/echo heihei                          # You can view the scheduled tasks
You have new mail in /var/spool/mail/root                 # The execution results are generated in the / var/spool/mail/root file


[root@localhost ~]# ansible webserver -m cron -a 'name="test cron job" state=absent' / / specify the name of the scheduled task and remove the scheduled task with the state=absent parameter

[root@localhost ~]# ansible webserver -a 'crontab -l'     # Check again and the scheduled task disappears
192.168.10.30 | CHANGED | rc=0 >>

3.3 user module (user operation)

# The user module requests three instructions: useradd,userdel and usermod
[root@localhost ~]# ansible-doc -s user                            # View user module parameter description
[root@localhost ~]# ansible mysql -m user -a 'name="test01"'       # Create user test01

[root@localhost ~]# id test01                                      # Go to 192.168.10.170 (i.e. mysql) to check whether the user has established
uid=1001(test01) gid=1001(test01) group=1001(test01)

[root@localhost ~]# ansible mysql -m command -a 'tail -1 /etc/passwd'  # You can also view the new user test01
192.168.10.170 | CHANGED | rc=0 >>
test01:x:1001:1001::/home/test01:/bin/bash

[root@localhost ~]# ansible mysql -m user -a 'name="test01" state=absent'        # Delete user test01. The state=absent parameter is used to delete

3.4. Group module (user group operation)

# The group module requests three instructions: groupadd,groupdel and groupmod.

[root@localhost ~]# ansible-doc -s group    # View group module parameter description

[root@localhost ~]# ansible mysql -m group -a 'name=mysql gid=306 system=yes'     # Create a user group mysql, specify uid, and system=yes to create a system group

[root@localhost ~]# ansible mysql -a 'tail -1 /etc/group'      # View new user groups
192.168.10.170 | CHANGED | rc=0 >>
mysql:x:306:

[root@localhost ~]# ansible mysql -m user -a 'name=test01 uid=306 system=yes group=mysql'    # Create test01 user, specify uid and ground group name, and add to mysql group

[root@localhost ~]# ansible mysql -a 'tail -1 /etc/passwd'       # Check that there are more test01 user Members in the mysql group
192.168.10.170 | CHANGED | rc=0 >>
test01:x:306:306::/home/test01:/bin/bash

[root@localhost ~]# ansible mysql -a 'id test01'      # Check the test01 user and indicate the group
192.168.10.170 | CHANGED | rc=0 >>
uid=306(test01) gid=306(mysql) groups=306(mysql)

3.5 copy module (copy directory or file)

[root@localhost ~]# ansible-doc -s copy                # View the parameter description of copy module

[root@localhost ~]# ansible mysql -m copy -a 'src=/etc/fstab dest=/opt/fstab.back owner=root mode=640'
# Parameter interpretation:
# src: source file (file to be copied);
# dest: target file;
# owner: primary attribute;
# mode: file permission attribute

[root@localhost ~]# ansible mysql -a 'ls -l /opt'       # View the files in the past of copy. They belong to the primary root and have permissions of 640
192.168.10.170 | CHANGED | rc=0 >>
total 4
-rw-r-----. 1 root root 465 Nov 29 22:34 fstab.back

[root@localhost ~]# ansible mysql -a ' cat /opt/fstab.back'                 # View content

[root@localhost ~]# ansible mysql -m copy -a 'content="hello heihei !" dest=/opt/fstab.back'      # Put hello heihei! Write / opt / fstab back

[root@localhost ~]# ansible mysql -a 'cat /opt/fstab.back'      # View what was written
192.168.10.170 | CHANGED | rc=0 >>
hello heihei !

3.6. File module (modify file attributes)

1. Modify the file attribute, ansible all -m file -a "path=/root/test.sh owner=test group=test mode=0644"
2. Generate link file: ansible all -m file -a "src=/root/test.sh dest=/root/testlink.sh owner=root group=root state=link"
3. Create an empty file: ansible all -m file -a "path=/root/testtouch.sh state=touch mode=0644"
4. Create an empty directory: ansible all -m file -a "path=/root/testdirectory state=directory mode=0644"
5. Delete directories or files and enforce: ansible all -m file -a "path=/root/testdirectory state=absent force=yes"

[root@localhost ~]# ansible-doc -s file          # View the parameter description of file module

[root@localhost ~]# ansible mysql -m user -a ' name=mysql system=yes'

[root@localhost ~]# ansible mysql -m group -a ' name=mysql system=yes'

[root@localhost ~]# ansible mysql -m file -a 'owner=mysql group=mysql mode=644 path=/opt/fstab.back'   # Modify file owner, group and permission

[root@localhost ~]# ansible mysql -m file -a ' src=/opt/fstab.back path=/opt/fstab.link state=link'    # To the original file / opt / fstab Back establishes a soft connection using the state=link parameter

[root@localhost ~]# ansible mysql -m file -a "path=/opt/fstab.back state=absent"                 # Delete a file or directory

[root@localhost ~]# ansible mysql -m file -a "path=/opt/test state=touch"                 # Create an empty file

[root@localhost ltp]# ansible 192.168.2.100 -m file -a "name=/abc state=directory"             # Create a directory

3.7 ping module (test whether the managed host is online)

[root@localhost ~]# ansible all -m ping      ## ping all categories
192.168.10.30 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"                                      ## "pong" means it can ping
}
192.168.10.170 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

3.8. yum module

[root@localhost ~]# ansible-doc -s yum   # View module help documentation
[root@localhost ~]# Ansible webserver - M Yum - a 'name = "httpd"' / / Yum install httpd service
   
[root@localhost ~]# rpm -q httpd      ##Check on 192.168.10.20. The installation is successful
httpd-2.4.6-97.el7.centos.x86_64
 
[root@localhost ~]# ansible webserver -m yum -a 'name=httpd state=absent' / / uninstall httpd

[root@localhost ~]# rpm -q httpd       ##Check on 192.168.10.20 again and it has been uninstalled
package httpd is not installed

3.9. Service module (used to start the service)

[root@localhost ~]# ansible-doc -s service

[root@localhost ~]# ansible webserver -m yum -a 'name="httpd"' 

[root@localhost ~]# ansible webserver -a 'systemctl status httpd' / / view the running status of the web server httpd
192.168.10.30 | FAILED | rc=3 >>
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:httpd(8)
           man:apachectl(8)non-zero return code

[root@localhost ~]# ansible webserver -m service -a 'enabled=true name=httpd state=started' / / start the httpd service and start it automatically

[root@localhost ~]# ansible webserver -a 'systemctl status httpd' / / check whether it is enabled. It is successfully enabled 
192.168.10.30 | 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 2020-11-29 23:30:11 CST; 8s ago
     Docs: man:httpd(8)
           man:apachectl(8)

3.10 shell module (execute shell command)

[root@localhost ~]# ansible-doc -s shell

[root@localhost ~]# ansible webserver -m user -a 'name=jack'      ##Create a user

[root@localhost ~]# ansible webserver -m shell -a 'echo abc123 | passwd --stdin jack'      ##Use no interaction mode to set the password for the user
192.168.10.30 | CHANGED | rc=0 >>
Changing password for user jack.
passwd: all authentication tokens updated successfully.     ##Password free setting succeeded

3.11 script module (write the script locally and execute it on the control host using ansible)

ansible-doc -s script

[root@localhost ~]# vim /opt/test.sh       ##Write a script
#!/bin/bash
echo "hello ansible from script"> /opt/script.txt

[root@localhost ~]# chmod +x test.sh     ##Give execution permission

[root@localhost ~]# ansible mysql -m script -a '/opt/test.sh'       ##Specify the script module and script location to execute the script

[root@localhost ~]# cat /opt/script.txt            ##Go to 192.168.10.170 to check whether the script is executed successfully
hello ansible from script

3.12. setup module (obtain host information)

ansible-doc -s setup

ansible mysql -m setup               //Get facts information of mysql group host (including ip information, version information, etc.)

5, Ansible playbooks mode

  • The ansible playbook script allows more flexible configuration and deployment of different hosts

1. Check the help document of ansible playbook

[root@localhost ~]# ansible-playbook -h

usage: ansible-playbook [-h] [--version] [-v] [-k]
                        [--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
                        [-c CONNECTION] [-T TIMEOUT]
                        [--ssh-common-args SSH_COMMON_ARGS]
                        [--sftp-extra-args SFTP_EXTRA_ARGS]
                        [--scp-extra-args SCP_EXTRA_ARGS]
                        [--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
                        [--flush-cache] [-b] [--become-method BECOME_METHOD]
                        [--become-user BECOME_USER] [-K] [-t TAGS]
                        [--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
                        [-i INVENTORY] [--list-hosts] [-l SUBSET]
                        [-e EXTRA_VARS] [--vault-id VAULT_IDS]
                        [--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
                        [-f FORKS] [-M MODULE_PATH] [--list-tasks]
                        [--list-tags] [--step] [--start-at-task START_AT_TASK]
                        playbook [playbook ...]

......

2. Explain the yaml of playbook

  • playbook is written according to yaml syntax format file
  • For ansible, each yaml file starts with a list, and each item in the list is a key value pair, which is often referred to as a "hash" or "dictionary".
  • The starting line of all yaml files should be "-", which is part of yaml format and indicates the beginning of a file.
  • All members in the list start at the same indentation level and start with a "-" (a horizontal bar "-" and a space) ")

Data structures supported by YAML:

1.object:A collection of key value pairs, also known as a mapping(mapping)/Hash(hashes)/word
 for example:
name: Example Developer
 key        value

2.array:A set of values arranged in order, also known as a sequence(sequence)/list(list)
for example:
- Apple 
- Orange

3.Pure quantity:A single, indivisible value
 for example: 
number: 12.30
sure: true

yaml example:

---
# A list of delicious fruits
- Apple
- Oranage
- Strawebrry
- Mango

A dictionary is composed of a simple key: value form (Note: this ":" colon must be followed by a space)

---
# Records of an employee
name: Example Developer
job: Developer
skill: Elite

Dictionaries can also be represented in indented form (this format is not often used in ansible)

---
# An employee record
{name: Example Developer, job: Developer, skill: Elite}

You can specify a Boolean value in the following format

---
create_key: yes
need_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: False

Example: integrate the above example into a yaml

---
# An employee record
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
  - Apple
  - Orange
  - Strawberry
  - Mango
# Equivalent to {foods:[Apple, Orange, Strawberry, Mango]}
languages:
  ruby: Elite
  python: Elite
  dotnet: Lame
# Equivalent to {languages:{ruby: Elite, python: Elite, dotnet: Lame}}

3. Try to write playbook yaml

playbooks itself consists of the following parts

  • (1) Tasks: tasks, that is, an operation completed by the calling module. Executing tasks is equivalent to executing transactions. Once one fails, roll back;
  • (2) Variables: Variables
  • (3) Templates: Templates
  • (4) Handlers: processor that triggers the operation to be executed when certain conditions are met;
  • (5) Roles: role.

Example 1:

[root@localhost ~]# cat /etc/ansible/hosts |grep -Ev "^$|^#" 
[work]
master
node
[master]
192.168.10.10
[node]
192.168.10.20

[root@localhost ~]# vim MyPlaybook.yaml
- shosts: master
  remote_user: root
  task:
    - name: read sys time
      shell: echo "$(date +'%Y-%m-%d %T')" > time.txt
- hosts: slave
  remote_user: root
  task:
    - name: list file
      shell: ls -ltr > list.txt

Execution result:

[root@localhost ~]# ansible-playbook MyPlaybook.yaml --ask-pass
SSH password: 

PLAY [master] ********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.10]

TASK [read sys time] *************************************************************************************************
changed: [192.168.10.10]

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [list file] *****************************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.10              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.10.20              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# View files generated after execution
[root@localhost ~]# ansible all -m shell -a "ls -ltr |tail -1"
192.168.10.10 | CHANGED | rc=0 >>
-rw-r--r--  1 root root   20 5 September 23-21:14 time.txt
192.168.10.20 | CHANGED | rc=0 >>
-rw-r--r--  1 root root    1051 5 September 23-21:14 list.txt

-f: You can specify the number of concurrent processes
For example: ansible playbook myplaybook Yaml -- ask pass - F 3 # means that it is executed by three concurrent processes

Example 2
Here is an example of a playbook:

# Check the content of the template. In the template, {variable name}} is used to call playbook The variable values in yaml are as follows
[root@localhost temp]# vim httpd-temp.conf
Listen {{http_port}}
MaxClients {{max_clients}}
[root@localhost temp]# vim HttpPlaybook.yaml
- hosts: node                        # The defined host group, that is, the host of the application, cannot be changed. The previous (- hosts:) indicates the group declared in / etc/ansible/hsots
  vars:                              # Define variables   
    http_port: 80
    max_clients: 200 
  user: root                         #  Remote is recommended for remote execution_ User remote user
  tasks:                             # Tasks performed
  - name: ensure apache is at the latest version   # Specifying the task name will display the content (customized) when executing the task, which is helpful to locate the location of the error
    yum: pkg=httpd state=latest                    # yum is the module, pkg specifies whether the detection package, state=latest, is the latest
  - name: write the apache config file
    template: src=httpd-temp.conf dest=/etc/httpd/conf/httpd.conf   # Define profile template
    notify:                          # Call the following customized restart apache (the specific content of restart apache is defined in handlers)
    - restart apache
  - name: ensure apache is running
    service: name=httpd state=started
  handlers:                          # When a certain condition is met, the processor triggers the operation to be executed, which is used in combination with notify and called by notify;
    - name: restart apache
      service: name=httpd state=restarted

Execution result:

[root@localhost temp]# ansible-playbook HttpPlaybook.yaml 

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [ensure apache is at the latest version] ************************************************************************
ok: [192.168.10.20]

TASK [write the apache config file] **********************************************************************************
ok: [192.168.10.20]

TASK [ensure apache is running] **************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@localhost temp]# ansible node -m shell -a "systemctl status httpd"
192.168.10.20 | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Day 2021-05-23 21:30:07 CST; 21s ago
     Docs: man:httpd(8)
           man:apachectl(8)
 Main PID: 7544 (httpd)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
   Memory: 3.3M
   CGroup: /system.slice/httpd.service
           ├─7544 /usr/sbin/httpd -DFOREGROUND
           ├─7545 /usr/sbin/httpd -DFOREGROUND
           ├─7546 /usr/sbin/httpd -DFOREGROUND
           ├─7547 /usr/sbin/httpd -DFOREGROUND
           ├─7548 /usr/sbin/httpd -DFOREGROUND
           └─7549 /usr/sbin/httpd -DFOREGROUND

5 September 23-21:30:07 node01 systemd[1]: Starting The Apache HTTP Server...
5 September 23-21:30:07 node01 httpd[7544]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::20c:29ff:fe47:c5d7. Set the 'ServerName' directive globally to suppress this message
5 September 23-21:30:07 node01 systemd[1]: Started The Apache HTTP Server.

4. Commands related to ansible Playbook

Execute a playbook

Syntax: ansible playbook [yaml file name]
For example: ansible playbook Ping yml
Parameter: - K (- ask pass): used to enter ssh password interactively
-K (- ask come pass): used to interactively enter sudo password (lifting right)
-u: Designated user

Supplementary order:

#Check the syntax of yaml file
ansible-playbook nginx.yaml --syntax-check
#Check tasks
ansible-playbook nginx. yaml --list-task
#Check valid hosts
ansible-playbook nginx. yaml --list-hosts
#Specify the task execution in the playbook and check the effect
ansible-playbook nginx.yaml --start-at-task='Copy Nginx.conf'
#Specifies the number of parallel threads executing playbook
ansible-playbook nginx. Number of threads - yaml

5. Introduction to hosts and users

- hosts: webserver     # Specify the host group, which can be one or more groups.
  remote_user: root    # Specify the user name of the remote host. Note that the user must have execution permission

You can also define remote execution users for each task:

- hosts: mysql
  remote_user: root
  tasks: 
  -name: test connection
    ping:
    remote_user: mysql        # Specifies the user that the remote host uses to execute tasks

When executing Playbook: ansible playbook Ping yml -k

Specify the remote host sudo switch user:

-hosts: mysql
  remote_user: root
  become: yes                      ## Parameters after version 2.6, which used to be sudo, have the same meaning
  become_user: mysql         ## Specify the sudo user as mysql, and then the user executing the task will become mysql

When executing Playbook: ansible playbook Ping yml -K

6. tasks list and action s

1. The main part of Play is the task list. The tasks in the task list are executed one by one on the host specified in hosts

  • In hosts, when running playbook (from top to bottom), if a host fails to execute a task, the whole task will be rolled back and the error in playbook will be corrected
  • The purpose of Task is to execute the module with the specified parameters, and variables can be used in the module parameters

2. Each task must have a name, so that when you run playbook, you can well identify which part of the task belongs to from the output task execution information

3. Define a task. The common format: "module: options" is the form of "module corresponding parameters", for example: yum: name=htttpd

4. Among the built-in modules of ansible, the command module and shel1 module do not need to use the format of key=value

Example:

- hosts: 192.168.10.20
  remote_user: root
  tasks:
  - name: disable selinux
    command: '/sbin/setenforce o'
  - name: make sure apache is running
    service: name=httpd state=started

In playbook, as long as the return value of executing the command is not 0, an error will be reported and tasks will stop
To report an error and not stop executing tasks, modify the following ignore_errors: True

- hosts: webserver
  remote_user: root
  tasks:
  - name: disable selinux
    command: '/sbin/setenforce 0'
    ignore_errors: True                #Ignore the error, force the return to success and continue the execution. The Boolean value of true is case insensitive
  - name: make sure apache is running
    service: name=httpd state=started

Here is another example that you can read

- hosts: webserver
  remote_user: root
  tasks:
  - name: create nginx group
    group: name=nginx system=yes gid=208
  - name: create nginx user
    user: name=nginx uid=208 group=nginx system=yes
- hosts: mysql
  remote_user: root
  tasks:
  - name: copy file to mysql
    copy : src=/etc/inittab dest=/opt/inittab.back

7. Introduction to handlers

  • Handlers are also lists of some tasks, which are no different from general tasks.
  • Notify is performed by the notifier. If it is not notified, the Handlers will not execute. If no matter how many notifiers notify, wait until all task s in play are completed,
  • Only when the action in a task is executed, the notify in the task will take effect and the action in the handler will be notified

Example 1

- hosts: webserver
  remote_user: root
  tasks:
  - name: install httpd package
    yum: name=httpd state=latest
  - name: install configuration file for httpd
    copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
      - restart httpd
  - name: start httpd service
    service: enabled=true name=httpd state=started
  handlers:
  - name: restart httpd
    service: name=httpd state=restarted

Example 2: test whether to continue to execute notify if the task where notify is located fails to execute

[root@localhost temp]# vim testvarPlaybook.yaml 
- hosts: node
  remote_user: root
  vars:                   # Define variables      
  - path: /root/
  - filename: test.txt
  tasks:
  - name: delete file
    file: path=/root/test.txt state=absent
    ignore_errors: True
    notify:
    - modify file
  handlers:
  - name: modify file
    shell: echo "123" >{{path}}{{filename}}

  • If there is no test in the target and its root directory Txt file. The task of "delete file" cannot be executed successfully. It is found that notify will not call handler
# The target and its have no test Txt file
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | FAILED | rc=1 >>
cat: test.txt: There is no such file or directory non-zero return code

# Execute playbook
[root@localhost temp]# ansible-playbook testvarPlaybook.yaml 
PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [delete file] ***************************************************************************************************
ok: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# Check again, there is still no test Txt file
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | FAILED | rc=1 >>
cat: test.txt: There is no such file or directory non-zero return code
  • If there is test in the root directory of the target machine Txt file, and the task of "delete file" can be executed successfully. It is found that the handler called by notify has also been executed, and the test Txt
# First, create test. On the target machine Txt file
[root@localhost temp]# ansible node -m file -a "path=/root/test.txt state=touch"
192.168.10.20 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "dest": "/root/test.txt", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "size": 0, 
    "state": "file", 
    "uid": 0
}
# View file content is empty
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | CHANGED | rc=0 >>

# Execute playbook
[root@localhost temp]# ansible-playbook testvarPlaybook.yaml 
PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [delete file] ***************************************************************************************************
changed: [192.168.10.20]

RUNNING HANDLER [modify file] ****************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# Check test Txt file, and the action of the handler is called and executed
[root@localhost temp]# ansible node -m shell -a "cat test.txt"
192.168.10.20 | CHANGED | rc=0 >>
123

8.playbook import variable

How playbook uses variables:
1. Use vars in the yml file to set variables
2. Declare variables after the host name in the / etc/ansible/hosts file (e.g. variable username=lisi)
3. When executing ansible playbook, assign value to the variable by adding - e variable name = value; Such as ansible playbook test yml -e “service=httpd”

Example 1

- hosts: webserver
  remote_user: root
  vars:
  - package: httpd
  - service: httpd
  tasks:
  - name: install httpd package
    yum: name={{package}} state=latest
  - name: install configuration file for httpd
    copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
      - restart httpd
  - name: start httpd service
    service: enabled=true name={{service}} state=started
  handlers:
  - name: restart httpd
    service: name={{service}} state=restarted

9. Reference the fixed variable of ansible

Examples

[root@localhost temp]# vi test.yml
- hosts: node
  remote_user: root
  tasks:
  - name: copy filel
     # {{ansible_all_ipv4_addresses}} is a fixed variable that references ip
    copy: content="{{ansible_all_ipv4_addresses}}," dest=/opt/iplist.txt

results of enforcement

[root@localhost temp]# ansible-playbook test.yaml 

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [copy filel] ****************************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@localhost temp]# ansible node -m shell -a "cat /opt/iplist.txt"
192.168.10.20 | CHANGED | rc=0 >>
([u'192.168.122.1', u'192.168.10.20'],)

# Check the ip address of the target machine. There are indeed 192.168.122.1 and 192.168.10.20 ip addresses
[root@localhost temp]# ansible node -m shell -a "ip a"
192.168.10.20 | CHANGED | rc=0 >>
......
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:47:c5:d7 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.20/24 brd 192.168.10.255 scope global ens33
......
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000
    link/ether 52:54:00:13:da:e3 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
......

10. Condition test and condition judgment

  • If you need to use the variable facts (setup) or the execution results of previous tasks as the basis for the execution of a task,
    You can add a when clause after the task to use conditional testing: the when clause supports jinjia2 expressions or

10.1 single condition judgment

[root@localhost temp]# vim test.yaml 
- hosts: node
  remote_user: root
  tasks:
  - name: "look os"
    shell: echo {{ansible_distribution}} >os.txt
    when: ansible_distribution == "CentOS"

results of enforcement

[root@localhost temp]# ansible-playbook test.yaml 

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [look os] *******************************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# View OS Txt file
[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
CentOS

10.2. Multi condition judgment

[root@localhost temp]# cat test.yaml 
- hosts: node
  remote_user: root
  tasks:
  - name: "look os"
    shell: echo "{{ansible_distribution}}.{{ansible_distribution_major_version}}" >os.txt
    when:
    - ansible_distribution == "CentOS"
    - ansible_distribution_major_version == "7"

results of enforcement

[root@localhost temp]# ansible-playbook test.yaml 
PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [look os] *******************************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
CentOS.7

10.3 group condition judgment

[root@localhost temp]# cat test.yaml 
- hosts: node
  remote_user: root
  tasks:
  - name: "look os"
    shell: echo "{{ansible_distribution}}.{{ansible_distribution_major_version}}" >os.txt
    when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7") or (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6")

## If the system is centos and version 6, or the system text is centos and version 6, execute the command

results of enforcement

[root@localhost temp]# ansible-playbook test.yaml 

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [look os] *******************************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
CentOS.7

10.4 condition test of user-defined variables

[root@localhost temp]# vi test.yaml 
- hosts: node
  remote_user: root
  vars:
    msg: 'hellow world'
    exist: True
    flag: None
  tasks:
  - name: "existed file"
    shell: rm -rf os.txt
    when:
    - exist == False
  - name: 'look file'
    shell: echo "{{msg}}" >os.txt
    when: flag == "None"

results of enforcement

[root@localhost temp]# ansible-playbook test.yaml 

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [existed file] **************************************************************************************************
skipping: [192.168.10.20]

TASK [look file] *****************************************************************************************************
changed: [192.168.10.20]

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

[root@localhost temp]# ansible node -m shell -a "cat os.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world

11. Iteration

  • When there are tasks that need to be performed repeatedly, the iterative mechanism can be used.
  • Iterators, similar to a for loop, execute sequentially

11.1. Directly call the item iterator

[root@localhost temp]# vim test.yaml 
- hosts: node
  remote_user: root
  vars:
    path: /ltp/
    msg: "hellow world"
  tasks:
  - name: "Save Msg"
    shell: echo {{msg}} > {{path}}{{item}}   # Fixed variable item with the following value_ Items: parameters under, traversal and execution
    with_items:                              # Defines the value of item
    - first.txt
    - second.txt
    - third.txt
    register: shell_result                   # Register is used to store the execution results. It is used in the debugging stage. The following debug is used to return the results
  - debug: var=shell_result.stdout verbosity=0 

results of enforcement

# view file contents
[root@localhost temp]# ansible node -m shell -a "cat /ltp/first.txt"
192.168.10.20 | CHANGED | rc=0 >>
I am the first
[root@localhost temp]# ansible node -m shell -a "cat /ltp/second.txt"
192.168.10.20 | CHANGED | rc=0 >>
I am the second
[root@localhost temp]# ansible node -m shell -a "cat /ltp/third.txt"
192.168.10.20 | CHANGED | rc=0 >>
I am the third

# Execute playbook
[root@localhost temp]# ansible-playbook test.yaml 

PLAY [node] **********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [192.168.10.20]

TASK [Save Msg] ******************************************************************************************************
changed: [192.168.10.20] => (item=first.txt)
changed: [192.168.10.20] => (item=second.txt)
changed: [192.168.10.20] => (item=third.txt)

TASK [debug] *********************************************************************************************************
ok: [192.168.10.20] => {
    "shell_result.stdout": "VARIABLE IS NOT DEFINED!"
}

PLAY RECAP ***********************************************************************************************************
192.168.10.20              : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


# Check the contents of the file again and everything has been changed
[root@localhost temp]# ansible node -m shell -a "cat /ltp/first.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world
[root@localhost temp]# ansible node -m shell -a "cat /ltp/second.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world
[root@localhost temp]# ansible node -m shell -a "cat /ltp/third.txt"
192.168.10.20 | CHANGED | rc=0 >>
hellow world

11.2. Custom iterator

You can also define iterator properties yourself

[root@localhost temp]# vim item.yaml
- hosts: node
  remote_user: root
  tasks:
  - name: "Add users"
    # with_items: the next line is a value of item, item Name refers to the value of the name field, such as test1
    user: name={{item.name}} state=present groups={{item.groups}}  
    with_items:
    - {name: 'test1',groups: 'wheel'}
    - {name: 'test2',groups: 'root'}
#  The primary user group and the subordinate user group are created and executed respectively

12. Tag task s

  • tags module:
    In a playbook, we usually define many tasks. If we only want to perform one or some operations, we can add a tags tag under the tasks operation statement to specify the execution.

Example:

[root@localhost temp]# vim host.yaml
- hosts: webserver
  remote_user: root
  tasks:
  - name: touch file
    file: path=/opt/host01 state=touch
  - name: Copy hosts file
    copy : src=/etc/hosts dest=/opt/hosts
    tags:
    - abc
  - name: touch file
    file: path=/opt/host02 state=touch
  • Execute command:
    ansible-playbook hosts.yml --tags="abc" # add "– tags = tag" to execute only the tagged operation statement
    ansible-playbook hosts.yml # if "– tags = tag" is not added, all task s will be executed
  • In fact, it is not only possible to specify the same tasks for a single or multiple tasks. playbook also provides a special tags tag (always). For tasks labeled with always, it will execute whether the tag is specified or not.

Examples

[root@localhost temp]# wim host.yaml
- hosts: mysql
  remote_user: root
  tasks:
  - name: Copy hosts file
    copy: src=/etc/hosts dest=/opt/hosts
    tags:
    - only
  - name: touch file
    file: path=/opt/host1 state=touch
    tags:
    - always

Execute command
ansible-playbook host.yaml --tags="only" # specifies to execute the command with only tag, and it is found that the command with always tag will also be executed

Topics: Python