ansible-playbook

1 目标

最终:根据服务使用流程,书写出对应的剧本.

2 剧本

2.1 剧本

  • playbook 文件,用于长久保存并且实现批量管理,维护,部署的文件. 类似于脚本存放命令和变量,剧本中存放的时候?模块..
  • 剧本yaml格式,yaml格式的文件: 空格,冒号.
  • 剧本未来我们批量管理,运维必会的内容.
 

ans剧本

ans ad-hoc(命令行) -m -a

共同点

批量管理,使用模块 批量管理,使用模块

区别

重复调用,加上变量. 不是很方便,不容易重复

应用建议(应用场景)

部署服务,多个步骤的任务 测试模块,临时性任务

2.2 剧本书写格式

2.2.1 剧本核心概念:

角色 play 通过hosts部分指定的 (指定你要管理的主机(主机清单里面的)

任务 tasks 具体要执行的模块(根据你的步骤转换)

模块(根据你的操作流程,步骤选择模块)

2.2.2 基本格式

# 1. 顶格---开头(可以不写)
# 2. 以.yml或.yaml结尾
---
- hosts: all
  tasks:
    - name: 01 走到门前
      shell: echo 01 >>/tmp/house.log
      
    - name: 02 小心将鲜花放到门口
      shell: echo 02 >>/tmp/house.log
      
    - name: 03 默默祈祷
      shell: echo 03 >>/tmp/house.log

    - name: 04 扭头就跑
      shell: echo 04 >>/tmp/house.log

执行脚本

[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 01_test.yaml

黄色字体说明文件等有改动绿色字体说明没改动红色字体是报错

2.2.3 书写Ans playbook注意事项:⭐ ⭐ ⭐ ⭐ ⭐

同一个层级的内容对齐的.

不同层级的通过2个空格对齐

不能使用tab键

3 剧本案例

3.1 创建目录并分发文件

02_distribute.yaml
 [root@m01 /server/ans/playbook]# cat 02_distribute.yaml 
---
  - hosts: all
    tasks:
      - name: touch directory
        file: 
          path: /server/files
          state: directory
          
      - name: mv hosts  
        copy:
          src: /etc/hosts
          dest: /server/files
          
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 02_distribute.yaml 
PLAY [all] ****************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.68]
ok: [172.16.1.69]
ok: [172.16.1.67]

TASK [touch directory] ****************************************************************************************************************************************************
changed: [172.16.1.67]
changed: [172.16.1.69]
changed: [172.16.1.68]

TASK [mv hosts] ***********************************************************************************************************************************************************
changed: [172.16.1.67]
changed: [172.16.1.69]
changed: [172.16.1.68]

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.67                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.68                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.69                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@m01 /server/ans/playbook]# 

[root@m01 /server/ans/playbook]# ansible all -i /server/ans/playbook/hosts -a 'tree -F /server/files'
172.16.1.68 | CHANGED | rc=0 >>
/server/files
└── hosts

0 directories, 1 file
172.16.1.67 | CHANGED | rc=0 >>
/server/files
└── hosts

0 directories, 1 file
172.16.1.69 | CHANGED | rc=0 >>
/server/files
└── hosts

0 directories, 1 file
[root@m01 /server/ans/playbook]# 

3.2 批量添加定时任务

3.2.1 删除之前的定时任务

sed -ri '/sync|ntpdate/d' /var/spool/cron/root
 [root@m01 /server/ans/playbook]# ansible all -i /server/ans/playbook/hosts -a "sed -r /sync|ntpdate/d /var/spool/cron/root"
172.16.1.67 | CHANGED | rc=0 >>

172.16.1.69 | CHANGED | rc=0 >>

172.16.1.68 | CHANGED | rc=0 >>

[root@m01 /server/ans/playbook]# ansible all -i /server/ans/playbook/hosts -a "sed -ri /sync|ntpdate/d /var/spool/cron/root"
172.16.1.69 | CHANGED | rc=0 >>

172.16.1.67 | CHANGED | rc=0 >>

172.16.1.68 | CHANGED | rc=0 >>

[root@m01 /server/ans/playbook]# ansible all -i /server/ans/playbook/hosts -a "crontab -l"
172.16.1.67 | CHANGED | rc=0 >>

172.16.1.69 | CHANGED | rc=0 >>

172.16.1.68 | CHANGED | rc=0 >>

3.2.2 添加定时任务

03_sync_date.yaml
 #添加脚本
[root@m01 /server/ans/playbook]# cat 03_sync_date.yaml 
---
  - hosts: all
    tasks:
      - name: sync time
        cron:  
          name: update date
          minute: "*/5"
          job: "/sbin/ntpdate  ntp.aliyun.com >/dev/null 2>&1 "
          state: present
[root@m01 /server/ans/playbook]#

# 批量执行脚本
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 03_sync_date.yaml 
PLAY [all] ****************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.69]
ok: [172.16.1.67]
ok: [172.16.1.68]

