3.1 Ansible Playbook Advanced One

Handlers trigger

This thing is similar to a trigger. For example, in such a scenario, we copy the nginx conf configuration file to the target machine, then when the configuration file is updated, nginx needs to be restarted. For similar requirements, we use Ansible handlers to do

    - name: Copy configuration files
      copy:
        src: xtest1.conf
        dest: /etc/nginx/conf.d/xtest1.conf
      notify:
         - restart_nginx

  handlers:
    - name: restart_nginx
      service:
        name: nginx
        state: restarted

Complete example

https://gitee.com/as4k/ysansible/blob/master/handlers/main.yml

Environment variable increase and modification

There are many scenarios, we need to change some variables (or configuration) of the target machine, such as turning off selinux. If this operation is written as a shell script, it can be as follows

sed 's#^SELINUX=.*#SELINUX=disabled#g' /etc/selinux/config

Ansible also provides similar usage, as shown below

- name: Ensure SELinux is set to disabled mode
    lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    line: SELINUX=disabled

If you need to change a line in a text file, or add a line, basically use the lineinfilemodule

For example, we are ~/.bash_profileadding environment variables, similar to the following

    - name: Add an environment variable to the remote user's shell. 
      lineinfile: 
        path: "~/.bash_profile" 
        regexp: "^ENV_VAR="
        line: "ENV_VAR=value_helloworld"

The meaning of the above module is to ensure ~/.bash_profilethat there is this line ENV_VAR=value_helloworld, some remain unchanged, and there is no increase.

Another thing to mention is that different environment variables are best placed in a separate file, which is the most convenient for maintenance. For example, environment variables can be placed in CenOS7 /etc/profile.d, so that we can simply copy the file, which is easy to read and maintain.

    - name: Copy java_env
      copy:
        src: java_env.sh
        dest: /etc/profile.d/java_env.sh

Although Ansible has many advanced and awesome usages, using Ansible in a production environment is not to show off skills. If you can use simple modules to solve problems, use simple modules.

Complete example

https://gitee.com/as4k/ysansible/blob/master/env_variables/main.yml

Use variables in the script

Whether in a programming language or in Ansible, there are always some things that need to be used repeatedly. At this time, we should put these things into variables to facilitate maintenance and modification. For example, we write a The script of the blog software written by PHP), then the software version number is more suitable to be a variable, so we need to upgrade the script in the future or give the script to others, just change the version number, don’t need to go to the corresponding script in the script Modify the places manually

Generally, when you get a script, you first need to see which variables are available. These variables are equivalent to the external access interface. If something like the version number of the software and the data storage directory of the software, these obviously need to be used according to different scenarios. , It is usually recommended to use the commission variable

Variable naming rules

开头是 [A-Za-z]
其它地方可以包含 下划线_  数字[0-9]

合法的变量示例:foo, foo_bar, foo_bar_5
不合法的变量示例:_foo, foo-bar, 5_foo_bar, foo.bar

Variables embedded in the script

  vars:
    http_port: 80
https://gitee.com/as4k/ysansible/blob/master/variables/playbook_var_in_file.yml

Variables written separately in YAML file

  vars_files: 
    - vars.yml
https://gitee.com/as4k/ysansible/blob/master/variables/playbook_var_file.yml    

Variables added directly on the command line

# ansible-playbook playbook_var_cmd.yml  --extra-vars "foo=bar" --limit 192.168.31.100 
# ansible-playbook playbook_var_cmd.yml  --extra-vars "@vars.yml" --limit 192.168.31.100
https://gitee.com/as4k/ysansible/blob/master/variables/playbook_var_cmd.yml

There is a priority difference in the use of variables in these ways. The variables used in the command line have the highest priority. For details, please refer to the following document

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

If you just use the script to organize Ansible (more elementary, we will introduce roles later), then less variables are embedded in the playbook, and more variables are independent of one or more files. It is recommended to use less --extra-varsform, unless it is used for testing. , Because this form is not easy to track, but it is written in a file and can be tracked through code management tools such as git

Register variable register to capture command output

In some scenarios, for example, we need to install a software on the target machine, but before installation, we need to execute a command to dynamically determine the state of the target machine. Assume that there are three states of A, B, and C, and what needs to be executed in each state It's not the same, so it is necessary to save the state (that is, the variable) first, for later use, as shown below

    - name: Register the output of the 'uptime' command. 
      command: uptime
      register: system_uptime

    - name: Print a simple message if a command resulted in a change. 
      debug: msg="Command resulted in a change!"
      when: system_uptime.changed

https://gitee.com/as4k/ysansible/blob/master/registered_var/main1.yml

