Make writing a habit together! This is my first day to participate in the “Gold Digging Day New Plan · April More text challenge”, click to see the details of the activity.

If you have done operation and maintenance or website development, you must have contact with service deployment, then what is the general process of service deployment? Find a Linux machine, install the software needed to run the environment, and deploy the service on it. One machine can do this, but what about clusters? Every single one of them has to do that. If we manage hundreds of machines, and suddenly the company requires a piece of software to be installed on all of them, then it’s not possible to do it manually, and you have to use an automated script to do it.

There are many ways to automate execution, the most primitive of which is shell scripts, but it clearly doesn’t meet our needs. Slatstack and Ansible are two of the most popular automated configuration management tools. Both are developed in Python, but Ansible has a greater advantage because of its large number of modules and plug-ins. You can also find a lot of scripted scripts written by other people on GitHub and Gitee that you can basically just grab and use.

Introduction of Ansible

Although I think you probably know at least a little bit about Ansible by the time you read this article, a brief introduction is worth mentioning. Ansible is an open source configuration management tool that you can use to automate tasks and deploy applications to implement YOUR IT infrastructure. Ansible can be used to automate routine tasks such as server initialization, security baseline configuration, updating and patching systems, and installing software packages.

Ansible installation

  • Centos
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum clean all
yum makecache
yum install -y ansible
Copy the code
  • Ubuntu
apt-get install software-properties-common
apt-add-repository ppa:ansible/ansible
apt-get update
apt-get install ansible
Copy the code
  • PIP install
pip install ansible
Copy the code

PIP is the most convenient method, after all, we usually have Python installed, but there is a problem. After installing Python, we can not find the configuration file, use ansible –version check and find the config file is none, so we can not use it properly. Because ansible loads configuration files in a sequential path.

Ansible. CFG file loading sequence

The ansible. CFG file is used as a configuration file. The ansible file is read from multiple paths in the following sequence:

  • ANSIBLE_CONFIG: Environment variable
  • Ansible. CFG: in the current execution directory
  • . Ansible. CFG: ~ /. Ansible. CFG
  • /etc/ansible/ansible.cfg

Therefore, you are advised to create a project directory and store all configuration files in this directory to facilitate migration. The following information is displayed in ansible. CFG:

[defaults]
inventory = ./hosts
host_key_checking = False
Copy the code

Ansible. CFG will be installed in the Python directory by default and copied to the current directory.

There are three configuration files:

  1. CFG — The default configuration is used for ansible configuration files. You only need to add host_key_checking=False and do not use fingerprint verification. Fingerprint authentication is when we SSH in from one Linux machine to another Linux, and the first connection asks us to type Yes/No
  2. Hosts – List of host files
  3. Roles – a folder where roles are configured, which is empty by default

Configure the Ansible host list

List configuration Chinese document

A host list defines host information to be managed, including IP addresses, users, passwords, and SSH key configurations. You can configure groups and include relationships between groups, so that we can operate hosts by group allocation. The configuration file is stored in /etc/ansible/hosts

Password – based connection

vim /etc/ansible/hosts

[Web] 192.168.133.111 ANSIBLE_ssh_user =root AnSIBLE_ssh_pass =123456 192.168.133.112 ANSIBLE_ssh_user =root Ansible_ssh_pass =123456 192.168.133.123 ANSIBLE_ssh_user =root AnSIBLE_ssh_pass =123456 192.168.133.112 192.168.133.123 [web:vars] anSIBLE_ssh_user =root AnSIBLE_ssh_pass =123456 # create directory group_vars in /etc/ansible directory The yML file named after the group name vim /etc/ansible/group_vars/web.yml # Contains the following contents: anSIBle_ssh_user: root AnSIBle_ssh_pass: 123456Copy the code

The test command

ansible web -a 'ls /'
Copy the code

The connection is based on SSH keys

The following commands are executed on the Ansible host and do not need to be performed on the managed host