TASK [sync time] **********************************************************************************************************************************************************
changed: [172.16.1.67]
changed: [172.16.1.68]
changed: [172.16.1.69]

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.67                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.68                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.69                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# 批量查看结果 
[root@m01 /server/ans/playbook]# ansible all -i hosts -a 'crontab -l'
172.16.1.69 | CHANGED | rc=0 >>
#Ansible: update date
*/5 * * * * /sbin/ntpdate  ntp.aliyun.com >/dev/null 2>&1 
172.16.1.67 | CHANGED | rc=0 >>
#Ansible: update date
*/5 * * * * /sbin/ntpdate  ntp.aliyun.com >/dev/null 2>&1 
172.16.1.68 | CHANGED | rc=0 >>
#Ansible: update date
*/5 * * * * /sbin/ntpdate  ntp.aliyun.com >/dev/null 2>&1 
[root@m01 /server/ans/playbook]# cd 

3.3 nfs服务

3.3.1 要求:

nfs服务端:在xxx上部署nfs服务,共享/backup-nfs目录,all_squash,匿名用户:www-ans uid 2999 2999

nfs客户端:web挂载 /ans-upload目录挂载nfs服务端共享的/backup-nfs(永久挂载)

3.3.2 根据步骤流程-->模块

# 查看nfs server 配置
[root@nfs01 ~]# showmount -e
Export list for nfs01:
/data    172.16.1.0/24
/nfsdata 172.16.1.0/24
[root@nfs01 ~]# 
[root@nfs01 ~]# hostname -I
10.0.0.68 172.16.1.68 
[root@nfs01 ~]# cat /etc/exports
/nfsdata/  172.16.1.0/24(rw,all_squash)
/data/ 172.16.1.0/24(rw,all_squash,anonuid=3999,anongid=3999)
[root@nfs01 ~]

# 新的服务端配置文件
[root@m01 /server/ans/playbook]# cat exports 
/nfsdata/  172.16.1.0/24(rw,all_squash)
/data/ 172.16.1.0/24(rw,all_squash,anonuid=3999,anongid=3999)
/nfs01_ans/ 172.16.1.0/24(rw,all_squash,anonuid=4999,anongid=4999)
[root@m01 /server/ans/playbook]#

#1.nfs server
- hosts: nfs01
  tasks:
    - name: 1.安装 nfs
    - name: 2.配置 /etc/exports
    - name: 3.添加用户组 add group www-ans 4999
    - name: 4.添加用户 add user www-ans   
    - name: 5.创建并更改目录属组/主 chown dir /nfs01_ans
    - name: 6.启动rpc
    - name: 7.启动 nfs

#2.nfs client
- hosts: web01
  tasks:
    - name: 1.安装nfs
    - name: 2.添加用户组 add group  4999
    - name: 3.添加用户 add user 
    - name: 4.创建目录 dir /data_ans
    - name: 5.挂载 mount  

3.3.3 书写剧本

04_nfs_server_client.yaml
 [root@m01 /server/ans/playbook]# cat 04_nfs_server_client.yaml 
# 1.nfs server
- hosts: nfs01
  tasks:
    - name: 1.安装 nfs
      yum: 
        name: rpcbind, nfs-utils
        state: installed
        
    - name: 2.配置 /etc/exports
      copy:
        src: exports
        dest: /etc/exports
        backup: yes

    - name: 3.添加用户组 add group www-ans 4999
      group: 
        name: www-ans
        gid: 4999
        state: present
        
    - name: 4.添加用户 add user www-ans 
      user:
        name: www-ans
        uid: 4999
        group: www-ans
        shell: /sbin/nologin
        create_home: no
        state: present
        
    - name: 5.创建并更改目录属组/主 chown dir /nfs01_ans
      file:
        path: /nfs01_ans
        state: directory
        owner: www-ans
        group: www-ans
        
    - name: 6.启动rpc
      systemd:
        name: rpcbind
        state: restarted
        
    - name: 7.启动 nfs
      systemd:
        name: nfs
        state: restarted

# 2.nfs client
- hosts: web01
  tasks:
    - name: 1.安装nfs
      yum: 
        name: rpcbind, nfs-utils
        state: installed
        
    - name: 2.添加用户组 add group  4999
      group: 
        name: www-ans
        gid: 4999
        state: present
        
    - name: 3.添加用户 add user 
      user:
        name: www-ans
        uid: 4999
        group: www-ans
        shell: /sbin/nologin
        create_home: no
        state: present
        
    - name: 4.创建目录 dir /data_ans
      file:
        path: /data_ans
        state: directory
        
    - name: 5.挂载 mount
      mount:
        src: 172.16.1.68:/nfs01_ans
        path: /data_ans
        fstype: nfs
        state: mounted
[root@m01 /server/ans/playbook]# 

# 测试 -C 模拟运行剧本并不会真的运行
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts -C 04_nfs_server_client.yaml

# 实际执行
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts  04_nfs_server_client.yaml
PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.68                : ok=8    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.69                : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

4 项目小结

1. 理清服务作用,服务使用流程.
2. 书写剧本核心: 列出步骤-->根据步骤找出对应的ansible模块
3. 书写剧本.
4. 调试剧本 ansible-playbook -i 主机清单文件 -C模拟运行 剧本(-C, --check)
5. 书写剧本前拍摄快照,边书写剧本边测试,最后测试完成,恢复快照,重新跑一次.(分步测试,联合测试)

5 Ansible中的变量

变量无处不在,在ans中大部分地方都可以定义变量.

比较常用的创建变量的地方:剧本中,类似于``功能,共用的变量文件.

可以定义变量的地方

说明

在剧本文件中定义

比较常用. 仅仅限于当前的play使用.
register变量(注册变量)

ip=`hostname -I` 实现脚本中反引号的功能,可以获取命令结果

