环境准备


rht-vmctl reset control
rht-vmctl reset node1
rht-vmctl reset node2
rht-vmctl reset node3
rht-vmctl reset node4
rht-vmctl reset node5
然后ssh control主机,如果可以yum -y install ansible 就不用下列操作


如果ssh control主机之后yum不能用,要按下列操作还原环境
真实主机:

  1. mount /iso/rhel-8.2-x86_64-dvd.iso /var/ftp/rhel
  2. ln -s /var/ftp/rhel /var/www/html/rhel8.2
  3. ln -s /var/ftp/rhel /var/www/html/rhel8
  4. scp /linux-soft/2/ansible_soft.tar.gz con: //拷贝ansible软件包control主机管理员家目录

control主机:

yum repolist  -v    //查看下yum,应该就可以用了
cd
yum -y install tar
tar -xf ansible_soft.tar.gz
cd ansible_soft
yum -y install *.rpm    //安装ansible

另外

ls  /var/www/html/materials  # 要有 hardware.empty  name_list.yml  newhosts.j2  topsec.yml  这个几个文件
ls  /var/www/html/roles  # 要有  haproxy.tar  myphp.tar   这几个文件,如果上述文件没有,去网盘里找ce素材.zip

——————————————————————————————————————————-
ansible的控制主机和被控主机都可以选择不同的用户,考试时
很可能是第二种,也就是用普通用户指挥远程主机时也用普通用户
控制主机root —————————> 被控主机root
控制主机alice ————————-> 被控主机alice
——————————————————————————————————————————-

环境说明

真机(RHEL8.2)

server1.lab0.example.com 172.25.0.254/24
# 预设 root 口令为 tedu
# 提供 RHEL8 软件源 http://server1.lab0.example.com/rhel8/BaseOS
# 提供 RHEL8 软件源 http://server1.lab0.example.com/rhel8/AppStream
# 提供 DNS 服务,为区域 lab0.example.com 中相关站点提供解析
# 提供 NTP 网络时间服务;提供 NFS 文件服务,共享/rhome/ldapuser0 目录

虚拟机 control(RHEL8.2) —— 控制机

control.lab0.example.com 172.25.254.100/24
# 可从 server1 免密 SSH 登录到 root 用户,已预设授权 sudo 用户 alice
# 预设 IP 地址 172.25.254.100/24,已做好主机名映射

虚拟机 node1~node5(RHEL8.2) —— 受管机:

node[1-5].lab0.example.com 172.25.254.10[1-5]/24
# 预设授权 sudo 用户 alice,可从控制机 control 免密 SSH 登录
# 预设 IP 地址 172.25.254.101~105/24,已做好主机名映射

其他信息:

除非另有指定,否则所有工作都需要归属在控制机的 /home/alice/ansible/ 目录下

考试技巧

ansible-doc -l | grep 关键字 # 可以查询模块名
ansible-doc 模块名 搜索/EXAM # 可以查询模块的使用模板
多利用查询和复制功能,避免手敲命令出错

RHCE核心知识总结

  • Ansible是一款简洁、高效的运维自动化工具。
  • 将ansible安装在主控机器上,就可以通过SSH协议实现针对大量受管服务器的批量化、剧本化的管理。
  • ansible 使用 ssh 命令远程管理目标主机,必须确保管理主机能够免密登录目标主机(或在配置文件中提供root密码)

ansible.cfg 加载顺序:

  1. ANSIBLE_CONFIG 环境变量
  2. 当前目录下 ansible.cfg
  3. /etc/ansible/ansible.cfg

ansible运行的 2 种方式:

  • 1、adhoc 命令行: ansible 组名称,主机 -m 模块名称 -a 模块的参数
  • 2、playbook方式: ansible-playbook 你编写的文件.yaml

yaml 核心语法:

  1. 以空格缩进表示层级结构,同级别的参数要缩进对齐
  2. 键值对使用 “: “ 作为分隔符,数组使用 “- “ 作为分隔符(注意:冒号和减号后面都有空格)

ansible 调用角色就是调用编写好的 playbook,一般一个角色就是一个 目录,创建角色目录使用 ansible-galaxy init 目录名称

查询系统facts变量的方法有:
ansible node1 -m setup
ansible localhost -m debug -a ‘var=hostvars[“localhost”]’

  • ansible 判断使用 when 语法
  • ansible 循环使用 loop 语法
  • ignore_errors: True 用来忽略错误继续执行
  • block 要执行的若干语句 要执行的若干语句 rescue 当上面的 块 执行失败的时候,执行这里的语句 当上面的 块 执行失败的时候,执行这里的语句 always 总会被执行,不管上面执行失败还是正确

真题练习

01. 安装和配置 ansible 环境

1)安装所需软件包
2)在/home/alice/ansible/inventory 文件中设置主机清单,要求:
node1 属于 test01 主机组
node2 属于 test02 主机组
node3 和 node4 属于 web 主机组
node5 属于 test05 主机组
web 组属于 webtest 主机组
3)在/home/alice/ansible 目录中创建 ansible.cfg,满足以下需求:
主机清单文件为 /home/alice/ansible/inventory
playbook 中角色位置为 /home/alice/ansible/roles

解题思路

1)安装软件包可以使用 yum ,在control主机安装ansible即可,但考试时候给的是普通用户,可以使用 sudo 提权
2)按照题目要求创建自定义目录,并且配置 ansible.cfg 文件

  • /etc/ansible/ansible.cfg //从默认配置文件,复制配置,多使用关键字查询
  • defaults:remote_user(使用哪个用户控制);inventory;roles_path;host_key_checking
  • privilege_escalation(找到直接粘贴即可):become;become_method;become_user;become_ask_pass