Ssh-keygen # copy the public key to the target host ssh-copy-id [email protected] # execute the following statement: If you enter the password, the target host will generate a file /root/.ssh/authorized_keys # and then connect to the target host without the passwordCopy the code

AD – hoc command

Ad-hoc is a temporary command that, like the shell commands we execute, ends as soon as it is executed. The format of the ad-hoc command is as follows:

ansible web -m command -a 'df -h'
Copy the code

Command explanation:

  • Ansible: command
  • Web: host name /IP address/group
  • -m: specifies the module (default is command, so you can drop -m command)
  • Command: indicates the module name
  • -a: indicates module parameters
  • ‘df -h’ : parameter value

The color of the result returned by executing the command represents:

Green: The managed end is not modified

Yellow: The managed end is changed

Red: The execution is faulty

Introduction to Common Modules

We use Ansible mainly because it has a large number of modules and plug-ins. Although there are many modules, there are only a few commonly used modules. Here are some commonly used modules:

Yum command

Example:

Then the Apache ansible Web -m yum -a "name= HTTPD state=latest" # Apache Ansible Web -m yum -a "name= HTTPD State =latest enablerepo=epel" # ansible web -m yum -a "name= HTTPD state=absent"Copy the code

Copy command

Example:

# copy the apache configuration file to the target machine ansible web - m copy - a "SRC = HTTPD. Conf dest = / etc/HTTPD/conf/HTTPD. Conf owner = root group = root Mode =644" And the backup target file copy ansible web - m - a "SRC = HTTPD. Conf dest = / etc/HTTPD/conf/HTTPD. Conf owner = root group = root mode = 644 Ansible web -m copy -a "content=HelloWorld dest=/home/index.html"Copy the code

Get_url command

Ansible web -m get_url -a "url=http://xx.xx.xx/ssss.txt dest=/home/xx.txt mode=655"Copy the code

The file command

Ansible web -m file -a "path=/home/aaa. TXT state=touch" # ansible web -m file -a "path=/home/test Ansible web -m file -a "path=/home owner=nginx group=nginx mode=766 recurse=yes"Copy the code

The git command

The above are some common module explanations and examples, because there are many ansible modules and parameters, we will not explain in detail. But one very, very important point to make here is that all of the above is nonsense. Ansible provides a very detailed explanation for each module. For example, check the usage of cron modules with the following command:

ansible-doc cron

There are not only parameter explanations, but also examples of execution:

If you want to see which modules are available, go to ansible-doc -l > ansible.doc. Of course, the execution examples are shown as ansible-playbook, but we can use ad-doc with a slight modification

Error handling

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: oldboy
Copy the code

This problem is usually caused by not specifying the inventory file in ansible. CFG. Configure the correct inventory path or specify it by adding -i to the ansible command.

playbook

Playbook is a completely different approach to Ansible than ad-hoc, similar to SaltStack’s state files. Ad-hoc doesn’t last. Playbook does. Playbook is a list of one or more plays. The main function of Play is to dress up a group of hosts as a role defined by task in Ansible. Basically, a task is nothing more than a module that calls Ansible. Organizing multiple Plays into one PlayBook allows them to work together to accomplish a task in a choreographed way.

The Playbook is programmed with YML syntax and is very simple to use, requiring only a few basic keywords.

  • Hosts:
  • The tasks:
  • Vars:
  • Templates:
  • Handlers:
  • Tags:

Here’s a simple example:

# httpd.yaml
- hosts: web  
  tasks:    
    - name: install httpd server      
      yum: name=httpd state=present          
    
    - name: configure httpd server      
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf          
     
    - name: configure httpd server      
      copy: src=index.html dest=/var/www/html/index.html          
        
    - name: service httpd server      
      service: name=httpd state=started enabled=yes
Copy the code

This is the process of installing Apache, configuring it, and starting it. Let’s look at the keywords.

  • Hosts: indicates the host, group, and IP address to be executed
  • Tasks: Tasks to be performed
  • Name: indicates the task description
  • Yum /copy/service: execution module

This is the basic Playbook structure, and it’s a basic Playbook structure, as well as more advanced operations, which we’ll show you in more examples below.