变量文件,**根据主机清单分分组进行定义变量**

如果多个剧本,使用相同的变量,大型的剧本roles

inventory主机清单中定义变量

未来可以用于批量修改主机使用,其他很少用了

命令行中

几乎不用
facts变量

一般用于获取主机基本信息:ip,主机名,系统(centos/ubuntu) 如果不需要可以关闭,用于加速剧本的执行

5.1  剧本中使用变量⭐⭐⭐⭐⭐

ansible 变量命名规则:

  1. 与shell类似,不能以数字开头.
  2. 变量中仅包含_下划线即可.不要包含其他特殊符号.
05_vars.yaml
 [root@m01 /server/ans/playbook]# cat 05_vars.yaml 
# vars : variables 变量的内容,变量.
---
- hosts: web01
  vars:
    dir: /xk/test/upload
    file: 1.txt
  tasks:
    - name: 01.mkdir
      file:
        path: "{{ dir }}"
        state: directory
        
    - name: 02.touch
      file:
        path: "{{ dir }}/{{ file }}"
        state: touch
        
    - name : 输出结果
      debug: 
        msg: "目录名字:{{  dir }}   文件名字:{{  file }}"
[root@m01 /server/ans/playbook]# 

[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 05_vars.yaml 

PLAY [web01] **************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.69]

TASK [01.mkdir] ***********************************************************************************************************************************************************
changed: [172.16.1.69]

TASK [02.touch] ***********************************************************************************************************************************************************
changed: [172.16.1.69]

TASK [输出结果] ***********************************************************************************************************************************************************
ok: [172.16.1.69] => {
    "msg": "目录名字:/xk/test/upload   文件名字:1.txt"
}

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.69                : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@m01 /server/ans/playbook]# 
[root@m01 /server/ans/playbook]# ansible web01 -i hosts -a 'tree -F /xk/test'
172.16.1.69 | CHANGED | rc=0 >>
/xk/test
└── upload/
    └── 1.txt

1 directory, 1 file

⚠ 温馨提示: 

使用变量的时候如果变量是某个选项的开头,则变量引用的时候需要加上双引号

变量是开头加""
 - hosts: web01
  vars:
    dir: /xk/test/upload
    file: 1.txt
  tasks:
    - name: 01.mkdir
      file:
        path: "{{ dir }}"   # 这种要添加"",变量是开头.
        state: directory
        
    - name: 02.touch
      file:
        path: "{{ dir }}/{{ file }}"  # 这种要添加"",变量是开头.
        state: touch
        
    - name : 输出结果
      debug: 
        msg: "目录名字:{{  dir }}   文件名字:{{  file }}"  # 这种可以不加引号,变量不是开头.

在剧本play中定义变量应用:

  1. 仅仅在当前play生效.
  2. 一般用来存放路径,用户名,ip地址,类似于之前使用的脚本.
  3. 注意引号使用.
  • 优势:使用简单,在剧本开头(play和tasks之间)创建即可.
  • 缺点:只能在当前的play中生效,其他play中要使用变量,需要重新定义.
  • 使用建议: 简单剧本,只有1个play可以使用.(一个hosts部分)

5.2 共用变量-变量文件

把变量写到1个文件中,在剧本play中通过vars_files指定变量文件

06_vars_file.yaml
 [root@m01 /server/ans/playbook]# cat vars.yml 
dir: /server/ans-test-01/
file: test.txt
[root@m01 /server/ans/playbook]# 

[root@m01 /server/ans/playbook]# cat 06_vars_file.yaml 
- hosts: web01
  vars_files:
    - ./vars.yml
  tasks:
    - name: mkdir
      file:
        path: "{{ dir }}" #类似于 $dir 变量是开头就要加上引号.
        state: directory

    - name: touch
      file:
        path: "{{ dir }}{{ file }}" #类似于 $dir 变量是开头就要加上引号.
        state: touch


- hosts: nfs01
  vars_files:
    - ./vars.yml
  tasks:
    - name: mkdir
      file:
        path: "{{ dir }}" #类似于 $dir 变量是开头就要加上引号.
        state: directory

    - name: touch
      file:
        path: "{{ dir }}{{ file }}" #类似于 $dir 变量是开头就要加上引号.
        state: touch
[root@m01 /server/ans/playbook]#
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 06_vars_file.yaml 

PLAY [web01] **************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.69]

TASK [mkdir] **************************************************************************************************************************************************************
changed: [172.16.1.69]

TASK [touch] **************************************************************************************************************************************************************
changed: [172.16.1.69]

PLAY [nfs01] **************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.68]

TASK [mkdir] **************************************************************************************************************************************************************
changed: [172.16.1.68]

TASK [touch] **************************************************************************************************************************************************************
changed: [172.16.1.68]

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.68                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.69                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@m01 /server/ans/playbook]# ansible web01 -i hosts -a 'tree -F /server/ans-test-01'
172.16.1.69 | CHANGED | rc=0 >>
/server/ans-test-01
└── test.txt

0 directories, 1 file
[root@m01 /server/ans/playbook]# ansible nfs01 -i hosts -a 'tree -F /server/ans-test-01'
172.16.1.68 | CHANGED | rc=0 >>
/server/ans-test-01
└── test.txt

0 directories, 1 file
  • 优点:相对于vars方法,通过vars_files指定共享变量文件.
  • 缺点:每次使用还需要在Play中指定vars_files
  • 使用建议,能够理解变量文件作用即可,一般使用下面的方法

