Linux云计算 |【第二阶段】AUTOMATION-DAY6

主要内容:

Ansible进阶(firewalld模块、template模块、语法:error、handlers、when条件判断、block任务块、loop循环)、Ansible Role基本概念、Roles标准规范、管理Anisble Role

一、ansible应用案例(进阶)

案例要求:

  • 1)熟悉firewalld和template模块(识别变量)的使用
  • 2)熟悉error处理机制(ignore_error)
  • 3)熟悉handlers任务(notify通知)
  • 4)熟悉when条件判断
  • 5)熟悉block任务块(block、rescue、always)
  • 6)熟悉loop循环的使用方法

1、firewalld模块

  • 使用firewalld模块可以配置防火墙策略

帮助:ansible-doc firewalld

[root@control ansible]# vim ~/ansible/firewall.yml
---
- hosts: test
  tasks:
    - name: install firewalld.    //任务1描述,安装firewalld
      yum:                     //调用yum模块安装软件
        name: firewalld         //需安装的软件名称为firewalld
        state: present          //state: present代表安装软件
    - name: run firewalld.       //任务2描述,运行firewalld
      service:                  //调用service模块启动服务
        name: firewalld        //启动的服务名称为firewalld
        state: started         //state: started代表启动服务
        enabled: yes          //enabled: yes是设置服务为开机自启
#### 以上任务已安装firewalld,已运行firewalld可忽略 ####
    - name: set firewalld rule.   //任务描述,设置防火墙规则
      firewalld:       //调用firewalld模块设置防火墙规则
        port: 80/tcp   //在防火墙规则中添加一个放行tcp,80端口的规则
        permanent: yes    //permanent 是设置永久规则
        immediate: yes    //immediate 是让规则立刻生效
        state: enabled     //state等于enabled是添加防火墙规则,相反disabled
[root@control ansible]# ansible-playbook firewall.yml
[root@node1 ~]# firewall-cmd --list-all     //验证
public (active)
  ports: 80/tcp
...

补充:临时规则,可不加 permanent

补充:不指定被控制端的防火墙区域,默认修改的为当前区域

2、template模块

1)copy模块

可以将一个文件拷贝给远程主机,但用户希望每个拷贝的文件内容都不一样(涉及变量),例如给所有web主机拷贝index.html内容是各自的IP地址,则需要用到template模块。

  • copy模块与template模块语法与作用一样,区别是copy模块拷贝文件中的变量是不识别的,template模块拷贝的变量会识别
  • 补充:Ansible可以利用Jinja2模板引擎读取变量,之前在playbook中调用变量也是Jinja2的功能,Jinja2模块的表达式包含在分隔符"{{ }}"内。

2)template模块

参数:src指定需要拷贝的源文件,dest指定需要拷贝的目标位置

帮助:ansible-doc template

例如:给webserver主机拷贝index.html文件并放到/tmp/目录,要求每个文件内容不同(facts变量)

[root@control ansible]# vim ~/ansible/index.html    //准备测试的源文件
Welcome to {{ansible_hostname}} on {{ ansible_eth0.ipv4.address }}.

[root@control ansible]# vim ~/ansible/template.yml
---
- hosts: webserver
  tasks:
    - name: use template copy index.html to webserver.  //任务描述,需要调用template模块
      template:
           src: ~/ansible/index.html   //相对或绝对路径都可以,保证能找到文件
           dest: /tmp/index.html
[root@control ansible]# ansible-playbook template.yml
[root@node3 ~]# cat /tmp/index.html      //验证
Welcome to node3 on 192.168.4.13.
[root@node4 ~]# cat /tmp/index.html      //验证
Welcome to node4 on 192.168.4.14.

解释说明:

# {{ansible_hostname}}和{{ ansible_eth0.ipv4.address }}是ansible自动的facts变量

# src参数: 指定源,~/ansible/index.html是在控制端创建的测试源文件,文件包含变量

# dest参数: 指定目标,将源文件拷贝到被控制端目标主机放在/tmp目录下