Set up the nginx service

-hosts: web vars: hello: Ansible tasks: # configuration software source-name: Configure Yum Repo yum_repository: name: nginx description: Nginx repo baseurl: http://nginx.org/packages/centos/7/$basearch/ gpgcheck: yes enabled: yes # install nginx - name: Install Nginx yum: name=ningx state=present # Install Nginx yum: name=ningx state=present # Configure Nginx copy: SRC: nginx.conf dest: The/etc/nginx/conf/nginx. Conf # modified homepage - name: Change the Home copy: content: "Hello {{Hello}}" dest: /var/ WWW/HTML /index.html # Start nginx - name: Start nginx service: name: nginx state: startedCopy the code

I used two examples for the module above

yum: name=nginx state=present

copy:  
  src: nginx.conf  
  dest: /etc/nginx/conf/nginx.conf
Copy the code

You can do both of these things, just write them differently, so I hope you don’t get misled, but the next thing we’ve introduced in this example is variables

Variables in Ansible

Why use variables?

First of all, why do we use variables? The word variable is often used in programming. We always emphasize that we should not use magic numbers in programming, instead, we should try to use macros or variables instead. On the one hand, the meaning of magic numbers is not clear enough. Using variables in Ansible makes the same sense.

How to define and use variables?

  • Define it using Vars under hosts in the Playbook file
  1. Define variables directly in the PlayBook file
- hosts: web vars: web_pack: httpd-2.4.6 ftP_pack: VSFTPD # -web_pack: httpd-2.4.6 Tasks: - name: Install {{pack_name}} yum: name: - "{{web_pack}}" - "{{ftp_pack}}" state: presentCopy the code
  1. Define an additional variable file

If you are using the same variable in multiple files, you can define a variable file and introduce it in the PlayBook using vars_files

# vars.yml web_pack: httpd-2.4.6ftp_pack: VSFTPDCopy the code
- hosts: web 
  vars_files:   
    - ./vars.yml
Copy the code
  • Defined in the host manifest file
  1. Defined in the host manifest file
# hosts [web] 192.168.143.122 [web:vars] pack_name= HTTPDCopy the code
-hosts: web tasks: - name: install {{pack_name}} yum: name={{pack_name}} state=presentCopy the code
  1. Define the group_vars and host_vars directories separately

Group_vars is a variable directory defined for the group. The file name is the group name, for example, group_vars/web. Host_vars is a variable directory defined for the host, the file name is IP, for example, host_vars/192.168.143.122.

Note: By default, the file name in the group_vars directory is the same as the group name in the hosts list. Therefore, this file is valid only for this group and cannot be used by other groups. However, the system provides a special group -all

Web file pack_name: HTTPDCopy the code
  • Playbook execution uses the -e argument to specify variables
ansible-playbook httpd.yml -e "pack_name=httpd" -e "hosts=web"
Copy the code

It is common to pass the hosts variable through -e. You can distinguish between test and production environments, but you can also define different files to do so

Priority of ansible variables

Above we have introduced the definition of multiple variables, so if the same variable is defined in more than one place, which one will be used first? This is where variable priority comes in.

  • A variable passed by executing a command
  • Introduce variables in vars_files in Playbook
  • The Vars variable defined in playbook
  • Variables defined in host_vars
  • Variables defined in the group name file in group_vars
  • Variables defined in the all file in group_vars

Ansible resister registry variable

When using ansible-playbook, its output is in a fixed format. If we want to check the status of the HTTPD service after starting it, we cannot log in to the target host to check.

- hosts: web  
  tasks:    
    - name: install httpd server      
      yum: name=httpd state=present          
       
    - name: service httpd server      
      service: name=httpd state=started enabled=yes          
        
    - name: check httpd state      
      shell: ps aux|grep httpd      
      register: httpd_status          
        
    - name: output httpd_status variable      
      debug:        
        msg: "{{httpd_status}}"
Copy the code

This is the output of all the content, if you need to output part of the content, just use variables. Properties, which is the dictionary under MSG