Types of variables and access to variables

We know that Ansible’s main development language is python, and many python data types are also available in Ansible, such as arrays, dictionaries, etc. Ansible uses jinjia syntax for template variable substitution.

The most basic

    - name: test1
      debug:
        msg: "{
   
   { foo }}"

不加双引号会报错

Array

foo3_list: 
  - one
  - two
  - three
==========
    - name: test3
      debug:
        msg: "{
   
   { foo3_list[1] }}"

    - name: test4
      debug:
        msg: "{
   
   { foo3_list|first }}"

数组从0开始
{
   
   { foo3_list|first }}  与 {
   
   { foo3_list[1] }} 等价, |first 是jinjia过滤器的语法

dictionary

foo4_dict:
  xiaoming: 186
  xiaowang: 187
  xiaoli: 188
============
    - name: test4
      debug:
        msg: "{
   
   { foo4_dict.xiaoming }}"

    - name: test5
      debug:
        msg: "{
   
   { foo4_dict['xiaoli'] }}"

    - name: test6
      debug:
        msg: "{
   
   { ansible_eth0['ipv4']['address'] }}"

{
   
   { foo4_dict.xiaoming }} 与 {
   
   { foo4_dict['xiaoli'] }} 等价
如果字典的key有些什么特殊符号之类,用第2种

Variable types can also be complex nested, but if not necessary, try to use simple data types

Complete example

https://gitee.com/as4k/ysansible/blob/master/acccessing_var/main1.yml

Inventory variables in the host list

The form is as follows

cat /etc/ansible/hosts
[allservers]
192.168.31.106
192.168.31.100
192.168.31.101
192.168.31.102
192.168.31.103
192.168.31.104
192.168.31.105
192.168.31.107
192.168.31.108

[webservers]
192.168.31.100 os=centos73 admin_user=jane
192.168.31.101 os=centos77 admin_user=jack
192.168.31.102 os=centos78

[webservers:vars]
dns1=223.5.5.5
dns2=8.8.8.8
admin_user=admin

There is not much difference between the variables defined here and the variables defined in the script. They can be used in the script. Generally, there are only variables that are strongly related to the specified machine or the specified machine group, such as the NTP time server used by a group of machines. All are in China, but one of the machines is special and uses a foreign time server, so you can use variables to identify it in the host list

However, if too many variables are written in the host list, it is messy. A more suitable solution is to separate them, that is, "host variables and group variables".

Host and Group variables

Observe the following directory structure

[root@192_168_31_106 /data/ysansible]# tree host_and_group_variables/
host_and_group_variables/
├── group_vars
│   └── webservers
├── hosts
├── host_vars
│   ├── 192.168.31.100
│   ├── 192.168.31.101
│   └── 192.168.31.102
├── main1.yml
└── README.md
# 对应线上代码在 https://gitee.com/as4k/ysansible/tree/master/host_and_group_variables

hosts is the host list file. When actually executed, we move to the current directory and use -iparameters to specify the host list, such as

ansible-playbook main1.yml -i hosts

group_varsThe and host_varsfolder is a fixed directory, and must be in the same level directory as the host list. The file name under group_vars corresponds to the group name in the host list, and the file name under host_vars corresponds to the hosts in the host list (may be IP or IP It may be a domain name), which respectively represent the variables shared by the group of machines and the variables owned by a single machine. The hosts_vars has a higher priority than group_vars

There is also a special group name (file name) all, which represents a variable that can be used by all machines (groups)

Facts system variable collection

The Linux operating system has a lot of basic information, such as memory, CPU, operating system version, intranet IP address, etc. This information is often used when we deploy services, etc. Ansible calls these things facts , and this feature is enabled by default , We can directly use

---
- hosts: all
  gather_facts: yes
  # gather_facts: no
  #默认是yes
  #关掉信息收集可以提升性能,但不能再使用相关变量

  tasks:

    - name: get ip address
      debug:
        msg: "{
   
   { ansible_eth0['ipv4']['address'] }}"

If we want to see all the facts that can be used, we can use the following command

ansible 192.168.31.100 -m setup > ansible_setup.json

For all the system variables collected by CentOS7, refer to the following:

https://gitee.com/as4k/ysansible/blob/master/facts/ansible_setup.json

Reference example: https://gitee.com/as4k/ysansible/blob/master/facts/main.yml