3)创建主机清单,注意[webtest:children]拼写
ansible.cfg 加载顺序
1,ANSIBLE_CONFIG 环境变量 2,当前目录下 3,/etc/ansible/ansible.cfg

解题参考

[alice@control ~]$ sudo yum install -y ansible
... ...
Installed:
  ansible-2.8.5-2.el8.noarch     python3-babel-2.5.1-5.el8.noarch                     
  python3-jinja2-2.10.1-2.el8_0.noarch   python3-jmespath-0.9.0-11.el8.noarch                 
  python3-markupsafe-0.23-19.el8.x86_64   python3-pytz-2017.2-9.el8.noarch                     
  python3-pyyaml-3.12-12.el8.x86_64   python3-setuptools-39.2.0-5.el8.noarch               
  sshpass-1.06-9.el8.x86_64                           

Complete!
[alice@control ~]$ mkdir ansible
[alice@control ~]$ vim ansible/ansible.cfg # 该配置文件中的所有配置参数都可以在 /etc/ansible/ansible.cfg 中找到 
[defaults]
inventory         = /home/alice/ansible/inventory  # 主机分组配置列表
roles_path        = /home/alice/ansible/roles      # 角色目录
host_key_checking = False               # 关闭sshkey检查,防止第一次输入 yes 时候卡住
remote_user       = alice               # 管理远程主机使用的用户

[privilege_escalation]                  # 普通用户提权配置
become            = True                # 执行操作前先自动提权
become_method     = sudo                # 提权使用的命令
become_user       = root                # 提权的目标用户
become_ask_pass   = False               # 是否需要输入密码,False无需输入密码
[alice@control ~]$ vim ansible/inventory 
[test01]
node1

[test02]
node2

[web]
node3
node4

[test05]
node5

[webtest:children]
web
[alice@control ~]$ mkdir ansible/roles

验证方案

[alice@control ~]$ id 
uid=1000(alice) gid=1000(alice) groups=1000(alice)
[alice@control ~]$ cd ~/ansible/
[alice@control ansible]$ ansible localhost -m debug -a 'var=groups'
localhost | SUCCESS => {
    "groups": {
        "all": [
            "node1",
            "node2",
            "node5",
            "node3",
            "node4"
        ],
        "test01": [
            "node1"
        ],
        "test02": [
            "node2"
        ],
        "test05": [
            "node5"
        ],
        "ungrouped": [],
        "web": [
            "node3",
            "node4"
        ],
        "webtest": [
            "node3",
            "node4"
        ]
    }
}
[alice@control ansible]$ ansible all -m ping
node5 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
node3 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
node4 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
node1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
node2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}

02. 创建和运行 Ansible 临时命令

编写脚本 /home/alice/ansible/adhoc.sh,用来为所有受管机配置 2 个 yum 仓库。
仓库 1:

仓库 2:

  1. 在adhoc.sh脚本中为多个机器配置服务需要使用 ansible 命令
  2. yum 仓库的配置模块为 yum_repository

模块的名称可以通过命令 ansible-doc -l |grep yum 进行查找

  1. 使用 ansible-doc yum_repository 查看帮助案例完成编写命令

模块选项使用 ansible-doc 模块名查找(name;description;baseurl;gpgcheck;gpgkey;enabled)

解题参考

[alice@control ansible]$ vim adhoc.sh 
#!/bin/bash 
ansible all -m yum_repository -a 'name=BASE description="software base"  baseurl=http://study.lab0.example.com/rhel8/BaseOS gpgcheck=yes gpgkey=http://study.lab0.example.com/rhel8/RPM-GPG-KEY-redhat-release enabled=yes' 
ansible all -m yum_repository -a 'name=STREAM description="software stream" baseurl=http://study.lab0.example.com/rhel8/AppStream gpgcheck=yes gpgkey=http://study.lab0.example.com/rhel8/RPM-GPG-KEY-redhat-release enabled=yes' 
[alice@control ansible]$ chmod +x adhoc.sh 
[alice@control ansible]$ ./adhoc.sh

验证方案

执行的结果全部为绿色成功
可以使用 yum repolist 验证

  • ansible all -m shell -a “ yum repolist -v | tail -1 “

在node1~node5可以看见Total packages:7040 yum包源数量


03. 编写剧本远程安装软件

创建名为/home/alice/ansible/tools.yml 的 playbook,能够实现以下目的:
1)将 php 和 tftp 软件包安装到 test01、test02 和 web 主机组中的主机上
2)将 RPM Development Tools 软件包组安装到 test01 主机组中的主机上
3)将 test01 主机组中的主机上所有软件包升级到最新版本

