playbook
6.1 巧用Includes
Includes在Ansible中主要起引用功能,其功能非常强大,不仅可以引用Playbook的YML文件,而且Vars、handlers、Files也支持Includes的引用。
6.1.1 Includes使用场景
有时,我们发现大量的Playbook内容需要重复编写,各Tasks之间功能需相互调用才能完成各自功能,Playbook庞大到维护困难,这时我们需要使用Includes。
该场景中共有A、B、C、D、E、F这6个Project(项目),但均需使用Restart PHP Process功能,此时,我们可以把Restart PHP Process功能作为单独的Playbook文件独立出来,以方便其他项目Includes(引用),而不必每个项目都重新写Restart PHP Process功能,这种场景下就需要使用Includes。
我们一起看下具体如何实现。
1)RestartPHPProcess.yml的配置如下:
---
- hosts: phpserver
remote_user: root #远程主机执行用户为root
tasks:
- name: RestartPHPProcess #该Task名为RestartPHPProcess
service: name=php-fpm state=restarted
2)A Project的配置如下:
---
- hosts: phpserver
remote_user: root
tasks:
- name: A Project command
command: A Project command
- name: RestartPHPProcess
hosts: phpserver
remote_user: root
tasks:
- include: RestartPHPProcess.yml
6.1.2 Includes用法
案例:Ansible结合Git完成指定版本的拉取及项目目录初始化。Includes在Playbook中使用方式很简单,格式也非常简洁,请参考如下的代码:
tasks:
- include: included-playbook.yml
其中,included-playbook.yml的内容如下:
---
- name: Add profile info for user.
copy:
src: example_profile
dest: "/home/{{ username }}/.profile"
owner: "{{ username }}"
group: "{{ username }}"
mode: 0744
- name: Add private keys for user.
copy:
src: "{{ item.src }}"
dest: "/home/.ssh/{{ item.src }}"
owner: "{{ username }}"
group: "{{ username }}"
mode: 0600
with_items: ssh_private_keys
- name: Restart example service.
service: name=example state=restarted
- name: create dir
# file模块,用于设置文件属性
file: path={{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}
-{{ project }} owner=www group=www mode=0755 recurse=yes state=directory
#这些任务负责检出git变量
- name: git pull
git: repo={{ repository_static }} dest={{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }} version= "{{ git_commit }}"
- name: Git init before git pull
command: /usr/bin/git fetch
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
- name: Git reset
command: /usr/bin/git reset --hard
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
- name: Git checkout
command: /usr/bin/git checkout {{ git_commit }}
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
在这个案例中,included-playbook.yml做了下面几件事情:
1)初始化用户环境变量;
2)添加key认证
3)重启服务
4)递归初始化git文件存放目录并设置目录属主属组为www.www;
5)Git pull指定版本的git库至指定目录;
6)Git checkout最新指定至指定目录。
该案例完成这样一件任务:新安装系统的服务器,初始化程序用户并添加key认证,结束后分发程序软件包至指定目录。这其中使用了很多变量,"{{}}"中的内容均为变量。可以利用Includes再次分割。我们将其分别拆分为如下几个文件。
1)user-config.yml:完成用户初始化工作。
---
- name: Add profile info for user.
copy:
src: " example_profile"
dest: "/home/{{ username }}/.profile"
owner: "{{ username }}"
group: "{{ username }}"
mode: 0744
- name: Add private keys for user.
copy:
src: "{{ item.src }}"
dest: "/home/.ssh/{{ item.dest }}"
owner: "{{ username }}"
group: "{{ username }}"
mode: 0600
with_items: ssh_private_keys
- name: Restart example service
service: name=example state=restarted
2)create_dir.yml:完成目录初始化工作
---
# 这些任务负责检出git变量
- name: create_dir
file: path={{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}
owner=www group=www mode=0755 recurse=yes state=directory
3)static_git_pull.yml:完成拉取git代码工作。
---
# 这些任务负责检出git变量
- name: Git pull
git: repo={{ repository_static }} dest={{ package_dir }}{{ project }}-release-{{ git_commit }}
/{{ flag }}-{{ project }} version= "{{ git_commit }}" force=yes
4)git_checkout.yml: 完成git初始化即指定版本拉取工作。
---
# 这些任务负责检出git变量
- name: Git init before git pull
command: /usr/bin/git fetch
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
- name: Git reset
command: /usr/bin/git reset --hard
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
- name: Git checkout
command: /usr/bin/git checkout {{ git_commit }}
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
将如上模块通过Includes模块再次封装,我们重命名新的Playbook名为Sysinit.yml。
5)Sysinit.yml: 完成所有任务的调度和执行工作。
---
- include: user-config.yml
vars:
username: johndoe
ssh_private_keys:
- { src: /path/to/johndoe/key1, dest: id_rsa }
- { src: /path/to/johndoe/key2, dest: id_rsa_2 }
- include: user-config.yml
vars:
username: janedoe
ssh_private_keys:
- { src: /path/to/janedoe/key1, dest: id_rsa }
- { src: /path/to/janedoe/key2, dest: id_rsa_2 }
- include: ./create_dir.yml
- include: ./static_git_pull.yml
- include: ./git_checkout.yml
6.1.3 动态Includes
# 引用附加的任务,该任务只在运行时有效
- name: Check if extra_tasks.yml is present.
stat: path=extras/extra-tasks.yml # 判断extras目录下extra-tasks.yml文件是否存在,获取状态返回值
register: extra_tasks_file
connection: local
- include: tasks/extra-tasks.yml # 结合如下when条件,只有当extra_tasks_file文件存在时在加载include
when: extra_tasks_file.stat.exists
6.1.4 Handler Includes使用技巧
Ansible Handler结合Notify主要用于当资源状态发生变化时一次性地执行指定操作。Handlers也支持Includes功能,用法和Tasks的调用方式一样,只是要写在Handlers区域。
举个简单的例子。
roles/logsync/handlers的目录结构如下:
我们希望main.yml引用epel.yml和syncinstall.yml,通过如下方式即可实现:
---
- include: epel.yml # 引用epel.yml文件
- include: syncinstall.yml # 引用syncinstall.yml文件
6.1.5 Playbooks Includes使用技巧
Ansible同样允许Playbook Includes Playbook,使用方式与Task、Handlers一样,下面示例可供参考:
通过如上方式,我们可以创建一个主Playbook文件,通过Includes加载其他独立的Playbook,当我们需要执行全部命令时,只要通过一条命令执行主Playbook文件即可,如希望针对某功能变更,执行对应的Playbook文件即可。
6.2 巧用Roles
Roles是Ansible1.2版本新加入的功能,字面意思是角色,可以理解为:有相互关联功能的集合。相对Includes功能,Roles更适合大项目Playbook的编排架构。简而言之,Ad-Hoc适用于临时命令的执行,Playbook适合中小项目,而大项目一定使用Roles。Roles不仅支持Tasks的集合,同时包括vars_files、tasks、handlers、meta、templates。
6.2.1 构建Roles
Roles主要依赖于目录的命名和摆放,默认tasks/main.yml是所有任务的入口,所以使用Roles的过程可以理解为目录规范化的过程。如下两个目录就可以构建Ansible Roles。
role_name/
meta/
tasks/
每个目录下均由main.yml定义该功能的任务集,tasks/main.yml默认执行所有指定的任务。Roles的调用文件playbook_role.yml的内容如下:
---
- hosts: all
roles:
- role_name
Role执行方法如下:
ansible-playbook playbook_role.yml
Roles目录可以摆放在/etc/ansible/ansible.cfg中"roles_path"定义的路径,也可以和入口playbook文件存放在同级目录,Ansible对此没有强制要求。
6.2.2 使用Roles重构Playbooks
Roles严重依赖目录命名规则和目录摆放,Roles重构后目录结构如下
Roles模块调用结构如图6-2所示
1)group_vars/all文件:定义roles变量,编辑内容如下。
---
# 以下列出的变量对所有主机和组有效,即全局有效
flag: king
javaflag: java
tech: php
damn: '-'
git: git
svn: svn
package_dir: /srv/deploy/
project_dir: /srv/www/
project: cp
group_vars目录下的文件定义Roles中调用的变量,Roles对应调用该目录同名文件中定义的变量,文件名为all的文件定义的变量针对所有Roles生效。
2)userconf.yml文件:设置调用Roles的git模块,编辑内容如下。
---
# 该playbook用于初始化用户配置
- hosts: localhost
remote_user: root
roles:
- role: git
roles为关键字,role:git表示调用roles的git模块。如希望同时调用图6-2中的user模块,于该行下同级别对齐添加如下配置即可。
- role: user
如需继续添加功能,方式一样。
3)roles/git/tasks/main.yml文件:设置调用git模块实现的功能,编辑内容如下。
---
- import_playbook: create_dir.yml
- import_playbook: static_git_pull.yml
- import_playbook: git_checkout.yml
在新版本中ansible2.4中,include用import_playbook替换:http://docs.ansible.com/ansible/latest/playbooks_reuse_includes.html
4)create_dir.yml、git_checkout.yml、static_git_pull.yml文件:设置我们希望完成的具体功能。具体代码如下,部分代码会做解释。
create_dir.yml代码如下:
---
- hosts: localhost
tasks:
- name: create_dir
file:
path: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
owner: www
group: www
mode: 0755
recurse: yes
state: directory
{{ }}在Ansible中表示变量引用,create_dir.yml要实现的功能是递归创建目录并定义目录属主、属组为www用户。
static_git_pull.yml的作用是拉取指定的git版本至指定目录。代码如下:
---
- hosts: localhost
tasks:
- name: Git pull
git:
repo: "{{ repository_static }}"
dest: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
version: "{{ git_commit }}"
force: yes
git_checkout.yml实现Git项目初始化,Checkout最新代码至指定目录。代码如下:
---
- hosts: localhost
tasks:
- name: Git init before git pull
command: /usr/bin/git fetch
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
- name: Git reset
command: /usr/bin/git reset --hard
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
- name: Git checkout
command: /usr/bin/git checkout {{ git_commit }}
args:
chdir: "{{ package_dir }}{{ project }}-release-{{ git_commit }}/{{ flag }}-{{ project }}"
6.2.3 Roles技巧之Handlers:动态变更
Roles不仅支持Tasks调用,同时支持vars、files、handlers、meta、templates的调用。本节介绍Handlers在Roles中的使用技巧。
Handlers通常和Notify搭配使用,当(文件、进程、返回等)状态有变换时,Notify会通过Handlers做指定的变更。我们通过一个功能完整的Roles来整体了解Vars、Files、Handlers、Meta、Templates,然后逐步深入Roles Handlers用法。请看示例example.yml:
site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
example.yml为大家展示了两个功能齐全的Roles,分别为common和webservers,每个Roles均包括files、templates、tasks、handlers、vars、defaults、meta。在Playbooks中的调用方式如下:
---
- hosts: webservers
roles:
- common
- webservers
了解了Roles支持的功能集和调用方式后,我们再来了解这些功能集的含义。
- roles/x/tasks/main.yml:主函数,包括在其中的所有任务将被执行
- roles/x/handlers/main.yml:所有包括在其中的handlers将被执行
- roles/x/vars/main.yml:所有包括在其中的变量将在roles中生效。
- roles/x/meta/main.yml:roles所有依赖将被正常登入。
- roles/x/{files,templates,tasks}/(dir depends on task):所有文件、模板都可存放在这里
案例场景:当Apache的配置文件发生变化时重启Apache进程。
步骤1:编排Roles目录结构如下。
roles
└── apache
├── handlers
│ └── main.yml
└── tasks
├── main.yml
└── restart.yml
步骤2:编辑roles/apache/handlers/main.yml的内容如下。
---
# sleep 10s
- name: restart apache
service: name=apache state=restarted
该YML要实现的功能非常简单:重启Apache进程。
步骤3:编辑roles/apache/tasks/restart.yml内容如下。
---
#- hosts: localhost
# tasks:
- name: transfer apache config
copy:
src: "httpd.conf"
dest: "/opt/apache/httpd.conf"
notify:
- restart apache
该YML功能为更新Apache配置文件,如配置文件有变化则重启Apache。
步骤4:编辑roles/apache/tasks/main.yml内容如下。
---
- hosts: localhost
tasks:
- import_tasks: restart.yml
步骤5:编辑Roles同级目录apache.yml文件,内容如下。
---
- hosts: webserver
remote_user: root
roles:
role: apache
该YML为总调度文件,完成Apache配置文件的变更和Apache的重启工作。
步骤6:执行命令ansible-playbook apache.yml,验证结果。
命令运行结果为更新Apache配置文件,如配置文件有更新则重启Apache,如无错误返回为正常。
6.2.4 Roles技巧之files:文件传输
Files和Templates均用于Ansible文件处理,两者主要区别是:Files(不是file模块)目录下的文件无需写绝对路径即可将文件传输至远程主机;Templates目录下的文件以Jinja2渲染,且传输文件至远程主机的同时支持预定义变量替换。接下来我们看Roles中Files的使用方式。
案例场景:将example role下的MAGEDU.PPT和STANLEY.PPT两个文件传输至远程,并修改文件名为英文小写。
步骤1:编排目录结构如下。
.
├── file.yml
└── roles
└── example
├── files
│ ├── MAGEDU.PPT
│ └── STANLEY.PPT
└── tasks
├── file.yml
└── main.yml
步骤2:依次创建文件MAGEDU.PPT、STANLEY.PPT。
MAGEDU.PPT内容如下:
This is magedu.ppt file.
STANLEY.PPT内容如下:
This is stanley.ppt file.
步骤3:依次编辑./file.yml、./roles/example/tasks/file.yml、./roles/example/tasks/main.yml。
./file.yml内容如下:
---
# 该playbook是整个项目的调度入口
- hosts: 192.168.230.100
remote_user: root
gather_facts: false
roles:
- role: example
./roles/example/tasks/file.yml内容如下:
---
- name: file change example
# copy: src=MAGEDU.PPT dest=/data/magedu.ppt owner=root group=root
copy:
src: "{{ item.src }}"
dest: "/data/{{ item.dest }}"
owner: root
group: root
with_items:
- { src: 'MAGEDU.PPT',dest: 'magedu.ppt' }
- { src: 'STANLEY.PPT',dest: 'stanley.ppt' }
.roles/example/tasks/main.yml内容如下:
---
- import_tasks: file.yml
步骤4:传输文件到远程主机并修改文件名为英文小写。Roles的Files功能设计主要针对业务文件传输需求,凡存放于对应的Roles的Files目录下的文件,传输时只需指定相对路径即可,这在很大程度上保证了管理机故障迁移时Ansible的健壮性,同时也从规则上使使用者有意规范自己的文件存放习惯。在企业中不仅会遇到文件传输的需求,对于应用的配置文件,针对不同的主机需要进行相应的变更该怎么办呢?Templates可以满足我们需求。
6.2.5 Roles技巧之Templates:模板替换
Templates常被用作传输文件,同时支持预定义变量替换。因Templates由Jinja2渲染格式,Jinja2官网http://jinja.pocoo.org/
案例场景:将order.j2分发至远程主机/data/{{ PROJECT }}/目录下,并改名为order.conf,且替换配置文件中变量为对应的值。
步骤1:编排目录如下:
.
├── roles
│ └── template
│ ├── tasks
│ │ ├── main.yml
│ │ └── template.yml
│ ├── templates
│ │ └── order.j2
│ └── vars
│ └── main.yml
└── template.yml
步骤2:依次编辑template.yml(和roles目录同级)任务总调度文件。
---
# 该playbook是整个项目的调度入口
- hosts: 192.168.230.100
remote_user: root
gather_facts: false
roles:
- role: template
该YML文件是任务总调用文件,主要指定远程主机、执行用户、调用的roles等,相当于"总指挥"的角色。
步骤3:依次编辑roles/template/tasks/{main.yml,template.yml}任务定义文件。
编辑main.yml内容如下:
---
- import_tasks: template.yml
编辑template.yml内容如下:
---
- name: template transfer example
template: src=order.j2 dest=/data/{{ PROJECT }}/order.conf
{{ PROJECT }}的变量引用文件即本节伊始提到的Jinja2格式。源文件是order.j2,远程目录及目的文件名分别是/data/{{ PROJECT }}/和order.conf。
步骤4:编辑roles/template/templates/order.j2,定义模板文件。
project: {{ PROJECT }}
switch: {{ SWITCH }}
dbport: {{ DBPORT }}
步骤5:编辑roles/template/vars/main.yml,定义变量。
---
PROJECT: "JAVA"
SWITCH: "ON"
DBPORT: "3306"
步骤6:我们来执行命令并看返回及结果。
6.2.6 更多复杂的跨平台Roles
Ansible支持多平台甚至windows(client)。linux开源版本多,且各版本间应用管理、进程启动等命令不尽相同.
案例场景:为Debian、Redhat两种类型的系统安装Apache服务。
步骤1:编辑inventory文件/etc/ansible/hosts。
[cross-platform]
192.168.37.162 ansible_ssh_user="stanley"
192.168.37.159
需要注意的是,192.168.37.162为Debian系统平台,我们默认使用非root用户,因为Ansible获取主机信息(gather_facts)是在执行Tasks前进行的,同时Redhat系统平台使用的用户是root,所以我们需要预先定义执行用户,不然会因为使用错误的用户导致认证失败。
步骤2:针对不同的系统平台分别编辑httpd_db、httpd_rh的Role。
roles/httpd_db/tasks/{httpd.yml,main.yml}内容如下:
# httpd.yml
---
- name: ubuntu install httpd
remote_user: stanley
apt: name=Mini-httpd state=present
# main.yml
---
- import_tasks: httpd.yml
roles/httpd_rh/tasks/{httpd.yml,main.yml}内容如下:
# httpd.yml
---
- name: centos install httpd
remote_user: root
yum: name=httpd state=latest
# main.yml
---
- import_tasks: httpd.yml
步骤3:编辑httpd.yml任务调度文件。
---
- name: cross-platform install httpd
hosts: cross-platform
roles:
- { role: httpd_db,when: ansible_os_family == 'Debian' }
- { role: httpd_rh,when: ansible_os_family == 'Redhat' }
最后的安装过程很简单,执行如下命令即可。
ansible-playbook httpd.yml
6.3 Jinja2实现模板高度自定义
6.3.1 Jinja2 For循环
{% for item in all_items %}
{{ item }}
{% endfor %}
案例场景:为远程主机生成服务器列表,该列表从192.168.37.201 web01.magedu开始,到192.168.37.211 web11.magedu结束。
{% for id in range(201,211) %}
192.168.37.{{ id }} web{{ "%02d"|format(id-200) }}.magedu
{% endfor %}
最终执行后结果如下:
6.3.2 Jinja2 If条件
案例场景:生成mysql配置文件,如果人工指定监听端口则配置为指定端口(预设1331),否则为默认端口即3306.
步骤1:我们编排目录结构如下。
.
├── mysqlconf.yml
└── roles
└── mysqlconf
└── templates
└── mycnf.j2
该目录结构中,我们只定义了Templates而没有定义Tasks,Ansible也支持这样的方式,只是mysqlconf这个role的功能不全而已,但不影响其正常使用。我们本次的Tasks调度配置在mysqlconf.yml文件中。接下来我们看该文件的配置。
步骤2:配置mysqlconf.yml,配置如下。
---
- hosts: localhost
gather_facts: no
vars:
PORT: 1331
tasks:
- template: src=roles/mysqlconf/templates/mycnf.j2 dest=/etc/mycnf.conf.yml
该YML文件调用mysqlconf这个role下的mycnf.j2的template,并将其传输至远程主机192.168.230.100的/etc下后,改名为mycnf.conf.yml。
步骤3:编辑roles/mysqlconf/templates/mycnf.j2模板文件。
{% if PORT %}
bind-address=0.0.0.0:{{ PORT }}
{% else %}
bind-address=0.0.0.0:3306
{% endif %}
该代码的含义是,如果变量PORT被存在,则bind-address=0.0.0.0:{{PORT变量的值}},否则,bind-address=0.0.0.0:3306.
步骤4:执行命令
6.3.3 Jinja多值合并
{% for node in groups["db"] %}
{{ node|join("") }}:5672
{% if not loop.last %}
{% endif %}
{% endfor %}
这段代码因为涉及Jinja和Ansible的内置变量,这里对部分代码做一下解释,
- 第1行代码中groups为Ansible的内置变量,同类型的内置变量如表6-1所示。中括号里的db为Inventory文件中配置的主机组。
http://jinja.pocoo.org/docs/2.10/
我们看下该命令执行方式及结果,编排目录如下:
.
├── join.yml
└── roles
└── join
└── templates
└── list.j2
roles/join/templates/list.j2内容如下:
{% for node in group["db"] %}
{{ node | join("") }}:5672
{% if not loop.last %}
{% endif %}
{% endfor %}
编辑join.yml内容如下:
---
- hosts: db
gather_facts: no
vars:
PORT: 1331
tasks:
- template: src=roles/join/templates/list.j2 dest=/data/list.txt
roles:
- { role: join }
执行命令:
如果第二行代码变为如下:
{{ node | join("-") }}:5672
输出结果:
[root@users 6.3.3]# ansible-playbook join.yml
PLAY [db] **********************************************************************
TASK [template] ****************************************************************
changed: [192.168.230.100]
PLAY RECAP *********************************************************************
192.168.230.100 : ok=1 changed=1 unreachable=0 failed=0
[root@users 6.3.3]# cat /data/list.txt
1-9-2-.-1-6-8-.-2-3-0-.-1-0-0:5672
6.3.4 Jinja default()设定
default()默认值的设定有助于程序的健壮性,所幸Jinja也支持该功能,如6.3.2生成MySQL配置文件中的端口定义,如果指定则PORT=1331,否则PORT=3306.可以将该案例改造为使用default()。
编辑roles/mysqlconf/templates/mycnf.j2,内容如下:
bind-address=0.0.0.0:{{ PORT | default(3306) }}
6.3.5 Ansible结合Jinja2生成Nginx配置
案例场景:为2台Nginx Proxy、1台Nginx Web通过一套模板生成对应的配置。
步骤1:编排目录如下。
├── nginxconf.yml
└── roles
└── nginxconf
├── tasks
│ ├── file.yml
│ └── main.yml
├── templates
│ └── nginx.conf.j2
└── vars
└── main.yml
步骤2:编辑nginxconf role的tasks调度文件roles/nginxconf/tasks/{file.yml,main.yml}。
编辑file.yml,定义nginxconf role的一个功能集(一个文件一个功能集)。
编辑main.yml
步骤3:定义nginxconf role的模板文件roles/nginxconf/templates/nginx.conf.j2,该模板的灵活性将直接影响Ansible-playbook的代码行数和整体Playbook的灵活性健壮性,该模板文件将被替换变量后生成最终的Nginx配置文件。
步骤4:编辑nginxconf role的变量文件roles/nginxconf/vars/main.yml。
该变量文件需要关注的是nginx_proxies定义的变量组,其下的变量列表通过for循环读取后可以通过"."来引用,即如下proxy.name这样的引用方式。
{% for proxy in nginx_proxies %}
upstream {{ proxy.name }} {
# server 127.0.0.1:{{ proxy.port }};
步骤5:编辑总调度文件nginxconf.yml。
在nginxconf.yml文件中,同样我们也定义了nginx_use_proxy、nginx_ssl_cert_name、nginx_ssl_cert_key、nginx_use_auth、project_name、nginx_server_static等变量,同时不同类型的主机定义的不同变量生成的配置也不尽相同,Ansible的灵活性可见一斑。
步骤6:验证结果。
执行命令如下:
ansible-playbook nginxconf.yml
6.3.6 Ansible结合Jinja2生成Apache多主机配置
案例场景:通过Ansible的Jinja模板,生成如下的Apache多主机配置
NamevirtualHost *:80
<VirtualHost *:80>
ServerName apache.magedu.com
DocumentRoot /data/magedu/
<Directory "/data/magedu/">
allowoverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName apache.magedu.otherdomain.com
DocumentRoot /data/otherdomain/
ServerAdmin [email protected]
<Directory "/data/otherdomain/">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
步骤1:编排目录结构如下。
.
├── apacheconf.yml
└── roles
└── apacheconf
├── tasks
│ ├── file.yml
│ └── main.yml
├── templates
│ └── apache.conf.j2
└── vars
└── main.yml
步骤2:编辑apacheconf role的tasks调度文件roles/apacheconf/tasks/{file.yml,main.yml}。
编辑file.yml,内容如下:
编辑main.yml,内容如下:
步骤3:定义apacheconf role的模板文件roles/apacheconf/templates/apache.conf.j2。内容如下:
步骤4:编辑apacheconf role的变量文件roles/apacheconf/vars/main.yml。
步骤5:编辑总调度文件apacheconf.yml。
步骤6:验证结果。
6.3.7 Jinja2动态变量配置及架构优化
场景案例:我们希望将变量通过命令行传递给Playbook,当param1定义的时候,myvariable=param1及value1。
当param1、param2定义的时候,myvariable=value1,value2。
当param1、param2、param3定义的时候,myvariable=value1,value2,value3。
按常规思路,通过如下命令即能完成功能所需:
ansible-playbook playbook.yml -e "param1=value1 param2=value2 param3=value3"
步骤1:编排myrole目录。
├── myrole.yml
└── roles
└── myrole
├── templates
│ └── myvar.j2
└── vars
└── main.yml
步骤2:编辑模板文件roles/myrole/templates/myvar.j2和创建空变量文件。
myvariable: {{ myvariable }}
创建空变量文件。
mkdir roles/myrole/vars/ && touch roles/myrole/vars/mian.yml
步骤3:编辑总调度文件myrole.yml。- name : Test var
hosts : 192.168.230.100
gather_facts : no
vars:
myvariable: "{{[param1|default(''), param2|default(''), param3|default('')]|join(',')}}"
tasks:
- debug:
var=myvariable
- template: src=roles/myrole/templates/myvar.j2 dest=/data/main.yml
roles:
- { role: myrole }
- name : Test var
hosts : 192.168.230.100
gather_facts : no
vars:
myvariable : false
tasks:
- name: param1
set_fact:
myvariable: "{{param1}}"
when: param1 is defined
- name: param2
set_fact:
myvariable: "{{ param2 if not myvariable else myvariable + ',' + param2 }}"
when: param2 is defined
- name: param3
set_fact:
myvariable: "{{ param3 if not myvariable else myvariable + ',' + param3 }}"
when: param3 is defined
- name: default
set_fact:
myvariable: "default"
when: not myvariable
- debug:
var=myvariable
- template: src=roles/myrole/templates/myvar.j2 dest=/data/main.yml
roles:
- { role: myrole }
6.4 Ansible Galaxy
Galaxy是Ansible官方Roles分享平台,在Galaxy平台上所有人可以免费上传和下载Roles,在这里好的技巧、思想、架构得以积累和传播。
6.4.1 Ansible-galaxy命令用法
Ansible-galaxy是Ansible系列工具之一,主要用于管理galaxy.ansible.com的Roles,默认下载的Roles存放于/etc/ansible/roles目录下,可在/etc/ansible/ansible.cfg中自定义存放目录。其命令用法如下。
1)获取命令用法。
2)Ansible-galaxy有init、info、install、list、remove方法,用法如下。
init:创建空Roles,用于向galaxy.ansible.com上传代码。Usage: ansible-galaxy init [options] role_name
info:显示Roles的版本号、作者、下载次数、Commit信息、版本依赖等详细信息。Usage: ansible-galaxy info [options] role_name[,version]。如显示manala.mysql这个Role的详细信息,命令用法为:ansible-galaxy info manala.mysql
install:安装Roles,Usage:ansible-galaxy install [options] [-r FILE | role_name(s)[,version] | tar_file(s)]。如ansible-galaxy install manala.mysql
list:列出本地已安装的所有Roles。Usage:ansible-galaxy list [role_name]
remove: 移除本地指定的Roles。Usage:ansible-galaxy remove role1 role2...
6.4.2 使用Galaxy
(1)下载Roles
https://galaxy.ansible.com/explore#/多维度划分Roles的下载使用情况,如最流行、下载量最多、最新上架、最多贡献者等。https://galaxy.ansible.com/list#/roles?page=1&page_size=10可根据所需关键字搜索。Galaxy上的Roles命名规范遵循username.rolename。所以下载我们使用:
ansible-galaxy install username.rolename
如需同时下载多个Roles,可将所需Roles写入配置文件后,使用-r批量下载Roles,如:
# roles.txt
user1.role1,v1.0.0
user2.role2,v0.5
user2.role3
使用Ansible-galaxy批量安装Roles。
ansible-galaxy install -r roles.txt
另外,从Ansible1.8后开始,Galaxy支持从其他源下载、指定下载路径、Roles安装命名等高级下载功能,该功能可以通过编写YML文件实现。官方案例摘录如下:
# install_roles.yml
# 从galaxy下载
- src: yatesr.timezone
# 从Github下载
- src: https://GitHub.com/bennojoy/nginx
# 从GitHub下载安装到本机的相对路径下
- src: https://GitHub.com/bennojoy/nginx
path: vagrant/roles/
# 从GitHub下载指定版本的源码
- src: https://GitHub.com/bennojoy/nginx
version: master
name: nginx_role
# 从Web下载服务器,打包为tar.gz压缩包形式的源码
- src: https://some.webserver.example.com/files/master.tar.gz
name: http-role
# 如果bitbucket网站可用,从bitbucket站点下载
- src: git+http://bitbucket.org/willthames/git-ansible-galaxy
version: v1.4
# 从bitbucket网站下载
- src: http://bitbucket.org/willthames/hg-ansible-galaxy
scm: hg
安装Roles:
ansible-galaxy install -r install_roles.yml
(2)删除从Galaxy下载的Roles
删除的方式很简单,可以手动至/etc/ansible/roles/删除指定的目录即可。Ansible-galaxy也提供了专门的删除命令:ansible-galaxy remove role1 role2...。
如先来查看本地下载的所有Roles。
ansible-galaxy list ...
删除
ansible-galaxy remove ...
(3)上传分享自己的优秀Roles
想上传自己的Roles需要满足如下几个条件。
- 正常访问Internet,能正常打开http://www.GitHub.com、http://galaxy.ansible.com。
- 开通了GitHub账户。
- 编写好遵循Galaxy标准规范的Roles。