We can also manually add system variables by ourselves. The following is an example of using a shell command to obtain an IP address

    - name: Get host IP address.
      shell: >
          prefix=`/sbin/ip route | awk '/default/ { print $3 }' | sed -r 's#\.[0-9]+$##g'`;
          hostname -I | egrep -o "$prefix\.[0-9]+"
      register: host_ip
      changed_when: false

    - name: Set host_ip_address variable.
      set_fact:
        host_ip_address: "{
   
   { host_ip.stdout }}"

Reference example: https://gitee.com/as4k/ysansible/blob/master/facts/set_fact.yml

Built-in host inventory variables

In this regard, we introduce an ansible_host

    - name: ansible_host
      debug:
        msg: "echo {
   
   { ansible_host }}"

This built-in variable is specifically used to obtain the IP address in the host list (of course, it may also be a domain name), because in a production environment usually the machine has more than one network card, and more than one internal network IP address, but there is usually one that is mainly used Intranet IP address. At this time, if we use the facts in the previous section to collect IP addresses, we will get multiple. How to distinguish which IP is our main IP address is a bit troublesome. Therefore, we directly use ansible_hostthis built-in host clearing variable, so we only need to put the main IP address in the host list by ourselves.

Reference example: https://gitee.com/as4k/ysansible/blob/master/centos7_init/centos7_init.yml

Vault secure encryption

Sometimes there is some sensitive information in our playbook, such as the root password of the database. I don’t want to be seen by others or synced directly to the git repository. At this time, the simpler way is to separate sensitive information such as related passwords, such as Put it directly outside the current project, and copy it to the target machine when used. However, this method is not easy to manage and messy, destroying the integrity of the original playbook. In this case, we can consider using the Ansible Vault encryption function.

Look at a simple example

cat vars.yml
my_password: hello123456

=============

#执行加密指令
ansible-vault encrypt vars.yml #系统会要求输入密码,需要记住这个密码
New Vault password: 123456
Confirm New Vault password: 123456
Encryption successful

=============

cat vars.yml
$ANSIBLE_VAULT;1.1;AES256
37613864313965393631653339356633376666386537353338613865373863316562396461303366
3161643662343963316534396365643265383562303862360a363662636437313033646333363339
30333232656361363233626436383434386234646361303130353662633566373231333934656535
6561373861346434650a303635333632616263373631393566666363373334303162363161386338
39646333353137396133363831663166633366323731646339396261623432336361303039643164
34393365383932393236653733366362303766663833376433633864343638346338646430326664
35396630663162313238396262616539376361663534623132346634613865386135643335636138
34346431636430383366323235346662653337633739366564643637313164326662633933346236
32636538646537663933373836386234366337363661323334313635346633313266643365653165
6437643437666365363830353162666163643365313366353937

As you can see, the original text has been directly modified and encrypted. Let’s see how to use it.

Enter password interactively to execute

[root@192-168-31-106 /data/ysansible/vault]# ansible-playbook main1.yml  --limit 192.168.31.100 --ask-vault-pass
Vault password: 123456 (这个是我们执行ansible-vault encrypt vars.yml命令要求输入的密码,不是vars.yml里面记录的内容)
....

Non-interactive direct operation

touch ~/.ansible/vault_pass.txt
echo "123456" > ~/.ansible/vault_pass.txt
chmod 0600  ~/.ansible/vault_pass.txt
ansible-playbook main1.yml  --limit 192.168.31.100 --vault-password-file ~/.ansible/vault_pass.txt

Other vault commonly used commands

解密成原始文本,需要输入密码
ansible-vault decrypt vars.yml 

编辑原始文件,需要输入密码
ansible-vault edit vars.yml

查看原始的文本
ansible-vault view vars.yml

In summary, to use Ansible to encrypt information, we need to:

  1. Encrypt the text (the text content does not need to be changed)
  2. Keep the encryption password properly
  3. Add --vault-password-fileparameters when executing commands

The introduction of encryption still requires some additional maintenance costs. The encrypted text alone is basically meaningless. You can choose according to the situation.

Reference example: https://gitee.com/as4k/ysansible/blob/master/vault/main1.yml

Register variable register

Sometimes, we need to read a variable from the target configuration file and record it for subsequent use. For example, read out the computer room information of the target machine, which can be registerimplemented, as shown below

    # ignore_errors 用来防止playbook被打断
    - name: Run a shell command and register its output as a variable
      shell: cat /etc/redhat-release
      register: foo_result
      ignore_errors: true

    - name: Run a shell command using output of the previous task
      shell: echo "ok" > /tmp/tmp.txt
      when: foo_result.rc == 0

Reference example: https://gitee.com/as4k/ysansible/blob/master/env_variables/main.yml

Reference

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#playbooks-conditionals

Guess you like

Origin blog.csdn.net/xys2015/article/details/113857548