Ansible从入门到精通【六】

大家好,我是早九晚十二,目前是做运维相关的工作。写博客是为了积累,希望大家一起进步!

我的主页:早九晚十二

专栏名称:Ansible从入门到精通 立志成为ansible大佬

ansible templates

模板(templates)的认识

模板的使用方式

  1. 文本文件,嵌套有脚本(使用模板编程语言编写)
  2. jinja2语言,使用字面量,有下面形式
    字符串:使用单引号或者双引号
    数字:整数,浮点数
    列表:[item1,item2,...]
    元组;(item1,item2,...)
    字典:{key1:value1,key2:value2,...}
    布尔:true/false
  3. 算数运算:+,-,*,/,//,%,**
  4. 比较运算:==,!=,>,>=,<,<=
  5. 逻辑运算:and,or,not
  6. 流表达式:For If When

模板的目录

一般建议在ansible目录下创建templates目录,与playbook剧本平行

帮助文档

bash 复制代码
[root@zhaoyj ansible]# ansible-doc -s template
- name: Template a file out to a remote server
  template:
      attributes:            # The attributes the resulting file or directory should have. To get supported flags look at the man page for `chattr' on the target
                               system. This string should contain the attributes in the same order as the one displayed by `lsattr'. The
                               `=' operator is assumed as default, otherwise `+' or `-' operators need to be included in the string.
      backup:                # Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly.
      block_end_string:      # The string marking the end of a block.
      block_start_string:    # The string marking the beginning of a block.
      dest:                  # (required) Location to render the template to on the remote machine.
      follow:                # Determine whether symbolic links should be followed. When set to `yes' symbolic links will be followed, if they exist. When set to `no'
                               symbolic links will not be followed. Previous to Ansible 2.4, this was hardcoded as `yes'.
      force:                 # Determine when the file is being transferred if the destination already exists. When set to `yes', replace the remote file when contents
                               are different than the source. When set to `no', the file will only be transferred if the destination does
                               not exist.
      group:                 # Name of the group that should own the file/directory, as would be fed to `chown'.
      lstrip_blocks:         # Determine when leading spaces and tabs should be stripped. When set to `yes' leading spaces and tabs are stripped from the start of a
                               line to a block. This functionality requires Jinja 2.7 or newer.
      mode:                  # The permissions the resulting file or directory should have. For those used to `/usr/bin/chmod' remember that modes are actually octal
                               numbers. You must either add a leading zero so that Ansible's YAML parser knows it is an octal number
                               (like `0644' or `01777') or quote it (like `'644'' or `'1777'') so Ansible receives a string and can do
                               its own conversion from string into number. Giving Ansible a number without following one of these rules
                               will end up with a decimal number which will have unexpected results. As of Ansible 1.8, the mode may be
                               specified as a symbolic mode (for example, `u+rwx' or `u=rw,g=r,o=r').
      newline_sequence:      # Specify the newline sequence to use for templating files.
      output_encoding:       # Overrides the encoding used to write the template file defined by `dest'. It defaults to `utf-8', but any encoding supported by python
                               can be used. The source template file must always be encoded using `utf-8', for homogeneity.
      owner:                 # Name of the user that should own the file/directory, as would be fed to `chown'.
      selevel:               # The level part of the SELinux file context. This is the MLS/MCS attribute, sometimes known as the `range'. When set to `_default', it
                               will use the `level' portion of the policy if available.
      serole:                # The role part of the SELinux file context. When set to `_default', it will use the `role' portion of the policy if available.

使用模板管理nginx

模拟一个nginx的模板文件

bash 复制代码
cp /etc/nginx/nginx.conf /root/ansible/templates/nginx.conf.j2

编写yml剧本

yaml 复制代码
[root@zhaoyj ansible]# cat templates.yml 
---
- hosts: test
  remote_user: root

  tasks:
    - name: install pkg
      yum: name=nginx
    - name: copy template
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    - name: start service
      service: name=nginx state=started enabled=yes
...

测试yml

bash 复制代码
[root@zhaoyj ansible]# ansible-playbook -C templates.yml 