解题思路

  • 题目要求在不同的分组中安装不同的软件包,需要书写多个 play
  • 安装升级软件包需要使用 yum 模块(使用 ansible-doc yum 查看案例)

    解题参考

    ```shell [alice@control ansible]$ vim tools.yml
  • hosts: test01, test02, web tasks:
    • yum: pkg=”php,tftp” state=present //安装 php 和 tftp 软件包
  • hosts: test01 tasks:

    • yum: name=”@RPM Development Tools” state=present //安装 xx 包组
    • yum: name=”*” state=”latest” //升级所有包 [alice@control ansible]$ ansible-playbook tools.yml //验证剧本 ```

      验证方案

  • 剧本跑完后, 所有执行结果中 failed=0

  • 到node1~5等主机上检查

    [root@node1 ~]# rpm -q php    //剧本跑完后到node1等主机上检查
    [root@node1 ~]# rpm -q tftp
    [root@node1 ~]# yum grouplist   //查包组
    Installed Groups:    //已经安装的包
     RPM Development Tools
    

    04. 安装并使用系统角色

    安装 RHEL 角色软件包,并创建剧本 /home/alice/ansible/timesync.yml,满足以下要求:
    1)在所有受管理节点运行
    2)使用 timesync 角色
    3)配置该角色,使用时间服务器 172.25.254.250,并启用 iburst 参数

    解题思路

    • 需使用yum安装rhel-system-roles软件包,会生成/usr/share/ansible/roles/rhel-system-roles.timesync,将其拷贝到已建好的roles目录下
    • 忘记包名的话 yum list | grep roles # 查询一下roles是有关的包
    • 角色目录下会有README.md帮助文档,找到Example处,可作参考
    • 除了(timesync)时间同步角色,rhel系统中selinux角色也要重点练习
      vim roles/rhel-system-roles.timesync/README.md   //查看帮助文件,大概
      # 在76行,然后将下面这些内容复制到题目要求的剧本中稍加改编即可
      vars:
      timesync_ntp_servers:
      - hostname: foo.example.com
         iburst: yes
      

      解题参考

      ```shell [alice@control ~]$ cd ~alice/ansible [alice@control ansible]$ sudo yum list|grep roles # 查找角色软件包 rhel-system-roles.noarch 1.0-10.el8_1 appstream [alice@control ansible]$ sudo yum install -y rhel-system-roles.noarch # 安装软件包 [alice@control ansible]$ rpm -ql rhel-system-roles.noarch # 查找系统角色的安装路径,并拷贝到 ansible\roles 目录下 /usr/share/ansible /usr/share/ansible/roles … … [alice@control ansible]$ cp -a /usr/share/ansible/roles/rhel-system-roles.timesync ~/alice/ansible/roles/ [alice@control ansible]$ cat roles/rhel-system-roles.timesync/README.md # 通过帮助文件查询使用方法 [alice@control ansible]$ vim timesync.yml

  • hosts: all vars: timesync_ntp_servers: # 设置 NTD 服务器变量

    - hostname: 172.25.254.250
      iburst: yes
    

    roles:

    • rhel-system-roles.timesync # 调用角色 [alice@control ansible]$ ansible-playbook timesync.yml # 验证剧本 ```

      验证方案

  • 该题的playbook运行时会有报错,但是会忽略,属于正常现象

  • 然后去node1~node5检查/etc/chrony.conf 可以看到server 172.25.254.250 iburst,使用 chronyc sources -v 来验证时间是否同步成功,使用命令ansible all -m shell -a “chronyc sources -v”

    05. 通过 galaxy 安装角色

    创建剧本 /home/alice/ansible/roles/down.yml,用来从以下 URL 下载角色,并安装到 /home/alice/ansible/roles 目录下:

  • http://study.lab0.example.com/roles/haproxy.tar 此角色名为 haproxy

  • http://study.lab0.example.com/roles/myphp.tar 此角色名为 myphp

    解题思路

  • 角色的本质就是一个目录,安装角色就是下载别人写好的 playbook 存放到指定的位置

    知识拓展

    ansible-galaxy

    • 连接galaxy.ansible.com下载相应的roles(角色)
      roles(角色):就是一堆playbook的集合

ansible-galaxy list会查看三个地方的role文件:

  • ./roles
  • /usr/share/ansible/role
  • /etc/ansible/roles
  • 创建角色

ansible-galaxy install下载安装角色

  • -r 指定导入的角色列表的文件
  • -p 指定角色的目录路径,默认问ansible.cfg中配置的路径

ansible-galaxy init 自定义角色

解题参考

[alice@control ansible]$ vim /home/alice/ansible/roles/down.yml //配置角色导入信息
- name: haproxy
  src: http://study.lab0.example.com/roles/haproxy.tar
- name: myphp
  src: http://study.lab0.example.com/roles/myphp.tar
[alice@control ansible]$ ansible-galaxy install -r roles/down.yml //导入角色

验证方案

查看到 successfully 以后可以查看是否有目录创建

[alice@control ansible]$ ls roles/
down.yml  haproxy  myphp  rhel-system-roles.timesync

06. 创建及使用自定义角色

根据下列要求,在/home/alice/ansible/roles 中创建名为 httpd 的角色:

  • 1)安装 httpd 软件,并能够开机自动运行
  • 2)开启防火墙,并允许 httpd 通过
  • 3)使用模板 index.html.j2,用来创建/var/www/html/index.html 网页,内容如下(其 中,HOSTNAME 是受管理节点的完全域名,IPADDRESS 是 IP 地址): Welcome to HOSTNAME on IPADDRESS

然后创建剧本 /home/alice/ansible/myrole.yml,为 webtest 主机组启用 httpd 角色。

解题思路