5.3 共用变量-根据主机组使用变量 ⭐⭐⭐⭐⭐

  • 这种方案本质:还是变量文件,多了个组功能.
  • group_vars根据主机清单的分组去匹配变量文件.
  • 主机组有变量用组机组的,没有去all里面找
  • 主机组创建变量文件.

group_vars

主机组变量文件存放位置
 [root@m01 /server/ans/playbook]# tree -F /server/ans/playbook/
/server/ans/playbook/
├── 01_test.yaml        # 剧本
├── 02_distribute.yaml  # 剧本
├── 03_sync_date.yaml   # 剧本
├── group_vars/
│   ├── all/
│   │   └── vars.yml  # 所有主机公有的变量文件
│   └── web01/
│       └── vars.yml     # web01组私有的变量文件
└── hosts  # 主机清单

3 directories, 16 files

[root@m01 /server/ans/playbook]# cat group_vars/all/vars.yml 
dir: /server/ans-test-01/
file: test.txt

创建目录和文件

web01和nfs01
 - hosts: web01
  tasks:
    - name: mkdir
      file:
        path: "{{ dir }}" .
        state: directory

    - name: touch
      file:
        path: "{{ dir }}{{ file }}" 
        state: touch

      
- hosts: nfs01
  tasks:
    - name: mkdir
      file:
        path: "{{ dir }}"
        state: directory

    - name: touch
      file:
        path: "{{ dir }}{{ file }}" 
        
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 07_vars_group_all.yaml 
[root@m01 /server/ans/playbook]# cat group_vars/all/vars.yml
dir: /server/ans-test-01/
file: test.txt 
[root@m01 /server/ans/playbook]# cat group_vars/web01/vars.yml
dir: /server/ans-test-02/
file: 1.txt 
[root@m01 /server/ans/playbook]# ansible all -i hosts -a 'tree -F /server'
172.16.1.68 | CHANGED | rc=0 >>
/server
├── ans-test-01/
│   └── test.txt
├── files/
     └── hosts
172.16.1.69 | CHANGED | rc=0 >>
/server
├── ans-test-02/
     └── 1.txt

5.4 变量定义小结

5.5 facts变量

Ansible定义变量方式

应用场景

⭐ 剧本文件中定义vars定义

变量仅在1个play中使用.(1个剧本中只有1个-hosts:) 常用

变量文件,剧本文件中通过vars_files调用

同1个剧本中多个play使用,别人使用你能理解含义.

⭐ 变量文件 (组),group_vars

自动读取group_vars/all/vars.yml内容. 未来用于书写大型剧本.

facts变量相当于是ansible内置变量,存放被管理机器的基本信息.运行剧本的时候会运行:Gathering Facts task任务.

Gathering Facts :ansible收集被管理端基本信息.cpu,内存,磁盘,网络,系统.

我们在剧本中使用facts变量,未来如果不用可以关闭gather facts功能,加速剧本运行效果.

  • ans内置变量,ans运行剧本的时候会有一个默认的task(Gathering Facts),这个背后在收集每个主机的基本信息.(eg:ip信息,主机名,磁盘,这个主机的各种基本信息)
  • 这些基本信息就称为facts变量.

5.5.1 facts变量setup模块获取

    • setup模块被用来收集目标主机的系统信息。setup模块是Ansible的一个核心模块,它不需要额外的安装,用于收集主机的各种事实(facts),
      比如操作系统类型、内存大小、磁盘空间等
setup模块收集主机信息
 [root@m01 /server/ans/playbook]# ansible -i hosts 172.16.1.68 -m setup >facts.yaml
#文件内容700多行,只看一些关键信息
"ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "172.16.1.68",
            "10.0.0.68"
        ],
        "ansible_date_time": {
            "date": "2024-10-17",
            ...
        },
        "ansible_hostname": "nfs01",
        "ansible_default_ipv4": {
            "address": "10.0.0.68",
            "alias": "ens33",
            "broadcast": "10.0.0.255",
            "gateway": "10.0.0.2",
            "interface": "ens33",
            "macaddress": "00:50:56:2c:73:be",
            "mtu": 1500,
            "netmask": "255.255.255.0",
            "network": "10.0.0.0",
            "type": "ether"
        },
        "ansible_distribution": "Kylin Linux Advanced Server",
        "ansible_distribution_file_path": "/etc/os-release",,
        "ansible_distribution_version": "V10",
        "ansible_dns": {
            "nameservers": [
                "223.5.5.5",
                "223.6.6.6"
            ]
        },
        "ansible_machine": "x86_64",
        "ansible_machine_id": "59ee89b9aaee492f86c8f945a2228acf",
        "ansible_memfree_mb": 1335,
        "ansible_memory_mb": {
            "nocache": {
                "free": 1602,
                "used": 354
            },
            "real": {
                "free": 1335,
                "total": 1956,
                "used": 621
            },
            "swap": {
                "cached": 0,
                "free": 2047,
                "total": 2047,
                "used": 0
            }
        },
        "ansible_memtotal_mb": 1956,
        "ansible_processor_cores": 2,  # 核心
        "ansible_processor_count": 1,
        "ansible_processor_nproc": 2,
        "ansible_processor_threads_per_core": 1,
        "ansible_processor_vcpus": 2,  # cpu核心总数量
        "ansible_selinux": {
            "status": "disabled"
        },
}

