公司内部紧急会议话题:在两周内完全掌握Ansible入门概述

对于Ansible我完全不懂。

首先

因为有机会在工作中使用Ansible来自动化服务器的构建,我从头开始重新学习了它,所以总结了一些关于Playbook、Inventory以及目录结构等方面的写作方法。
我没有详细说明模块的细节。

這並不是正確的答案,而是依照這樣的方式製作,然後這樣運作的內容進行了有序的解釋。

环境

    • CentOS 7.6 1810

1台でもできるけど、Ansible実行用と処理対象用の複数台あるとわかりやすい

Ansible 2.6 (最新は2.8)

参考书籍

    Ansible実践ガイド第2版 impress top gearシリーズ Kindle版

安装和配置Ansible

虚拟机

如果是为了验证,可以使用VirtualBox和Vagrant来构建基于Ansible验证环境的Vagrant,通过设置多个虚拟机、虚拟机之间的SSH公钥认证和共享文件夹,可以简单地创建所需的最低限度环境。

安装yum

在没有进行任何特别设置的情况下,在CentOS 7.6上执行yum install ansible命令,会安装版本为2.4的Ansible。

通过安装centos-release-ansible26软件包,可以添加针对2.6版本的存储库,然后使用yum来安装Ansible 2.6,因此选择使用这种方式进行安装。

[root@ansible-controller ~]# yum install centos-release-ansible26

然后就会生成这样的文件:/etc/yum.repos.d/CentOS-ANSIBLE.repo

使用yum install ansible命令后,将会安装2.6版本的ansible。

[root@ansible-controller ~]# yum install ansible
[vagrant@ansible-controller ~]$ ansible --version
ansible 2.6.14
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Jun 20 2019, 20:27:34) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
[vagrant@ansible-controller ~]$

Ansible的安装只需要在执行Ansible的服务器上进行,不需要任何处理目标服务器(只要SSH可用)。

对目标节点的SSH访问权限

使用Ansible进行远程服务器的环境配置,需要确保远程服务器可以进行无密码的SSH公钥验证(尽管有些设置不需要,但为了简化ansible和ansible-playbook的执行过程,省略密码可以使操作更简洁)。

鍵設定的概要是使用适用于Ansible验证环境的Vagrant创建虚拟机 – 包括多个虚拟机、虚拟机之间的SSH公钥身份验证设置和共享文件夹。

使用”sudo”命令

当在远程服务器上执行具有root权限的操作时,需要确保sudo可以无需密码就能执行。若是在使用Vagrant创建的虚拟机中使用vagrant用户,则应该无需这一步骤。


如果将构成图示出来的话,会是这样的感觉。

ansible.png

Ansible配置文件

Ansible的配置文件

[defaults]
host_key_checking = False

当首次进行SSH连接时,若在known_hosts中没有SSH服务器的配置,会被询问是否连接到该主机,即使之前没有连接过。但如果事先设置这些配置,就可以被省略。
另外还有日志输出配置和并发处理数量等。

读取设置文件的优先级如下所示。

    1. 通过环境变量ANSIBLE_CONFIG指定的路径文件

 

    1. 当前目录的ansible.cfg

执行用户的~/.ansible.cfg

执行主机的/etc/ansible/ansible.cfg

Ansible配置设置 — Ansible文档

战略手册和库存。

战略规划书

Playbook定义了“做什么”的内容。采用YAML格式。
许多Ansible模块可以组合使用,用于进行软件包安装、配置文件更改等操作。

库存

库存定义了“处理对象是什么”。类似于Windows的ini格式。
可以对目标主机进行分组,或者为每个组定义专有的设置变量。
也可以使用YAML格式在外部文件中进行定义。

最小的构建档案和清单。

虽然称之为最小,但目标有两个,但那就暂且放在一边。

[ansible_practice]
192.168.244.120
192.168.244.121

被pip的VM被记录在库存中。
[ansible_practice]是“组名”,在Playbook中,我们将描述在这个组名中执行任务的目标。
在组名的描述之后,是目标主机的处理。

---
- hosts: ansible_practice
  tasks:
    - ping:

要执行 Ansible Playbook,需要使用 ansible-playbook 命令运行编写在 Playbook 中的任务。
必需参数是 Playbook 文件。可以使用 -i Inventory 文件名 来指定 Inventory 文件(如果未指定,默认使用 /etc/ansible/hosts)。

[vagrant@ansible-controller practice]$ ls
inventory.ini  inventory.yml  playbook.yml
[vagrant@ansible-controller practice]$ ansible-playbook -i inventory.ini playbook.yml