3、Ansible高级语法应用

应用案例:error、handles、when、block、loop

3.1 error 错误处理

默认ansible在遇到error会立刻停止playbook;假设一个剧本里有20个任务,执行到第3个时失败,则不再往下执行任务;(使用ignore_errors可忽略错误任务,继续后续的任务);

参数:ignore_errors关键词,针对某个任务或全局任务忽略错误(取决于关键词位置)


示例1:

① 测试Playbook执行一个错误任务,查看执行的意外中断效果

[root@control ansible]# vim ~/ansible/error.yml
---
- hosts: test
  tasks:
    - name: start a service that does not exit.
      service:
        name: hehe     //启动一个不存在的服务hehe,测试error报错
        state: started
    - name: touch a file.
      file:
        path: /tmp/service.txt
        state: touch
[root@control ansible]# ansible-playbook error.yml

结果:执行成功任务1次,错误任务1次,执行到错误任务立刻停止playbooky,所以中断了后续的touch任务;

② 测试Playbook,执行时因为忽略了错误(针对某一个任务),不会被中断。

[root@control ansible]# vim ~/ansible/error.yml
---
- hosts: test
  tasks:
    - name: start a service that does not exit.
      service:
        name: hehe     //启动一个不存在的服务
        state: started
      ignore_errors: true   //ignore_errors是关键词,针对某一个任务忽略错误
    - name: touch a file.
      file:
        path: /tmp/service.txt
        state: touch
[root@control ansible]# ansible-playbook error.yml

结果:执行成功任务3次(包括默认任务、改变任务、忽略任务),错误任务0次,执行到被针对的错误任务后被忽略,并执行后续的touch任务;

注意:ignore_errors 需要与 service任务为同一层级,才能实现忽略service任务错误效果

示例2:

测试Playbook,执行时因为忽略了错误(针对所有任务),不会被中断

[root@control ansible]# vim ~/ansible/error.yml
---
- hosts: test
  ignore_errors: true     //针对playbook全局忽略错误(位置不同,实现效果不同)
  tasks:
    - name: start a service that does not exit.
      service:
        name: hehe
        state: started
    - name: touch a file.
      file:
        path: /tmp/service.txt
        state: touch
[root@control ansible]# ansible-playbook error.yml

结果:执行成功任务3次(包括默认任务、改变任务、忽略任务),错误任务0次,针对全局的所有错误任务都会被忽略,并执行后续的touch任务;

注意:ignore_errors需要与tasks为同一层级,且要在tasks任务前,才能实现忽略全局任务错误效果

 

3.2 handlers

在剧本中 tasks用来定义任务(一定会执行),handlers也可以定义任务(不一定执行),handlers任务要想执行必须要被notify通知触发才能执行。

  • 可以通过 handlers定义一组任务,仅当某个任务触发 (notify)handlers时,才执行相应的任务,如果有多个notify触发执行 handlers任务,也仅执行一次。
  • handlers 任务在所有其他 tasks任务都执行完成后才执行。
  • 仅当任务的执行状态为 changed时,handlers任务才执行。
[root@control ansible]# vim ~/ansible/handlers.yml
---
- hosts: test
  tasks:
    - name: create directory.
      file:       //调用file模块创建目录
         path: /tmp/parents/subdir/   //指定创建的具体目录名称
         state: directory    //state=directory代表创建目录
      notify: touch file   //notify后面名称必须和handlers中的任务name名称一致
  handlers:      //通过handlers再定义一组任务
    - name: touch file   //任务描述,内容需要与notify对应
      file:
         path: /tmp/parents/subdir/new.txt
         state: touch
[root@control ansible]# ansible-playbook handlers.yml

注意:handlers与tasks需要在同一层级,notify与file任务为同一个层级;

注意:notity通知后面的名称,必须和handlers下面name描述定义的任务名称一致(名称可以任意)

补充:第一次执行playbook成功后任务状态是changed,下次执行playbook时,根据幂等性,任务状态将不再是changed;由于notify实现条件必须是仅当file模块执行成功并且状态为changed时才会通过notify触发执行handlers下面的任务,所以多次执行该剧本时,handlers任务不会被重复执行。