这道题考的知识点较多:

  1. 自定义角色,可以使用 ansible-galaxy init 角色名称来创建
  2. 在角色中定义任务,本质和定义tasks一样,使用 ansible-doc 查找帮助信息,编写 tasks/main.yml 这道题中用到的模块有 yum、template 、service(记得重启服务)、firewalld
  3. 题目要求使用变量替换,查询系统facts变量的方法有: ansible node1 -m setup / ansible localhost -m debug -a ‘var=hostvars[“localhost”]’
  4. 变量采用 json 格式显示,不同层级的变量使用 . 作为分隔符,例如ansible_eth0.ipv4.address

    解题参考

    ```shell [alice@control ansible]$ ansible-galaxy init roles/httpd //为新角色创建初始目录结构 [alice@control ansible]$ vim roles/httpd/templates/index.html.j2 //编写角色模板(网页) Welcome to {{ ansible_fqdn }} on {{ ansible_eth0.ipv4.address }} [alice@control ansible]$ vim roles/httpd/tasks/main.yml //编写角色主任务
  • yum: pkg=httpd state=present //装 httpd 包
  • template: src=index.html.j2 dest=/var/www/html/index.html //配置网页
  • service: name=httpd state=restarted enabled=yes //起 httpd 服务
  • firewalld: service=http state=enabled permanent=yes immediate=yes //配置防火墙,允许访问 web 端口 [alice@control ansible]$ vim myrole.yml //编写启动脚本
  • hosts: webtest roles:

    • httpd [alice@control ansible]$ ansible-playbook myrole.yml //验证剧本
      <a name="l1IIq"></a>
      ### 验证方案
      执行结果 failed=0,使用 curl 访问 webtest 组的主机,查看返回结果
      ```shell
      [alice@control ansible]$ curl http://node3/
      Welcome to node3.lab0.example.com on 172.25.254.103
      [alice@control ansible]$ curl http://node4/
      Welcome to node4.lab0.example.com on 172.25.254.104
      

      07. 使用之前通过 galaxy 下载的角色

      创建剧本 /home/alice/ansible/web.yml,满足下列需求:
  • 1)该剧本中包含一个 play,可以在 test05 主机组运行 haproxy 角色(此角色已经配置 好网站的负载均衡服务)

  • 2)多次访问 http://node5.lab0.example.com 可以输出不同主机的欢迎页面
  • 3)该剧本中包含另一个 play,可以在 webtest 主机组运行 myphp 角色(此角色已经配置 好网站的 php 页面)
  • 4)多次访问 http://node5.lab0.example.com/index.php 也输出不同主机的欢页面

    解题思路

  • 一个典型的web负载均衡集群image.png

  • webtest web网页静态页面已经在 06 题目配置完成(06 没有做对的,这道题会有问题)
  • 本题需要配置一个负载均衡 test05,还需要在 webtest 主机中安装PHP页面支持
  • 本题隐藏内容:webtest上题已配置firewalld,test05未配置
  • i本题所使用到的ansible模块有 firewalld

    解题参考

    ```shell [alice@control ansible]$ vim web.yml
  • name: use role B //先部署 web 节点(node3、node4) hosts: webtest roles:
    • myphp
  • name: use role A hosts: test05 //再配置负载均衡器(node5) roles:

    • haproxy tasks:
    • firewalld: service=http state=enabled permanent=yes immediate=yes //配置防火墙,允许访问负载均衡器的 web 端口 [alice@control ansible]$ ansible-playbook web.yml //验证剧本
      <a name="nM5YL"></a>
      ### 验证方案
      返回结果中 failed=0,使用 curl 访问负载均衡查看结果
      ```shell
      [alice@control ansible]$ curl http://node5.lab0.example.com
      Welcome to node3.lab0.example.com on 172.25.254.103
      [alice@control ansible]$ curl http://node5.lab0.example.com
      Welcome to node4.lab0.example.com on 172.25.254.104
      [alice@control ansible]$ curl http://node5.lab0.example.com/index.php
      hello php world from node3.lab0.example.com
      [alice@control ansible]$ curl http://node5.lab0.example.com/index.php
      hello php world from node4.lab0.example.com
      

      08. 编写剧本远程管理逻辑卷

      创建剧本 /home/alice/ansible/lvm.yml,用来为所有受管机完成以下部署:
  • 1)在卷组 search 中创建名为 mylv 的逻辑卷,大小为 1000MiB

  • 2)使用 ext4 文件系统格式化该逻辑卷
  • 3)如果无法创建要求的大小,应显示错误信息 insufficient free space,并改为 500MiB
  • 4)如果卷组 search 不存在,应显示错误信息 VG not found
  • 5)不需要挂载逻辑卷

    解题思路

    根据题目检查所有结点的磁盘空间剩余情况 ```shell [alice@control ansible]$ ansible all -m shell -a ‘vgs’ node2 | CHANGED | rc=0 >> VG #PV #LV #SN Attr VSize VFree
    rhel 1 2 0 wz—n- <49.00g 0 search 1 0 0 wz—n- 664.00m 664.00m

node4 | CHANGED | rc=0 >> VG #PV #LV #SN Attr VSize VFree rhel 1 2 0 wz—n- <49.00g 0

node1 | CHANGED | rc=0 >> VG #PV #LV #SN Attr VSize VFree rhel 1 2 0 wz—n- <49.00g 0

node5 | CHANGED | rc=0 >> VG #PV #LV #SN Attr VSize VFree rhel 1 2 0 wz—n- <49.00g 0 search 1 0 0 wz—n- <1.86g <1.86g

node3 | CHANGED | rc=0 >> VG #PV #LV #SN Attr VSize VFree rhel 1 2 0 wz—n- <49.00g 0

可以总结为三种情况:

   1. 有search卷组 够1000M
   1. 有search卷组 不够1000M
   1.  没有search卷组 

首先找出没有search卷组的主机,输出错误信息" VG not found ",使用fail模块(与debug模块相似),输出信息并停止后续任务。<br />然后判断卷组够不够1000M,使用block任务块,创建1000M逻辑卷;如果失败执行救援任务rescue,输出信息" insufficient free space ",划分500M逻辑卷;执行永久任务always,格式化该逻辑卷。
<a name="HXc0L"></a>
### 解题参考 
```shell
[alice@control ansible]$ vim lvm.yml 
- name: manager volume 
  hosts: all 
  tasks: 
    - name: 1. failed when VG not found 
      fail: msg="VG not found" # 目标 VG 不存在时报错 ,停止后续任务 
      when: "'search' not in ansible_lvm.vgs"  
    - name: 2. lvcreate 
      block:         # 配置指令块 
        - lvol: lv=mylv size=1000M vg=search force=yes 
      rescue:        # 若块操作失败,则执行补救 
        - debug: msg="insufficient free space" 
        - lvol: lv=mylv size=500M vg=search force=yes 
      always:        # 始终需要执行的任务 
        - filesystem: dev=/dev/search/mylv fstype=ext4 force=yes 
[alice@control ansible]$ ansible-playbook lvm.yml   # 验证剧本

验证方案