5.5.2 常用fact变量

常用fact变量
ansible_hostname #主机名
ansible_memtotal_mb #内存大小(总计) 单位mb
ansible_processor_vcpus #cpu核心总数数量
ansible_default_ipv4.address #默认的网卡ip eth0
ansible_distribution #系统发行版本名字 CentOS Ubuntu  Debian ...
ansible_distribution_version #系统的版本
ansible_date_time.date # 年-月-日

5.5.3 输出常用基本信息到屏幕,系统基本信息写入到/opt/facts.txt中.

08_facts.yaml
 [root@m01 /server/ans/playbook]# cat 08_facts.yaml 

- hosts: all
  tasks:
    - name: 调试变量 
      debug:
        msg: |
          "主机名:{{ ansible_hostname  }}"
          "内存大小:{{ ansible_memtotal_mb  }}"
          "cpu核数:{{ ansible_processor_vcpus  }}"

    - name: 保存到文件中
      lineinfile:
        path: /opt/facts.txt
        create: true
        line: |
          主机名:{{ ansible_hostname  }}
          内存大小:{{ ansible_memtotal_mb  }}
          cpu核数:{{ ansible_processor_vcpus  }}
          系统: {{ ansible_distribution }}
          系统版本:{{ ansible_distribution_version }}
[root@m01 /server/ans/playbook]# 
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 08_facts.yaml

PLAY [all] ****************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.68]
ok: [172.16.1.69]
ok: [172.16.1.87]

TASK [调试变量] ***********************************************************************************************************************************************************
ok: [172.16.1.69] => {
    "msg": "\"主机名:web01\"\n\"内存大小:1956\"\n\"cpu核数:2\"\n"
}
ok: [172.16.1.68] => {
    "msg": "\"主机名:nfs01\"\n\"内存大小:1956\"\n\"cpu核数:2\"\n"
}
ok: [172.16.1.87] => {
    "msg": "\"主机名:backup\"\n\"内存大小:1927\"\n\"cpu核数:2\"\n"
}

TASK [保存到文件中] *******************************************************************************************************************************************************
changed: [172.16.1.87]
changed: [172.16.1.68]
changed: [172.16.1.69]

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.68                : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.69                : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.1.87                : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@m01 /server/ans/playbook]# 
[root@m01 /server/ans/playbook]# ansible all -i hosts -a 'cat /opt/facts.txt'
[DEPRECATION WARNING]: Ansible will require Python 3.8 or newer on the controller starting with Ansible 2.12. Current version: 3.7.9 (default, Jun 10 2022, 11:25:35) [GCC
 7.3.0]. This feature will be removed from ansible-core in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
172.16.1.87 | CHANGED | rc=0 >>
主机名:backup
内存大小:1927
cpu核数:2
系统: Ubuntu
系统版本:22.04
172.16.1.68 | CHANGED | rc=0 >>
主机名:nfs01
内存大小:1956
cpu核数:2
系统: Kylin Linux Advanced Server
系统版本:V10
172.16.1.69 | CHANGED | rc=0 >>
主机名:web01
内存大小:1956
cpu核数:2
系统: Kylin Linux Advanced Server
系统版本:V10
[root@m01 /server/ans/playbook]# 

说明:

debug模块用于在剧本中输出与调试,一般用于输出变量内容.

| 表示下面的内容是多行,用于输出或写入多行到文件中,注意索引对齐.

5.5.4 ans-facts 变量与判断

09_check_os.yaml
 [root@m01 /server/ans/playbook]# cat 09_check_os.yaml 
- hosts: all
  tasks:
    - name: 输出系统发行版本
      debug: 
        msg: "发行版本 {{ ansible_distribution }}"

    - name: if Kylin|CentOS
      yum:
        name: cowsay
        state: present
      when: ansible_distribution is match ("Kylin|CentOS")

    - name: if Ubuntu|Debian
      apt:
        name: cmatrix
        state: present
      when: ansible_distribution is match ("Ubuntu|Debian")
[root@m01 /server/ans/playbook]# 
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 09_check_os.yaml 

PLAY [all] ****************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.69]
ok: [172.16.1.68]
ok: [172.16.1.87]

TASK [输出系统发行版本] ***************************************************************************************************************************************************
ok: [172.16.1.69] => {
    "msg": "发行版本 Kylin Linux Advanced Server"
}
ok: [172.16.1.68] => {
    "msg": "发行版本 Kylin Linux Advanced Server"
}
ok: [172.16.1.87] => {
    "msg": "发行版本 Ubuntu"
}

TASK [if Kylin|CentOS] ****************************************************************************************************************************************************
skipping: [172.16.1.87]
ok: [172.16.1.69]
ok: [172.16.1.68]

TASK [if Ubuntu|Debian] ***************************************************************************************************************************************************
skipping: [172.16.1.69]
skipping: [172.16.1.68]
changed: [172.16.1.87]

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.68                : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
172.16.1.69                : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
172.16.1.87                : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

[root@m01 /server/ans/playbook]# 

facts变量实际应用案例:

  1. 通过facts变量获取系统的基本信息
  2. 通过facts变量获取信息并进行判断
  3. 如果不需要可以进行关闭,加速剧本的运行( gather_facts: false )
  4. 修改ansible.cfg #gathering = implicit去掉注释,永久关闭,后期剧本中需要开启gather_facts: true
  5. 布尔类型的数据:
      真:yes,True,true   (开启,启动)   
      假:no,False,false   假(关闭).