PLAY [ansible_practice] ********************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.244.121]
ok: [192.168.244.120]

TASK [ping] ********************************************************************
ok: [192.168.244.120]
ok: [192.168.244.121]

PLAY RECAP *********************************************************************
192.168.244.120            : ok=2    changed=0    unreachable=0    failed=0
192.168.244.121            : ok=2    changed=0    unreachable=0    failed=0

[vagrant@ansible-controller practice]$

实行结果简要总结将显示在PLAY RECAP部分。

項目意味ok指定の状態にすでになっているため処理されなかった(冪等性)changed指定の状態に変更されたunreachable接続に失敗したfailed処理に失敗した

指定主机名

用主机名指定存货

[ansible_practice]
ansible-controller
ansible-node01

无论是使用DNS还是/etc/hosts进行名称解析都可以,但如果无法解析名称,当然会出现错误……应该是这样的,但最近的CentOS还是Vagrant环境是这样的,仅仅使用主机名时会添加.localhost(这是/etc/resolv.conf中search的设置),而且在同一网段内还有一个神秘的DNS服务器运行,并且返回127.0.0.1,所以即使采用了意外的设置,它仍然可以运行一次。

虽然如此,在解释时很容易偏离主题,但是只需要在Inventory中添加主机变量(host variable),也就是”ansible_host”,将IP地址写入到此行为清单参数(behavioral inventory parameters)中即可。

[ansible_practice]
ansible-controller ansible_host=192.168.244.120
ansible-node01     ansible_host=192.168.244.121

那么,在执行Ansible时,将会将”ansible-node01″的地址处理为”192.168.244.121″。

[vagrant@ansible-controller practice]$ ansible-playbook -i inventory.ini playbook.yml

PLAY [ansible_practice] ********************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-node01]
ok: [ansible-controller]

TASK [ping] ********************************************************************
ok: [ansible-controller]
ok: [ansible-node01]

PLAY RECAP *********************************************************************
ansible-controller         : ok=2    changed=0    unreachable=0    failed=0
ansible-node01             : ok=2    changed=0    unreachable=0    failed=0

[vagrant@ansible-controller practice]$

增加任务

我尝试在这个playbook.yml中添加任务(操作)。

创建目录

尝试使用文件模块创建一个目录。

---
- hosts: ansible_practice
  tasks:
    - ping:

    - file:
        path: /tmp/ansible/practice
        state: directory
        owner: vagrant
        mode: 0755

进行

[vagrant@ansible-controller practice]$ ansible-playbook -i inventory.ini playbook.yml

PLAY [ansible_practice] ********************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-node01]
ok: [ansible-controller]

TASK [ping] ********************************************************************
ok: [ansible-controller]
ok: [ansible-node01]

TASK [file] ********************************************************************
changed: [ansible-controller]
changed: [ansible-node01]

PLAY RECAP *********************************************************************
ansible-controller         : ok=3    changed=1    unreachable=0    failed=0
ansible-node01             : ok=3    changed=1    unreachable=0    failed=0

[vagrant@ansible-controller practice]$

结果 (jié guǒ)

[vagrant@ansible-controller practice]$ ls -al /tmp/ansible/
total 4
drwxr-xr-x.  3 vagrant vagrant   22 Jul 14 00:45 .
drwxrwxrwt. 10 root    root    4096 Jul 14 00:48 ..
drwxr-xr-x.  2 vagrant vagrant    6 Jul 14 00:45 practice
[vagrant@ansible-controller practice]$ ssh 192.168.244.121 ls -al /tmp/ansible/

total 4
drwxr-xr-x.  3 vagrant vagrant   22 Jul 14 00:45 .
drwxrwxrwt. 10 root    root    4096 Jul 14 00:45 ..
drwxr-xr-x.  2 vagrant vagrant    6 Jul 14 00:45 practice

使用yum进行安装,并获取root权限。

从这里开始,尝试使用yum安装Ruby软件包。

---
# - hosts: ansible_host=192.168.244.121
- hosts: ansible_practice
  tasks:
    - ping:

    - file:
        path: /tmp/ansible/practice
        state: directory
        owner: vagrant
        mode: 0755

    - yum:
        name: ruby
        state: present

如果你是聪明的人,我相信你会注意到的,…

[vagrant@ansible-controller practice]$ ansible-playbook -i inventory.ini playbo
ok.yml

PLAY [ansible_practice] ********************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-node01]
ok: [ansible-controller]