验证结果,这次执行后是有错误的,但根据题目要求,这些错误可以忽略,我们只验证正确的结果即可

[alice@control ansible]$ ansible all -m shell -a 'blkid |grep mylv'
node3 | FAILED | rc=1 >>
non-zero return code

node5 | CHANGED | rc=0 >>
/dev/mapper/search-mylv: UUID="b815ece4-0dc8-4a27-b5aa-c1740a8ea897" TYPE="ext4"

node1 | FAILED | rc=1 >>
non-zero return code

node2 | CHANGED | rc=0 >>
/dev/mapper/search-mylv: UUID="aaf7539f-a6c8-4ce5-a53d-4aeba59aa0ae" TYPE="ext4"

node4 | FAILED | rc=1 >>
non-zero return code

习题拓展

磁盘挂载练习:mount模块

  • path: /mnt/dvd
  • src: /dev/sr0
  • fstype: iso9660,ext4,xfs
  • state: present,mounted,unmount

09. 根据模板部署主机文件

1)从 http://study.lab0.example.com/materials/newhosts.j2 下载模板文件
2)完成该模板,用来生成新主机清单(主机的显示顺序没有要求),结构如下

  • 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
  • ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
  • 172.25.254.101 node1.lab0.example.com node1
  • 172.25.254.102 node2.lab0.example.com node2
  • 172.25.254.103 node3.lab0.example.com node3
  • 172.25.254.104 node4.lab0.example.com node4
  • 172.25.254.105 node5.lab0.example.com node5

3)创建剧本 /home/alice/ansible/newhosts.yml,它将使用上述模板在 test01 主机组的主 机上生成文件/etc/newhosts

注意事项

只在test01上执行任务无法收集其他主机的hostvars变量,需要先收集所有主机的hostvars变量。

解题思路

  • 下载模板查看后发现需要补齐的数据是 node1 … … node5
  • 根据模板的扩展名可以知道这个是一个 jinja2 的模板,可以使用 jinja2 循环语法实现
    • ansible中特殊变量的使用