常见报错:当handlers下面定义的任务名称与notify通知的名称不一致,则报错

3.3 when条件判断

  • when可以定义判断条件,条件为“真”时,才执行某个任务(类似shell中的while)
  • 常见条件操作符:==、!=、>、>=、
  • 多个条件可以使用and(并且)或or(或者)分割;
  • 注意:when表达式中调用变量不要使用{{ }}

例如1:远程node1主机,当系统剩余内存不足700M则关闭httpd.service服务

[root@node1 ~]# free -h     //查看node1当前内存剩余空间(570M<700M)
              total        used        free      shared  buff/cache   available
Mem:          979Mi       192Mi       570Mi       6.0Mi       216Mi       641Mi
Swap:            0B          0B          0B
[root@control ansible]# vim ~/ansible/when_1.yml
---
- hosts: test
  tasks:
    - name: check memory size.
      service:
        name: httpd.service
        state: stopped
      when: ansible_memfree_mb < 700   //注意:调用变量不要使用{{}}
[root@control ansible]# ansible-playbook when_1.yml

注意:when与service任务需要是同一个层级

解释说明:

# ansible_memfree_mb 是 ansible自带的 facts变量,代表剩余内存的容量。

补充:设置内存ansible_memfree_mb 当when条件不满足时,则跳过任务(skipping)


例如2:远程node1主机,判断操作系统是RedHat8则创建测试文件(使用and连接多个条件)

[root@control ansible]# ansible test -m setup | less     //查看facts变量
[root@control ansible]# vim ~/ansible/when_2.yml
---
- hosts: test
  tasks:
    - name: touch a file
      file:
        path: /tmp/when.txt
        state: touch
      when: >        //YAML的语法格式中>支持多行输入
        ansible_distribution == "RedHat"    //判断是否是红帽操作系统RedHat
        and
        ansible_distribution_major_version == "8"  //判断是否是8版本
[root@control ansible]# ansible-playbook when_2.yml
[root@node1 ~]# ls /tmp/when.txt    //验证
/tmp/when.txt

解释说明:

# YAML的语法格式中>支持多行输入,但不保留换行符(计算机会认为实际是一行内容)

# ansible_distribution和ansible_distribution_major_version都是自带的facts变量

# 当when的两个条件(“and且”)都成立时,则执行对应的file任务;

3.4 block任务块

当用户满足条件并需要执行N个任务时,可给N个任务后面都加when判断(但很麻烦),此时可使用block定义一个任务块,当条件满足时执行整个任务块(任务组);

  • block任务块,将把多个任务合并为一个任务组(对于block任务块,可使用rescue语句定义在block任务执行失败时要执行的其他任务,还可使用always语句定义无论block任务是否成功,都要执行的任务)
  • rescue关键字,字面意思为"救援",表示当block中的任务执行失败时,会执行rescue中的任务进行补救;
  • always关键字,无论block中的任务执行成功还是失败,always中的任务都会被执行;

例如1:判断远程的目标主机的Linux发行版本是否是RedHat,当满足条件再执行任务组中的任务

[root@control ansible]# vim ~/ansible/block_1.yml
---
- hosts: test
  tasks:
    - name: define a group of tasks.
      block:        //block是关键词,定义任务组
        - name: install httpd.     //任务组中的第一个任务
          yum:       //调用yum模块安装httpd软件包
            name: httpd
            state: present
        - name: start httpd.      //任务组中的第二个任务
          service:     //调用service模块启动httpd服务
            name: httpd
            state: started
      when: ansible_distribution == "RedHat"
[root@control ansible]# ansible-playbook block_1.yml

注意:when和block是在同一个层级,当条件满足时执行的是block任务组(不是某一个任务)

补充:当when条件满足时,假设执行的其中一个任务失败,也会执行另一个任务