- hosts: all
gather_facts: false
tasks: ...

 

 默认开启,不使用的时候临时关闭: gather_facts: false hosts: tasks之间

彻底关闭,使用的时候在剧本中临时开启 gather_facts: true

ansible.cfg
 cat>/etc/ansible/ansible.cfg<<EOF
[defaults]
gathering = explicit
host_key_checking = False
deprecation_warnings = False
interpreter_python = /usr/bin/python3
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
EOF
gathering = explicit #彻底关闭facts,如果需要开启需要在剧本中设置,gather_facts: true
gathering = implicit ##开启facts变量 默认就是开启 如果需要关闭gather_facts: false

facts变量小结

  • 需要通过变量获取主机的基本信息,ip或主机名...
  • 使用的时候一般搭配when进行判断. 判断主机名,判断发行版本 when : xxx is match("Kylin")
  • 如果不使用facts变量可以在剧本中关闭. gather_facts: false

5.6 register变量注册变量 ⭐⭐

本质上就是用来实现脚本中的反引号功能. ip=`hostname -I`

用户通过命令获取的内容都存放到Register变量中.

应用场景:获取命令执行结果或获取模块执行的结果.

5.6.1. 获取register变量信息

get_register_info
 [root@m01 /server/ans/playbook]# cat 10_register_ip.yaml 
- hosts: web01
  tasks:
    - name: get ip
      shell: hostname -I | awk '{print $1}'
      register: ip

    - name: use ip
      debug:
        msg: "ip: {{ ip }}"

[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 10_register_ip.yaml 

PLAY [web01] **************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.69]

TASK [get ip] *************************************************************************************************************************************************************
changed: [172.16.1.69]

TASK [use ip] *************************************************************************************************************************************************************
ok: [172.16.1.69] => {
    "msg": "ip: {'changed': True, 'stdout': '10.0.0.69', 'stderr': '', 'rc': 0, 'cmd': \"hostname -I | awk '{print $1}'\", 'start': '2024-10-17 17:02:54.378986', 'end': '2024-10-17 17:02:54.384595', 'delta': '0:00:00.005609', 'msg': '', 'stdout_lines': ['10.0.0.69'], 'stderr_lines': [], 'failed': False}"
}

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.69                : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

变量格式

json形式数据. key: value

"msg": "ip: {
    'changed': True, 
    'stdout': '10.0.0.69', 
    'stderr': '',
    'rc': 0, 
    'cmd': \"hostname -I | awk '{print $1}'\", 
    'start': '2024-10-17 17:02:54.378986', 
    'end': '2024-10-17 17:02:54.384595',
    'delta': '0:00:00.005609',
    'msg': '', 
    'stdout_lines': ['10.0.0.69'], 
    'stderr_lines': [], 
    'failed': False
 }"

5.6.2 使用register变量信息

[root@m01 /server/ans/playbook]# cat 10_register_ip.yaml 
- hosts: web01
  tasks:
    - name: get ip
      shell: hostname -I | awk '{print $1}'
      register: ip

    - name: use ip
      debug:
        msg: "ip: {{ ip.stdout }}"

    - name: touch dir
      file:
        path: /opt/{{ ip.stdout }}
        state: directory
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 10_register_ip.yaml 

PLAY [web01] **************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [172.16.1.69]

TASK [get ip] *************************************************************************************************************************************************************
changed: [172.16.1.69]

TASK [use ip] *************************************************************************************************************************************************************
ok: [172.16.1.69] => {
    "msg": "ip: 10.0.0.69"
}

TASK [touch dir] **********************************************************************************************************************************************************
ok: [172.16.1.69]

PLAY RECAP ****************************************************************************************************************************************************************
172.16.1.69                : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

符号说明

msg:中的|表示下面的内容是多行. |也可以用于其他模块中.

5.7 总结

Ansible定义变量方式

应用场景

⭐ 剧本文件中定义vars定义

变量仅在1个play中使用.(1个剧本中只有1个- hosts:) 常用

变量文件,剧本文件中通过vars_files调用

同1个剧本中多个play使用.

⭐ 变量文件group_vars

自动读取group_vars/all/vars.yml内容. 未来用于书写大型剧本.

facts变量(ansible运行收集的信息)

获取基本信息,未来一般与判断一起用.

如果不用可以关闭,加速剧本运行

register(注册变量) 创建变量存放命令的结果,命令行反引号

 

可以用于替代部分facts功能.一般与判断一起使用.

官网:https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html

6 案例

 6.1 nfs 存储

6.1.1 nfs_server剧本

nfs_server_playbook
  # 1.nfs server
- hosts: nfs01
  tasks:
    - name: 1.安装 nfs
      yum: 
        name: rpcbind, nfs-utils
        state: installed
        
    - name: 2.配置 /etc/exports
      copy:
        src: exports
        dest: /etc/exports
        backup: yes
      notify:
        - 7.启动 nfs

    - name: 3.添加用户组 add group www-ans 4999
      group: 
        name: www-ans
        gid: 4999
        state: present
        
    - name: 4.添加用户 add user www-ans 
      user:
        name: www-ans
        uid: 4999
        group: www-ans
        shell: /sbin/nologin
        create_home: no
        state: present
        
    - name: 5.创建并更改目录属组/主 chown dir /nfs01_ans
      file:
        path: /nfs01_ans
        state: directory
        owner: www-ans
        group: www-ans
        
  handlers:
  
    - name: 6.启动rpc
      systemd:
        name: rpcbind
        state: restarted  
        
    - name: 7.启动 nfs
      systemd:
        name: nfs
        state: reloaded