执行(这里报错了,是因为主控机有证书)

bash 复制代码
[root@zhaoyj ansible]# ansible-playbook  templates.yml 

PLAY [test] ***********************************************************************************************************************************************************************************************************

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

TASK [install pkg] ****************************************************************************************************************************************************************************************************
changed: [192.168.6.249]

TASK [copy template] **************************************************************************************************************************************************************************************************
changed: [192.168.6.249]

TASK [start service] **************************************************************************************************************************************************************************************************
fatal: [192.168.6.249]: FAILED! => {"changed": false, "msg": "Unable to start service nginx: Job for nginx.service failed because the control process exited with error code. See \"systemctl status nginx.service\" and \"journalctl -xe\" for details.\n"}

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

修改nginx的work数量

修改nginx的work数量,根据实际的cpu生成

ansible cpu变量查看

bash 复制代码
[root@zhaoyj ansible]# ansible test -m setup |grep "cpu"
        "ansible_processor_vcpus": 8, 

编辑模板文件

bash 复制代码
[root@zhaoyj templates]# vim nginx.conf.j2 


user  nginx;
worker_processes  {{ ansible_processor_vcpus*2 }};

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

修改template剧本

yaml 复制代码
[root@zhaoyj ansible]# cat templates.yml 
---
- hosts: test
  remote_user: root

  tasks:
    - name: install pkg
      yum: name=nginx
    - name: copy template
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify: restart service
    - name: start service
      service: name=nginx state=started enabled=yes
  handlers:
    - name: restart service
      service:  name=nginx state=restarted
...

再次执行

bash 复制代码
[root@zhaoyj ansible]# ansible-playbook templates.yml 

PLAY [test] ***********************************************************************************************************************************************************************************************************

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

TASK [install pkg] ****************************************************************************************************************************************************************************************************
ok: [192.168.6.249]

TASK [copy template] **************************************************************************************************************************************************************************************************
changed: [192.168.6.249]

TASK [start service] **************************************************************************************************************************************************************************************************
changed: [192.168.6.249]

RUNNING HANDLER [restart service] *************************************************************************************************************************************************************************************
changed: [192.168.6.249]

PLAY RECAP ************************************************************************************************************************************************************************************************************
192.168.6.249              : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

查看配置文件是否读取变量

bash 复制代码
192.168.6.249 | CHANGED | rc=0 >>
worker_processes  16;
[root@zhaoyj ansible]# ansible test -m shell -a "ps aux|grep nginx"
192.168.6.249 | CHANGED | rc=0 >>
root     16342  0.0  0.0  49072  1168 ?        Ss   17:16   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    16343  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16344  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16345  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16346  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16347  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16348  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16349  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16350  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16351  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16352  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16353  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16354  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16355  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16356  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16357  0.0  0.0  49460  1900 ?        S    17:16   0:00 nginx: worker process
nginx    16358  0.0  0.0  49460  1636 ?        S    17:16   0:00 nginx: worker process
root     17699  0.0  0.0 113284  1204 pts/1    S+   17:20   0:00 /bin/sh -c ps aux|grep nginx
root     17701  0.0  0.0 112816   960 pts/1    S+   17:20   0:00 grep nginx

when的使用

条件测试:

如果需要根据变量,facts或此前任务的执行结果来做为某task执行与否的前提是要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式
when语句:

在task后添加when子句即可使用条件测试,when语句支持jinja2语法

比如:

查看版本号