例如2:包含block任务块、rescue、always执行任务的判断条件示例

  • 情况1:当block默认任务成功时,就会在/tmp/目录下创建test1.txt,所以不执行rescue;
  • 情况2:当block默认任务失败时,就执行rescue任务,创建test2.txt;
  • 情况3:不管block任务是否成功都会执行always任务,创建test3.txt;
[root@control ansible]# vim ~/ansible/block_2.yml
---
- hosts: test
  tasks:
    - block:
        - name: touch a file test1.txt
          file:
             name: /tmp/test1.txt 
             state: touch
      rescue:
        - name: touch a file test2.txt
          file:
             name: /tmp/test2.txt
             state: touch
      always:
        - name: touch a file test3.txt
          file:
             name: /tmp/test3.txt
             state: touch
[root@control ansible]# ansible-playbook block_2.yml
[root@node1 ~]# ls /tmp/test?.txt    //验证
/tmp/test1.txt  /tmp/test3.txt

结果:block的任务执行成功,rescue的任务不执行,always不管block是否成功都执行

注意:block、rescue、always在同一个层级

例如3:当block中有两个任务,其中一个任务失败,一个任务成功,block依旧会以任务失败报错,执行rescue任务;若在失败任务加上ignore_errors,rescue不会执行;

[root@control ansible]# vim block_2.yml
---
- hosts: test
  tasks:
    - block:
        - name: touch a file failed test.txt
          file:
             name: /tmp/1/test.txt  //假设修改为/tmp/1/test.txt测试无法创建成功
             state: touch
        - name: touch a file test1.txt
          file:
             name: /tmp/test1.txt
             state: touch
      rescue:
        - name: touch a file test2.txt
          file:
             name: /tmp/test2.txt
             state: touch
      always:
        - name: touch a file test3.txt
          file:
             name: /tmp/test3.txt
             state: touch

结果:block的其中一个任务失败,则不执行,rescue的任务执行,always的任务执行;

[root@control ansible]# vim block_2.yml
---
- hosts: test
  tasks:
    - block:
        - name: touch a file failed test.txt
          file:
             name: /tmp/1/test.txt
             state: touch
          ignore_errors: yes      //忽略错误任务
        - name: touch a file test1.txt
          file:
             name: /tmp/test1.txt
             state: touch
      rescue:
        - name: touch a file test2.txt
          file:
             name: /tmp/test2.txt
             state: touch
      always:
        - name: touch a file test3.txt
          file:
             name: /tmp/test3.txt
             state: touch

结果:block的其中一个任务失败并被忽略,不影响另一个任务执行,rescue的任务不执行,always的任务执行;

3.5 loop循环

相同模块需要反复被执行,使用loop循环可以避免重复添加模块(类似shell中的for)

  • 【-】表示一个数组,loop循环定义的值为数组;
  • item是关键字,调用loop循环的值;
  • loop是关键词,定义循环的值

例如1:编写Playbook,循环创建目录

[root@control ansible]# vim ~/ansible/simple_loop.yml
---
- hosts: test
  tasks:
     - name: mkdir multi directory.
       file:
          path: /tmp/{{item}}    //item是关键字,调用loop循环的值
          state: directory
       loop:    // loop是关键词,定义循环的值,下面是具体的值(值有多少则循环几次)
          - School
          - Legend
          - Life
[root@control ansible]# ansible-playbook simple_loop.yml

注意:loop循环需要与哪一个模块在同一层级,就能对模块实现循环;

[root@node1 ~]# ls /tmp/    //验证,/tmp目录下创建3个子目录,file模块被循环执行3次
Legend
Life
School

解释说明:

# item是关键字,调用loop循环的值;

# loop是关键词,定义循环的值

例如2:编写Playbook,循环创建用户并设置密码

[root@control ansible]# vim ~/ansible/complex_loop.yml
---
- hosts: test
  tasks:
     - name: create multi user.
       user:
          name: "{{item.iname}}"
          password: "{{item.ipass | password_hash('sha512')}}"
       loop:
          - { iname: 'tom' , ipass: '123456' }     //定义一个数组,执行一次循环
          - { iname: 'jerry' , ipass: '123321' }