TASK [ping] ********************************************************************
ok: [ansible-controller]
ok: [ansible-node01]

TASK [file] ********************************************************************
ok: [ansible-controller]
ok: [ansible-node01]

TASK [yum] *********************************************************************
fatal: [ansible-node01]: FAILED! => {"changed": false, "msg": "You need to be root to perform this command.\n", "rc": 1, "results": ["Loaded plugins: fastestmirror\n"]}
fatal: [ansible-controller]: FAILED! => {"changed": false, "msg": "You need to be root to perform this command.\n", "rc": 1, "results": ["Loaded plugins: fastestmirror\n"]}
        to retry, use: --limit @/ansible/practice/playbook.retry

PLAY RECAP *********************************************************************
ansible-controller         : ok=3    changed=0    unreachable=0    failed=1
ansible-node01             : ok=3    changed=0    unreachable=0    failed=1

[vagrant@ansible-controller practice]$

由于没有根权限,操作失败。
另外,前一步骤的文件创建已经是”ok”状态(因为已经处于该状态,所以没有进行其他处理)。具备冪等性。

要以root身份运行,需要指定become(默认为false)。
将become设为true,将默认以root身份运行。
要以become以root权限运行,必须在主机上配置sudo su -可以无需密码以root身份启动shell。

---
- hosts: ansible_practice
  become: true
  tasks:
    - ping:

    - file:
        path: /tmp/ansible/practice
        state: directory
        owner: vagrant
        mode: 0755

    - yum:
        name: ruby
        state: present
[vagrant@ansible-controller practice]$ ansible-playbook -i inventory.ini playbook.yml

PLAY [ansible_practice] ********************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-node01]
ok: [ansible-controller]

TASK [ping] ********************************************************************
ok: [ansible-controller]
ok: [ansible-node01]

TASK [file] ********************************************************************
ok: [ansible-controller]
ok: [ansible-node01]

TASK [yum] *********************************************************************
changed: [ansible-node01]
changed: [ansible-controller]

PLAY RECAP *********************************************************************
ansible-controller         : ok=4    changed=1    unreachable=0    failed=0
ansible-node01             : ok=4    changed=1    unreachable=0    failed=0

[vagrant@ansible-controller practice]$

已安装了Ruby。

[vagrant@ansible-controller practice]$ ruby --version
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]
[vagrant@ansible-controller practice]$ ssh 192.168.244.121 ruby --version
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]
[vagrant@ansible-controller practice]$

通过名字来说明任务

在执行ansible-playbook时,只会输出所使用的模块名称,例如file和yum,导致很难明确知道具体执行了什么。为了方便在执行时进行确认,可以通过在任务的name中简洁地描述任务的内容。

    - name: create directory
      file:
        path: /tmp/ansible/practice
        state: directory
        owner: vagrant
        mode: 0755

    - name: install ruby package
      yum:
        name: ruby
        state: present

发挥力量

TASK [create directory] ********************************************************
ok: [ansible-controller]
ok: [ansible-node01]

TASK [install ruby package] ****************************************************
ok: [ansible-node01]
ok: [ansible-controller]

PLAY RECAP *********************************************************************
ansible-controller         : ok=4    changed=0    unreachable=0    failed=0
ansible-node01             : ok=4    changed=0    unreachable=0    failed=0

安装Apache并更改端口号以及启用服务。

相当常见的一些小例子

- hosts: ansible_practice
  become: true
  tasks:
    - name: install httpd server
      yum:
        name: httpd
        state: present

    - name: configure httpd server
      replace:
        path: /etc/httpd/conf/httpd.conf
        regexp: ^#?Listen 80$
        replace: Listen 8080

    - name: enable httpd service
      systemd:
        name: httpd
        state: restarted
        enabled: yes

使用正则表达式进行文件编辑时的注意事项

    - name: configure httpd server
      replace:
        path: /etc/httpd/conf/httpd.conf
        regexp: Listen 80
        replace: Listen 8080

如果写成这样的话…
第一次执行

- Listen 80
+ Listen 8080

在更新并执行两次后,regexp:Listen 80仍然与此行匹配,所以这次是指

- Listen 8080
+ Listen 808080

执行时需要注意排除重复的情况。在进行重复执行时,需要注意排除的对象。 (例如,在这个例子中,可以使用`^ $`来明确表示行首和行尾等)。

设置Inventory文件的配置

团体

到目前为止,我们只使用了[ansible_practice]组,但是当然可以定义多个组,并且可以将某个节点(处理目标主机)设置为多个组。