powershell 复制代码
[root@zhaoyj ansible]# ansible test -m setup -a "filter="*distribution*""
192.168.6.249 | SUCCESS => {
    "ansible_facts": {
        "ansible_distribution": "CentOS", 
        "ansible_distribution_file_parsed": true, 
        "ansible_distribution_file_path": "/etc/redhat-release", 
        "ansible_distribution_file_variety": "RedHat", 
        "ansible_distribution_major_version": "7", 
        "ansible_distribution_release": "Core", 
        "ansible_distribution_version": "7.9", 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}

记录 "ansible_distribution_major_version": "7", 设置当系统等于7时,复制配置文件

修改模板文件

powershell 复制代码
[root@zhaoyj ansible]# cat templates.yml 
---
- hosts: test
  remote_user: root

  tasks:
    - name: install pkg
      yum: name=nginx
    - name: copy template
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      when: ansible_distribution_major_version == "7"
      notify: restart service
    - name: start service
      service: name=nginx state=started enabled=yes
  handlers:
    - name: restart service
      service:  name=nginx state=restarted
...

执行剧本

powershell 复制代码
[root@zhaoyj ansible]# ansible-playbook templates.yml 

PLAY [test] ***********************************************************************************************************************************************************************************************************

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

TASK [install pkg] ****************************************************************************************************************************************************************************************************
ok: [192.168.6.249]

TASK [copy template] **************************************************************************************************************************************************************************************************
changed: [192.168.6.249]

TASK [start service] **************************************************************************************************************************************************************************************************
changed: [192.168.6.249]

RUNNING HANDLER [restart service] *************************************************************************************************************************************************************************************
changed: [192.168.6.249]

PLAY RECAP ************************************************************************************************************************************************************************************************************
192.168.6.249              : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@zhaoyj ansible]# ansible test -m shell -a "cat /etc/nginx/nginx.conf|grep centos"
192.168.6.249 | CHANGED | rc=0 >>
#centos 7

嵌套变量传递

我们在制作模板是支持传递变量,可传递单一变量,或者是以列表方式传递,例如:

yaml 复制代码
---
- hosts: test
  remote_user: root

  tasks:
    - name: create some groups
      group: name={{ item }}
      with_items:
        - group1
        - group2
        - group3

    - name: create some user
      user: name={{ item.name }} group={{ item.group }}
      with_items:
        - { name: 'name1', group: 'group1' }
        - { name: 'name2', group: 'group2' }
        - { name: 'name3', group: 'group3' }
...

执行