[root@control ansible]# ansible-playbook complex_loop.yml

[root@node1 ~]# id tom   //验证
uid=1004(tom) gid=1004(tom) groups=1004(tom)
[root@node1 ~]# id jerry
uid=1005(jerry) gid=1005(jerry) groups=1005(jerry)

[root@node1 ~]# tail -2 /etc/shadow    //验证
tom:$6$BpLPPtmYV5sZWb6/$bLSmhlZEyqqteLiCv85UeGV4597lmPBAwUzD.FrelOLN7aS.zyTcIjK5AZ1HxPqn0o7SvAl80.B2yz.iwyw2Z.:18743:0:99999:7:::
jerry:$6$et8wbhTs.UkzfcWV$R/HI453zOXwpK.4XGVE.q7Ubiqv57HyfchugLnv7tqhMzJGsQth1hUfYcVAA0b ZOd.K18q6rtgcwLZu5XUJM3.:18743:0:99999:7:::

解释说明:

loop循环第一次调用user模块创建用户,创建用户时会读取loop里面的第一个值。

  1. loop第一个值(数组)里面有两个子值,iname和ipass
  2. 创建用户item.iname就是loop第一个值里面的iname=tom
  3. 修改密码item.ipass就是loop第一个值里面的ipass=123456

loop循环第二次调用user模块创建用户,创建用户时会读取loop里面的第二个值。

  1. loop第二个值(数组)里面有两个子值,iname和ipass
  2. 创建用户item.iname就是loop第二个值里面的iname=jerry
  3. 修改密码item.ipass就是loop第二个值里面的ipass=123321

二、Ansible Roles

安装包:rhel-system-roles //提供了默认的roles,通过README文件还可查看Playbook案例

案例要求:

  • 1)自定义Ansible Role
  • 2)编写playbook调用role
  • 3)使用ansible-galaxy管理Roles

Ansible Roles应用场景:在实际生产环境中,为了实现不同的功能,用户会编写大量的playbook文件,而且每个playbook还可能会调用其他文件(如变量文件),对于海量的、无规律的文件管理起来非常困难。Ansible从1.2版本开始支持Role(角色)

Role(角色)是管理ansible文件的一种规范(目录结构),Role(角色)会按照标准的规范,自动到特定的目录和文件中读取数据。

创建了一个名称为user.example的Role(角色),则其标准的目录结构如下图所示:

Roles规范的目录结构及主要文件/目录的作用:

  • - defualts/main.yml:定义变量的缺省值,优先级较低
  • - files目录:存储静态文件的目录,如tar包、音乐、视频等
  • - handlers/main.yml:定义handlers
  • - meta/main.yml:写作者、版本等描述信息
  • - README.md:整个角色(role)的描述信息
  • - tasks/main.yml:定义任务的地方
  • - templates目录:存放动态数据文件的地方(文件中包含了变量的模板文件)
  • - vars/main.yml:定义变量,优先级高

Role应用案例1:

1)创建Roles

案例目的:编写一个包含变量的模板文件,编写任务调用template模块,将模板文件拷贝给被管理端主机的/etc/issue文件。

命令:ansible-galaxy     //可以创建、管理自己的roles;

选项:init 初始化

[root@control ansible]# mkdir ~/ansible/roles     //创建一个存放“角色”的目录
[root@control ansible]# ansible-galaxy init ~/ansible/roles/issue     //创建一个名称为issue的Role(角色)即目录
- /root/ansible/roles/issue was created successfully   
[root@control ansible]# ls ~/ansible/roles/issue/
README.md  defaults  files  handlers  meta  tasks  templates  tests  vars