0 ansible中的特殊变量

  - 常见魔法变量:hostvars、groups、group_names、inventory_hostname
  - 如果想要输出json数据的某一字典项,则应该用"key.dict"或"key['dict']"的方式引用,例如hostvars['node1']或hostvars.node1或hostvars[item](item为变量)
  - 使用filter可以筛选指定的facts信息,ansible localhost -m setup -a "filter=*ipv4"
  - jinja2基本语法介绍
     - when判断语法
     - 条件判断
{% if daxin.safe %}
daxin is safe.
{% elif daxin.dead %}
daxin is dead
{% else %}
daxin is okay
{% endif %}
     - 循环结构
 {% for file in filenames %}
        # 取值
        {{ file }}
 {% endfor %}
  • 我们可以通过循环 inventory 文件配置模板
  • 为了能够让模板顺利执行,拷贝模板使用 template 模块

    解题参考

    [alice@control ansible]$ sudo yum -y install wget 
    [alice@control ansible]$ wget http://study.lab0.example.com/materials/newhosts.j2 
    [alice@control ansible]$ vim newhosts.j2  # 制作 J2 动态模板文件 
    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
    {% for id in groups.all %} 
    {{hostvars[id].ansible_eth0.ipv4.address}} {{hostvars[id].ansible_fqdn}} {{hostvars[id].ansible_hostname}} 
    {% endfor %} 
    [alice@control ansible]$ vim newhosts.yml 
    - hosts: all //搜集所有主机的信息 
    - hosts: test01 //只为 xx 主机组部署 
    tasks: 
    - template: src=newhosts.j2 dest=/etc/newhosts force=yes # 通过模板部署文件 
    [alice@control ansible]$ ansible-playbook newhosts.yml # 验证剧本 
    # 然后可以在node1主机上查看文件验证是否完成任务
    

    验证方案

    返回状态 failed=0,到目标主机查看文件即可
    [alice@control ansible]$ ssh node1
    Last login: Sat Jun 19 01:28:23 2021 from 172.25.254.100
    [alice@node1 ~]$ sudo cat /etc/newhosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    172.25.254.101    node1.lab0.example.com node1
    172.25.254.102    node2.lab0.example.com node2
    172.25.254.105    node5.lab0.example.com node5
    172.25.254.103    node3.lab0.example.com node3
    172.25.254.104    node4.lab0.example.com node4
    

    习题拓展

    魔法变量:group.all、hostvars(所有变量)

    10. 编写剧本修改远程文件内容

    创建剧本 /home/alice/ansible/newissue.yml,满足下列要求:
    1)在所有清单主机上运行,替换/etc/issue 的内容
    2)对于 test01 主机组中的主机,/etc/issue 文件内容为 test01
    3)对于 test02 主机组中的主机,/etc/issue 文件内容为 test02
    4)对于 web 主机组中的主机,/etc/issue 文件内容为 Webserver

    解题思路

  • 在所有主机上运行,不同主机写入不同的数据,这里考察的是 判断 语法的使用
  • 在主机上运行应该判断当前主机所在的组可以通过 主机名称 in groups.组名称判断
  • 本题只用到了 copy 模块

    解题参考

    ```shell [alice@control ansible]$ vim newissue.yml
  • name: deploy /etc/issue hosts: all tasks:
    • copy: content=”test01” dest=/etc/issue force=yes when: (‘test01’ in group_names) //如果所在组包括 test01
    • copy: content=”test02” dest=/etc/issue force=yes when: (‘test02’ in group_names) //如果所在组包括 test02
    • copy: content=”Webserver” dest=/etc/issue force=yes when: (‘web’ in group_names) //如果所在组包括 web [alice@control ansible]$ ansible-playbook newissue.yml //验证剧本 **方法二:**shell [alice@control ansible]$ vim newissue.yml

  • name: 修改issue文件 hosts: all tasks:
    • name: 修改配置文件 copy: content: |
      {% if "web" in group_names %}
      Webserver
      {% elif "test01" in group_names %}
      test01
      {% elif "test02" in group_names %}
      test02
      {% endif %}
      
      dest: /etc/issue when: ‘group_names | intersect([“test01”,”test02”,”web”])’ **方法三:**shell [alice@control ansible]$ vim newissue.yml
  • name: deploy /etc/issue hosts: all tasks:
    • template: src=newissue.j2 dest=/etc/issue force=yes # 根据模板部署远程文件 [alice@control ansible]$ vim newissue.j2 # 编写模板内容 {% if “test01” in group_names %} //如果所在组包括 test01 test01 {% elif “test02” in group_names %} //如果所在组包括 test02 test02 {% elif “web” in group_names %} //如果所在组包括 web Webserver {% endif %} [alice@control ansible]$ ansible-playbook newissue.yml //验证剧本 ```

      验证方案

      failed=0 没有报错,到目标结点查看 issue 的文件内容 ```shell [alice@control ansible]$ ansible all -m shell -a ‘cat /etc/issue’ node2 | CHANGED | rc=0 >> test02

node5 | CHANGED | rc=0 >> \S Kernel \r on an \m

node4 | CHANGED | rc=0 >> Webserver

node3 | CHANGED | rc=0 >> Webserver

node1 | CHANGED | rc=0 >> test01

<a name="s11F6"></a>
## 11. 编写剧本部署远程 Web 目录 
创建剧本 /home/alice/ansible/webdev.yml,满足下列要求: 

- 1)在 test01 主机组运行 
- 2)创建目录/webdev,属于 webdev 组,常规权限为 rwxrwxr-x,具有 SetGID 特殊权限 
- 3)使用符号链接/var/www/html/webdev 链接到/webdev 目录 
- 4)创建文件/webdev/index.html,内容是 It's works! 
- 5)查看 test01 主机组的 web 页面 http://node1/webdev/ 将显示 It's works! 
<a name="nZlTP"></a>
### 解题思路

- 创建文件、目录、链接使用 file 模块完成
- 注意隐藏需求:
   - 创建webdev组、安装http软件包、http服务开机自启、防火墙和selinux(注意之前的题目要求是否要求selinux开启)
   - 如果要求selinux开启:
      - 因为网页文件使用软连接,所以selinx任务不安全,需进行修改
      - - shell: chcon -R -t httpd_sys_content_t  /webdev
         - chcon命令的-R参数是递归全部子目录和文件
         - chcon命令的-t参数是添加一个类型
      - 使selinux认为该文件为httpd的文件
- 用到的模块 group、file、copy、service、firewalld、shell
- 设置权限时因为涉及特殊权限,所以开头不为0,
   - 1代表 Sticky bit
   - 2代表 SetGID
   - 4代表 SetUid
   - 6代表 同时设置 SetUid 和SetGID
<a name="GegvI"></a>
### 解题参考:
```shell
[alice@control ansible]$ vim webdev.yml 
- name: Prepare Web Directory
  hosts: test01
  tasks:
    - yum: name=httpd state=present //装 httpd 包
    - group: name=webdev state=present //配置组账号
    - file: name=/webdev group=webdev mode=2775 state=directory //配置目录
    - file: src=/webdev name=/var/www/html/webdev state=link force=yes //配置链接
    - copy: content="It's works!" dest=/webdev/index.html force=yes //配置网页
    - firewalld: service=http state=enabled permanent=yes immediate=yes //配置防火墙
    - service: name=httpd state=restarted enabled=yes //起 httpd 服务
    - command: setenforce 0 //取消 SELinux 限制
    - command: sed -i '/^SELINUX=/cSELINUX=Permissive' /etc/selinux/config  //永久取消
[alice@control ansible]$ ansible-playbook webdev.yml //验证剧本

验证方案

安装正常 failed=0,访问 node1 查看页面

[alice@control ansible]$ curl http://node1/webdev/
It's works!

12. 编写剧本为受管机生成硬件报告

创建名为/home/alice/ansible/hardware.yml 的 playbook,满足下列要求:
1)使所有受管理节点从以下 URL 下载文件:
http://study.lab0.example.com/materials/hardware.empty
2)并用来生成以下硬件报告信息,存储在各自的/root/hardware.txt 文件中

  • 清单主机名称
  • 以 MB 表示的总内存大小
  • BIOS 版本
  • 硬盘 vda 的大小
  • 硬盘 vdb 的大小

其中,文件的每一行含有一个 key=value 对,如果项目不存在,则显示 NONE。