6.1.2 nfs_client剧本

nfs_client_playbook
  # 2.nfs client
- hosts: web01
  tasks:
    - name: 1.安装nfs
      yum: 
        name: rpcbind, nfs-utils
        state: installed
        
    - name: 2.添加用户组 add group  4999
      group: 
        name: www-ans
        gid: 4999
        state: present
        
    - name: 3.添加用户 add user 
      user:
        name: www-ans
        uid: 4999
        group: www-ans
        shell: /sbin/nologin
        create_home: no
        state: present
        
    - name: 4.创建目录 dir /data_ans
      file:
        path: /data_ans
        state: directory
        
    - name: 5.挂载 mount
      mount:
        src: 172.16.1.68:/nfs01_ans
        path: /data_ans
        fstype: nfs
        state: mounted

 6.1.3 配置文件 /etc/exports

# nfs_server_cfg
/nfsdata/  172.16.1.0/24(rw,all_squash)
/data/ 172.16.1.0/24(rw,all_squash,anonuid=3999,anongid=3999)
/nfs01_ans/ 172.16.1.0/24(rw,all_squash,anonuid=4999,anongid=4999)

6.1.4 运行与调试

# nfs_server
# 调试
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts -C nfs_server_playbook.yaml
# 执行
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts nfs_server_playbook.yaml

# nfs_cleint
# 调试
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts -C nfs_client_playbook.yaml
# 执行
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts nfs_client_playbook.yaml

6.2 rsync 定时备份

根据shell 脚本书写playbook步骤

列出剧本任务
 # rsync_server
- hosts:backup  
  tasks:
    - name: 1.安装rsync 
    - name: 2.添加用户
    - name: 3.创建备份目/nfs01backup录且更改权限rsync
    - name: 4.修改配置文件/etc/rsyncd.conf
    - name: 5.创建密码文件,修改权限600
    - name: 6.rsync重启
    - name: 7.文件校验(shell脚本实现) ans_bak_file_server.sh
    - name: 8.备份数据(shell脚本实现) ans_bak_file_server.sh
    - name: 9.将shell脚本分发到rsync_server
    - name: 10.将脚本加入定时任务
    
# rsync_client
- hosts:nfs01 
  tasks:
    - name: 1.创建备份目录 /nfs01backup
    - name: 2.创建密码文件,修改权限600
    - name: 3.打包数据(shell脚本实现) ans_bak_file_client.sh
    - name: 4.数据加密 md5(shell脚本实现) ans_bak_file_client.sh
    - name: 5.远程备份(shell脚本实现) ans_bak_file_client.sh
    - name: 6.清理7天前数据(shell脚本实现) ans_bak_file_client.sh
    - name: 7.将shell脚本分发到rsync_client
    - name: 8.将脚本加入定时任务 

6.2.1 rsync_server 剧本

21_rsync_server.yaml
 - hosts: backup
  gather_facts: true 
  tasks:
    - name: 1.安装rsync 
      yum:
        name: rsync
        state: present
      when: ansible_distribution is match("Kylin|CentOS")
      
    - name: 1.安装rsync
      apt:
        name: rsync
        state: present
      when: ansible_distribution is match("Debian|Ubuntu")
      
    - name: 2.添加用户
      user:
        name: rsync
        shell: /sbin/nologin
        create_home: no
        state: present
        
    - name: 3.创建备份目录/nfs01backup且更改权限rsync
      file:
        path: /nfs01backup
        state: directory
        owner: rsync
        group: rsync
        
    - name: 4.修改配置文件/etc/rsyncd.conf
      template:
        src: ./rsyncd.conf
        dest: /etc/rsyncd.conf
        backup: yes
    
    - name: 5.创建密码文件,写入内容
      ansible.builtin.lineinfile:
        path: /etc/rsync.password
        line: "rsync_backup:Xk123456"
        state: present
        
    - name: 6.修改权限600
      file:
        path: /etc/rsync.password
        mode: "0600"
             
    - name: 7.rsync重启
      systemd:
        name: rsyncd
        state: restarted
      when: ansible_distribution is match("Kylin|CentOS")

    - name: 7.rsync重启
      systemd:
        name: rsync
        state: restarted
      when: ansible_distribution is match("Debian|Ubuntu")

    - name: 8.分发脚本
      copy:
        src: ./ans_bak_file_server.sh
        dest: /server/scripts
        backup: yes

    - name: 9.将脚本加入定时任务
      cron:
        name: bak_data
        minute: "00"
        hour: "00"
        job: "/bin/bash /server/scripts/ans_bak_file_server.sh >/dev/null 2>&1"
        state: present

6.2.2 rsync _client 剧本

22_rsync_client.yaml
 #rsync_client