Meaning of ansible facts variables

Here is a print of our Apache installation, which can be seen broken down into several processes: PLAY, TASK, PLAY RECAP, the first print of the TASK we see is Gathering Facts, but we did not add this TASK, ansible automatically added this TASK for us, what is this TASK for? In the process of implementation, we found that this piece of implementation time is still relatively long. The main function of this task is to obtain information about the target host. Let’s see what information we can obtain. We can print the following statement: ansible Web -m setup

This includes CPU, memory, hard disk, network, host name, binding information, system version information, and so on, all of which can be used as variables in the PlayBook.

- hosts: web  
  tasks:    
    - name: Query Host Info      
      debug:        
        msg: IP address is {{ansible_default_ipv4.address}} in hosts {{ansible_distribution}}
Copy the code

So when can this be used? For example, configure the number of concurrent nginx processes based on the number of cpus on the target host. Of course, we can also disable it if it is not in use.

- hosts: web  
  gather_facts: no    
  
  tasks:    
    - name: install httpd server      
      yum: name=httpd state=present          
        
    - name: service httpd server      
      service: name=httpd state=started enabled=yes
Copy the code

Here’s an example: Install memcache

# memcache.yml
- hosts: web  

  tasks:    
    - name: install memcached server      
      yum: name=memcached state=present          
        
    - name: configure memcached server      
      template: src=./memcached.j2 dest=/etc/sysconfig/memcached          
        
    - name: service memcached server      
      service: name=memcached state=started enabled=yes          
        
    - name: check memcached server      
      shell: ps aux|grep memcached      
      register: check_mem          
        
    - name: debug memcached variables      
      debug:        
        msg: "{{check_mem.stdout_lines}}"
Copy the code
# memcached. J2, PORT="11211" USER="memcached" MAXCONN="1024" CACHESIZE="{{anSIBle_memtotal_MB // 2}}" OPTIONS=""Copy the code

Here we use a new module called template, which is the equivalent of Djangos template syntax and supports the Jinjia2 rendering engine and syntax. This does most of what the PlayBook does, but that’s just general practice, and there are more flexible issues to deal with, such as:

We only want to perform one task in the PlayBook, right?

Check the nginx status. If it is normal, start or restart it. If it is not normal, ignore it and perform other tasks

If the nginx configuration file has not changed, we do not execute the start or restart command

This is where Ansible’s power lies. Let’s take a look at the task control process

Task Task control

Task control includes the following logical keywords:

  1. Conditional judgment when
  2. Loop with_items
  3. The trigger handlers
  4. The label tags
  5. Contains the include
  6. Ignore the error ignore_error
  7. Error handling change

conditional

Assuming we have Apache installed, HTTPD is installed on centos and HTTPD2 is installed on Ubuntu, so we need to determine the host information and install different software.

- hosts: web  
  tasks:    
    - name: Install CentOS Httpd      
      yum: name=httpd state=present      
      when: ( ansible_distribution == "CentOS" )          
        
    - name: Install Ubuntu Httpd      
      yum: name=httpd2 state=present      
      when: ( ansible_distribution == "Ubuntu" )
Copy the code

When a task is executed, the system checks whether the condition is met. If so, the task will be executed. If not, the task will not be executed. Let’s look at another example: restart Apache if the service is abnormal, otherwise skip.

- hosts: web  
  tasks:    
    - name: check httpd server      
      command: systemctl is-active httpd      
      register: check_httpd          
        
    - name: httpd restart      
      service: name=httpd state=restarted      
      when: check_httpd.rc == 0
Copy the code

Loop the with_items command

Start multiple services, such as nginx, HTTPD

- hosts: web  
  tasks:    
    - name: Service Start      
      service: name={{item}} state=restarted      
      with_items:        
        - nginx        
        - httpd
Copy the code

Copy multiple configuration files