[ansible_practice]
ansible-controller ansible_host=192.168.244.120
ansible-node01     ansible_host=192.168.244.121

[php-server]
ansible-node01

如果这样写,[ansible_practice]组将包括ansible-controller和ansible-node01,而[php-server]组只包含ansible-node01。

ansible-node01同时包含在[ansible_practice]和[php-server]两个群组中。

简而言之,如果在Playbook中将hosts指定为ansible_practice,那么该Playbook将在ansible-controller和ansible-node01上执行;而如果指定为php-server,那么该Playbook将只在ansible-node01上执行。

顺便说一下,使用ansible_host进行IP地址指定似乎只需要在第一次使用即可。

库存变量

在使用Ansible进行处理的内容基本上都会写到Playbook中,但是针对不同的环境会创建多个Inventory文件,因为不同的环境有不同的设置……比如在环境A中,web服务器使用8080/TCP运行,而在环境B中使用8888/TCP运行,等等……虽然可以为每个环境准备一份Playbook,但任务除了端口号之外的内容是相同的,所以如果能够将端口号作为变量写入Inventory文件中就很方便了吧。(对吧?)

Playbook是共通的,在Inventory中,变量的定义位于以下形式的[组名:vars]之后。
Playbook是共通的,在Inventory中,变量定义应位于以下[组名:vars]之后。

[ansible_practice]
ansible-controller ansible_host=192.168.244.120
ansible-node01     ansible_host=192.168.244.121

[ansible_practice:vars]
http_port=8080
[ansible_practice]
ansible-controller ansible_host=172.16.10.10
ansible-node01     ansible_host=172.16.10.11

[ansible_practice:vars]
http_port=8888

通过在[ansible_practice:vars]部分进行配置,您可以在处理组[ansible_practice]时,使用变量名http_port来引用值。

根据此变量的引用,我们可以修改前面提到的处理web服务器端口号重写的Playbook,以实现与环境无关的描述,大概可以这样做。

    - name: configure httpd server
      replace:
        path: /etc/httpd/conf/httpd.conf
        regexp: ^#?Listen [0-9]+$
        replace: Listen {{ http_port }}

现在,通过将之前在Playbook中硬编码的配置值提取到Inventory变量中,我们可以根据不同的环境执行ansible-playbook,对于环境A,使用inventory-a.ini文件,对于环境B,使用inventory-b.ini文件,从而构建各自的环境。

顺便说一下,不写在组名中,而写在[all:vars]中,也可以定义与组无关的可引用值。也就是所谓的全局变量。

将 Inventory 变量外部化为文件。

由于可以将Inventory变量定义为key=value形式的ini文件,所以对于单个设置是没有问题的。但是无法表达列表(数组)或映射(哈希・字典)格式。

例如,用户可以列举 “/etc/hosts” 的主机和IP地址清单(数量不确定),或者列举通过 iptables 允许的目标端口号清单,还可以列举在 DHCP 服务器上为特定客户端设置固定地址时的MAC地址和IP地址对。

在这种情况下,您可以在Playbook或Inventory文件的相同目录下创建group_vars/组名.yml文件,并在其中以YAML格式编写任意设置,从而使Playbook可以引用该文件。

使用`with_items`和YAML格式的Inventory变量进行循环处理。

[smbserver]
ansible-node01

在group_vars目录下创建与Inventory文件中的组名同名的YAML文件。

---
shared_folder:
  - name: logs
    comment: log directory
    path: /opt/logs
    create_mask: "0644"
    directory_mask: "0755"
    writable: "no"
    browseable: "no"
  - name: share
    comment: shared directory
    path: /share
    create_mask: "0664"
    directory_mask: "0775"
    writable: "yes"
    browseable: "yes"

在有此Inventory文件的情况下,定义Playbook如下。

- hosts: smbserver
  become: true
  tasks:
    - name: install samba server
      yum:
        name: samba
        state: present

    - name: configure samba server
      blockinfile:
        path: /etc/samba/smb.conf
        marker: "# {mark} {{ item.name }} configuration by ansible"
        block: |
          [{{ item.name }}]
                  comment = {{ item.comment }}
                  path = {{ item.path }}
                  create mask = {{ item.create_mask }}
                  directory mask = {{ item.directory_mask }}
                  writable = {{ item.writable }}
                  browseable = {{ item.browseable }}
      with_items: '{{ shared_folder }}'

当使用这个ansible-playbook进行执行时,/etc/samba/smb.conf的相关部分如下所示。