[root@control ansible]# yum -y install tree   //tree命令实现,需安装tree软件包
[root@control ansible]# tree ~/ansible/roles/issue   //查看issue下的目录结构
/root/ansible/roles/issue
|-- README.md
|-- defaults
|   `-- main.yml
|-- files
|-- handlers
|   `-- main.yml
|-- meta
|   `-- main.yml
|-- tasks
|   `-- main.yml
|-- templates
|-- tests
|   |-- inventory
|   `-- test.yml
`-- vars
`-- main.yml

2)修改Role文件

定义名称为myfile.txt的模板文件(该文件包含变量,因此必须放置templates目录)

[root@control ansible]# vim ~/ansible/roles/issue/templates/myfile.txt
This is the system {{ansible_hostname}}
Today's date is:{{ansible_date_time.date}}
Contact to {{admin}}    //自定义的变量

自定义变量文件(前面调用了admin这个变量,需要在vars/main.yml定义admin变量并赋值)

[root@control ansible]# vim ~/ansible/roles/issue/vars/main.yml
---
# vars file for /root/ansible/roles/issue
admin: anj@tedu.cn      //变量名为admin,变量的值为anj@tedu.cn

补充:当文件准备好以后,计算机不会自动将文件拷贝给被管理端主机,需要编写任务调用模块实现拷贝的功能。

修改任务文件(任务文件中不需要tasks关键词,Role的各文件之间相互调用不需要写文件的路径)

[root@control ansible]# vim ~/ansible/roles/issue/tasks/main.yml
---
# tasks file for /root/ansible/roles/issue
- name: delever issue file.
  template:
    src: myfile.txt
    dest: /etc/issue

解释:编写任务,调用template模块将myfile.txt文件拷贝给被管理端主机。

3)在Playbook中调用Role

Role创建好,role不会自己运行,需要编写一个剧本调用上面的role。

- 编写playbook剧本文件,通过roles关键词调用role。

[root@control ansible]# vim ~/ansible/issue.yml
---
- hosts: test
  roles:
     - issue     //调用role(补充:- role2支持加载多个role)
[root@control ansible]# ansible-playbook issue.yml

验证:

[root@node1 ~]# cat /etc/issue
This is the system node1
Today's date is:2021-04-26
Contact to anj@tedu.cn

4)修改ansible.cfg配置文件,定义roles目录(了解)

结合mkdir ~/ansible/roles/,因配置文件已指定./roles目录,所以调用role时,会在该目录下找创建的role(默认就在./roles目录)

[root@control ansible]# vim ~/ansible/ansible.cfg
[defaults]
inventory = ./inventory
roles_path = ./roles          //指定到哪个目录下找role
remote_user = alice
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

galaxy命令行下载(了解内容)

公共Roles仓库管理:https://galaxy.ansible.com 

1)使用ansible-galaxy install 可以直接下载Role;

[root@control ansible]# ansible-galaxy search 'httpd'    //联网搜索roles
[root@control ansible]# ansible-galaxy info acandid.httpd  //查看roles基本信息
[root@control ansible]# ansible-galaxy install acandid.httpd -p ~/ansible/roles/   //下载roles到特定的目录

补充:[-p]选项,可以指定下载到哪个目录;install可不指定网址,默认为官网;“acandid.httpd”为acandid用户的httpd角色

2)编写requirements.yml文件下载Role

[root@control ansible]# vim ~/ansible/roles/requirements.yml
## 格式一:可以直接从Ansible Galaxy官网下载
- src: acandid.httpd

## 格式二:可以从某个git服务器下载
- src: http://gitlab.com/xxx/xxx.git
  scm: git
  version: 56e00a54
  name: nginx-acme

## 格式三:可以指定位置下载tar包,支持http、https、file
- src:  http://example.com/myrole.tar
  name:  myrole

[root@control ansible]# ansible-galaxy install -r ~/ansible/roles/requirements.yml -p roles
# -r后面跟文件名,该文件中包含了需要下载哪些role以及他们的链接位置;
# -p 指定将下载的role保存到哪个目录;

思维导图:

 

小结:

本篇章节为【第二阶段】AUTOMATION-DAY6 的学习笔记,这篇笔记可以初步了解到 YAML语法格式,层级关系、Ansible Playbook文件及语法格式、Ansible变量。


Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解

  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值