- hosts: web  
  tasks:    
    - name: Copy Configure File      
      copy:         
        src: {{item.src}}        
        dest: {{item.dest}}        
        mode: {{item.mode}}      
      with_items:        
        - { src: './nginx.conf', dest: '/etc/nginx/conf/nginx.conf' }        
        - { src: './httpd.conf', dest: '/etc/httpd/conf/httpd.conf' }
Copy the code

The trigger handlers

When one task changes, another task is triggered, such as a restart task if the HTTPD configuration file changes

- hosts: web tasks: - name: install httpd server yum: name=httpd state=present - name: configure httpd server copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf notify: Handlers: - Restart Httpd Server name: service Httpd Server service: name=httpd state=started enabled=yes handlers: - name: Restart Httpd Server service: name=httpd state=restartedCopy the code

The handlers do not execute the triggered commands until all tasks are completed. If another task fails, the handlers do not execute the triggered commands.

Tags, labels

After assigning a tag to a task, we can use ansible-playbook to assign a tag to the task. We do not need to perform all tasks using ansible-playbook. Set one label for each task. 2. Set multiple labels for each task. 3

- hosts: web tasks: - name: install httpd server yum: name=httpd state=present tags: install - name: configure httpd server copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf notify: Handlers: Restart Httpd Server tags: configure-name: service Httpd Server service: name=httpd state=started enabled=yes tags: start handlers: - name: Restart Httpd Server service: name=httpd state=restartedCopy the code

Ansible-playbook httpd.yml -t “configure”

Ansible-playbook httpd.yml –skip-tags “install”

The include contains

We can write tasks in a separate YAML file and then include them in other tasks that need to be used in include_tasks: xxx.yml, for example:

# a.yml
- name: restart httpd service  
  service: name=httpd state=restarted
Copy the code
# b.yml
- hosts: web  
  tasks:    
    - name: configure httpd server      
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf          
        
    - name: restat httpd      
      include_tasks: ./a.yml
Copy the code

Of course, we could merge the two full PlayBooks together

# a.yml
- hosts: web  
  tasks:    
    - name: install httpd server      
      yum: name=httpd state=present
Copy the code
# b.yml
- hosts: web  
  tasks:    
    - name: configure httpd server      
      copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
Copy the code
# total.yml
- import_playbook: ./a.yml
- import_playbook: ./b.yml
Copy the code

When total.yml is executed, it is actually a.yml and then B.yml, and the contents are not really merged

Ignore error ignore_errors

We know, in the implementation of the playbook, if one of the mission failed, it will no longer perform the task of the following, but sometimes we don’t need all the tasks are successful, some tasks can be failure, then this time the need for fault tolerance, the failure in this task, not affect the mission behind it.

- hosts: web tasks: - name: check httpd status command: ps aux|grep httpd register: httpd_status ignore_errors: Restarted HTTPD service: name= HTTPD state=restartedCopy the code

Error handling

  • Handlers are called whenever handlers are triggered, regardless of whether a task has failed
- hosts: web 
  force_handlers: yes   
  
  tasks:   
    - name: install httpd     
      yum: name=httpd state=present         
        
    - name: install fuck     
      yum: name=fuck state=present   
  
  handlers:   
    - name: restart httpd     
      service: name=httpd state=restarted
Copy the code
  • change_when

When the task is executed, if the controlled host is changed, the change will be changed. However, some commands, such as some shell commands, only query the information without any modification, but always display the change state. At this time, we can force the change state to be turned off.

- hosts: web 
  tasks:   
    - name: test task     
    shell: ps aux     
    change_when: false
Copy the code

For another example, if we modify the configuration file successfully, we execute the restart command, otherwise we do not execute the restart command

- hosts: web tasks: - name: install nginx server yum: name=nginx state=present - name: configure nginx copy: SRC =. / nginx. Conf dest = / etc/nginx/conf/nginx. Conf # check nginx configuration file command - name: check nginx configure command: /usr/sbin/nginx -t register: check_nginx changed_when: ( check_nginx.stdout.find('successful') ) - name: service nginx server service: name=nginx state=restartedCopy the code

Jinja template