# BEGIN logs configuration by ansible
[logs]
        comment = log directory
        path = /opt/logs
        create mask = 0660
        directory mask = 0770
        writable = no
        browseable = no
# END logs configuration by ansible
# BEGIN share configuration by ansible
[share]
        comment = shared directory
        path = /share
        create mask = 0644
        directory mask = 0755
        writable = yes
        browseable = yes
# END share configuration by ansible

通过在任务中使用with_items来指定一个数组形式的变量,可以在循环内部(在with_items上方的代码块中)使用{{ item }}作为变量名进行引用。

在编程语言中,可以类比为 foreach(var item in shared_folder) { … },它们的功能是相同的。(在循环中,变量名item是固定的)

ansible _ with_items (2).png

在上述的配置中,shared_folder的元素是以地图形式的,如name、comment等,因此可以使用{{ item.comment }}等来引用每个设置值。

有关blockinfil模块,请参考文档。

使用with_items的循环不仅可以引用在Inventory变量中定义的数组,还可以在现场定义的列表进行循环处理。语法如下所示。

      with_items:
        - foo
        - bar
        - baz

在循环的块内,将{{ item }}替换为foo、bar、baz,每次循环都会产生不同的结果。

※ 自Ansible 2.5版本之后,通过with_X(如with_items)循环处理已被替换为loop。

将任务分割为角色

在此之前的例子中,Playbook的内容如下所示。

    • ping

 

    • ディレクトリ作成

 

    • rubyのyumインストール

 

    • httpdのyumインストール

 

    • httpd.confの編集

 

    • httpdサービスの有効化

 

    • sambaのyumインストール

 

    smb.confの設定

这些内容都被写在了playbook.yml文件中,类似于编程中的main()函数中包含了所有的处理过程,这种状态非常不好维护和阅读(特别是考虑到未来可能会增加更多的处理内容)。

在编程中,我们可以为每个处理单元创建函数,并从main()函数中调用它们。同样地,Playbook也可以使用Role来实现同样的目的。

将main()函数或其他函数化只是作者个人的感觉和比喻。

表达成图像的话就是如下这种感觉

ansible _ role.png

创建角色

试着将httpd的安装、配置和服务设置分离为角色。
在Playbook中将任务创建为角色的文件是roles/角色名/tasks/main.yml。

---
- name: install httpd server
  yum:
    name: httpd
    state: present

- name: configure httpd server
  replace:
    path: /etc/httpd/conf/httpd.conf
    regexp: ^#?Listen [0-9]+$
    replace: Listen {{ http_port }}

- name: enable httpd service
  systemd:
    name: httpd
    state: restarted
    enabled: yes

同样的,安装Samba。

---
- name: install samba server
  yum:
    name: samba
    state: present

- name: configure samba server
  blockinfile:
    path: /etc/samba/smb.conf
    marker: "# {mark} {{ item.name }} configuration by ansible"
    block: |
      [{{ item.name }}]
              comment = {{ item.comment }}
              path = {{ item.path }}
              create mask = {{ item.create_mask }}
              directory mask = {{ item.directory_mask }}
              writable = {{ item.writable }}
              browseable = {{ item.browseable }}
  with_items: '{{ shared_folder }}'

- name: enable samba service
  systemd:
    name: smb
    state: restarted
    enabled: yes

角色的引用(调用)

从Playbook中调用所创建的Role。
就像函数调用一样。

- hosts: wwwserver
  become: true
  roles:
    - install_httpd

- hosts: smbserver
  become: true
  roles:
    - install_samba

就像函数调用一样,当然也可以从多个地方调用。

例如,在上述情况中,将web服务器和samba服务器分别放在不同的组中,但即使在”为了热备份准备一台服务器,并在一台服务器上运行web/samba”的情况下,也可以使用相同的角色,只需更改清单和Playbook。

- hosts: wwwserver
  become: true
  roles:
    - install_httpd

- hosts: smbserver
  become: true
  roles:
    - install_samba

- hosts: standby
  become: true
  roles:
    - install_httpd
    - install_samba

可以按照以下方式进行。
在这种情况下,通过将web服务器的端口号设置为group_vars/wwwserver.yml中的http_port: 8080,并将group_vars/standby中的http_port: 28080来修改备用服务器的配置。

模块

在Ansible中,已经默认提供了各种模块。
无论是操作系统的配置更改、软件包管理还是更新配置文件等,通常都可以通过组合模块来实现。应该是这样的。