解题思路

  • 远程下载文件使用 get_url ,修改文件使用 replace ,该题主要考察 facts 变量值的获取,可以使用循环简化文件
  • 该题目用到的知识 loop 循环,get_url、replace 模块
  • 判断变量是否存在可用 {{ 变量 if ‘变量关键字’ in 变量 else ‘输出文本’ }} 或者 {{ 变量 if 变量 is defined else ‘输出文本’ }}/

    解题参考

    ```shell [alice@control ansible]$ vim hardware.yml
  • name: hardware report hosts: all vars:
    • host: “{{inventory_hostname}}” //提取清单主机名
    • mem: “{{ansible_memtotal_mb}}” //提取总内存大小(MB)
    • bios: “{{ansible_bios_version}}” //提取 BIOS 版本
    • vdasize: “{{ansible_devices.vda.size}}” //提取磁盘 vda 大小
    • vdbsize: “{{ansible_devices.vdb.size if ansible_devices.vdb.size is defined else ‘NONE’ }}” //提取磁盘 vdb 大小,或 NONE tasks: //制作硬件报告
    • get_url: url=http://study.lab0.example.com/materials/hardware.empty dest=/root/hardware.txt force=yes
    • replace: path=/root/hardware.txt regexp=inventoryhostname replace={{host}}
    • replace: path=/root/hardware.txt regexp=memory_in_MB replace={{mem}}
    • replace: path=/root/hardware.txt regexp=BIOS_version replace={{bios}}
    • replace: path=/root/hardware.txt regexp=disk_vda_size replace={{vdasize}}
    • replace: path=/root/hardware.txt regexp=disk_vdb_size replace={{vdbsize}} [alice@control ansible]$ ansible-playbook hardware.yml //验证剧本

      然后可以在其他主机上查看文件验证是否完成任务

      **方法二:**shell [alice@control ansible]$ vim hardware.yml

  • name: 在远程下载模板文件 hosts: all tasks:
    • name: 下载文件hardware.empty get_url: url: http://study.lab0.example.com/materials/hardware.empty dest: /root/hardware.txt
    • name: 修改模板文件中参数的值 replace: path: /root/hardware.txt regexp: “{{ item.k }}” replace: “{{ item.v }}” loop:
      • k: inventoryhostname v: “{{ inventory_hostname }}”
      • k: memory_in_MB v: “{{ ansible_memtotal_mb | string }}”
      • k: BIOS_version v: “{{ ansible_bios_version }}”
      • k: disk_vda_size v: “{{ ansible_devices.vda.size if ‘vda’ in ansible_devices else ‘NONE’ }}”
      • k: disk_vdb_size v: “{{ ansible_devices.vdb.size if ‘vdb’ in ansible_devices else ‘NONE’ }}” ```

        验证方案

        结果正常 failed=0,查看生成的文件 ```shell [alice@control ansible]$ ansible all -m shell -a ‘cat /root/hardware.txt’ node3 | CHANGED | rc=0 >> hostname=node3 mem=979 bios=1.11.1-4.module+el8.1.0+4066+0f1aadab vdasize=50.00 GB vdbsize=NONE

node1 | CHANGED | rc=0 >> hostname=node1 mem=979 bios=1.11.1-4.module+el8.1.0+4066+0f1aadab vdasize=50.00 GB vdbsize=NONE

node4 | CHANGED | rc=0 >> hostname=node4 mem=979 bios=1.11.1-4.module+el8.1.0+4066+0f1aadab vdasize=50.00 GB vdbsize=2.00 GB

node2 | CHANGED | rc=0 >> hostname=node2 mem=979 bios=1.11.1-4.module+el8.1.0+4066+0f1aadab vdasize=50.00 GB vdbsize=1.00 GB

node5 | CHANGED | rc=0 >> hostname=node5 mem=979 bios=1.11.1-4.module+el8.1.0+4066+0f1aadab vdasize=50.00 GB vdbsize=5.00 GB

<a name="ujZ3W"></a>
## 13. 创建保险库文件 
1)创建 ansible 保险库 /home/alice/ansible/passdb.yml,其中有 2 个变量: 

- pw_dev,值为 ab1234 
- pw_man,值为 cd5678 

2) 加密和解密该库的密码是 pwd@1234 ,密码在/home/alice/ansible/secret.txt 中 
<a name="RGvtE"></a>
### 解题思路

- ansilbe加密使用 ansible-vault 命令
<a name="GA78E"></a>
### 解题参考
```shell
[alice@control ansible]$ vim passdb.yml 
---
pw_dev: ab1234
pw_man: cd5678
[alice@control ansible]$ echo 'pwd@1234' >secret.txt 
[alice@control ansible]$ chmod 0600 secret.txt 
[alice@control ansible]$ ansible-vault encrypt --vault-id=secret.txt passdb.yml 
Encryption successful

方法二:

[alice@control ansible]$ echo 'pwd@1234' > secret.txt //创建保险库钥匙文件
[alice@control ansible]$ ansible-vault create passdb.yml --vault-password-file=secret.txt
pw_dev: ab1234 //创建保险库文件
pw_man: cd5678

验证方案

查看文件已经被加密了

[alice@control ansible]$ cat passdb.yml 
$ANSIBLE_VAULT;1.1;AES256
.......

14. 编写剧本为受管机批量创建用户,要求使用保险库中的密码

