六、Ansible playbook 简介
playbook 是 ansible 用于配置,部署,和管理被控节点的剧本。 通过 playbook 的详细描述,执行其中的一系列 tasks ,可以让远端主机达到预期的状态。playbook 就像 Ansible 控制器给被控节点列出的的一系列 to-do-list ,而被控节点必须要完成。 也可以这么理解,playbook 字面意思,即剧本,现实中由演员按照剧本表演,在Ansible中,这次由计算机进行表演,由计算机安装,部署应用,提供对外服务,以及组织计算机处理各种各样的事情。
七、Ansible playbook使用场景
执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但是有时一个设施过于复杂,需要大量的操作时候,执行的ad-hoc命令是不适合的,这时最好使用playbook。 就像执行shell命令与写shell脚本一样, 也可以理解为批处理任务,不过playbook有自己的语法格式。 使用playbook你可以方便的重用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码。在你使用Ansible的过程中,你也会发现,你所处理的大部分操作都是编写playbook。可以把常见的应用都编写成playbook,之后管理服务器会变得十分简单。
八、Ansible playbook格式
1、格式简介
playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与OrenBen-Kiki也是这语言的共同设计者。 YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。首先学习了解一下YMAL的格式,对我们后面书写playbook很有帮助。
以下为playbook常用到的YMAL格式: 1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。 2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。 3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。 4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。 5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":"分隔表示,":"后面还要增加一个空格。
下面是一个举例:
--- #安装与运行mysql服务 - hosts: node1 remote_user: root tasks: - name: install mysql-server package yum: name=mysql-server state=present - name: starting mysqld service service: name=mysql state=started
我们的文件名称应该以.yml
结尾,像我们上面的例子就是mysql.yml
。其中,有三个部分组成:
host部分
:使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts ,hosts也可以使用通配符格式。主机或主机组在 inventory 清单中指定,可以使用系统默认的/etc/ansible/hosts
,也可以自己编辑,在运行的时候加上-i
选项,指定清单的位置即可。在运行清单文件的时候,–list-hosts
选项会显示那些主机将会参与执行 task 的过程中。remote_user
:指定远端主机中的哪个用户来登录远端系统,在远端系统执行 task 的用户,可以任意指定,也可以使用 sudo,但是用户必须要有执行相应 task 的权限。tasks
:指定远端主机将要执行的一系列动作。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。tasks 包含name
和要执行的模块
,name 是可选的,只是为了便于用户阅读,不过还是建议加上去,模块是必须的,同时也要给予模块相应的参数。
使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言 | 绿色代表执行成功,系统保持原样 | 黄色代表系统代表系统状态发生改变 | 红色代表执行失败,显示错误输出 执行有三个步骤:1、收集facts 2、执行tasks 3、报告结果
2、核心元素
Playbook的核心元素:
Hosts
:主机组;Tasks
:任务列表;Variables
:变量,设置方式有四种;Templates
:包含了模板语法的文本文件;Handlers
:由特定条件触发的任务;
3、基本组件
Playbooks配置文件的基础组件:
Hosts
:运行指定任务的目标主机remote_user
:在远程主机上执行任务的用户;sudo_user
:tasks
:任务列表
模块,模块参数
:格式: (1) action: module arguments (2) module: arguments 注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;
handlers
:任务,在特定条件下触发;接收到其它任务的通知时被触发;
(1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
(2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
举例
① 定义playbook
[root@server ~]# cd /etc/ansible [root@server ansible]# vim nginx.yml --- - hosts: web remote_user: root tasks: - name: install nginx yum: name=nginx state=present - name: copy nginx.conf copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes notify: reload #当nginx.conf发生改变时,通知给相应的handlers tags: reloadnginx #打标签 - name: start nginx service service: name=nginx state=started tags: startnginx #打标签 handlers: #注意,前面没有-,是两个空格 - name: reload service: name=nginx state=restarted #为了在进程中能看出来
运行前三部曲 检查错误 ansible-playbook nginx.yml --syntax-check 列出所有任务 ansible-playbook nginx.yml --list-task 列出在那些机器执行 ansible-playbook nginx.yml --list-hosts 运行 ansible-playbook nginx.yml
② 测试运行结果 写完了以后,我们就可以运行了:
[root@server ansible]# ansible-playbook nginx.yml
现在我们可以看看两台机器的端口是否开启:
[root@server ansible]# ansible web -m shell -a 'ss -nutlp |grep nginx' 192.168.37.122 | SUCCESS | rc=0 >> tcp LISTEN 0 128 *:80 *:* users:(("nginx",pid=8304,fd=6),("nginx",pid=8303,fd=6)) 192.168.37.133 | SUCCESS | rc=0 >> tcp LISTEN 0 128 *:80 *:* users:(("nginx",pid=9671,fd=6),("nginx",pid=9670,fd=6))
③ 测试标签 我们在里面已经打上了一个标签,所以可以直接引用标签。但是我们需要先把服务关闭,再来运行剧本并引用标签:
[root@server ansible]# ansible web -m shell -a 'systemctl stop nginx' [root@server ansible]# ansible-playbook nginx.yml -t startnginx
④ 测试notify 我们还做了一个notify
,来测试一下: 首先,它的触发条件是配置文件被改变,所以我们去把配置文件中的端口改一下:
[root@server ansible]# vim /tmp/nginx.conf listen 8080;
然后我们重新加载一下这个剧本:
发现我们执行的就是reload段以及我们定义的notify
部分。 我们来看一看我们的端口号:
[root@server ansible]# ansible web -m shell -a 'ss -ntlp | grep nginx' 192.168.37.122 | SUCCESS | rc=0 >> LISTEN 0 128 *:8080 *:* users:(("nginx",pid=2097,fd=6),("nginx",pid=2096,fd=6)) 192.168.37.133 | SUCCESS | rc=0 >> LISTEN 0 128 *:8080 *:* users:(("nginx",pid=3061,fd=6),("nginx",pid=3060,fd=6))
可以看出,我们的nginx端口已经变成了8080。
4、variables 部分
上文中,我们说到了variables
是变量,有四种定义方 法,现在我们就来说说这四种定义方法:
① facts :可直接调用
上一篇中,我们有说到setup
这个模块,这个模块就是通过调用facts组件来实现的。我们这里的variables
也可以直接调用facts
组件。 具体的facters
我们可以使用setup
模块来获取,然后直接放入我们的剧本中调用即可。
ansible_all_ipv4_addresses:仅显示ipv4的信息 ---> [u'192.168.95.143'] ansible_eth0['ipv4']['address']:仅显示ipv4的信息 ---> eth0 的ip地址 ansible_devices:仅显示磁盘设备信息 ansible_distribution:显示是什么系统,例:centos,suse等 ansible_distribution_version:仅显示系统版本 ansible_machine:显示系统类型,例:32位,还是64位 ansible_eth0:仅显示eth0的信息 ansible_hostname:仅显示主机名 ansible_kernel:仅显示内核版本 ansible_lvm:显示lvm相关信息 ansible_memtotal_mb:显示系统总内存 ansible_memfree_mb:显示可用系统内存 ansible_memory_mb:详细显示内存情况 ansible_swaptotal_mb:显示总的swap内存 ansible_swapfree_mb:显示swap内存的可用内存 ansible_mounts:显示系统磁盘挂载情况 ansible_processor:显示cpu个数(具体显示每个cpu的型号) ansible_processor_vcpus:显示cpu个数(只显示总的个数) ansible_python_version:显示python版本
例如:批量修改主机 host 文件
--- - hosts: web vars: IP: "{{ ansible_eth0['ipv4']['address'] }}" tasks: - name: 将原有的hosts文件备份 shell: mv /etc/hosts /etc/hosts_bak - name: 将ansible端的hosts复制到各自机器上 copy: src=/root/hosts dest=/etc/ owner=root group=root mode=0644 - name: 在新的hosts文件后面追加各自机器内网ip和hostname lineinfile: dest=/etc/hosts line="{{ IP }} {{ ansible_hostname }} "
② 用户自定义变量
我们也可以直接使用用户自定义变量,想要自定义变量有以下两种方式:
通过命令行传入
ansible-playbook
命令的命令行中的-e VARS, --extra-vars=VARS
,这样就可以直接把自定义的变量传入。
在playbook中定义变量
我们也可以直接在playbook中定义我们的变量:
vars: - var1: value1 - var2: value2
举例
① 定义剧本 我们就使用全局替换把我们刚刚编辑的文件修改一下:
[root@server ansible]# vim nginx.yml
这样一来,我们的剧本就定义完成了。 ② 拷贝配置文件 我们想要在被监管的机器上安装什么服务的话,就直接在我们的server端上把该服务的配置文件拷贝到我们的/tmp/
目录下。这样我们的剧本才能正常运行。 我们就以keepalived
服务为例:
[root@server ansible]# cp /etc/keepalived/keepalived.conf /tmp/keepalived.conf
③ 运行剧本,变量由命令行传入
[root@server ansible]# ansible-playbook nginx.yml -e rpmname=keepalived
④ 修改剧本,直接定义变量 同样的,我们可以直接在剧本中把变量定义好,这样就不需要在通过命令行传入了。以后想要安装不同的服务,直接在剧本里把变量修改一下即可。
[root@server ansible]# vim nginx.yml
⑤ 运行定义过变量的剧本 我们刚刚已经把变量定义在剧本里面了。现在我们来运行一下试试看:
[root@server ansible]# ansible-playbook nginx.yml
发现这样也是可以的~
③ 通过roles传递变量
具体的,我们下文中说到 roles 的时候再详细说明。
④ Host Inventory
我们也可以直接在主机清单中定义。 定义的方法如下:
向不同的主机传递不同的变量:
IP/HOSTNAME varaiable=value var2=value2
向组中的主机传递相同的变量:
[groupname:vars] variable=value
Ansible Inventory 内置参数
使用内置变量把用户名密码写在Inventory中,也就是/etc/ansible/hosts文件里,缺点就是暴露了账号密码,不安全。如果有多个主机需要使用同样的变量,可以用组变量的形式,书写格式如下:
[web] 192.168.100.10 192.168.100.11 192.168.100.12 [web:vars] #给名为webservers的组定义一个变量,:vars是固定格式 ansible_ssh_port=22 ansible_ssh_user='root' ansible_ssh_pass='1234.com'
5、模板 templates
模板是一个文本文件,嵌套有脚本(使用模板编程语言编写)。 Jinja2
:Jinja2是python的一种模板语言,以Django的模板语言为原本。 模板支持:
字符串:使用单引号或双引号; 数字:整数,浮点数; 列表:[item1, item2, ...] 元组:(item1, item2, ...) 字典:{key1:value1, key2:value2, ...} 布尔型:true/false 算术运算: +, -, *, /, //, %, ** 比较操作: ==, !=, >, >=, <, <= 逻辑运算: and, or, not
通常来说,模板都是通过引用变量来运用的。
举例
① 定义模板 我们直接把之前定义的/tmp/nginx.conf
改个名,然后编辑一下,就可以定义成我们的模板文件了:
[root@server ansible]# cd /tmp [root@server tmp]# mv nginx.conf nginx.conf.j2 [root@server tmp]# vim nginx.conf.j2 worker_processes {{ ansible_processor_vcpus }}; listen {{ nginxport }};
② 修改剧本 我们现在需要去修改剧本来定义变量:
[root@server ansible]# vim nginx.yml
需要修改的部分如图所示。
copy模块 也需要修改为 template模块
③ 运行剧本 上面的准备工作完成后,我们就可以去运行剧本了:
[root@server ansible]# ansible-playbook nginx.yml -t reloadnginx PLAY [web] ********************************************************************* TASK [setup] ******************************************************************* ok: [192.168.37.122] ok: [192.168.37.133] TASK [copy nginx.conf] ********************************************************* ok: [192.168.37.122] ok: [192.168.37.133] PLAY RECAP ********************************************************************* 192.168.37.122 : ok=2 changed=0 unreachable=0 failed=0 192.168.37.133 : ok=2 changed=0 unreachable=0 failed=0
6、条件测试
when语句:在task中使用,jinja2的语法格式。 举例如下:
tasks: - name: install conf file to centos7 template: src=files/nginx.conf.c7.j2 when: ansible_distribution_major_version == "7" - name: install conf file to centos6 template: src=files/nginx.conf.c6.j2 when: ansible_distribution_major_version == "6"
循环:迭代,需要重复执行的任务; 对迭代项的引用,固定变量名为"item",而后,要在task中使用with_items给定要迭代的元素列表; 举例如下:
tasks: - name: unstall web packages yum: name={{ item }} state=absent with_items: - httpd - php - php-mysql
跳过错误:
tasks: - name: unstall web packages yum: name=httpd state=absent ignore_errors: yes
7、字典
ansible playbook 还支持字典功能。举例如下:
- name: install some packages yum: name={{ item }} state=present with_items: - nginx - memcached - php-fpm - name: add some groups group: name={{ item }} state=present with_items: - group11 - group12 - group13 - name: add some users user: name={{ item.name }} group={{ item.group }} state=present with_items: - { name: 'user11', group: 'group11' } - { name: 'user12', group: 'group12' } - { name: 'user13', group: 'group13' }
8、角色订制:roles
① 简介
对于以上所有的方式有个弊端就是无法实现复用假设在同时部署Web、db、ha 时或不同服务器组合不同的应用就需要写多个yml文件。很难实现灵活的调用。 roles 用于层次性、结构化地组织playbook。roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量(vars)、文件(file)、任务(tasks)、模块(modules)及处理器(handlers)放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
② 角色集合
角色集合:roles/ mysql/ httpd/ nginx/ files/:存储由copy或script等模块调用的文件; tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用; handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行“包含”调用; vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;其它的文件需要由main.yml进行“包含”调用; templates/:存储由template模块调用的模板文本; meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用; default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;
③ 角色定制实例
1. 在roles目录下生成对应的目录结构
[root@server ansible]# cd roles/ [root@server roles]# ls [root@server roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default} [root@server roles]# tree . ├── httpd │ ├── default │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ ├── templates │ └── vars ├── mysql │ ├── default │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ ├── templates │ └── vars └── nginx ├── default ├── files ├── handlers ├── meta ├── tasks ├── templates └── vars 24 directories, 0 files
2. 定义配置文件 我们需要修改的配置文件为/tasks/main.yml
,下面,我们就来修改一下:
[root@server roles]# vim nginx/tasks/main.yml - name: cp rpm for nginx copy: src=nginx-1.10.2-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm - name: install yum: name=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm state=latest - name: conf template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf tags: nginxconf notify: new conf to reload - name: start service service: name=nginx state=started enabled=true
3. 放置我们所需要的文件到指定目录 因为我们定义的角色已经有了新的组成方式,所以我们需要把文件都放到指定的位置,这样,才能让配置文件找到这些并进行加载。 rpm包放在files
目录下,模板放在templates
目录下:
[root@server nginx]# cp /tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm ./files/ [root@server nginx]# cp /tmp/nginx.conf.j2 ./templates/ [root@server nginx]# tree . ├── default ├── files │ └── nginx-1.10.2-1.el7.ngx.x86_64.rpm ├── handlers ├── meta ├── tasks │ └── main.yml ├── templates │ └── nginx.conf.j2 └── vars 7 directories, 3 files
4. 修改变量文件 我们在模板中定义的变量,也要去配置文件中加上:
[root@server nginx]# vim vars/main.yml nginxprot: 9999
5. 定义handlers文件 我们在配置文件中定义了notify
,所以我么也需要定义handlers
,我们来修改配置文件:
[root@server nginx]# vim handlers/main.yml - name: new conf to reload service: name=nginx state=restarted
6. 定义剧本文件 接下来,我们就来定义剧本文件,由于大部分设置我们都单独配置在了roles里面,所以,接下来剧本就只需要写一点点内容即可:
[root@server ansible]# vim roles/roles.yml - hosts: web remote_user: root roles: - nginx
完成后的目录结构 # tree ./ ./ ├── httpd │ ├── default │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ ├── templates │ └── vars ├── mysql │ ├── default │ ├── files │ ├── handlers │ ├── meta │ ├── tasks │ ├── templates │ └── vars ├── nginx │ ├── default │ ├── files │ │ └── nginx-1.10.2-1.el7.ngx.x86_64.rpm │ ├── handlers │ │ └── main.yml │ ├── meta │ ├── tasks │ │ └── main.yml │ ├── templates │ │ └── nginx.conf.j2 │ └── vars │ └── main.yml └── roles.yml
7. 启动服务 剧本定义完成以后,我们就可以来启动服务了:
[root@server ansible]# ansible-playbook roles.yml PLAY [web] ********************************************************************* TASK [setup] ******************************************************************* ok: [192.168.37.122] ok: [192.168.37.133] TASK [nginx : cp] ************************************************************** ok: [192.168.37.122] ok: [192.168.37.133] TASK [nginx : install] ********************************************************* changed: [192.168.37.122] changed: [192.168.37.133] TASK [nginx : conf] ************************************************************ changed: [192.168.37.122] changed: [192.168.37.133] TASK [nginx : start service] *************************************************** changed: [192.168.37.122] changed: [192.168.37.133] RUNNING HANDLER [nginx : new conf to reload] *********************************** changed: [192.168.37.122] changed: [192.168.37.133] PLAY RECAP ********************************************************************* 192.168.37.122 : ok=6 changed=4 unreachable=0 failed=0 192.168.37.133 : ok=6 changed=4 unreachable=0 failed=0
启动过后照例查看端口号:
[root@server ansible]# ansible web -m shell -a "ss -ntulp |grep 9999" 192.168.37.122 | SUCCESS | rc=0 >> tcp LISTEN 0 128 *:9999 *:* users:(("nginx",pid=7831,fd=6),("nginx",pid=7830,fd=6),("nginx",pid=7829,fd=6)) 192.168.37.133 | SUCCESS | rc=0 >> tcp LISTEN 0 128 *:9999 *:* users:(("nginx",pid=9654,fd=6),("nginx",pid=9653,fd=6),("nginx",pid=9652,fd=6))
可以看出我们的剧本已经执行成功。
九、Ansible使用jinja2管理配置文件以及jinja2语法简介
1、Jinja2介绍
Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity。它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。jinja2使用BSD授权
Jinja2的语法是由variables(变量)和statement(语句)组成,如下;
1、variables:可以输出数据
my_variables
{{ some_dudes_name | capitalize }}
2、statements: 可以用来创建条件和循环等
if语句: {% if my_conditional %} ... {% endif %} for 语句: {% for item in all_items %} `item` …… {% endfor %}
从上面第二个variables的例子中可以看出,jinja2支持使用带过滤器的Unix型管道操作符,有很多的内置过滤器可供使用。我们可以仅仅用一堆简单if和for就可以建立几乎任何的常规配置文件,不过如果你有意更进一步,jinja2 documentation (Jinja — Jinja Documentation (3.2.x))包含了很多有趣的东西可供了解。我们可以看到ansible允许在模板中使用诸如绘制时间此类的一些额外的模板变量
第一个例子:引用变量
# tree . ├── site.yml ├── templates │ └── order.j2 └── vars └── main.yml 2 directories, 3 files
总调度yml文件:
# cat site.yml --- - hosts: 192.168.19.154 user: root vars: - PROJECT: "JAVA" SWITCH: "ON" DBPORT: "8080" tasks: - name: create{{ PROJECT }}directory file: path=/data/{{ PROJECT }} state=directory - name: template transfor java template: src=order.j2 dest=/data/{{ PROJECT }}/order.conf
注意:这里 - role: template 和 - template 是一样的!
其他yml文件,如下:
# cat templates/order.j2 project: {{ PROJECT }} switch: {{ SWITCH }} dbport: {{ DBPORT }} 测试: # ansible-playbook templates.yml --syntax-check playbook: templates.yml 执行: PLAY [192.168.19.154] ********************************************************** TASK [Gathering Facts] ********************************************************* ok: [192.168.19.154] TASK [createJAVAdirectory] ***************************************************** changed: [192.168.19.154] TASK [template transfor java] ************************************************** changed: [192.168.19.154] PLAY RECAP ********************************************************************* 192.168.19.154 : ok=3 changed=2 unreachable=0 failed=0 #cat /data/JAVA/order.conf project: JAVA switch: ON dbport: 8080
第二个例子:for 语句
为远程主机生成服务器列表,加入该列表从192.168.13.201 web01.test.com 到192.168.13.211 web11.test.com 结束,如果手动添加就很不科学了,这里需要使用jinja2语法的for循环通过模板批量生成对应的配置文件,如下:
ansible目录结构:
#cd /etc/ansible/roles/test_hosts . ├── meta │ └── main.yml ├── tasks │ ├── file1.yml │ └── main.yml ├── templates │ └── test1.j2 └── vars └── main.yml
各个目录下yml文件内容:
# cat tasks/file1.yml - name: ansible jinja2 template for hosts config template: src=test1.j2 dest=/etc/httpd/conf/httpd.conf.test # cat tasks/main.yml - include: file1.yml # cat templates/test1.j2 {% for id in range(201,212) %} 192.168.13.{{ id }} web{{ "%02d" |format(id-200) }}.test.com {% endfor %} 解释: {{ id }} 提取for循环中对应的变量id值 "%02d" 调用的是python内置的字符串格式化输出(%d格式化整数)因为是01,02这种格式,所以是保留2位,故用02 然后将结果通过管道符 “|” 传递给format 函数做二次处理。
执行结果:
#cat httpd.conf.test 192.168.13.201 web01.test.com 192.168.13.202 web02.test.com 192.168.13.203 web03.test.com 192.168.13.204 web04.test.com 192.168.13.205 web05.test.com 192.168.13.206 web06.test.com 192.168.13.207 web07.test.com 192.168.13.208 web08.test.com 192.168.13.209 web09.test.com 192.168.13.210 web10.test.com 192.168.13.211 web11.test.com
第三个例子:if语句
说明:如果定义端口号,就绑定定义的端口号,如果不定义端口号,就绑定默认端口号
ansible目录结果 #cd /etc/ansible/roles/mysql_cnf #tree . ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates │ └── test3.j2 └── vars
主要的yml文件是templates目录下面的test3.j2
# cat templates/test3.j2 {% if PORT %} bind_address=10.0.90.27:{{ PORT }} {% else %} bind_address=10.0.90.27:3306 {% endif %}
playbook主文件
# cat jinj2_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: false vars: PORT: 3136 tasks: - name: copy file to client template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf
执行:
# ansible-playbook jinj2_test.yml PLAY [10.0.90.27] ************************************************************** TASK [copy file to client] ***************************************************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=1 changed=1 unreachable=0 failed=0
查看
# cat my.cnf bind_address=10.0.90.27:3136
如果将vars变量去掉,执行结果:
# cat jinj2_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: false vars: PORT: false tasks: - name: copy file to client template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf
查看:
# cat my.cnf bind_address=10.0.90.27:3306
3、Jinja default()设定
精通程序编码的朋友皆知,default()默认值的设定有助于程序的健壮性和简洁性。所幸Jinja也支持该功能,上面的例子中生成Mysql配置文件中的端口定义,如果指定则PORT=3136,否则PORT=3306,我们将该案例改造为使用default()试试
编辑/etc/ansible/roles/mysql_cnf/templates/test3.j2内容如下,这种方法更简介。
bind_address=10.0.90.27:{{ PORT | default(3306) }}
2、ansible使用jinja2生成apache多主机配置
1、创建目录,创建好之后如下:
#cd /etc/ansible/roles/apache_conf # tree ./ ./ ├── meta │ └── main.yml ├── tasks │ ├── file.yml │ └── main.yml ├── templates │ └── apache.config.j2 └── vars └── main.yml 4 directories, 5 files
2、创建tasks调度文件,如下:
#cat file.yml - name: ansible jinja2 template for apache config template: src=apache.config.j2 dest=/etc/httpd/conf/httpd.conf.template #cat main.yml - include: file.yml
3、创建apache的jinja2模板文件,如下:
#cat apache.config.j2 NameVirtualHost *:80 {% for vhost in apache_vhost %} <VirtualHost *:80> ServerName {{ vhost.servername }} DocumentRoot {{ vhost.documentroot }} {% if vhost.serveradmin is defined %} ServerAdmin {{ vhost.serveradmin }} {% endif %} <Directory "{{ vhost.documentroot }}"> AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost> {% endfor %}
4、创建变量,如下:
#cat vars/main.yml apache_vhost: - {servername: "apache.test1.com", documentroot: "/data/test1/"} - {servername: "apache.test2.com", documentroot: "/data/test2/"}
5、创建总调度yml文件,如下:
#cat /etc/ansible/apache_test.yml --- - hosts: 10.0.90.27 user: root gather_facts: no roles: - { role: apache_conf }
6、测试:
#ansible-playbook apache_test.yml --syntax-check playbook: apache_test.yml
7、执行测试
#ansible-playbook apache_test.yml PLAY [10.0.90.27] ************************************************************** TASK [apache_conf : include] *************************************************** included: /etc/ansible/roles/apache_conf/tasks/file.yml for 10.0.90.27 TASK [apache_conf : ansible jinja2 template for apache config] ***************** changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.27 : ok=2 changed=1 unreachable=0 failed=0
8、到客户端查看
#cat httpd.conf.template NameVirtualHost *:80 <VirtualHost *:80> ServerName apache.test1.com DocumentRoot /data/test1/ <Directory "/data/test1/"> AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost> <VirtualHost *:80> ServerName apache.test2.com DocumentRoot /data/test2/ <Directory "/data/test2/"> AllowOverride All Options -Indexes FollowSymLinks Order allow,deny Allow from all </Directory> </VirtualHost>
3、ansible使用jiaja2生成nginx一个模板多种不同配置
说明:为2台Nginx Proxy,1台Nginx Web通过一套模板生成对应的配置
1、ansible目录结构:
# cd roles/nginx_conf/ #tree . ├── files ├── meta │ └── main.yml ├── tasks │ ├── file.yml │ └── main.yml ├── templates │ └── nginx.conf.j2 └── vars └── main.yml
2、tasks目录下文件内容:
#cat tasks/file.yml - name: nginx.j2 template transfer example template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf.template #cat tasks/main.yml - include: file.yml
3、nginx模板文件
#cat templates/nginx.conf.j2 {% if nginx_use_proxy %} {% for proxy in nginx_proxies %} upstream {{ proxy.name }} #server 127.0.0.1:{{ proxy.port }}; server {{ ansible_eth0.ipv4.address }}:{{ proxy.port }}; } {% endfor %} {% endif%} server { listen 80; servername {{ nginx_server_name }}; access_log off; error_log /etc/nginx/nginx_error.log; rewrite ^ https://$server_name$request_uri? permanent; } server { listen 443 ssl; server_name {{ nginx_server_name }}; ssl_certificate /etc/nginx/ssl/{{ nginx_ssl_cert_name }}; ssl_certificate_key /etc/nginx/ssl/{{ nginx_ssl_cert_key }}; root {{ nginx_web_root }}; index index.html index.html; {% if nginx_use_auth %} auth_basic "Restricted"; auth_basic_user_file /etc/nginx/{{ project_name }}.htpasswd; {% endif %} {% if nginx_use_proxy %} {% for proxy in nginx_proxies %} location {{ proxy.location }} { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; proxy_pass http://{{ proxy.name }}; break; } {% endfor %} {% endif %} {% if nginx_server_static %} location / { try_files $url $url/ =404; } {% endif %} }
4、ansible变量文件
cat vars/main.yml nginx_server_name: www.testnginx.com nginx_web_root: /data/html/ nginx_proxies: - name: suspicious location: / port: 1234 - name: suspicious-api location: /api port: 4567
5、ansible主playbook文件
#cat nginx_test.yml ##The first roles - name: Nginx Proxy Server's Config Dynamic Create hosts: "10.0.90.25:10.0.90.26" remote_user: root vars: nginx_use_proxy: true nginx_ssl_cert_name: ifa.crt nginx_ssl_cert_key: ifa.key nginx_use_auth: true project_name: suspicious nginx_server_static: true gather_facts: true roles: - role: nginx_conf ##The second roles - name: Nginx WebServer's Config Dynamic Create hosts: 10.0.90.27 remote_user: root vars: nginx_use_proxy: false nginx_ssl_cert_name: ifa.crt nginx_ssl_cert_key: ifa.crt nginx_use_auth: false project_name: suspicious nginx_server_static: false gather_facts: false roles: - role: nginx_conf
6、测试并执行:
#ansible-playbook nginx_test.yml --syntax-check playbook: nginx_test.yml 执行: # ansible-playbook nginx_test.yml PLAY [Nginx Proxy Server's Config Dynamic Create] ****************************** TASK [setup] ******************************************************************* ok: [10.0.90.25] ok: [10.0.90.26] TASK [nginx_conf : include] **************************************************** included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.25, 10.0.90.26 TASK [nginx_conf : nginx.j2 template transfer example] ************************* changed: [10.0.90.26] changed: [10.0.90.25] PLAY [Nginx WebServer's Config Dynamic Create] ********************************* TASK [nginx_conf : include] **************************************************** included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.27 TASK [nginx_conf : nginx.j2 template transfer example] ************************* changed: [10.0.90.27] PLAY RECAP ********************************************************************* 10.0.90.25 : ok=3 changed=1 unreachable=0 failed=0 10.0.90.26 : ok=3 changed=1 unreachable=0 failed=0 10.0.90.27 : ok=2 changed=1 unreachable=0 failed=0
7、查看检测执行结果
到Nginx Proxy 服务器查看配置文件
#cat nginx.conf.template upstream suspicious #server 127.0.0.1:1234; server 10.0.90.26:1234; } upstream suspicious-api #server 127.0.0.1:4567; server 10.0.90.26:4567; } server { listen 80; servername www.testnginx.com; access_log off; error_log /etc/nginx/nginx_error.log; rewrite ^ https://$server_name$request_uri? permanent; } server { listen 443 ssl; server_name www.testnginx.com; ssl_certificate /etc/nginx/ssl/ifa.crt; ssl_certificate_key /etc/nginx/ssl/ifa.key; root /data/html/; index index.html index.html; auth_basic "Restricted"; auth_basic_user_file /etc/nginx/suspicious.htpasswd; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; proxy_pass http://suspicious; break; } location /api { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Url-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; proxy_pass http://suspicious-api; break; } location / { try_files $url $url/ =404; } }
到Nginx Web 服务器上查看配置文件
#cat nginx.conf.template server { listen 80; servername www.testnginx.com; access_log off; error_log /etc/nginx/nginx_error.log; rewrite ^ https://$server_name$request_uri? permanent; } server { listen 443 ssl; server_name www.testnginx.com; ssl_certificate /etc/nginx/ssl/ifa.crt; ssl_certificate_key /etc/nginx/ssl/ifa.crt; root /data/html/; index index.html index.html; }
到这里,就结束了。用同样的模板通过简单的if和变量设置就可以完成不同类型主机的Nginx conf配置,所以一方面在了解Ansible强大的模板功能的同时,也需要看到模板质量的重要性。
补充:
改配置 vim /etc/vimrc
set ts=2
set nu
set nolist 设置取消隐藏字符
set cursorline
set cursorcolumn
gather_facts: false 不收集远程信息
Ansible 在执行 playbook 时,默认会收集目标主机的一些基本信息,这被称为 facts。这些信息包括操作系统的版本、网络接口、主机名、可用的内存等。
ansible-play 的一些剧本
每写一个剧本,先执行三部曲
三部曲:
优先级
早上:
掌握基本ansible-playbook 用法
template有点问题
nginx.conf 里面用{{a}}
nginx.yml 里面配置
vars:
a: 1等等
使用剧本给其他两个机器安装配置wordpress
安装nginx和php的源
安装nginx和php的包
安装mysql源
启动mysql
修改密码并创建数据库和远程用户
拷贝nginx配置文件
上线代码
启动nginx和php
php80-php-xsl php80-php php80-php-cli php80-php-devel php80-php-gd php80-php-pdo php80-php-mysql php80-php-fpm -y
stty echo 取消回显
when那块没太懂
要巩固一下,整体回顾一下
role角色巩固:
首先ansible-galaxy init mysql 初始化一个mysql目录