简要解释一下

贝壳

执行shell命令于目标主机 – Ansible文档

执行Linux命令。然而,它不能保证幂等性(不会检查执行是否是必要的),因此在执行前需要添加检查任务或进行适当调整。

首先,我们可以尝试寻找一个可以实现所需命令的模块。作为寻找模块的方法,从类别页面开始搜索也是一个不错的选择。

image.png

在这个搜索框中输入命令(如果没有正确匹配的话,可以使用相关关键词),然后进行搜索,如果有的话会出现合适的模块。

image.png

如果有点击,可以查看模块说明页面的「参数」和「示例」,大概就能解决(很抱歉,只是个大概)。

模板

使用Python的模板引擎Jinja2,能够将模板文件通过Inventory变量等定义的变量进行替换,并将文件复制到目标服务器中。

与replace和lineinfile等文件更改处理不同,不需要过多考虑幂等性,因此简化了操作。

如果设置文件的修改部分大部分不是简单的键值对形式,使用模板可能更容易。

作为例子,DHCP服务器(dhcp-4.2.5-68.el7.centos.1.x86_64)的设定。

option domain-name "ansible.practice.localhost";
option domain-name-servers 192.168.244.120;
default-lease-time 3600;
max-lease-time 86400;
ddns-update-style none;
log-facility local7;

subnet 192.168.244.0 netmask 255.255.255.0 {
        option subnet-mask 255.255.255.0;
        option broadcast-address 192.168.244.255;
        option routers 192.168.244.1;
        range 192.168.244.60 192.168.244.99;
}

host client01 {
  hardware ethernet 00:00:5e:00:53:01;
  fixed-address 192.168.244.31;
}
host client02 {
  hardware ethernet 00:00:5e:00:53:02;
  fixed-address 192.168.244.32;
}

如果想创建这样一个文件的话…

option domain-name "{{ domain_name }}";
option domain-name-servers {{ dns }};
default-lease-time 3600;
max-lease-time 86400;
ddns-update-style none;
log-facility local7;

subnet {{ network_addr }} netmask {{ subnet_mask }} {
        option subnet-mask {{ subnet_mask }};
        option broadcast-address {{ broadcast }};
        option routers {{ gateway }};
        range {{ range_begin }} {{ range_end }};
}

{% for host in hosts_conf %}
host {{ host.name }} {
  hardware ethernet {{ host.hwaddr }};
  fixed-address {{ host.fixedaddr }};
}
{% endfor %}

将模板文件放置在tasks目录的同一级别下创建一个templates目录,并在其中以.j2扩展名进行配置。

---
- name: install dhcp server
  yum:
    name: dhcp
    state: present

- name: configure dhcp server
  template:
    src: dhcpd.conf.j2
    dest: /etc/dhcp/dhcpd.conf
    owner: root
    group: root
    mode: "0644"

在`role`中使用`template`模块来指定模板文件(.j2),通过`src`参数指定文件路径。如果不指定路径,将默认使用`templates`目录作为基准。

---
domain_name: ansible.practice.localhost
dns: "192.168.244.120"

network_addr: "192.168.244.0"
subnet_mask: "255.255.255.0"
broadcast: "192.168.244.255"
gateway: "192.168.244.1"
range_begin: "192.168.244.60"
range_end: "192.168.244.99"

hosts_conf:
  - name: client01
    hwaddr: 00:00:5e:00:53:01
    fixedaddr: "192.168.244.31"
  - name: client02
    hwaddr: 00:00:5e:00:53:02
    fixedaddr: "192.168.244.32"

下面是作为模板文件参数的Inventory变量的示例。
通过这个,模板文件中的{{ network_addr }}的部分将被替换为192.168.244.0。

在模板中使用for语法可以对所定义的hosts_conf列表进行循环处理。

{% for host in hosts_conf %}

{% endfor %}

与with_items固定项相比,使用模板可以自由设置循环内的变量(例如上面的例子中的host)。

整个文件架构

.
├── ansible.cfg
├── group_vars
│   ├── dhcpserver.yml
│   ├── smbserver.yml
│   └── wwwserver.yml
├── inventory.ini
├── playbook.yml
└── roles
    ├── install_dhcpd
    │   ├── tasks
    │   │   └── main.yml
    │   └── templates
    │       └── dhcpd.conf.j2
    ├── install_httpd
    │   └── tasks
    │       └── main.yml
    └── install_samba
        └── tasks
            └── main.yml
广告
将在 10 秒后关闭
bannerAds