模板(templates)的认识
模板的使用方式
- 文本文件,嵌套有脚本(使用模板编程语言编写)
- jinja2语言,使用字面量,有下面形式
字符串:使用单引号或者双引号
数字:整数,浮点数
列表:[item1,item2,…]
元组;(item1,item2,…)
字典:{key1:value1,key2:value2,…}
布尔:true/false - 算数运算:+,-,*,/,//,%,**
- 比较运算:==,!=,>,>=,<,<=
- 逻辑运算:and,or,not
- 流表达式:For If When
模板的目录
一般建议在ansible目录下创建templates目录,与playbook剧本平行
帮助文档
[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的模板文件
cp /etc/nginx/nginx.conf /root/ansible/templates/nginx.conf.j2
编写yml剧本
[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
[root@zhaoyj ansible]# ansible-playbook -C templates.yml
执行(这里报错了,是因为主控机有证书)
[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变量查看
[root@zhaoyj ansible]# ansible test -m setup |grep "cpu" "ansible_processor_vcpus": 8,
编辑模板文件
[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剧本
[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 ...
再次执行
[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
查看配置文件是否读取变量
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语法
比如:
查看版本号
[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时,复制配置文件
修改模板文件
[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 ...
执行剧本
[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
嵌套变量传递
我们在制作模板是支持传递变量,可传递单一变量,或者是以列表方式传递,例如:
--- - 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' } ...
执行
```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
验证结果
[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 %)**
示例:
[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 ...
编写一个模板文件
[root@192-168-6-228 ansible]# cat templates/port.j2 {% for port in ports %} server{ listen {{ port }} } {% endfor %}
注意:for循环里的in ports,这个ports需要和剧本里定义的一样
执行
[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 }
也可以改成字典方式去循环,例如:
[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 ...
模板修改
[root@192-168-6-228 ansible]# cat templates/port.j2 {% for port in ports %} server{ listen {{ port.listen_port }} } {% endfor %}
先删除之前的文件在看效果
[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变量为空,就不执行
--- - 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 ...
模板修改
[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情况下,代表参数未定义为真
结果查看
[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 }