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