swift 复制代码
```bash
[root@192-168-6-228 ansible]# ansible-playbook  test.yml 

PLAY [test] ****************************************************************************************************************************************************************************

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

TASK [create some groups] **************************************************************************************************************************************************************
changed: [192.168.6.223] => (item=group1)
changed: [192.168.6.223] => (item=group2)
changed: [192.168.6.223] => (item=group3)

TASK [create some user] ****************************************************************************************************************************************************************
changed: [192.168.6.223] => (item={u'group': u'group1', u'name': u'name1'})
changed: [192.168.6.223] => (item={u'group': u'group2', u'name': u'name2'})
changed: [192.168.6.223] => (item={u'group': u'group3', u'name': u'name3'})

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

验证结果

bash 复制代码
[root@192-168-6-228 ansible]# ansible test -m shell -a "getent passwd"|grep name
name1:x:1003:1003::/home/name1:/bin/bash
name2:x:1004:1004::/home/name2:/bin/bash
name3:x:1005:1005::/home/name3:/bin/bash

[root@192-168-6-228 ansible]# ansible test -m shell -a "getent group|grep 100[3-5]"
192.168.6.223 | CHANGED | rc=0 >>
group1:x:1003:
group2:x:1004:
group3:x:1005:

FOR循环与条件判断

FOR循环

格式**(% for vhost in nginx_vhosts %)**

示例:

bash 复制代码
[root@192-168-6-228 ansible]# cat test1.yml 
---
- hosts: test
  remote_user: root
  vars: 
    ports:
      - 81 
      - 82
      - 83

  tasks:
    - name: copy file
      template: src=port.j2 dest=/tmp/port 
...

编写一个模板文件

bash 复制代码
[root@192-168-6-228 ansible]# cat templates/port.j2
{% for port in ports %}
server{
	listen {{ port }}
}
{% endfor %}

注意:for循环里的in ports,这个ports需要和剧本里定义的一样

执行

bash 复制代码
[root@192-168-6-228 ansible]# ansible-playbook test1.yml 

PLAY [test] ****************************************************************************************************************************************************************************

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

TASK [copy file] ***********************************************************************************************************************************************************************
changed: [192.168.6.223]

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

结果查看

bash 复制代码
[root@192-168-6-228 ansible]# ansible test -m shell -a "cat /tmp/port"
192.168.6.223 | CHANGED | rc=0 >>
server{
	listen 81
}
server{
	listen 82
}
server{
	listen 83
}

也可以改成字典方式去循环,例如:

bash 复制代码
[root@192-168-6-228 ansible]# cat test1.yml 
---
- hosts: test
  remote_user: root
  vars: 
    ports:
      - listen_port: 81 
      - listen_port: 82
      - listen_port: 83

  tasks:
    - name: copy file
      template: src=port.j2 dest=/tmp/port 
...

模板修改

bash 复制代码
[root@192-168-6-228 ansible]# cat templates/port.j2
{% for port in ports %}
server{
	listen {{ port.listen_port }}
}
{% endfor %}

先删除之前的文件在看效果

bash 复制代码
[root@192-168-6-228 ansible]# ansible test -m shell -a "rm -f  /tmp/port"
[WARNING]: Consider using the file module with state=absent rather than running 'rm'.  If you need to use command because file is insufficient you can add 'warn: false' to this
command task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
192.168.6.223 | CHANGED | rc=0 >>

[root@192-168-6-228 ansible]# ansible test -m shell -a "cat   /tmp/port"
192.168.6.223 | FAILED | rc=1 >>
cat: /tmp/port: No such file or directorynon-zero return code

[root@192-168-6-228 ansible]# ansible-playbook test1.yml 

PLAY [test] ****************************************************************************************************************************************************************************

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

TASK [copy file] ***********************************************************************************************************************************************************************
changed: [192.168.6.223]

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

[root@192-168-6-228 ansible]# ansible test -m shell -a "cat   /tmp/port"
192.168.6.223 | CHANGED | rc=0 >>
server{
	listen 81
}
server{
	listen 82
}
server{
	listen 83
}

与第一种方法是一致的

if判断

模板里也支持if判断。例如修改上面的模板,当listen_port变量为空,就不执行

bash 复制代码
---
- hosts: test
  remote_user: root
  vars: 
    ports:
      - listen_port: 81 
      - listen_port: 82
      - listen_port:

  tasks:
    - name: copy file
      template: src=port.j2 dest=/tmp/port 
...

模板修改

bash 复制代码
[root@192-168-6-228 ansible]# cat templates/port.j2
{% for port in ports %}
server{
{% if port.listen_port is none %}
	listen {{ port.listen_port }}
{% endif %}
}
{% endfor %}

if是none情况下,代表参数定义但是值为空是真
if是defined情况下,代表参数定义了为真
if是undefined情况下,代表参数未定义为真

结果查看

bash 复制代码
[root@192-168-6-228 ansible]# ansible-playbook  test3.yml 

PLAY [test] ****************************************************************************************************************************************************************************

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

TASK [copy file] ***********************************************************************************************************************************************************************
changed: [192.168.6.223]

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

[root@192-168-6-228 ansible]# ansible test -m shell -a "cat   /tmp/port"
192.168.6.223 | CHANGED | rc=0 >>
server{
	listen 
}
相关推荐
leo__5202 天前
自动化运维:使用Ansible简化日常任务
运维·自动化·ansible
风清再凯7 天前
自动化工具ansible,以及playbook剧本
运维·自动化·ansible
IT乌鸦坐飞机7 天前
ansible部署数据库服务随机启动并创建用户和设置用户有完全权限
数据库·ansible·centos7
遇见火星20 天前
如何使用Ansible一键部署MinIO集群?
ansible
粥周粥20 天前
ANSIBLE
ansible
码农101号20 天前
Linux中ansible模块补充和playbook讲解
linux·运维·ansible
码农101号20 天前
Linux的Ansible软件基础使用讲解和ssh远程连接
ansible
烟雨书信21 天前
ANSIBLE运维自动化管理端部署
运维·自动化·ansible
碎碎-li21 天前
ANSIBLE(运维自动化)
运维·自动化·ansible
@donshu@24 天前
Linux运维-ansible-python开发-获取inventroy信息
linux·运维·ansible