- hosts: nfs01 
  tasks:
    - name: 1.创建备份目录 /nfs01backup
      file:
        path: /nfs01backup
        state: directory
        
    - name: 2.创建密码文件
      lineinfile:
        path: /etc/rsync.client
        line: "Xk123456"
        state: present

    - name: 3.修改权限
      file:
        path: /etc/rsync.client
        mode: "0600"      

    - name: 4.分发脚本
      copy:
        src: ./ans_bak_file_client.sh
        dest: /server/scripts
        backup: yes      
    
    - name: 5.将脚本加入定时任务
      cron:
        name: ans_data
        minute: "00"
        hour: "00"
        job: "/bin/bash /server/scripts/ans_bak_file_client.sh >/dev/null 2>&1"
        state: present

6.2.3 配置文件 /etc/rsyncd.conf

rsyncd.conf
 # rsyncd.conf_start
fake super =yes 
uid = rsync
gid = rsync
use chroot = no
max connections = 2000
timeout = 600
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
#hosts allow = 10.0.0.0/24
#hosts deny = 0.0.0.0/32
auth users = rsync_backup
secrets file = /etc/rsync.password
#####################################
[data]
comment = www by xk 14:18 2024-1-13
path = /data

[nfs01backup]
comment = www by xk 14:18 2024-1-13
path = /nfs01backup

[nfs01backup2]
comment = www by xk 14:18 2024-1-13
path = /nfs01backup2

6.2.4 rsync_server_shell脚本

ans_bak_file_server.sh
 #!/bin/bash
##############################################################
# File Name:ans_bak_file_server.sh
# Version:V1.0
# Author:xk
# Organization:
# Desc:
##############################################################

#rsync_server
# vars
dir=/nfs01backup
log_file=/var/log/bak.log

check_res(){
  ret="$?"
  params="$*"
  if [ $ret -eq 0 ];then
    echo "$params 执行成功" >> $log_file
  else
    echo "$params 执行失败" >> $log_file
  fi
}

# 校验
find $dir -type f -name *.md5 | xargs md5sum -c > $dir/md5.txt
check_res md5sum --check

#备份检查脚本,清理旧的备份(超过180天,不包含每周一的备份),通过邮件方式发给领导
find $dir -type f -name *.tar.gz ! *_1.tar.gz -mtime +180 | rm -f
check_res rm bak

6.2.5 rsync_client _shell脚本

ans_bak_file_client.sh
 [root@nfs01 ~]# cat /server/scripts/ans_bak_file_client.sh 
#!/bin/bash
##############################################################
# File Name:ans_bak_file_client.sh
# Version:V1.0
# Author:xk
# Organization:
# Desc:
##############################################################

# rsync_client
# vars
dir=/nfs01backup
module=nfs01backup
ip=`hostname -I | awk '{print $1}'`
# dst_ip="$1"
dst_ip="172.16.1.67"
time=`date +%F_%w`
path=$dir/$ip
bak_file=$path/$time.tar.gz
log_file=/var/log/bak.log
#secret="/etc/rsync.client"

check_res(){
  ret="$?"
  params="$*"
  if [ $ret -eq 0 ];then
    echo "$params 执行成功" >> $log_file
  else
    echo "$params 执行失败" >> $log_file
  fi
}

# 创建备份目录
mkdir $path

# tar
tar zcf $bak_file /etc/
check_res tar

# md5sum
md5sum $bak_file > $path/bak.md5
check_res md5sum

# rsync  $dir后面加上/
rsync -av $dir/ rsync_backup@$dst_ip::$module --password-file=/etc/rsync.client
check_res rsync

# 清理7天之前的文件
find /backup -type f -name *.tar.gz -mtime +7 | xargs rm -f
check_res rm bak +7

6.2.6 运行与调试

调试
 # 1.测试服务端剧本
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts -C 21_rsync_server.yaml

# 2.测试客户端剧本
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts -C 22_rsync_client.yaml

# 3.运行服务端剧本
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 21_rsync_server.yaml

# 4.运行客户端剧本
[root@m01 /server/ans/playbook]# ansible-playbook -i hosts 22_rsync_client.yaml

# 5.手动运行客户端(存储)脚本
[root@nfs01 ~]# bash -x  /server/scripts/ans_bak_file_client.sh
[root@nfs01 ~]# tree -F /nfs01backup/
/nfs01backup/
└── 10.0.0.68/
    ├── 2024-10-23_3.tar.gz
    └── bak.md5

1 directory, 2 files
[root@nfs01 ~]# cat /nfs01backup/10.0.0.68/bak.md5 
326a8de19879d1fabd2ce4330461c242  /nfs01backup/10.0.0.68/2024-10-23_3.tar.gz
[root@nfs01 ~]# 

# 6.手动运行服务端(备份)脚本
[root@backup ~]# bash -x  /server/scripts/ans_bak_file_server.sh
[root@backup ~]# tree -F /nfs01backup
/nfs01backup
├── 10.0.0.68/
│   ├── 2024-10-23_3.tar.gz
│   └── bak.md5
└── md5.txt

1 directory, 3 files
[root@backup ~]# cat /nfs01backup/md5.txt 
/nfs01backup/10.0.0.68/2024-10-23_3.tar.gz: 成功

 注意:

在 Linux 中,普通用户以 root 权限执行脚本,sudo 是最常用的方法,可以让普通用户以 root 权限执行特定命令或脚本。

1. 确保用户在 sudoers 文件中有权限。username ALL=(ALL) ALL

2. 然后 sudo bash 脚本名

6.3 lsyncd 实时备份

posted @ 2024-10-21 15:31  老虎死了还有狼  阅读(11)  评论(0编辑  收藏  举报