Playbook高级技巧进阶

6.1 巧用Includes

     Includes在Ansible中主要起引用功能,其功能非常强大,不仅可以引用Playbook的YML文件,而且Vars、Handlers、Files也支持Includes的引用。

6.1.1 Includes使用场景

     有时,我们发现大量的Playbook内容需要重复编写,各Tasks之间功能需相互调用才能完成各自功能,Playbook庞大到维护困难,这时我们需要使用Includes。

Playbook高级技巧进阶_第1张图片

    该场景中共有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的目录结构如下:

Playbook高级技巧进阶_第2张图片

我们希望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高级技巧进阶_第3张图片

    通过如上方式,我们可以创建一个主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重构后目录结构如下

Playbook高级技巧进阶_第4张图片

Roles模块调用结构如图6-2所示

Playbook高级技巧进阶_第5张图片

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:传输文件到远程主机并修改文件名为英文小写。 Playbook高级技巧进阶_第6张图片

Playbook高级技巧进阶_第7张图片

    Roles的Files功能设计主要针对业务文件传输需求,凡存放于对应的Roles的Files目录下的文件,传输时只需指定相对路径即可,这在很大程度上保证了管理机故障迁移时Ansible的健壮性,同时也从规则上使使用者有意规范自己的文件存放习惯。在企业中不仅会遇到文件传输的需求,对于应用的配置文件,针对不同的主机需要进行相应的变更该怎么办呢?Templates可以满足我们需求。

Playbook高级技巧进阶_第8张图片

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:我们来执行命令并看返回及结果。

Playbook高级技巧进阶_第9张图片

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 %}
最终执行后结果如下:

Playbook高级技巧进阶_第10张图片

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:执行命令

Playbook高级技巧进阶_第11张图片

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文件中配置的主机组。

Playbook高级技巧进阶_第12张图片

  • 第2行使用Python内置join函数格式化代码输出。
  • 第3行loop.last为Jinja2.8版本的内置变量,同类型及功能如下。

Playbook高级技巧进阶_第13张图片

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 }
执行命令:

Playbook高级技巧进阶_第14张图片

如果第二行代码变为如下:

{{ 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


  ServerName apache.magedu.com
  DocumentRoot /data/magedu/
  
    AllowOverride All
    Options -Indexes FollowSymLinks
    Order allow,deny
    Allow from all
  



  ServerName apache.magedu.otherdomain.com
  DocumentRoot /data/otherdomain/
  ServerAdmin [email protected]
  
    AllowOverride All
    Options -Indexes FollowSymLinks
    Order allow,deny
    Allow from all
  

步骤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 }
Playbook高级技巧进阶_第15张图片

- 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)获取命令用法。

Playbook高级技巧进阶_第16张图片

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。









































































你可能感兴趣的:(Ansible)