The Jinja template is a django-like template. If you have worked with Django, you should be familiar with it. Let’s use Jinja to configure nginx load balancing.

- hosts: web 
  vars:   
    - http_port: 80   
    - server_name: web.com     

  tasks:   
    - name: instal nginx server     
      yum: name=nginx state=present         
        
    - name: configure nginx     
      template: src=./nginx.conf dest=/etc/nginx/conf/nginx.conf         
        
    - name: start nginx     
      service: name=nginx state=started enabled=yes
Copy the code

For Jinja syntax to work, you must use the Template module, which is similar to copy but supports Jinja syntax rendering

# nginx.conf
 upstream {{server_name}} { 
   {% for i in range(2) %}  
     server 192.168.143.12{{i}}:{{http_port}};  
     server 192.168.143.12{{i}}:{{http_port}};
   {% endfor %}
 }
 server {  
   listen {{http_port}};  
   server_name {{server_name}}  
   location / {    
     proxy_pass http://web.com;    
     include proxy_params; 
   }
 }
Copy the code

The variables defined in playbook can be used in the configuration file. When we configure the MySQL master/slave replication cluster, the configuration of the my.cnf file is different for the master and slave hosts, so we can use the if syntax in Jinja for conditional rendering according to the host name

[mysqld]
{% if ansible_fqdn == "mysql_master" %} 
	log-bin=mysql-bin 
  server-id=1
{% else %} 
  server-id=2
{% endif %}
Copy the code

This completes configuration differentiation, executing the same template copy command is a different configuration file on different machines. PS:

Mysql_master: specifies the master host hostname that needs to be configured with master/slave replication. This variable can also be set using ansible

Ansible Roles

Finally, we’ll cover one of the most important concepts in Ansible, roles, which is pretty simple if you’ve got it all figured out. Roles in general is just a layout of what we talked about earlier. It dictates a strict directory format that we must create with a directory structure and file name, or its file system won’t load. The directory format is as follows:

  • Mysql. yml: Playbook file
  • Mysql: roles directory, also the role name
  • Files: Stores files, compressed packages, and installation packages
  • Handlers: We put the trigger tasks here
  • Tasks: Specific tasks
  • Templates: Stores template files rendered by template
  • Vars: Defines variables
  • Meta: Task dependencies

The main.yml names must be the same, and the directory names must be the same, but not all directories are required.

- hosts: web tasks: - name: install httpd server yum: name=httpd state=present tags: install - name: configure httpd server template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf notify: Handlers: Restart Httpd Server tags: configure-name: service Httpd Server service: name=httpd state=started enabled=yes tags: start handlers: - name: Restart Httpd Server service: name=httpd state=restartedCopy the code

Change this to roles, and the directory structure is as follows:

# httpd/handlers/main.yml
- name: Restart Httpd Server  
  service: name=httpd state=restarted
Copy the code
# httpd/tasks/config.xml - name: configure httpd server template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf notify: Handlers, and other handlers, can write multiple -restart Httpd Server tags: configureCopy the code
# httpd/tasks/install.yml
- name: install httpd server 
  yum: name=httpd state=present  
  tags: install
Copy the code
# httpd/tasks/start.yml
- name: service httpd server  
  service: name=httpd state=started enabled=yes  
  tags: start
Copy the code
# httpd/tasks/main.yml
- include_tasks: install.yml
- include_tasks: config.yml
- include_tasks: start.yml
Copy the code
# httpd1.yml - hosts: web roles: -role: nginx # -nginxCopy the code

Ansible-playbook httpd1.yml = httpd1.yml = httpd1.yml = httpd1.yml

Galaxy

Finally, there is an official website: Galaxy.ansible.com

It’s a site like GitHub and Docker. My site is too lame to open. It has roles written by someone else, for example, if you want to install Nginx, search for Nginx and it will provide a download command: Ansible-galaxy install geerlingguy.nginx, which will be downloaded to /root/.ansible-roles.

Ansible is developed in Python, so we often use it in combination with Python. We will write python operations on Ansible later.