从以下 URL 下载用户列表,保存到/home/alice/ansible 目录下:
创建剧本 /home/alice/ansible/users.yml 的 playbook,满足下列要求:

  • 1)使用之前题目中的 passdb.yml 保险库文件
  • 2)职位描述为 dev 的用户应在 test01、test02 主机组的受管机上创建,从 pw_dev 变量 分配密码,是补充组 devops 的成员
  • 3)职位描述为 man 的用户应在 web 主机组的受管机上创建,从 pw_man 变量分配密码,是 补充组 opsmgr 的成员
  • 4)该 playbook 可以使用之前题目创建的 secret.txt 密码文件运行

    解题思路

  • 这道题的逻辑关系较强,需要我们明确逻辑关系,伪代码如下:

    if  (职位描述 == dev) and (主机组 == test01 or 主机组 == test02) {
       创建用户,使用 pw_dev 作为密码
    }
    if  (职位描述 == man) and (主机组 == web) {
       创建用户,使用 pw_man 作为密码
    }
    
  • 本题用到的模块有 group、user、使用了过滤器 password_hash

  • loop循环使用变量时{{}}要用双引号括起来

    解题参考

    ```shell [alice@control ansible]$ curl -sO http://study.lab0.example.com/materials/name_list.yml [alice@control ansible]$ vim users.yml

  • name: 添加用户 hosts: web,test01,test02 vars_files:
    • passdb.yml
    • name_list.yml tasks:
    • name: # 创建附加组 group: name: “{{ item }}” state: present loop:
      • devops
      • opsmgr
    • name: # 添加用户 user: name: “{{ item.name }}” password: “{{ pw_dev | password_hash(‘sha512’) }}” groups: devops when: ‘(“dev” == item.job) and (“web” not in group_names)’ loop: “{{ users }}”
    • name: # 添加用户 user: name: “{{ item.name }}” password: “{{ pw_man | password_hash(‘sha512’) }}” groups: opsmgr when: ‘(“man” == item.job) and (“web” in group_names)’ loop: “{{ users }}” [alice@control ansible]$ ansible-playbook users.yml —vault-password-file =/home/alice/ansible/secret.txt //验证剧本 **方法二:**shell [alice@control ansible]$ wget http://study.lab0.example.com/materials/name_list.yml //获取用户列表文件 [alice@control ansible]$ cat name_list.yml //确认列表内容 users:
      • name: tom job: dev //用户岗位 a
      • name: jerry job: man //用户岗位 b [alice@control ansible]$ vim users.yml
  • name: batch users hosts: test01,test02,web vars_files:

    • passdb.yml //加载密码变量
    • name_list.yml //加载用户名变量 tasks:
      • group: name=devops //确保补充组 1 在指定主机已存在
      • group: name=opsmgr //确保补充组 2 在指定主机已存在
      • user: name={{item.name}} password={{pw_dev|password_hash(‘sha512’)}} groups=devops when: (item.job == ‘dev’) and (‘test01’ in group_names or ‘test02’ in group_names) loop: “{{users}}” //按条件添加 a 岗用户
      • user: name={{item.name}} password={{pw_man|password_hash(‘sha512’)}} groups=opsmgr when: (item.job == ‘man’) and (‘web’ in group_names) loop: “{{users}}” //按条件添加 b 岗用户 [alice@control ansible]$ ansible-playbook users.yml —vault-password-file =/home/alice/ansible/secret.txt //验证剧本
        <a name="ZhwMF"></a>
        ### 验证方案
        failed=0,使用新添加的用户登录即可,密码在13题文件中
        ```shell
        [alice@control ansible]$ ansible all -m shell -a "cat /etc/passwd | tail -2"  # 查看用户是否添加正确
        [alice@control ansible]$ ssh -l tom node1
        # tom@node1's password: 
        [alice@control ansible]$ ssh -l tom node2
        # tom@node2's password: 
        [alice@control ansible]$ ssh -l jerry node3
        # jerry@node3's password: 
        [alice@control ansible]$ ssh -l jerry node4
        # jerry@node4's password:
        

        15. 重设保险库密码

        1)从以下 URL 下载保险库文件到/home/alice/ansible 目录:
        http://study.lab0.example.com/materials/topsec.yml
        2)当前的库密码是 banana,新密码是 big_banana,请更新该库密码

        知识点拓展

  • 下载文件可以使用wget或者curl命令

    • curl -sO http://study.lab0.example.com/materials/topsec.yml
    • wget http://study.lab0.example.com/materials/topsec.yml
    • 修改ansible文件密码使用ansible-vault rekey命令

      解题参考

      [alice@control ansible]$ wget http://study.lab0.example.com/materials/topsec.yml  //下载指定保险库文件
      [alice@control ansible]$ ansible-vault rekey topsec.yml //为保险库设置新的密码
      Vault password: 输入当前的库密码
      New Vault password: 输入新的库密码
      confirm New Vault password: 再次输入新的库密码确认
      Rekey successful
      

      验证方案

      用新密码查看文件
      [alice@control ansible]$ ansible-vault view topsec.yml 
      Vault password: 
      dachui: banana
      

      新增练习

      补充1:

      安装系统角色,创建playbook /home/alice/ansible/selinux.yml,
      要求满足如下条件:
  1. 在所有被管理主机运行
  2. 使用selinux角色
  3. 使用角色配置强制状态运行SElinux
    cp  -r /usr/share/ansible/roles/rhel-system-roles.selinux/ ~/ansible/roles/selinux 
    cat ~/ansible/roles/selinux/README.md
    ## Usage The general usage is demonstrated in [selinux-playbook.yml](selinux-playbook.yml) playbook.
    ### selinux role
    This role can be configured using variables as it is described below.
    ```yaml
    vars:
    [ see below ]
    roles:
    - role: rhel-system-roles.selinux
     become: true
    
    这里说明了使用selinux角色的用法是先写变量vars,具体变量看下面的内容【see below】 然后再通过roles调用角色,后面是角色的名称
    ```shell
    #### set SELinux policy type and mode
    ```yaml
    selinux_policy: targeted
    selinux_state: enforcing
    ```.
    Allowed values for `selinux_state` are `disabled`, `enforcing` and `permissive`.
    
    对于设置SELinux配置而言,有两个变量,最终得出结论答案: ```shell vim ~/ansible/selinux.yml

  • hosts: all vars: selinux_policy: targeted selinux_state: enforcing roles:
    • rhel-system-roles.selinux ``` 这题和11题远程Web有冲突,如果需要开启SELinux,则11题不可以关闭selinux,执行shell模块命令:chcon -R -t httpd_sys_content_t /webdev

      补充2:

      编写剧本/home/alice/ansible/jihuarenwu.yml,在所有被管理主机运行,为用户alice创建计划任务: alice用户每隔5分钟执行echo “hello tarena”
      本题目使用cron模块 ```shell

      vim /home/alice/ansible/jihuarenwu.yml


  • hosts: all tasks:

    • name: create crontab job. cron: name: myjob minute: “*/5” job: ‘echo “hello world”‘ user: alice ```

      补充3

  • 学会编写ansible剧本可以创建分区、格式化、永久挂载 需要使用的模块包括parted、filesystem、mount

  • 需要自己通过ansible-doc,查看帮助自学这三个模块的使用方法!!!