ansible

Ansible

Ansible

  • Ansible是批量管理服务器的工具。是Michael DeHaan (也是Cobbler的作者)使用Python语言编写的,2015年被红帽公司收购。
    • Ansible的软件:ansible ,没有服务。
      Ansible的命令:ansible
    • Ansible基于ssh 进行管理(需要免密ssh),所以不需要额外在被控端安装软件(需要开启ssh服务)。
    • Ansible是用Python编写的,所以需要安装Python来运行Ansible的核心引擎。
  • Ansible管理远程主机,需要在工作目录下进行,管理 工作目录下的配置文件 ansible.cfg 中指定的 主机清单文件 中记录的主机,主要通过各种模块来实现管理。

环境准备

java 复制代码
// Ansible的环境准备
/* 准备四台主机pubserver(192.168.88.240)、web1(192.168.88.11)、web2(192.168.88.12)、db1(192.168.88.13)。
 * 四台主机配置主机名、IP地址,关闭SELinux和防火墙。
 * 主机pubserver拷贝真机/linux-soft/s2/zzg/ansible_soft目录下的rpm包,并配置为第三个YUM仓库。四台主机配置网络YUM仓库。
 * 主机pubserver配置名称解析、SSH免密登陆到另外三台主机。
 */
达内的真机(有脚本vm,可用 man vm 查看具体用法。创建的虚拟主机的用户root默认密码a):
[student@server1 ~]$ sudo -i
[root@server1 ~]# vm clone web{1,2} db1				// vm脚本创建虚拟主机
[root@server1 ~]# vm setip web1 192.168.88.1		// vm脚本配置IP地址
[root@server1 ~]# vm setip web2 192.168.88.12
[root@server1 ~]# vm setip db1 192.168.88.13
[root@server1 ~]# scp /linux-soft/s2/zzg/ansible_soft/* 192.168.88.240:		/* 将rpm包拷贝到主机pubserver */

控制端主机pubserver(192.168.88.240):
// 关闭SElinux和防火墙
]# vim /etc/selinux/config 
	SELINUX=disabled
]# setenforce 0
]# systemctl stop firewalld.service
]# systemctl disable firewalld.service
// 先配置本地YUM仓库,安装vsftpd、createrepo后再配置为网络仓库
]# yum install -y vsftpd createrepo
]# vim /etc/vsftpd/vsftpd.conf
     12 anonymous_enable=YES						// NO访问时会报错503
]# systemctl restart vsftpd.service
]# systemctl enable vsftpd.service
]# mkdir /var/ftp/{dvd,rpms}
]# mv ~/*.rpm /var/ftp/rpms							/* 将rpm包移动到ftp共享目录下的rpms目录 */
]# createrepo /var/ftp/rpms							// 创建rpms目录的仓库清单
]# cat /etc/yum.repos.d/local.repo					// 创建网络YUM仓库配置文件
	[app]
    name=appstream
    baseurl=ftp://192.168.88.240/dvd/AppStream
	gpgcheck=0
    [base]
	name=baseos
	baseurl=ftp://192.168.88.240/dvd/BaseOS
	gpgcheck=0
	[rpms]
    name=rpms
	baseurl=ftp://192.168.88.240/rpms
	gpgcheck=0
]# echo "/dev/sr0 /var/ftp/dvd iso9660 defaults 0 0" >> /etc/fstab	// 开机自动挂载
]# mount -a 
]# yum repoinfo
// 配置名称解析
]# for i in 1 2
> do
> echo -e "192.168.88.1$i\tweb$i" >> /etc/hosts
> done    
]# echo -e "192.168.88.13\tdb1" >> /etc/hosts
// SSH免密登陆
]# ssh-keygen					// 三个问题默认回车
]# for i in 1 2 3	
> do
> ssh-copy-id 192.168.88.1$i
> done
// 传递YUM仓库配置文件							
]# for i in 1 2 3
> do 
> scp /etc/yum.repos.d/local.repo 192.168.88.1${i}:/etc/yum.repos.d/local.repo
> done

真机管理虚拟机的命令

  • virsh list:真机查看运行中的KVM虚拟机。
  • virsh list --all:真机查看所有的KVM虚拟机。
  • virt-manager:打开KVM虚拟系统管理器。
  • virsh console 虚拟机名称:连接该台虚拟机的控制台。
    • 使用virsh console管理虚拟机,相比ssh命令,当IP地址变换时不会断开连接,重启虚拟机不会断开连接。
    • 但virsh console命令只能用于通过终端控制本地运行的虚拟机。
  • virsh net-list:查看虚拟机的所有网络。
java 复制代码
// virsh list
真机查看虚拟机的名称和状态
[student@server1 ~]$ sudo -i
[root@server1 ~]# virsh list			// 查看运行中的虚拟机
 Id   名称     状态
-----------------------
 4    166-2    运行中
 11   88-240   运行中
 12   db1      运行中
 13   web1     运行中
 14   web2     运行中

[root@server1 ~]# virsh list --all		// 查看所有虚拟机
 Id   名称     状态
-----------------------
 4    166-2    运行中
 11   88-240   运行中
 12   db1      运行中
 13   web1     运行中
 14   web2     运行中
 -    proxy    关闭
 -    win10    关闭

[root@server1 ~]# virsh console db1		// 连接虚拟机db1的控制台
连接到域 db1
Escape character is ^] (Ctrl + ])		// 按回车

Rocky Linux 8.6 (Green Obsidian)
Kernel 4.18.0-372.9.1.el8.x86_64 on an x86_64

db1 login: root
Password: 
Last login: Thu Jul 20 17:20:11 from 192.168.88.240
[root@db1 ~]# 							// 成功登陆虚拟机db1

[root@server1 ~]# virsh net-list 		// 查看虚拟机的所有网络
     名称         状态   自动开始   持久
    --------------------------------------
     ckavbr       活动   是         是
     default      活动   是         是
     network166   活动   是         是
     private1     活动   是         是
     private2     活动   是         是
     rhce         活动   是         是

Ansible远程管理

工作目录、配置文件、主机清单文件

  • Ansible管理远程主机,需要在工作目录下进行,管理 工作目录下的配置文件 ansible.cfg 中指定的 主机清单文件 中记录的主机,主要通过各种模块来实现管理。
  • 配置Ansible管理环境步骤:
    • 下载Ansible软件ansible(ansible是工具,下载后不用启动服务)
    • 创建Ansible的工作目录(任意取名1)并进入该工作目录(Ansible管理需要在该目录下进行)
    • 编写Ansible的配置文件 工作目录/ansible.cfg:指定主机清单文件
      • 第一行:[defaults]
        第二行:inventory=主机清单文件路径。相对路径从本配置文件父目录为起始。
        第三行:host_key_checking=false。第一次连接known_hosts没有记录过的主机时是否询问检查主机密钥(默认为是),如果连接没有记录过的主机必须写该项,如果连接有记录的可以不写该项。
      • 可参考默认配置文件是 /etc/ansible/ansible.cfg
      • Ansible配置文件的使用顺序:
        1. ANSIBLE_CONFIG变量定义的配置文件。
        2. 当前目录下的 ./ansible.cfg 文件。(一般使用该文件)
        3. 当前用户家目录下的 ~/ansible.cfg 文件。
        4. 默认配置文件 /etc/ansible/ansible.cfg
    • 编写Ansible的主机清单文件(任意取名2):指定被管理的所有主机
      • 第一行:[组名]。组名可任意取名。
        第二行:组内的主机名或IP地址
      • 第一行:[组名:children]。组名可任意取名。
        第二行:组内的子组组名
      • 可参考/etc/ansible/hosts
      • 组名或主机名或IP地址必须写在主机清单文件才能被Ansible管理
        • 注意:如果这里写主机名,则必须在 /etc/hosts 内增加名称解析 IP地址 主机名,否则ansible命令使用主机名会识别不了主机名的IP地址
        • 注意:如果这里写IP地址,则ansible命令需要使用IP地址,因为必须写在主机清单文件中才能被ansible命令使用
  • 查看被Ansible管理的主机(在Ansible工作目录下操作)
    • ansible --version:查看ansible相关信息。
    • ansible all --list-hosts:查看被管理的所有主机。
    • ansible 组名 --list-hosts:查看该组的所有主机。
    • ansible-inventory --graph:以图形化方式查看主机清单文件。
java 复制代码
// 配置Ansible管理环境
真机:
]# scp /linux-soft/s2/zzg/ansible_soft/ansible-6.3.0-1.el8.noarch.rpm  192.168.88.240:		// ansible软件
]# scp /linux-soft/s2/zzg/ansible_soft/ansible-core-2.13.3-1.el8.x86_64.rpm  192.168.88.240: // ansible的依赖

控制主机pubserver(192.168.88.240):
]# yum install -y ansible-core-2.13.3-1.el8.x86_64.rpm
]# yum install -y ansible-6.3.0-1.el8.noarch.rpm	// ansible是工具,下载后不用启动服务
]# mkdir ansibletest						// 创建Ansible的工作目录,任意取名
]# cd ansibletest/
ansibletest]# touch ansible.cfg inventorytest
ansibletest]# cat ansible.cfg 				// Ansible配置文件,固定名称ansible.cfg。
	[defaults]
    inventory=inventorytest	// 指定主机清单文件位置,相对路径从本配置文件父目录为起始
    host_key_checking=false	// 非必需项。是否检查主机密钥   
ansibletest]# cat inventorytest 			// 主机清单文件,任意取名
    [webs]					// [组名],任意取名
    web[1:2]				// 组内的主机名或IP地址。[1:2]表示从1到2。

    [dbs]					// [组名],任意取名
    db1						// 组内的主机名或IP地址。

    [cluster:children]		// [组名:children],任意取名
    webs					// 组内的子组
    dbs						// 组内的子组

// 注意,一定在工作目录下执行命令。
ansibletest]# ansible --version			
    ansible [core 2.13.3]
      config file = /root/ansibletest/ansible.cfg
      configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
      ansible python module location = /usr/lib/python3.9/site-packages/ansible
      ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
      executable location = /usr/bin/ansible
      python version = 3.9.7 (default, May 10 2022, 23:45:56) [GCC 8.5.0 20210514 (Red Hat 8.5.0-10)]
      jinja version = 3.1.2
      libyaml = True
ansibletest]# ansible-inventory --graph		// 以图形化方式查看主机清单文件
    @all:
      |--@cluster:
      |  |--@dbs:
      |  |  |--db1
      |  |--@webs:
      |  |  |--web1
      |  |  |--web2
      |--@ungrouped:
ansibletest]# ansible all --list-hosts		// 查看被管理的所有的主机
      hosts (3):
        web1
        web2
        db1
ansibletest]# ansible webs --list-hosts		// 查看webs组中所有的主机
      hosts (2):
        web1
        web2

// 报错
// 情况1:
ansibletest]# ansible db1 -a "ls -l /opt"
    db1 | UNREACHABLE! => {
        "changed": false,
        "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname db1: Name or service not known",
        "unreachable": true
    }
	// 原因:名称解析文件/etc/hosts中没有"192.168.88.13 db1",系统无法识别db1的IP地址。
// 情况2:
ansibletest]# ansible 192.168.88.13 -a "ls -l /opt"
    [WARNING]: Could not match supplied host pattern, ignoring: 192.168.88.13
    [WARNING]: No hosts matched, nothing to do
	// 原因:主机清单文件中没有记录"192.168.88.13",因此ansible命令无法管理该主机。
// 情况3:
ansibletest]# ansible 192.168.88.13 -a "ls -l /opt"
    192.168.88.13 | UNREACHABLE! => {
        "changed": false,
        "msg": "Failed to connect to the host via ssh: root@192.168.88.13: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
        "unreachable": true
    }
	// 原因:没有传递公钥"ssh-copy-id 192.168.88.13",无法免密ssh该主机,ansible命令基于ssh,因此报错。

Ansible远程管理方法

  • Ansible进行远程管理的两个方法(需要在Ansible工作目录下操作,都是通过模块和参数操作):

    • ad-hoc临时命令:在命令行上执行管理命令。
    • playbook剧本:把管理任务用特定格式写到剧本文件.yml中。

ad-hoc临时命令

  • 语法规范:ansible all或组名或主机 -m 模块 -a "参数键值对" [-i 主机清单文件路径](module-name,args):远程管理所有主机,或该组所有主机,或该主机。省略主机清单文件路径默认为ansible.cfg设置的主机清单文件。
  • 改变目标主机数据(CHANGED)则返回黄色,没有改变目标主机数据(SUCCESS)则返回绿色,拼写错误返回红色

ansible-doc说明文档

  • ansible-doc -l(list):查看全部模块。
  • ansible-doc -l | wc -l:查看模块数量(7214)。
  • ansible-doc -l | grep 字符串:查看包含字符串的模块名称。
  • ansible-doc 模块名称:查看该模块的说明文档。(/EXAMPLE 查看例子,按空格翻页,按q退出)
  • ansible-doc -s 模块名称(snippet ):查看该模块的所有参数及用法。

ping模块

  • ansible all或组名或主机 -m ping:检查配置的管理环境是否可用,是否可以管理 远程主机。(绿色SUCCESS表示成功)
    • 注意:ping模块通过ssh协议检查能否远程管理目标主机,而不同于ping命令使用ICMP协议。

command模块

  • ansible all或组名或主机 -m command -a "命令 [参数]"
    可简写为 ansible all或组名或主机 -a "命令 [参数]"
  • command模块是ansible的默认模块,用于在远程主机上执行任意命令。
  • command模块不支持shell特性,如管道、重定向。
  • command模块和shell模块需要被控端安装python(许多Linux发行版会默认安装python)。
  • 常用参数:
    • creates:如果该参数指定的文件存在,就不执行命令。
    • removes:如果该参数指定的文件不存在,就不执行命令。(只有该参数指定的文件存在,才执行命令)
java 复制代码
// command模块
ansibletest]# ansible all -a "mkdir /tmp/demo"
    web2 | CHANGED | rc=0 >>

    db1 | CHANGED | rc=0 >>

    web1 | CHANGED | rc=0 >>
ansibletest]# ansible webs -m command -a "mkdir /tmp/demo2"
    web2 | CHANGED | rc=0 >>

    web1 | CHANGED | rc=0 >>
// 其值路径存在不执行命令。参数removes,其值路径不存在就不执行命令
ansibletest]# ansible web1 -a "mkdir /cr"
ansibletest]# ansible web1 -a "touch /cr/a.txt"
ansibletest]# ansible web1 -a "touch /cr/b.txt creates=/cr/a.txt"	// 参数creates,其值路径存在不执行命令
    web1 | SUCCESS | rc=0 >>
    skipped, since /cr/a.txt existsDid not run command since '/cr/a.txt' exists
ansibletest]# ansible web1 -a "ls /cr"
    web1 | CHANGED | rc=0 >>
    a.txt
ansibletest]# ansible web1 -a "touch /cr/c.txt removes=/cr/b.txt"	// 参数removes,其值路径不存在就不执行命令
    web1 | SUCCESS | rc=0 >>
    skipped, since /cr/b.txt does not existDid not run command since '/cr/b.txt' does not exist
ansibletest]# ansible web1 -a "ls /cr"
    web1 | CHANGED | rc=0 >>
    a.txt

shell模块

  • ansible all或组名或主机 -m shell -a "命令"
  • shell模块与command模块类似,但是支持shell特性,如管道、重定向
  • 常用参数:
    • creates:如果该参数指定的文件存在,就不执行命令。
    • removes:如果该参数指定的文件不存在,就不执行命令。(只有该参数指定的文件存在,才执行命令)
java 复制代码
// shell模块
ansibletest]# ansible all -m command -a "ip a s eth0 | head -3"			// 报错,command模块不支持管道
	// 可简写为:ansible all -a "ip a s | head"
    web1 | FAILED | rc=255 >>
    Error: either "dev" is duplicate, or "|" is a garbage.non-zero return code
    web2 | FAILED | rc=255 >>
    Error: either "dev" is duplicate, or "|" is a garbage.non-zero return code
    db1 | FAILED | rc=255 >>
    Error: either "dev" is duplicate, or "|" is a garbage.non-zero return code

ansibletest]# ansible webs -m shell -a "ip a s eth0 | head -3"
	web1 | CHANGED | rc=0 >>
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 52:54:00:0b:d0:d8 brd ff:ff:ff:ff:ff:ff
        inet 192.168.88.11/24 brd 192.168.88.255 scope global noprefixroute eth0
    web2 | CHANGED | rc=0 >>
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 52:54:00:55:75:64 brd ff:ff:ff:ff:ff:ff
        inet 192.168.88.12/24 brd 192.168.88.255 scope global noprefixroute eth0

script模块

  • ansible all或组名或主机 -m script -a "脚本路径"
  • script模块用于在远程主机上执行脚本:将脚本上传到主机后,执行该脚本,然后删除该脚本
  • 常用参数:
    • creates:如果该参数指定的文件存在,就不执行命令。
    • removes:如果该参数指定的文件不存在,就不执行命令。(只有该参数指定的文件存在,才执行命令)
java 复制代码
// script模块
ansibletest]# cat test.sh
    #!/bin/bash
    for user in user{1..5}
    do
        useradd $user
        echo '123' | passwd --stdin $user
    done
ansibletest]# ansible webs -m script -a "test.sh"
ansibletest]# ansible webs -a "tail -5 /etc/passwd"
    web2 | CHANGED | rc=0 >>
    user1:x:1002:1002::/home/user1:/bin/bash
    user2:x:1003:1003::/home/user2:/bin/bash
    user3:x:1004:1004::/home/user3:/bin/bash
    user4:x:1005:1005::/home/user4:/bin/bash
    user5:x:1006:1006::/home/user5:/bin/bash
    web1 | CHANGED | rc=0 >>
    user1:x:1002:1002::/home/user1:/bin/bash
    user2:x:1003:1003::/home/user2:/bin/bash
    user3:x:1004:1004::/home/user3:/bin/bash
    user4:x:1005:1005::/home/user4:/bin/bash
    user5:x:1006:1006::/home/user5:/bin/bash

幂等性

  • 幂等性:执行任意次所产生的影响均与执行一次的影响相同。例如:不会因为重复创建同一个数据而报错。
  • command模块、shell模块、script模块的参数是命令模式,不具备幂等性,因此不建议使用。
  • ansible工具其他模块是声明模式,具备幂等性。

file模块

  • ansible all或组名或主机 -m file -a "参数1=值1 参数n=值n"
  • file模块可以创建删除文件、目录、链接等,还可以修改权限、归属关系等。
  • 常用的参数:
    • pathname:指定被操作数据的路径。
    • statetouch表示创建文件(已存在则改变修改时间),directory表示创建目录,link表示创建软链接,hard表示创建硬链接,absent表示删除。
    • owner:设置被操作数据的所有者。该所有者在被控端必须存在否则报错。
    • group:设置被操作数据的所属组。该所属组在被控端必须存在否则报错。
    • mode:设置被操作数据的权限。
    • src(source):指定链接源数据路径。
    • dest(destination):指定链接目标数据路径。
    • recurse:是否递推修改属性。
    • force:是否强制覆盖同名数据。省略默认为no
java 复制代码
// file模块
ansibletest]# ansible-doc file			// 查看file密块说明文档

// state=touch 创建文件。文件不存在则创建(返回黄色);文件存在则只改变它的修改时间(返回黄色)
ansibletest]# ansible webs -m file -a "path=/tmp/file.txt state=touch"

// state=directory 创建目录。目录不存在则创建(返回黄色);目录存在则不改变(返回绿色)
ansibletest]# ansible webs -m file -a "path=/tmp/demo state=directory"

// owner=所有者、group=所属组、mode=权限。配置不同则修改(返回黄色),配置相同则不修改(返回绿色)
ansibletest]# ansible webs -m file -a "path=/tmp/file.txt owner=sshd group=adm mode=777"
ansibletest]# ansible webs -a "ls -l /tmp/file.txt"
    web1 | CHANGED | rc=0 >>
    -rwxrwxrwx 1 sshd adm 0 Jul 17 15:17 /tmp/file.txt
    web2 | CHANGED | rc=0 >>
    -rwxrwxrwx 1 sshd adm 0 Jul 17 15:17 /tmp/file.txt

// state=absent 删除数据。数据存在则删除(返回黄色);数据不存在则无改变(返回绿色)
ansibletest]# ansible webs -m file -a "path=/tmp/file.txt state=absent"

// state=link 创建软链接。src=源数据路径,dest=目标数据路径。
ansibletest]# ansible webs -m file -a "src=/etc/hosts dest=/tmp/hosts.txt state=link"
ansibletest]# ansible webs -a "ls -l /etc/hosts"				// 查看软链接源文件
    web2 | CHANGED | rc=0 >>
    -rw-r--r--. 1 root root 158 Sep 10  2018 /etc/hosts
    web1 | CHANGED | rc=0 >>
    -rw-r--r--. 1 root root 158 Sep 10  2018 /etc/hosts
ansibletest]# ansible webs -a "ls -l /tmp/hosts.txt"			// 查看软链接
    web2 | CHANGED | rc=0 >>
    lrwxrwxrwx 1 root root 10 Jul 17 15:39 /tmp/hosts.txt -> /etc/hosts
    web1 | CHANGED | rc=0 >>
    lrwxrwxrwx 1 root root 10 Jul 17 15:39 /tmp/hosts.txt -> /etc/hosts

copy模块

  • ansible all或组名或主机 -m copy -a "参数1=值1 参数n=值n"
  • copy模块可以用于将数据(文件或目录)从控制端拷贝(上传)到被控端。可以拷贝,也可以在被控端直接凭空创建数据。
  • 常用参数:
    • src(source):指定控制端的源数据路径。只拷贝源数据,不拷贝路径
    • dest(destination):指定被控端的目标数据路径(相对路径是登陆用户的家目录)。(需存在父目录)
    • content:覆盖重定向文件内容。(结尾\n换行符)
    • force:是否强制覆盖同名文件。省略默认为no
    • backup:是否重命名同名文件(带时间戳)以备份。yes则将被控端的同名文件重命名备份并上传控制端的文件,省略默认为no
    • owner:设置目标数据所有者。
    • group:设置目标数据所属组。
    • mode:设置目标数据权限。
  • template模块\](# template模块)和copy模块的区别: * copy模块可以上传文件,但是文件内容固定。 * template模块可以上传包含变量的文件。当远程主机接收到文件之后,文件中的变量将会变成具体的值。

// copy模块
// src=控制端源数据路径,dest=被控端目标数据路径
ansibletest]# echo '123456' > a3.txt
ansibletest]# ansible webs -m copy -a "src=a3.txt dest=/root" // 控制端相对路径
ansibletest]# ansible webs -a "cat /root/a3.txt"
web1 | CHANGED | rc=0 >>
123456
web2 | CHANGED | rc=0 >>
123456

ansibletest]# echo '789' > a4.txt
ansibletest]# ansible webs -m copy -a "src=/root/ansibletest/a4.txt dest=/root" // 控制端绝对路径
ansibletest]# ansible webs -a "cat /root/a4.txt"
web1 | CHANGED | rc=0 >>
789
web2 | CHANGED | rc=0 >>
789

ansibletest]# ls -ld /etc/security/
drwxr-xr-x. 7 root root 4096 7月 17 12:53 /etc/security/
ansibletest]# ansible webs -m copy -a "src=/etc/security dest=/opt" // 控制端目录
ansibletest]# ansible webs -a "ls -ld /opt/security"
web1 | CHANGED | rc=0 >>
drwxr-xr-x 7 root root 4096 Jul 17 15:50 /opt/security
web2 | CHANGED | rc=0 >>
drwxr-xr-x 7 root root 4096 Jul 17 15:50 /opt/security

// dest=被控端目标数据路径,content='文件内容'
ansibletest]# ansible webs -m copy -a "dest=/root/a3.txt content='Hello world\n'" // 凭空创建,同名覆盖
ansibletest]# ansible webs -a "cat /root/a3.txt"
web2 | CHANGED | rc=0 >>
Hello world
web1 | CHANGED | rc=0 >>
Hello world

// dest需存在父目录
ansibletest]# ansible webs -a "ls -l /mnt"
web2 | CHANGED | rc=0 >>
total 4
drwxr-xr-x 7 sshd adm 4096 Jul 17 20:34 security
web1 | CHANGED | rc=0 >>
total 4
drwxr-xr-x 7 sshd adm 4096 Jul 17 20:34 security
ansibletest]# ansible webs -m copy -a "src=/etc/passwd dest=/mnt/b/c"
// 报错:"msg": "Destination directory /mnt/b does not exist"
ansibletest]# ansible webs -m copy -a "src=/etc/passwd dest=/mnt/b"
ansibletest]# ansible webs -a "ls -l /mnt"
web2 | CHANGED | rc=0 >>
total 8
-rw-r--r-- 1 root root 2507 Jul 17 21:56 b // 文件b
drwxr-xr-x 7 sshd adm 4096 Jul 17 20:34 security
web1 | CHANGED | rc=0 >>
total 8
-rw-r--r-- 1 root root 2507 Jul 17 21:56 b
drwxr-xr-x 7 sshd adm 4096 Jul 17 20:34 security

// backup=yes 重命名同名文件(带时间戳)以备份
ansibletest]# ansible web1 -a "mkdir /cpbk"
ansibletest]# ansible web1 -m shell -a "echo 'hello' > /cpbk/a.txt"
ansibletest]# echo 'bye' > a.txt
ansibletest]# ansible web1 -m copy -a "src=a.txt dest=/cpbk/a.txt backup=yes"
ansibletest]# ansible web1 -a "ls /cpbk"
web1 | CHANGED | rc=0 >>
a.txt // 上传的新文件
a.txt.4285.2023-08-17@20:24:38~ // 重命名同名文件(带时间戳)以备份
ansibletest]# ansible web1 -a "cat /cpbk/a.txt"
web1 | CHANGED | rc=0 >>
bye
ansibletest]# ansible web1 -a "cat /cpbk/a.txt.4285.2023-08-17@20:24:38~"
web1 | CHANGED | rc=0 >>
hello

复制代码
#### fetch模块

* `ansible all或组名或主机 -m fetch -a "参数1=值1 参数n=值n"`

<!-- -->

* fetch模块与copy模块相反,copy模块是将数据(文件或目录)上传到被控端,fetch模块是将文件下载到控制端。
* 常用参数:
  * `src`(source):指定被控端的源文件路径(相对路径是登陆用户的家目录)。**必须是文件** 。**默认会下载路径** ,但去掉开头的根目录 `/`。
  * `dest`(destination):指定控制端的目标文件路径。(**可以直接创建不存在的多级目录**)
  * `flat`:是否不下载路径。只对单个主机生效,省略默认为否。

```java
// fetch模块
// src=被控端源文件路径,dest=控制端目标文件路径
ansibletest]# ansible webs -m fetch -a "src=/etc/hostname dest=/opt"
ansibletest]# tree /opt
    /opt
    ├── web1
    │   └── etc
    │       └── hostname		// 会下载路径 etc/hostname
    └── web2
        └── etc
            └── hostname

    4 directories, 2 files

// 只能操作文件
ansibletest]# ansible webs -m fetch -a "src=/etc/security dest=/opt"	// 报错,只能下载文件
    web1 | FAILED! => {
        "changed": false,
        "msg": "remote file is a directory, fetch cannot work on directories"	// 不可以下载目录
    }
    web2 | FAILED! => {
        "changed": false,
        "msg": "remote file is a directory, fetch cannot work on directories"
    }

// dest可以不存在父目录,直接创建不存在的多级目录
ansibletest]# ls /mnt
	a
ansibletest]# ansible webs -m fetch -a "src=/etc/passwd dest=/mnt/b/c"
ansibletest]# tree /mnt
    /mnt
    ├── a
    └── b
        └── c					// 可以直接创建不存在的b目录和c目录
            ├── web1
            │   └── etc
            │       └── passwd
            └── web2
                └── etc
                    └── passwd

    7 directories, 2 files

// flat=yes 不下载路径,只下载文件本身。只能用于单台主机
ansibletest]# mkdir /flat
ansibletest]# ansible web1 -m file -a "path=/fetchflat state=directory"
ansibletest]# ansible web1 -m copy -a "dest=/fetchflat/flat.txt content='testflat'"
ansibletest]# ansible web1 -m fetch -a "src=/fetchflat/flat.txt dest=/flat/mome/"
ansibletest]# ansible web1 -m fetch -a "src=/fetchflat/flat.txt dest=/flat/none/ flat=yes"
	// 注意dest的目录可以不存在,但必须以`/`结尾,否则为文件重命名
ansibletest]# tree /flat
    /flat
    ├── mome
    │   └── web1
    │       └── fetchflat
    │           └── flat.txt		// 默认flat=no 下载路径/fetchflat/flat.txt
    └── none
        └── flat.txt				// flat=yes 不下载路径,只下载文件flat.txt

    4 directories, 2 files

lineinfile模块??

  • ansible all或组名或主机 -m lineinfile -a "参数1=值1 参数n=值n"
  • lineinfile模块用于确保存目标文件中有某一行内容。
  • 常用参数:
    • path:指定目标文件路径。
    • line:设置写入该文件的一行内容(严格匹配)。如果该行不存在,则默认添加到文件结尾。
    • regexp:指定被替换的行(正则表达式,包含匹配)。多行满足匹配则从后往前依次替换。
    • state:默认为present??
java 复制代码
// lineinfile模块
ansibletest]# ansible webs -a "cat /etc/issue"
    web2 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m
    web1 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

// path=目标文件路径,line='严格匹配某一行内容'
ansibletest]# ansible webs -m lineinfile -a "path=/etc/issue line='Hello World'"	// webs组的主机的/etc/issue中严格匹配某一行内容为Hello World。如果该行不存在,则默认添加到文件结尾
ansibletest]# ansible webs -m lineinfile -a "path=/etc/issue line=' Hello World'"	// 严格匹配,多个空格也匹配失败
ansibletest]# ansible webs -a "cat /etc/issue"
    web2 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    Hello World
     Hello World				
    web1 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    Hello World
     Hello World

// regexp=包含匹配被替换的行
ansibletest]# ansible webs -m lineinfile -a "path=/etc/issue line='goodbye' regexp='Hello'"		// 将webs组的主机的/etc/issue中包含匹配字符串Hello的行,替换成goodbye
ansibletest]# ansible webs -a "cat /etc/issue"
    web1 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    Hello World
    goodbye							// 多行满足匹配则从后往前依次替换
    web2 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    Hello World
    goodbye
ansibletest]# ansible webs -m lineinfile -a "path=/etc/issue line='goodbye' regexp='Hello'"
ansibletest]# ansible webs -a "cat /etc/issue"
    web2 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    goodbye							// 多行满足匹配则从后往前依次替换
    goodbye
    web1 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    goodbye
    goodbye

replace模块

  • ansible all或组名或主机 -m replace -a "参数1=值1 参数n=值n"
  • lineinfile模块替换一行,replace模块可以替换部分。
  • 常用参数:
    • path:指定目标文件路径。
    • regexp:指定被替换的内容(正则表达式,严格匹配)。多个满足匹配则全部被替换。
    • replace:设置替换后的内容。
java 复制代码
// replace模块
// path=目标文件路径,replace=替换后的内容,regexp=严格匹配被替换的内容
ansibletest]# ansible webs -a "cat /etc/issue"
    web2 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

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

    goodbye
    goodbye
ansibletest]# ansible webs -m replace -a "path=/etc/issue replace=' work' regexp='bye'"		// 将webs组的主机的/etc/issue的所有字符串bye替换为 work
ansibletest]# ansible webs -a "cat /etc/issue"
    web2 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    good work					// 多个满足匹配则全部被替换
    good work					// 多个满足匹配则全部被替换
    web1 | CHANGED | rc=0 >>
    \S
    Kernel \r on an \m

    good work
    good work

user模块

  • ansible all或组名或主机 -m user -a "参数1=值1 参数n=值n"
  • user模块可以实现用户管理

  • 常用参数:

    • name:待创建的用户名(已创建则指定用户)。
    • statepresent表示创建,absent表示删除,省略默认为present
    • remove:是否删除家目录、邮箱等。配合state=absent使用,是为yes或true或1,省略默认为否。
    • uid:设置用户的UID。
    • group:设置基本组。
    • groups:设置附加组。
    • home:设置家目录。
    • password:重置用户密码。(返回黄色)
      • password={``{'密码' | password_hash('sha512')}}{``{}}是固定格式,表示执行命令。password_hash是函数,sha512是加密算法。
java 复制代码
// user模块
// name=用户名,state=present创建(省略默认为present),uid=UID,group=基本组,groups=附加组1,附加组n
ansibletest]# ansible webs -m user -a "name=zhangsan uid=1010 group=adm groups=daemon,root"
ansibletest]# ansible webs -a "id zhangsan"
    web2 | CHANGED | rc=0 >>
    uid=1010(zhangsan) gid=4(adm) groups=4(adm),0(root),2(daemon)
    web1 | CHANGED | rc=0 >>
    uid=1010(zhangsan) gid=4(adm) groups=4(adm),0(root),2(daemon)

// home=家目录,password={{'密码'|password_hash('sha512')}}
ansibletest]# ansible webs -m user -a "name=lisi home=/home/lisitest password={{'123'|password_hash('sha512')}}"
ansibletest]# ansible webs -a "tail -1 /etc/passwd"
    web2 | CHANGED | rc=0 >>
    lisi:x:1011:1011::/home/lisitest:/bin/bash
    web1 | CHANGED | rc=0 >>
    lisi:x:1011:1011::/home/lisitest:/bin/bash

// state=absent删除,remove=yes或true连同家目录和邮箱删除(省略默认否)
ansibletest]# ansible webs -m user -a "name=zhangsan state=absent"
ansibletest]# ansible webs -m user -a "name=lisi state=absent remove=yes"
ansibletest]# ansible webs -a "ls -l /home"
    web1 | CHANGED | rc=0 >>
    total 0
    drwx------ 2 user1 user1 83 Jul 17 14:36 user1
    drwx------ 2 user2 user2 83 Jul 17 14:36 user2
    drwx------ 2 user3 user3 62 Jul 17 14:35 user3
    drwx------ 2 user4 user4 62 Jul 17 14:35 user4
    drwx------ 2 user5 user5 62 Jul 17 14:35 user5
    drwx------ 2  1007  1007 83 Jul 17 17:48 zhangsan		// /home/zhangsan保留
    web2 | CHANGED | rc=0 >>
    total 0
    drwx------ 2 user1 user1 62 Jul 17 14:35 user1
    drwx------ 2 user2 user2 62 Jul 17 14:35 user2
    drwx------ 2 user3 user3 62 Jul 17 14:35 user3
    drwx------ 2 user4 user4 62 Jul 17 14:35 user4
    drwx------ 2 user5 user5 62 Jul 17 14:35 user5
    drwx------ 2  1007  1007 62 Jul 17 17:34 zhangsan

group模块

  • ansible all或组名或主机 -m group -a "参数1=值1 参数n=值n"
  • group模块用于创建、删除组
  • 常用参数:
    • name:待创建的组名(已创建则指定组)。
    • gid:设置组的GID。
    • statepresent表示创建,absent表示删除,省略默认present
java 复制代码
// group模块
// name=组名,gid=GID,state=present创建(省略默认为absent)
ansibletest]# ansible webs -m group -a "name=test gid=1020"
ansibletest]# ansible webs -a "tail -2 /etc/group"
    web1 | CHANGED | rc=0 >>
    user5:x:1006:
    test:x:1020:
    web2 | CHANGED | rc=0 >>
    user5:x:1006:
    test:x:1020:

// state=absent删除
ansibletest]# ansible webs -m group -a "name=test state=absent"
ansibletest]# ansible webs -a "tail -1 /etc/group"
    web2 | CHANGED | rc=0 >>
    user5:x:1006:
    web1 | CHANGED | rc=0 >>
    user5:x:1006:

yum_repository模块

  • ansible all或组名或主机 -m yum_repository -a "参数1=值1 参数n=值n"
  • yum_repository模块用于编写YUM仓库配置文件。
  • 常用参数:
    • file:设置配置文件名(不含扩展名.repo),在目标主机的/etc/yum.repos.d下创建该文件。
    • name:设置仓库唯一标识ID。
    • description:设置仓库name,创建仓库时不可省略。
    • baseurl:指定仓库位置(本地或网络)。
    • enabled:是否启用本仓库,省略默认为是。(1或true或yes,0或false或no)
    • gpgcheck:是否检查红帽签名。(1或true或yes,0或false或no)
    • gpgkey:红帽签名信息 /etc/pki/rpm-gpp/RPM-GPG-KEY-rockyofficial
    • statepresent表示创建该仓库,absent表示删除该仓库,省略默认为present
      • 一次创建一个仓库:file(配置文件名)不存在则新建文件,file相同且name(仓库ID)相同则重置该仓库,file相同但name不同则追加仓库。
      • 一次删一个仓库,删除最后的仓库会删除文件。
java 复制代码
// yum_repository模块
// 查找包含yum字符串的ansible模块
ansibletest]# ansible-doc -l | grep yum
    [WARNING]: dellemc.openmanage.ome_active_directory has a documentation
    formatting error
    community.general.packaging.os.yum_versionlock	Locks / unlocks a installed package(s) from being updated by yum p...
    yum                                             Manages packages with the `yum' p...
    yum_repository 									Add or remove YU...

// state=present创建仓库,省略默认为present。file=配置文件名,name=仓库ID,description=仓库name
// 编写YUM仓库配置文件。file不存在则新建文件,file(文件名)相同且name(仓库ID)相同则重置该仓库,file相同但name不同则追加仓库。
ansibletest]# ansible db1 -m yum_repository -a "file=myrepo1 name=ida \		// file不存在
> description=test gpgcheck=0 enabled=1
> baseurl=ftp://192.168.88.240/dvd/AppStream"
    /* 在主机db1的/etc/yum.repos.d下创建一个"myrepo1.repo"文件,仓库ida
    [root@db1 ~]# ls /etc/yum.repos.d/
        local.repo  myrepo1.repo
    [root@db1 ~]# cat /etc/yum.repos.d/myrepo1.repo 
        [ida]
        async = 1
        baseurl = ftp://192.168.88.240/dvd/AppStream
        enabled = 1
        gpgcheck = 0
        name = test
     */
ansibletest]# ansible db1 -m yum_repository -a "file=myrepo1 name=ida \		// file相同且name相同
> description=test gpgcheck=0 enabled=1
> baseurl=ftp://192.168.88.240/dvd/BaesOS"
    /* 在主机db1的/etc/yum.repos.d下的"myrepo1.repo"文件,重置仓库ida
    [root@db1 ~]# ls /etc/yum.repos.d/
        local.repo  myrepo1.repo
    [root@db1 ~]# cat /etc/yum.repos.d/myrepo1.repo 
        [ida]
        async = 1
        baseurl = ftp://192.168.88.240/dvd/BaesOS
        enabled = 1
        gpgcheck = 0
        name = test
     */
ansibletest]# ansible db1 -m yum_repository -a "file=myrepo1 name=idb \		// file相同但name不同
> description=test gpgcheck=0
> baseurl=ftp://192.168.88.240/dvd/AppStream"
	/* 在主机db1的/etc/yum.repos.d下的"myrepo1.repo"文件,追加仓库idb
    [root@db1 ~]# ls /etc/yum.repos.d/
        local.repo  myrepo1.repo
	[root@db1 ~]# cat /etc/yum.repos.d/myrepo1.repo 
        [ida]
        async = 1
        baseurl = ftp://192.168.88.240/dvd/BaesOS
        enabled = 1
        gpgcheck = 0
        name = test

        [idb]
        async = 1
        baseurl = ftp://192.168.88.240/dvd/AppStream
        gpgcheck = 0
        name = test
	 */
ansibletest]# ansible db1 -m yum_repository -a "file=myrepo2 name=ida \		// file不存在
> description=test gpgcheck=0
> baseurl=ftp://192.168.88.240/dvd/AppStream"
	/* 在主机db1的/etc/yum.repos.d下创建一个"myrepo2.repo"文件,仓库ida
    [root@db1 ~]# ls /etc/yum.repos.d/
    	local.repo  myrepo1.repo  myrepo2.repo
	 */

// state=absent删除仓库,一次删除一个仓库,删除最后的仓库会删除文件
ansibletest]# ansible db1 -m yum_repository -a "file=myrepo1 name=idb state=absent"	
	/* 在主机db1的/etc/yum.repos.d下的"myrepo1.repo"文件,删除仓库idb
	[root@db1 ~]# cat /etc/yum.repos.d/myrepo1.repo 
        [ida]
        async = 1
        baseurl = ftp://192.168.88.240/dvd/BaesOS
        enabled = 1
        gpgcheck = 0
        name = test
     */
ansibletest]# ansible db1 -m yum_repository -a "file=myrepo1 name=ida state=absent"	
	/* 在主机db1的/etc/yum.repos.d下的"myrepo1.repo"文件,删除最后的仓库ida,也会删除"myrepo1.repo"文件
	[root@db1 ~]# cat /etc/yum.repos.d/myrepo1.repo 
		cat: /etc/yum.repos.d/myrepo1.repo: No such file or directory
    [root@db1 ~]# ls /etc/yum.repos.d/
    	local.repo  myrepo2.repo
     */
// 也可以通过file模块直接删除文件
ansibletest]# ansible db1 -m file -a "path=/etc/yum.repos.d/myrepo2.repo state=absent"
    /*[root@db1 ~]# ls /etc/yum.repos.d/
        local.repo
     */

yum模块

  • ansible all或组名或主机 -m yum -a "参数1=值1 参数n=值n"
  • yum模块用于rpm软件包管理,如安装、升级、卸载。
  • 常用参数:
    • name:指定 rpm包的软件名(支持通配符)或 @rpm包组名,多个软件名用 , 隔开。
    • statepresent表示安装,latest表示安装或升级到最新版本,absent表示卸载,省略默认为present
java 复制代码
// yum模块
// name=软件名。state=present安装,省略默认为present,已安装返回绿色,未安装则安装并返回黄色
ansibletest]# ansible db1 -m yum -a "name=net-tools"
    db1 | SUCCESS => {							// 已安装返回绿色
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false,
        "msg": "Nothing to do",
        "rc": 0,
        "results": []
    }
ansibletest]# ansible db1 -m yum -a "name=wget,net-tools "
    db1 | CHANGED => {							// 未安装则安装并返回黄色
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": true,
        "msg": "",
        "rc": 0,
        "results": [
            "Installed: wget-1.19.5-10.el8.x86_64",
            "Installed: libmetalink-0.1.3-7.el8.x86_64"
        ]
    }
// state=latest,如果仓库内有多个版本,安装最新版本
ansibletest]# ansible db1 -m yum -a "name=nginx state=latest"
// state=absent卸载
ansibletest]# ansible db1 -m yum -a "name=wget state=latest"

service模块

  • ansible all或组名或主机 -m service -a "参数1=值1 参数n=值n"
  • service模块用于systemctl命令控制服务。启动、关闭、重启、开机自启。
  • 常用参数:
    • name:指定rpm包的服务名,一次一个。
    • statestarted表示启动,stopped表示关闭,restarted表示重启,reloaded表示重载配置文件。不能省略
    • enabled:1或yes或ture表示设置开机自启,0或no或false表示设置开机不要自启。
java 复制代码
// service模块
// name=服务名。state=started启动,enabled=1或yes或true开机自启
ansibletest]# ansible db1 -m service -a "name=nginx state=started enabled=1"	// 启动并开机自启
ansibletest]# ansible db1 -a "systemctl status nginx"
    db1 | CHANGED | rc=0 >>
    ● nginx.service - The nginx HTTP and reverse proxy server
       Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
       Active: active (running) since Tue 2023-07-18 10:18:30 CST; 39s ago
	......省略一万字
// enabled=0或no或false开机不自启
ansibletest]# ansible db1 -m service -a "name=nginx enabled=0"					// 开启不自启
ansibletest]# ansible db1 -a "systemctl status nginx"
    db1 | CHANGED | rc=0 >>
    ● nginx.service - The nginx HTTP and reverse proxy server
       Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
       Active: active (running) since Tue 2023-07-18 10:18:30 CST; 1min 42s ago
	......省略一万字

lvg模块

  • ansible all或组名或主机 -m lvg -a "参数1=值1 参数n=值n"
  • lvg模块(Logical Volume Group)用于创建、删除卷组,修改卷组大小。
  • 常用参数:
    • vg:设置卷组名(已存在则重置该卷组的大小,即物理卷组成)。
    • pvs:指定组成卷组的逻辑卷,多个逻辑卷用 , 隔开。(直接写硬盘分区会自动创建物理卷,但删除卷组后需要手动删除物理卷)
    • statepresent表示创建,absent表示删除,省略默认为present。如果卷组还有逻辑卷则无法删除。
java 复制代码
// lvg模块
/* 关闭虚拟机db1,为其添加2块20GB的硬盘,给新添的第一块硬盘分区为5G和15G
 * LINUX下KVM虚拟机新加的硬盘,名称是/dev/vdb和/dev/vdc
 * Windows下vmware虚拟机新加的硬盘,名称是/dev/sdb和/dev/sdc
 * 如果选nvme硬盘,名称可能是/dev/nvme0n1和/dev/nvme0n2
 */
ansibletest]# ansible dbs -a "lsblk"
    db1 | CHANGED | rc=0 >>
    NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
    vda    253:0    0  20G  0 disk 
    └─vda1 253:1    0  20G  0 part /
    vdb    253:16   0  20G  0 disk 
    ├─vdb1 253:17   0   5G  0 part 			// 分区1为5G
    └─vdb2 253:18   0  15G  0 part 			// 分区2为15G
    vdc    253:32   0  20G  0 disk 

// vg=卷组名,pvs=物理卷1,物理卷n(直接写硬盘分区会自动创建物理卷)
ansibletest]# ansible db1 -m lvg -a "vg=myvg pvs=/dev/vdb1"		// 创建卷组myvg
ansibletest]# ansible db1 -a "vgs" 
    db1 | CHANGED | rc=0 >>
      VG   #PV #LV #SN Attr   VSize  VFree 
      myvg   1   0   0 wz--n- <5.00g <5.00g		

// 卷组vg同名会重置原卷组
ansibletest]# ansible db1 -m lvg -a "vg=myvg pvs=/dev/vdb2"		// 重置卷组myvg
ansibletest]# ansible db1 -a "vgs"
    db1 | CHANGED | rc=0 >>
      VG   #PV #LV #SN Attr   VSize   VFree  
      myvg   1   0   0 wz--n- <15.00g <15.00g	// 重置卷组myvg为15G(/dev/vdb2)

// 扩展卷组
ansibletest]# ansible db1 -m lvg -a "vg=myvg pvs=/dev/vdb1,/dev/vdb2"	// 重置卷组myvg
ansibletest]# ansible db1 -a "vgs"
    db1 | CHANGED | rc=0 >>
      VG   #PV #LV #SN Attr   VSize  VFree 
      myvg   2   0   0 wz--n- 19.99g 19.99g		// 重置卷组myvg为20G(/dev/vdb1,/dev/vdb2)

// 删除卷组
ansibletest]# ansible db1 -m lvg -a "vg=myvg state=absent"		// 删除卷组myvg
ansibletest]# ansible db1 -a "vgs"
	db1 | CHANGED | rc=0 >>						// 已删除卷组
ansibletest]# ansible db1 -a "pvs"
    db1 | CHANGED | rc=0 >>
      PV         VG Fmt  Attr PSize   PFree  	// 自动生成的物理卷也要手动删除
      /dev/vdb1     lvm2 ---    5.00g   5.00g	
      /dev/vdb2     lvm2 ---  <15.00g <15.00g
ansibletest]# ansible db1 -a "pvremove /dev/vdb1 /dev/vdb2"		// 手动删除逻辑卷,释放硬盘
ansibletest]# ansible db1 -a "pvs"
    db1 | CHANGED | rc=0 >>						// 已删除逻辑卷

lvol模块

  • ansible all或组名或主机 -m lvol -a "参数1=值1 参数n=值n"
  • lvol模块(Logical Volume)用于创建、删除逻辑卷,修改逻辑卷大小。
  • 常用参数:
    • lv:设置逻辑卷名。
    • vg:指定用于创建逻辑卷的卷组。
    • size:设置逻辑卷的大小,单位为M、G等。省略单位默认为M。
    • force:是否强制执行。(1或true或yes,0或false或no)
    • statepresent表示创建,absent表示删除,省略默认为present。如果逻辑卷被挂载使用无法删除。
    • resizefs:是否更新文件系统(已经格式化的逻辑卷扩展时给扩展的部分创建文件系统)。
java 复制代码
// lvol模块
ansibletest]# ansible db1 -m lvg -a "vg=myvg pvs=/dev/vdb1,/dev/vdb2"
ansibletest]# ansible db1 -a "vgs"
    db1 | CHANGED | rc=0 >>
      VG   #PV #LV #SN Attr   VSize  VFree 
      myvg   2   0   0 wz--n- 19.99g 19.99g	
// vg=卷组名,lv=逻辑卷名,size=逻辑卷大小。state=present创建逻辑卷,省略默认为present。
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=2G"		// 创建逻辑卷mylv
ansibletest]# ansible db1 -a "lvs"
    db1 | CHANGED | rc=0 >>
      LV   VG   Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
      mylv myvg -wi-a----- 2.00g       
                                      
// size=逻辑卷大小,如果重置后的逻辑卷更大则为扩展
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=4G"		// 扩展逻辑卷mylv
ansibletest]# ansible db1 -a "lvs"
    db1 | CHANGED | rc=0 >>
      LV   VG   Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
      mylv myvg -wi-a----- 4.00g      
// size=逻辑卷大小,如果重置后的逻辑卷更小则为缩减。默认不能缩减逻辑卷,使用force=yes强制执行
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=1G"				// 缩减逻辑卷mylv报错
    db1 | FAILED! => {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false,
        "msg": "Sorry, no shrinking of mylv without force=yes."
    }
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=1G force=yes"	// 强制缩减逻辑卷mylv
ansibletest]# ansible db1 -a "lvs"
    db1 | CHANGED | rc=0 >>
      LV   VG   Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
      mylv myvg -wi-a----- 1.00g     			// 逻辑卷mylv大小1g
ansibletest]# ansible db1 -a "vgs"
    db1 | CHANGED | rc=0 >>
      VG   #PV #LV #SN Attr   VSize  VFree 
      myvg   2   1   0 wz--n- 19.99g 18.99g		// 卷组myvg大小19.99g,可用大小18.99g

// state=absent删除逻辑卷。默认不能缩减逻辑卷,使用force=yes强制执行
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg state=absent"				// 删除逻辑卷mylv报错
    db1 | FAILED! => {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false,
        "msg": "Sorry, no removal of logical volume mylv without force=yes."
    }
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg state=absent force=yes"	// 强制删除逻辑卷mylv
ansibletest]# ansible db1 -a "lvs"
    db1 | CHANGED | rc=0 >>						// 已删除逻辑卷mylv
ansibletest]# ansible db1 -a "vgs"
    db1 | CHANGED | rc=0 >>
      VG   #PV #LV #SN Attr   VSize  VFree 		
      myvg   2   1   0 wz--n- 19.99g 19.99g		// 卷组myvg大小19.99g,可用大小19.99g

filesystem模块

  • ansible all或组名或主机 -m filesystem -a "参数1=值1 参数n=值n"
  • filesystem模块用于格式化,也就是创建文件系统。可以作用于硬盘分区,也可以作用于逻辑卷。
  • 常用参数:
    • dev:指定要格式化的设备路径,可以是硬盘分区,也可以是逻辑卷。
    • fstype:指定文件系统类型(xfs、ext4)。
    • statepresent表示创建文件系统,absent表示删除文件系统,省略默认为present
java 复制代码
// filesystem模块
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=6G"
ansibletest]# ansible db1 -a "lvs"
    db1 | CHANGED | rc=0 >>
      LV   VG   Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
      mylv myvg -wi-a----- 6.00g     
// dev=格式化的设备路径(分区或逻辑卷),fstype=文件系统类型。state=present创建文件系统,省略默认为present
ansibletest]# ansible db1 -m filesystem -a "dev=/dev/myvg/mylv fstype=xfs"
    /*
    [root@db1 ~]# blkid /dev/myvg/mylv
        /dev/myvg/mylv: UUID="fefa93d0-5d2e-4409-acd6-2d7d76d31860" BLOCK_SIZE="512" TYPE="xfs"
     */
// state=absent删除文件系统
ansibletest]# ansible db1 -m filesystem -a "dev=/dev/myvg/mylv fstype=xfs"
    /*
    [root@db1 ~]# blkid /dev/myvg/mylv		// 没有返回内容
     */

mount模块

  • ansible all或组名或主机 -m mount -a "参数1=值1 参数n=值n"
  • mount模块用于挂载已创建文件系统 的设备。可以挂载硬盘分区,也可以挂载逻辑卷。设备未创建文件系统的部分不会被df命令识别
  • 常用参数:
    • src:指定要挂载的设备路径,可以是硬盘分区,也可以是逻辑卷。(需要先格式化)
    • path:指定挂载点路径。
    • fstype:指定文件系统类型(xfs、ext4)。
    • state不能省略
      • mounted表示永久挂载(增加开机自动挂载信息并立即挂载),如果挂载点不存在会自动创建。
      • unmounted表示卸载(不会删除开机自动挂载信息),不会删除挂载点
      • present表示增加开机自动挂载信息(不立即挂载)。
      • absent表示永久卸载 (立即卸载并删除开机自动挂载信息和挂载点)。
java 复制代码
// mount模块
ansibletest]# ansible db1 -m filesystem -a "dev=/dev/myvg/mylv fstype=xfs"
    /*
    [root@db1 ~]# blkid /dev/myvg/mylv
        /dev/myvg/mylv: UUID="fefa93d0-5d2e-4409-acd6-2d7d76d31860" BLOCK_SIZE="512" TYPE="xfs"
 	[root@db1 ~]# lsblk /dev/myvg/mylv
        NAME      MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
        myvg-mylv 252:0    0   6G  0 lvm 
     */
// src=要挂载的设备路径(分区或逻辑卷),path=挂载点路径,fstype=文件系统类型。state=mounted永久挂载
ansibletest]# ansible db1 -m mount -a "src=/dev/myvg/mylv path=/data fstype=xfs state=mounted"
    /* 	在/etc/fstab中增加设备/dev/myvg/mylv的自动挂载
    [root@db1 ~]# df -Th /data
        Filesystem            Type  Size  Used Avail Use% Mounted on
        /dev/mapper/myvg-mylv xfs   6.0G   76M  6.0G   2% /data
     */
// state=absent永久卸载并删除挂载点
ansibletest]# ansible db1 -m mount -a "src=/dev/myvg/mylv path=/data fstype=xfs state=absent"
	/*	/etc/fstab中设备/dev/myvg/mylv的自动挂载被删除
    [root@db1 ~]# ls /data
		ls: cannot access '/data': No such file or directory
	 */
    

ansibletest]# ansible db1 -a "df -Th /dev/myvg/mylv"
    db1 | CHANGED | rc=0 >>
    Filesystem            Type  Size  Used Avail Use% Mounted on
    /dev/mapper/myvg-mylv xfs   6.0G   77M  6.0G   2% /data

逻辑卷的扩展

  • 格式化后的逻辑卷如果扩展,需要使用lvol模块的参数 resizefs 来更新文件系统。如果是扩展未格式化的逻辑卷,扩展后直接格式化
java 复制代码
// 格式化后的逻辑卷如果扩展,需要使用参数resizefs=yes来更新文件系统
ansibletest]# ansible db1 -m mount -a "src=/dev/myvg/mylv path=/data fstype=xfs state=mounted"
	/*
 	[root@db1 ~]# lsblk /dev/myvg/mylv
        NAME      MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
        myvg-mylv 252:0    0   6G  0 lvm 
    [root@db1 ~]# df -Th /data
        Filesystem            Type  Size  Used Avail Use% Mounted on
        /dev/mapper/myvg-mylv xfs   6.0G   76M  6.0G   2% /data
     */
// 如果没有更新文件系统:设备未创建文件系统的部分不会被df命令识别
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=7G"
	/*
 	[root@db1 ~]# lsblk /dev/myvg/mylv					// 逻辑卷已扩展至7G
        NAME      MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
        myvg-mylv 252:0    0   7G  0 lvm 							
    [root@db1 ~]# df -Th /data							// 扩展部分未创建文件系统
        Filesystem            Type  Size  Used Avail Use% Mounted on
        /dev/mapper/myvg-mylv xfs   6.0G   76M  6.0G   2% /data
     */
// resizefs=true更新文件系统
ansibletest]# ansible db1 -m lvol -a "lv=mylv vg=myvg size=8G resizefs=true"	// 如果size=7G,ansible不会changed
    /*
    [root@db1 ~]# lsblk /dev/myvg/mylv					// 逻辑卷已扩展至8G
        NAME      MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
        myvg-mylv 252:0    0   8G  0 lvm  /data
    [root@db1 ~]# df -Th /data							// 扩展部分已创建文件系统
        Filesystem            Type  Size  Used Avail Use% Mounted on
        /dev/mapper/myvg-mylv xfs   8.0G   90M  8.0G   2% /data
     */

// 快捷操作:
// 按Ctrl+R:
(reverse-i-search)`': 
// 按7:
(reverse-i-search)`7': ansible db1 -m lvol -a "vg=myvg lv=mylv size=7G"
// 按Esc,修改为8G,并更新文件系统
ansibletest]# ansible db1 -m lvol -a "vg=myvg lv=mylv size=8G resizefs=true"

parted模块

  • ansible all或组名或主机 -m parted -a "参数1=值1 参数n=值n"

  • parted模块使用parted命令进行硬盘分区。

  • 常用参数

    • device:指定用于分区的硬盘路径。

    • label:指定分区模式(分区规划、分区表)。msdosgpt,省略默认为msdos

    • statepresent表示创建分区,absent表示删除分区,info表示查看硬盘分区详情。省略默认为info

    • number:分区编号。只能写一个数字。

    • part_type:指定新分区的类型。primary表示主分区,extended表示扩展分区,logical表示逻辑分区,省略默认为primary

    • part_start:指定新分区的起始位置。创建第一个分区时要省略不能为0。单位可以是MB、MiB、GB、GiB等,也可以写为百分比。

    • part_end:指定新分区的结束位置。创建第一个分区时省略则为整个硬盘。上一个分区的结束位置是下一个分区的起始位置。单位可以是MB、MiB、GB、GiB等,也可以写为百分比。

      • 电脑存储最小单位:位(比特bit)。单位以iB显示。
        • 1Byte=8bit
          1KB=1000B(1KiB=1024B)
          1MB=1000KM(1MiB=1024KB)
    • 如果编写剧本,可以使用参数 part 来同时创建或删除多个分区 :每个分区指定参数numberpart_typepart_startpart_end

java 复制代码
// parted模块
/* device=硬盘路径。state=present创建分区,省略默认为info。
 * label=msdos或gpt,省略默认为msdos。
 * number=分区编号
 * part_type=primary或extended或logical,省略默认为primary。
 * part_start=新分区起始位置,第一个分区要省略。
 * part_end=新分区结束位置,第一个分区省略则为整个硬盘。
 */
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=present number=1 part_end=1GiB"

// 起始位置和结束位置,单位GB和GiB大小不同
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc number=2 part_start=1GiB part_end=5GiB state=present"
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc number=3 part_start=5GiB part_end=9GB state=present"
    /*
    [root@db1 ~]# lsblk /dev/vdc
        NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
        vdc    253:32   0   20G  0 disk 
        ├─vdc1 253:33   0 1023M  0 part 			// 由于硬盘开头会保留一部分用于存储硬盘信息,所以不足1GiB
        ├─vdc2 253:34   0    4G  0 part 			// 4GiB
        └─vdc3 253:35   0  3.4G  0 part 			// 9GB-5GiB=8.38GiB-5GiB=3.34GiB
     */

// part_type=extended扩展分区
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=present number=4 part_type=extended part_start=9GB part_end=100%"
// part_type=logical逻辑分区
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=present number=5 part_type=logical part_start=9GB part_end=75%"
// 起始位置和结束位置,可以写为百分比
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=present number=6 part_type=logical part_start=75% part_end=100%"
    /*
    [root@db1 ~]# lsblk /dev/vdc
        NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
        vdc    253:32   0   20G  0 disk 			// 20GiB
        ├─vdc1 253:33   0 1023M  0 part 
        ├─vdc2 253:34   0    4G  0 part 
        ├─vdc3 253:35   0  3.4G  0 part 
        ├─vdc4 253:36   0    1K  0 part 			// 扩展分区,SIZE不准
        ├─vdc5 253:37   0  6.6G  0 part 			// 逻辑分区
        └─vdc6 253:38   0    5G  0 part 			// 逻辑分区
     */
// state=absent删除分区
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=absent number=6"
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=absent number=5"
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=absent number=4"
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=absent number=3"
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=absent number=2"
ansibletest]# ansible db1 -m parted -a "device=/dev/vdc state=absent number=1"
    /*
    [root@db1 ~]# lsblk /dev/vdc
        NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
        vdc  253:32   0  20G  0 disk 
     */

firewalld模块

  • ansible all或组名或主机 -m firewalld -a "参数1=变量1 参数n=变量n"
  • firewalld模块用于配置防火墙。
  • 常用参数:
    • port:指定 端口/udp端口号/tcp。服务名和端口号对应关系的说明文件:/etc/services
    • source:指定 源IP地址/子网掩码
    • zone
    • permanent:是否永久生效,但不会立即生效(重启服务生效)
    • immediate:是否立即生效,临时生效(重启服务失效)
    • statepresent表示,absent表示,enabled表示放行访问,disabled表示拒绝访问,不能省略。
  • 配置服务器的防火墙,只需要配置允许开放哪些服务或端口。没有明确允许的,都是默认拒绝。
java 复制代码
// firewalld模块
// db1主机安装并开启防火墙
db1主机(192.168.88.13):
[root@db1 ~]# yum install -y nginx
[root@db1 ~]# echo "nginx-db1~~" > /usr/share/nginx/html/index.html 
	/* 
	[root@pubserver ansibletest]# curl 192.168.88.13
		nginx-db1~~
	 */
[root@db1 ~]# yum install -y firewalld
[root@db1 ~]# systemctl start firewalld
[root@db1 ~]# firewall-cmd --list-all
    public (active)
      target: default
      icmp-block-inversion: no
      interfaces: eth0
      sources: 
      services: cockpit dhcpv6-client ssh
      ports: 
      protocols: 
      forward: no
      masquerade: no
      forward-ports: 
      source-ports: 
      icmp-blocks: 
      rich rules: 
	/* 防火墙拒绝了其他设备对nginx服务(端口80)的访问
	[root@pubserver ansibletest]# curl 192.168.88.13
		curl: (7) Failed to connect to 192.168.88.13 port 80: 没有到主机的路由
	 */

// Ansible管理db1主机的防火墙
控制端(192.168.88.240):
// port=端口号/传输层协议。immediate=是否立即生效(重启服务失效)。state=enabled放行访问
ansibletest]# ansible db1 -m firewalld -a "port=80/tcp immediate=yes state=enabled"
ansibletest]# curl 192.168.88.13
	nginx-db1~~
    /*
    [root@db1 ~]# firewall-cmd --list-ports
    80/tcp
    [root@db1 ~]# systemctl restart firewalld.service 	// 重启服务放行端口80失效
    [root@db1 ~]# firewall-cmd --list-ports
	
	 */
ansibletest]# curl 192.168.88.13
	curl: (7) Failed to connect to 192.168.88.13 port 80: 没有到主机的路由

// immediate=是否立即生效(重启服务失效)。state=disabled拒绝访问
ansibletest]# ansible db1 -m firewalld -a "port=80/tcp immediate=yes state=enabled"
ansibletest]# curl 192.168.88.13
	nginx-db1~~
ansibletest]# ansible db1 -m firewalld -a "port=80/tcp immediate=yes state=disabled"
ansibletest]# curl 192.168.88.13
	curl: (7) Failed to connect to 192.168.88.13 port 80: 没有到主机的路由

// permanent=是否永久生效(不会立即生效,重启服务生效)。state=enabled放行访问
ansibletest]# ansible db1 -m firewalld -a "port=80/tcp permanent=yes state=enabled"
ansibletest]# curl 192.168.88.13
	curl: (7) Failed to connect to 192.168.88.13 port 80: 没有到主机的路由
    /*
    [root@db1 ~]# firewall-cmd --list-ports
	
    [root@db1 ~]# systemctl restart firewalld.service 	// 重启服务放行端口80生效
    [root@db1 ~]# firewall-cmd --list-ports
    80/tcp
	 */
ansibletest]# curl 192.168.88.13
	nginx-db1~~

// permanent=是否永久生效(不会立即生效,重启服务生效)。state=disabled拒绝访问
ansibletest]# ansible db1 -m firewalld -a "port=80/tcp permanent=yes state=disabled"
ansibletest]# curl 192.168.88.13
	nginx-db1~~
    /*
    [root@db1 ~]# firewall-cmd --list-ports
    80/tcp
    [root@db1 ~]# systemctl restart firewalld.service 	// 重启服务放行端口80失效
    [root@db1 ~]# firewall-cmd --list-ports
	
	 */
ansibletest]# curl 192.168.88.13
	curl: (7) Failed to connect to 192.168.88.13 port 80: 没有到主机的路由

// 一般permanet和immediate同时使用,即使重启服务也不影响
ansibletest]# ansible db1 -m firewalld -a "port=80/tcp permanent=yes immediate=yes state=enabled"
ansibletest]# curl 192.168.88.13
	nginx-db1~~
ansibletest]# ansible db1 -m service -a "name=firewalld state=restarted"
ansibletest]# curl 192.168.88.13
	nginx-db1~~

playbook剧本

剧本的编写和运行

  • 剧本(playbook)是一个文件,该文件中通过yaml语法格式来书写。
  • yaml语法规范(YAML Ain't a Markup Language)

    • 使用yaml语法书写的文件,扩展名一般为 .yml.yaml
    • 文件内容一般以 --- 作为第一行,非必需但常用。用 # 注释。
    • 键值对使用冒号 : 表示,冒号后面必须有空格。例如: key: value
    • 数组使用减号 - 表示,减号后面必须有空格。例如:多个play、多个任务、多个值等。(多个参数不用 -
    • 相同的层级必须有相同的缩进。如果缩进不对,则有语法错误。建议每一级缩进2个空格。
    • 全文不能使用制表符,必须使用空格。
    • 包含数字 的字符串必须使用引号。值以 {``{}} 开头必须使用引号。
  • 编写剧本:使用yaml语法书写,包含要素 hoststasks(包含要素 模块参数)等。

    • 一个剧本可以包含多个play(根据所作用的主机 hosts 来划分play)。play名省略则默认同 hosts的值。
      • 每个play的任务可以有多个(写在 tasks 中,每个任务使用一个模块)。
        • 每个任务包含 模块名模块的参数 。任务名省略则默认同 模块名
        • 每个play都有默认任务 Gathering Facts 。可以使用 gather_facts: no 来跳过该任务。
    • 每个play前使用 -空格,每个任务前使用 -空格
  • 运行剧本:ansible-playbook 剧本文件名

java 复制代码
// 剧本的编写和运行(组webs包含主机web1、web2,组dbs包含主机db1)
// 修改家目录/.vimrc,以方便书写
ansibletest]# cat ~/.vimrc
    set ai        	// autoindent,设置换行自动对齐上一行缩进
    set ts=2      	// tabstop,设置一个制表符缩进2个空格
    set et       	// expandtab,将制表符转换成相应个数的空格,这样YAML可以使用Tab键。
// 编写剧本
ansibletest]# cat test01.yml
    ---
    - name: create dir and copy file	// 剧本下的"-",第一个play。值为play名,省略同主机名
      hosts: webs,dbs    				// 值为组名或主机名,必须是出现在主机清单文件中的。该play对webs组和dbs组生效
      # gather_facts: no
      tasks:
        - name: create dir				// tasks下的"-",第一个任务。值为任务名,省略同模块名
          file:							// 键为模块名。使用file模块
            path: /tmp/demo				// 键为参数名
            state: directory
            mode: '0755'   
        - name: copy file				// tasks下的"-",第二个任务
          copy:
            src: /etc/hosts
            dest: /tmp/demo/hosts
// 运行剧本
ansibletest]# ansible-playbook test01.yml
    PLAY [create dir and copy file] *********************************** // 第一个play

    TASK [Gathering Facts] ********************************************	// 每个play都有默认任务Gathering Facts
    ok: [web1]
    ok: [web2]
    ok: [db1]

    TASK [create dir] ************************************************** // 第一个自定义任务
    ok: [web1]
    ok: [db1]
    ok: [web2]

    TASK [copy file] *************************************************** // 第二个自定义任务
    changed: [db1]
    changed: [web1]
    changed: [web2]

    PLAY RECAP ********************************************************* // 执行结果
    db1      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web1     : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2     : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
// 编写剧本
ansibletest]# cat test02.yml
    ---
    - name: useradd bob					// 第一个play
      hosts: webs
      tasks:					
        - name: useradd					// 第一个play的第一个任务
          user:
            name: bob
            groups: adm
			password: "{{'123' | password_hash('sha512')}}"		// 注意:{{}}写在值的开头时需要用引号
    - hosts: dbs						// 第二个play
      tasks:							
        - copy:							// 第二个play的第一个任务
            dest: /tmp/hi.txt
            content: Hello World\n
// 运行剧本
ansibletest]# ansible-playbook test02.yml 

    PLAY [useradd bob] ****************************************************	// 第一个play

    TASK [Gathering Facts] ************************************************	// 默认任务Gathering Facts
    ok: [web1]
    ok: [web2]

    TASK [useradd] ********************************************************	// 第一个自定义任务
    ok: [web1]
    ok: [web2]

    PLAY [dbs] ************************************************************	// 第二个play

    TASK [Gathering Facts] ************************************************	// 默认任务Gathering Facts
    ok: [db1]

    TASK [copy] ***********************************************************	// 第一个自定任务
    changed: [db1]

    PLAY RECAP ************************************************************	// 执行结果
    db1      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
    web1     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
    web2     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

测试剧本

  • 有两种方式可以测试一个playbook剧本而不真正对目标主机进行实际操作:
    • Dry Run模式:使用--check-C参数来启用Dry Run模式,模拟执行playbook。
    • Debug模式:使用-vvv参数来启用详细的debug模式,显示出Ansible执行过程中的详细信息,包括每个任务的计划和结果。
java 复制代码
// 测试剧本
// Dry Run
ansible-playbook --check playbook.yml
ansible-playbook -C playbook.yml
// Debug
ansible-playbook -vvv playbook.yml

折行语法 |>

  • | :以换行符折行。每行内容单独成行。
  • > :以空格折行。将多行内容合并为一行。
java 复制代码
// |和>

// |:每行内容单独成行
ansibletest]# cat f1.yml
    ---
    - name: play 1
      hosts: db1
      tasks:
        - name: mkfile 1.txt
          copy:
            dest: /tmp/1.txt
            content: |
              Hello World
              ni hao
ansibletest]# ansible-playbook f1.yml
    /*
    [root@db1 ~]# cat /tmp/1.txt 
        Hello world
        ni hao
     */

// >:将多行内容合并为一行
ansibletest]# cat f2.yml
    ---
    - name: play 2
      hosts: db1
      tasks:
        - name: mkfile 2.txt
          copy:
            dest: /tmp/2.txt
            content: >
              Hello World
              ni hao
ansibletest]# ansible-playbook f2.yml
    /*
    [root@db1 ~]# cat /tmp/2.txt 
        Hello world ni hao
     */

剧本进行硬盘管理

java 复制代码
// 分区与逻辑卷
// 创建分区
ansibletest]# cat disk.yml
    ---
    - name: disk manage
      hosts: db1
      tasks:
        - name: create partition
          parted:							// parted模块
            device: /dev/vdc				// 要分区的硬盘
            state: present					// 省略默认为info(查看硬盘分区详情)
            number: 1						// 分区编号
            part_end: 1GiB					// 结束位置。这里写1G会识别为1GB=1000MB=1000*1000B
			// 没有使用part_start参数:由于硬盘开头会保留一部分用于存储硬盘信息,因此不要从0开始。
ansibletest]# ansible-playbook disk.yml 
    /*
    [root@db1 ~]# lsblk /dev/vdc
        NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
        vdc    253:32   0   20G  0 disk 	
        └─vdc1 253:33   0 1023M  0 part 	// 硬盘开头会保留一部分用于存储硬盘信息,因此不足1GiB
     */
// 创建多个分区,parted模块的参数part
ansibletest]# cat disk.yml
    ---
    - name: disk manage
      hosts: db1
      tasks:
        - name: create partition
          parted:
            device: /dev/vdc
            state: present
            part:							// 参数part同时创建或删除多个分区
              - number: 1					// 第一个分区
                part_end: 1GiB
              - number: 2					// 第二个分区
				part_start: 1GiB
                part_end: 6GiB
ansibletest]# ansible-playbook disk.yml 
    /*
    [root@db1 ~]# lsblk /dev/vdc
        NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
        vdc    253:32   0   20G  0 disk 
        ├─vdc1 253:33   0 1023M  0 part 
        └─vdc2 253:34   0    5G  0 part 
     */
// 创建逻辑卷,格式化并挂载
ansibletest]# cat disk.yml
    ---
    - name: disk manage
      hosts: db1
      tasks:
        - name: create partition
          parted:							// 分区
            device: /dev/vdc
            state: present
            part:
              - number: 1
                part_end: 1GiB
              - number: 2
				part_start: 1GiB
                part_end: 6GiB

        - name: create my_vg			
          lvg:								// 卷组
            vg: my_vg
            pvs: /dev/vdc1,/dev/vdc2

        - name: create my_lv
          lvol:								// 逻辑卷
            vg: my_vg
            lv: my_lv
            size: 1G

        - name: mkfs my_lv
          filesystem:						// 格式化
            dev: /dev/my_vg/my_lv
            fstype: ext4

        - name: mount my_lv
          mount:							// 挂载
            src: /dev/my_vg/my_lv
            path: /data2					
            fstype: ext4
            state: mounted					// mounted永久挂载,挂载点不存在会自动创建
ansibletest]# ansible-playbook disk.yml 
    /*
    [root@db1 ~]# vgs my_vg
          VG    #PV #LV #SN Attr   VSize VFree
          my_vg   2   1   0 wz--n- 5.99g 4.99g
    [root@db1 ~]# lvs /dev/my_vg/my_lv 
          LV    VG    Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
          my_lv my_vg -wi-a----- 1.00g    
    [root@db1 ~]# df -Th /data2
        Filesystem              Type  Size  Used Avail Use% Mounted on
        /dev/mapper/my_vg-my_lv ext4  976M  2.6M  907M   1% /data2
     */

剧本安装软件包、软件包组、升级已安装软件

  • 如果参数支持同时赋多个值,有以下三种写法:(以yum模块的参数name为例)
    • yum命令的写法:name: 软件名1,软件名2,软件名n
    • python列表的标准写法:name: [软件名1,软件名2,软件名n]
    • yaml的标准写法:
      • name:
        空格空格- 软件名1
        空格空格- 软件名2
        空格空格- 软件名n
java 复制代码
// 安装多个软件包httpd、php、php-mysqlnd
ansibletest]# cat pkg.yml
	// 写法1:
    ---
    - name: install pkgs
      hosts: webs
      tasks:
        - name: install web pkgs 
          yum:
            name: httpd,php,php-mysqlnd		// yum命令的写法
            state: present					
    // 写法2:
    ---
    - name: install pkgs
      hosts: webs
      tasks:
        - name: install web pkgs
          yum:
            name: [httpd,php,php-mysqlnd]	// python列表的标准写法
            state: present
	// 写法3:
    ---
    - name: install pkgs
      hosts: webs
      tasks:
        - name: install web pkgs
          yum:
            name: 
              - httpd						// yaml的标准写法
              - php
              - php-mysqlnd
            state: present

// 安装软件包组
    /* 根据功能等,可以将一系列软件放到一个组中,安装软件包组,将会把很多软件一起安装上。
    [root@web1 ~]# yum grouplist   			 	    	// 列出所有的软件包组
    [root@web1 ~]# yum groupinstall "Development Tools"	// 安装该软件包组
    [root@web1 ~]# LANG=C yum grouplist					// 使用中文列出组名
     */
ansibletest]# cat pkg.yml
    ---
    - name: install pkgs
      hosts: webs
      tasks:
        - name: install web pkgs
          yum:
            name: 
              - httpd						
              - php
              - php-mysqlnd
            state: present
		- name: install gtoup
          yum:
			name: "@Development Tools"		// 使用@表示软件包组
            state: present

// 升级所有已安装的软件包到最新版本
    /* 更新已安装的软件包:卸载原来的Rocky8.6镜像,挂载新的Rocky8.7镜像(网络下载),然后使用升级命令yum update
    [root@web1 ~]# yum update
     */
ansibletest]# cat pkg.yml
    ---
    - name: install pkgs
      hosts: webs
      tasks:
        - name: install web pkgs
          yum:
            name: 
              - httpd						
              - php
              - php-mysqlnd
            state: present
		- name: install gtoup
          yum:
			name: "@Development Tools"		// 使用@表示软件包组
            state: present
        - name: update system    
          yum:
            name: "*"       				// 表示系统已经安装的所有包
            state: latest
ansibletest]# ansible-playbook pkg.yml

ansible变量

  • 在ansible中,调用变量使用 {``{变量名}}

facts变量

  • facts变量是ansible自带的预定义变量,用于描述被控端软硬件信息。
  • 常用的facts变量:
    • ansible_all_ipv4_addresses:所有的IPV4地址
    • ansible_eth0.ipv4.address:eth0的IPV4地址
    • ansible_bios_version:BIOS版本信息
    • ansible_memtotal_mb:总内存大小
    • ansible_memfree_mb:可用内存大小
    • ansible_hostname:主机名

setup模块

  • ansible all或组名或主机 -m setup:查看所有facts变量。
    ansible all或组名或主机 -m setup -a "filter=facts变量" :查看该facts变量的值。
  • setup模块可以获取facts变量。
  • 常用参数:
    • filter:指定具体的facts变量。
  • 找到facts变量完整路径的操作:
    • ansible 组名或主机名 -m setup | cat -n | grep "目标关键字":找到目标关键字的行号。
    • ansible 组名或主机名 -m setup | grep "目标关键字":找到目标关键字的行。
    • 鼠标放在关键字的开头不动,滑动鼠标滚轮找到上一级,每一级用 . 连接。
java 复制代码
// setup模块
// 查看所有facts变量。可以Shift+PageUp/PageDown在终端翻页
ansibletest]# ansible db1 -m setup

// 查看所有的IPv4地址,filter=facts变量
ansibletest]# ansible db1 -m setup -a "filter=ansible_all_ipv4_addresses"
    db1 | SUCCESS => {
        "ansible_facts": {
            "ansible_all_ipv4_addresses": [
                "192.168.88.13"
            ],
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false
    }
// 查看所有内存
ansibletest]# ansible db1 -m setup -a "filter=ansible_memtotal_mb"
    db1 | SUCCESS => {
        "ansible_facts": {
            "ansible_memtotal_mb": 1924,
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false
    }
// 查看可用内存
ansibletest]# ansible db1 -m setup -a "filter=ansible_memfree_mb"
    db1 | SUCCESS => {
        "ansible_facts": {
            "ansible_memfree_mb": 1633,
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false
    }
// 查看主板版本
ansibletest]# ansible db1 -m setup -a "filter=ansible_bios_version"
    db1 | SUCCESS => {
        "ansible_facts": {
            "ansible_bios_version": "rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org",
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false
    }
// 查看主机名
ansibletest]# ansible db1 -m setup -a "filter=ansible_hostname"
    db1 | SUCCESS => {
        "ansible_facts": {
            "ansible_hostname": "db1",
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": false
    }

debug模块

  • debug模块用于输出信息。
  • 常用的参数:
    • msg:指定输出内容。
  • 在ansible剧本中,调用变量使用{``{变量名}}
java 复制代码
// debug模块,参数msg。调用变量:{{变量名}}
/* 找到facts变量完整路径的操作:
 * ansible db1 -m setup | cat -n | grep "目标关键字"。找到目标关键字的行号。
 * ansible db1 -m setup | cat -n。找到目标关键字的行。
 * 鼠标放在关键字的开头不动,滑动鼠标滚轮找到上一级,每一级用"."连接。
 */

// 输出facts变量值的剧本
ansibletest]# cat debug.yml
    ---
    - name: 
      hosts: db1
      tasks:
        - name: print hostname and memory
          debug:
            msg: "hostname: {{ansible_hostname}}, memory: {{ansible_memtotal_mb}}MB"

ansibletest]# ansible-playbook debug.yml 

    PLAY [db1] **************************************

    TASK [Gathering Facts] ************************** 	// 收集facts变量任务。没有这一步,则无法识别facts变量
    ok: [db1]

    TASK [print hostname and memory] ****************
    ok: [db1] => {
        "msg": "hostname: db1, memory: 1924MB"
    }

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

// 输出facts变量值不能使用adhoc临时命令,因为没有"收集facts变量任务",无法识别facts变量,会报错
ansibletest]# ansible db1 -m debug -a "msg='hostname: {{ansible_hostname}}, memory: {{ansible_memtotal_mb}}MB'"
    db1 | FAILED! => {
        "msg": "The task includes an option with an undefined variable. The error was: 'ansible_hostname' is undefined. 'ansible_hostname' is undefined"
    }

ansibletest]# cat ip.yml 
    ---
    - name:
      hosts: db1
      tasks: 
        - name: display ipv4 and /vdb2
          debug:
            msg: "eth0 ip: {{ansible_eth0.ipv4.address}} , /vdb2 size: {{ansible_devices.vdb.partitions.vdb2.size}}"

自定义变量

  • 自定义变量的值为字符串时可以不加引号,为数字时必须加引号。

  • ansible支持10种以上的变量定义方式。常用的变量有:

    • facts变量
    • 主机清单变量,在主机清单文件中的自定义变量。
      • 组变量 :针对组内所有主机的变量:
        • [组名:vars]
          变量名=变量值
      • 主机变量 :针对单个主机的变量(写在组内): 主机名或主机IP 变量名=变量值
    • 剧本文件变量。在剧本文件中自定义的变量。
      • vars:
        空格空格- 变量名: 变量值
        空格空格- 变量名: 变量值
      • 剧本级变量 :针对play中的所有任务的变量(写在play内)
        任务级变量:针对某个任务的变量(写在任务内)
    • 变量文件的变量 。在变量文件中自定义的变量。
      • 剧本文件使用 vars_files: 变量文件名.yml 调用该变量文件中的变量(只能写在play内)。
  • 同名变量:任务级变量 > 变量文件变量 > 剧本级变量 > 主机变量 > 组变量

java 复制代码
// 自定义变量??
// 给webs组创建用户wangwu,给db1主机创建用户zhaoliu
// 普通的写法需要写两个play
ansibletest]# cat u1.yml 
    ---
    - name: create a user
      hosts: webs
      tasks:
        - name: useradd wangwu
          user:
            name: wangwu
    - name: create a user
      hosts: db1
      tasks:
        - name: useradd zhaoliu
          user:
            name: zhaoliu
ansibletest]# ansible-playbook u1.yml

// 主机清单文件变量
ansibletest]# cat inventorytest 
    [webs]
    web[1:2]

    [webs:vars]				// 组变量:针对组内所有主机生效:[组名:vars]
    username=wangwu			// 值为字符串可以不加引号,为数字需要加引号
    
	[dbs:vars]				// 组变量
    username=wangwu		
                
    [dbs]
    db1 username=zhaoliu	// 主机变量:针对单个主机生效:与主机写在同一行
                
    [cluster:children]
    webs
    dbs
ansibletest]# cat u2.yml 
    ---
    - name: create a user
      hosts: webs,db1
      tasks:
        - name: useradd
          user:
            name: "{{username}}"
ansibletest]# ansible_playbook u2.yml
	/* 同名变量优先级:主机变量 > 组变量。db1主机的变量username=zhaoliu,优先于wangwu
	[root@db1 ~]# id wangwu
		id: 'wangwu': no such user
    [root@db1 ~]# id zhaoliu
        uid=1008(zhaoliu) gid=1008(zhaoliu) groups=1008(zhaoliu)
	 */

// playbook变量
ansibletest]# cat u3.yml 
    ---
    - name: create a user
      hosts: db1
      vars:
        username: jack		// 剧本级变量:针对本play下的所有任务"useradd 1"和"useradd 2"生效
        mima: "123"
      tasks:
        - name: "useradd 1"
          user:
            name: "{{username}}"
            password: "{{mima | password_hash('sha512')}}"               
        - name: "useradd 2"
          vars:
            yonghu: rose	// 任务级变量:针对本任务"useradd 2"生效
            mima: "456"
          user:
            name: "{{username}}"
            password: "{{mima | password_hash('sha512')}}"
ansibletest]# ansible-playbook u3.yml
    /* 同名变量:任务级变量 > 剧本级变量 > 主机变量 > 组变量
    [root@db1 ~]# id jack		// db1主机的任务"useradd 1"的变量username=jack,优先于zhaoliu
        uid=1009(jack) gid=1009(jack) groups=1009(jack)
    [root@db1 ~]# id rose		// db1主机的任务"useradd 2"的变量username=rose,优先于jack
        uid=1010(rose) gid=1010(rose) groups=1010(rose)     
     */

// 变量文件变量    
ansibletest]# cat var.yml
    ---
    username: fileuser
    mima: "789"       
ansibletest]# cat u4.yml 
    ---
    - name: create a user
      hosts: db1
      vars_files: var.yml		// 同级无顺序,vars_files也可以写在vars下,结果一样
      vars:
        - username: playuser 
        - mima: "123"				
      tasks:
        - name: "useradd 1"
          user:
            name: "{{username}}"
            password: "{{mima | password_hash('sha512')}}"
        - name: "useradd 2"
          vars: 
            username: taskuser
            mima: "456"
          user:
            name: "{{username}}"
            password: "{{mima | password_hash('sha512')}}"
ansibletest]# ansible-playbook u4.yml
    /* 同名变量:任务级变量 > 变量文件变量 > 剧本级变量 > 主机变量 > 组变量
    [root@db1 ~]# id fileuser
        uid=1012(fileuser) gid=1012(fileuser) groups=1012(fileuser)
    [root@db1 ~]# id playuser	// 任务"useradd 1"的变量username=fileuser,优先于playuser
        id: 'playuser': no such user
    [root@db1 ~]# id taskuser	// 任务"useradd 2"的变量username=taskuser,优先于fileuser
        uid=1013(taskuser) gid=1013(taskuser) groups=1013(taskuser)
	 */

同名变量优先级

  • 在Ansible中,同名变量的优先级从高到低依次如下:越特例优先级越高
  1. 命令行参数:通过选项 --extra-vars(简写 -e)传递的变量具有最高优先级
    • ansible-playbook 剧本文件 -e "变量名=变量值"
    • ansible-playbook 剧本文件 -e "@变量文件" (变量文件支持 YAML 或 JSON)
  2. 任务级变量:在剧本文件为单个任务定义的变量。
  3. 变量文件变量:vars_files 调用变量文件的变量。
  4. 剧本级变量:在剧本文件为单个play定义的变量。
  5. 主机变量:在主机清单文件中为单个主机定义的变量。
  6. 组变量:在主机清单文件中为单个组定义的变量。
  7. 角色级变量:在角色的 defaults 目录下定义的变量将作为角色的默认值。??
  8. 包含角色:如果使用了角色,那么角色中定义的变量将覆盖其他位置定义的变量。??
  9. 包含关系:使用 includeimport 导入了其他文件中的变量。??
  10. 环境变量:环境变量中定义的变量。
  11. Ansible配置文件:在 ansible.cfg 中定义的变量。

template模块

  • ansible all或组名或主机 -m template -a "参数1=变量1 参数n=变量n"

  • template模块和[copy模块](# copy模块)的区别:

    • copy模块可以上传文件,但是文件内容固定。
    • template模块可以上传包含变量的文件。当远程主机接收到文件之后,文件中的变量将会变成具体的值。
  • template模块上传的文件,使用的语法叫Jinja2。

  • 常用参数:

    • src(source):指定控制端的源数据路径。只拷贝源数据,不拷贝路径
    • dest(destination):指定被控端的目标数据路径(相对路径是/root)。(只需存在父目录)
java 复制代码
// template模块
ansibletest]# vim index.html			// 编写包含facts变量的网页文件
	Welcome to {{ansible_hostname}} on {{ansible_eth0.ipv4.address}}
	// ansible_hostname变量是主机名,ansible_eth0.ipv4.address变量是eth0网卡的IPv4地址。
ansibletest]# vim templ.yml				// 使用template模块替换webs组的主机的默认网页文件
    ---
    - name: upload index
      hosts: webs
      tasks:
        - name: upload web index
          template:
            src: index.html
            dest: /usr/share/nginx/html/index.html		// rpm包安装的nginx的默认网页文件
ansibletest]# ansible-playbook templ.yml
ansibletest]# curl http://192.168.88.11
	Welcome to web1 on 192.168.88.11
ansibletest]# curl http://192.168.88.12
	Welcome to web2 on 192.168.88.12
	/* template模块上传的文件到远程主机后,变量会变成具体的值
	[root@web1 ~]# cat /usr/share/nginx/html/index.html
		Welcome to web1 on 192.168.88.11
	[root@web2 ~]# cat /usr/share/nginx/html/index.html
		Welcome to web2 on 192.168.88.12
	 */

错误处理 ignore_errors

  • 如果剧本文件中包含多个任务,当某一个任务遇到错误,剧本文件将崩溃,终止执行后面的任务。

  • 可以通过 ignore_errors: yes 忽略错误,继续执行后面的任务。

    • 写在任务中:对本任务生效。如果该任务出现错误,忽略它。
    • 写在play中:对本play中所有任务生效。无论该play中的哪个任务出现问题,都忽略它。
java 复制代码
// 错误处理 ignore_errors
// web1和web2没有mysql服务
ansibletest]# cat myerr.yml 
    ---
    - name:
      hosts: web1
      tasks:
        - name: start mysql service
          ignore_errors: yes			// 写在任务中:忽略本任务的错误继续执行其它任务。任务内同级无先后顺序
          service:
            name: mysql
            state: started
            enabled: yes
        - name: touch a file
          file:
            name: /tmp/service.txt
            state: touch
    - name:
      hosts: web2
      ignore_errors: yes				// 写在play中:对play中所有任务生效
      tasks:
        - name: start mysql service
          service:
            name: mysql
            state: started
            enabled: yes
        - name: touch a file
          file:
            name: /tmp/service.txt
            state: touch
ansibletest]# ansible-playbook myerr.yml 
    PLAY [web1] **************************************************

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

    TASK [start mysql service] ***********************************
    fatal: [web1]: FAILED! => {"changed": false, "msg": "Could not find the requested service mysql: host"}
    ...ignoring

    TASK [touch a file] ******************************************
    changed: [web1]

    PLAY [web2] **************************************************

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

    TASK [start mysql service] ***********************************
    fatal: [web2]: FAILED! => {"changed": false, "msg": "Could not find the requested service mysql: host"}
    ...ignoring

    TASK [touch a file] ******************************************
    changed: [web2]

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

触发执行任务 notify、handlers

  • 通过handlers定义触发执行的任务
  • handlers中定义的任务,不是一定会执行的。tasks中定义的任务是一定会执行的。
  • 在tasks中定义的任务,通过 notify: 任务名 通知handlers中的哪个任务要执行。只有tasks中的任务状态是changed才会进行通知。
java 复制代码
// 触发执行任务 notify、handlers??

ansibletest]# cat get_conf.yml 
    ---
    - name: download nginx.conf
      hosts: web1
      tasks:
        - name: nginx.conf
          fetch:
            src: /etc/nginx/nginx.conf
            dest: ./
            flat: 1						// 不下载路径,只能对一个主机生效

ansibletest]# vim nginx.conf
     39         listen       {{http_port}} default_server;
     40         listen       [::]:{{http_port}} default_server;
ansibletest]# cat trigger.yml 
    ---
    - name:
      hosts: webs
      vars:
        http_port: "8010"
      tasks:
        - name: upload nginx.conf
          template:
            src: nginx.conf
            dest: /etc/nginx/nginx.conf
          notify: reload nginx			// 当本任务changed时才通知handlers执行任务reload nginx

      handlers:
        - name: reload nginx
          service:
            name: nginx
            state: reloaded

when条件

  • 只有满足when为true时,才执行任务。作用类似于shell中的if结构
  • 常用的比较符:
    • ==:相等
    • !=:不等
    • >:大于
    • <:小于
    • <=:小于等于
    • >=:大于等于
  • 多个条件使用andor进行连接。
  • not结果取反
  • when表达式中的变量,可以不使用{``{}}
java 复制代码
# 当dbs组中的主机内存大于2G的时候,才安装mysql-server
[root@pubserver ansible]# vim when1.yml
---
- name: install mysql-server
  hosts: dbs
  tasks:
    - name: install mysql-server pkg
      yum:
        name: mysql-server
        state: present
      when: ansible_memtotal_mb>2048

# 如果目标主机没有2GB内存,则不会安装mysqld-server
[root@pubserver ansible]# ansible-playbook when1.yml



# 多条件。系统发行版是Rocky8才执行任务
# /etc/motd中的内容,将会在用户登陆时显示在屏幕上
[root@pubserver ansible]# vim motd
 _____________
< hello world >
 -------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

[root@pubserver ansible]# vim when2.yml
---
- name: when condition
  hosts: webservers
  tasks:
    - name: modify /etc/motd
      copy:
        dest: /etc/motd
        src: motd
      when: >
        ansible_distribution == "Rocky"
        and
        ansible_distribution_major_version == "8"

[root@pubserver ansible]# ansible-playbook when2.yml

regitster注册变量

Ansible的"register"模块是用于捕获和保存任务执行结果的,它允许将其他任务的输出作为变量使用。register是一个关键字,可以将任务执行的结果赋值给指定的变量名称。这个变量可以在后续任务中使用。 register模块可以捕获各种类型的输出,包括stdout、stderr、rc、changed等。它可以与其他模块一起使用,例如"when"条件、"loop"循环等。

java 复制代码
# 在web1组的主机上执行任务,创建/tmp/regfile1.txt,并打印创建结果
[root@pubserver ansible]# vim reg1.yml
---
- name: create file /tmp/regfile1.txt
  hosts: web1
  tasks:
    - name: create file
      file:
        path: /tmp/rgefile1.txt
        state: touch
      register: result

    - name: display output
      debug:
        msg: "{{result}}"

# 在web1主机上执行任务,创建文件/tmp/ademo/abc。如果创建不成功,则通过debug输出create failed
[root@pubserver ansible]# vim reg2.yml
---
- name: create file /tmp/ademo/abc
  hosts: web1
  ignore_errors: yes
  tasks:
    - name: create file
      file:
        path: /tmp/ademo/abc
        state: touch
      register: result
	  notify: print mode
	  
    - name: debug output
      debug:
        msg: "create failed"
      when: result.failed

  handlers:
  	- name: print mode
  	  debug:
  	    msg: "{{result.mode}}"
java 复制代码
// =两侧要有空格
"msg" = {									
    "changed": true,
    "dest": "/tmp/filereg1.txt",
    "diff": {
        "after": {
            "atime": 1689759842.9187007,
            "mtime": 1689759842.9187007,
            "path": "/tmp/filereg1.txt",
            "state": "touch"
        },
        "before": {
            "atime": 1689759423.64123,
            "mtime": 1689759423.64123,
            "path": "/tmp/filereg1.txt",
            "state": "file"
        }
    },
    "failed": false,
    "gid": 0,
    "group": "root",
    "mode": "0644",
    "owner": "root",
    "size": 0,
    "state": "file",
    "uid": 0
}

msg['mode']

任务块

  • 可以通过block关键字,将多个任务组合到一起
  • 可以将整个block任务组,一起控制是否要执行
java 复制代码
# 如果webservers组中的主机系统发行版是Rocky,则安装并启动nginx
[root@pubserver ansible]# vim block1.yml
---
- name: block tasks
  hosts: webservers
  tasks:
    - name: define a group of tasks
      block:
        - name: install nginx   # 通过yum安装nginx
          yum:
            name: nginx
            state: present

        - name: start nginx     # 通过service启动nginx服务
          service:
            name: nginx
            state: started
            enabled: yes
      when: ansible_distribution=="Rocky"   # 条件为真才会执行上面的任务

[root@pubserver ansible]# ansible-playbook block1.yml

快捷操作

java 复制代码
// 多行开头增加空格,例如第7行至最后一行
光标在要操作的第一行,Ctrl+v,下箭头至最后一行,大写I,键入空格,Esc退出
末行模式:7,$s/^/  /

block、rescue和always

  • block和rescue、always联合使用:
    • block中的任务都成功,rescue中的任务不执行
    • block中的任务出现失败(failed),rescue中的任务执行
    • block中的任务不管怎么样,always中的任务总是执行
java 复制代码
[root@pubserver ansible]# vim block2.yml
---
- name: block test
  hosts: webservers
  tasks:
    - name: block / rescue / always test1
      block:
        - name: touch a file
          file:
            path: /tmp/test1.txt
            state: touch
      rescue:
        - name: touch file test2.txt
          file:
            path: /tmp/test2.txt
            state: touch
      always:
        - name: touch file test3.txt
          file:
            path: /tmp/test3.txt
            state: touch

# 执行playbook web1上将会出现/tmp/test1.txt和/tmp/test3.txt
[root@pubserver ansible]# ansible-playbook block2.yml
[root@web1 ~]# ls /tmp/test*.txt
/tmp/test1.txt  /tmp/test3.txt

# 修改上面的playbook,使block中的任务出错
[root@web1 ~]# rm -f /tmp/test*.txt
[root@pubserver ansible]# vim block2.yml
---
- name: block test
  hosts: webservers
  tasks:
    - name: block / rescue / always test1
      block:
        - name: touch a file
          file:
            path: /tmp/abcd/test11.txt
            state: touch
      rescue:
        - name: touch file test22.txt
          file:
            path: /tmp/test22.txt
            state: touch
      always:
        - name: touch file test33.txt
          file:
            path: /tmp/test33.txt
            state: touch
# 因为web1上没有/tmp/abcd目录,所以block中的任务失败。但是playbook不再崩溃,而是执行rescue中的任务。always中的任务总是执行
[root@pubserver ansible]# ansible-playbook block2.yml
[root@web1 ~]# ls /tmp/test*.txt
/tmp/test22.txt  /tmp/test33.txt

loop循环

  • 相当于shell中for循环。旧版本是with_item

  • ansible中循环用到的变量名是固定的,叫item

    在test组中的主机上创建5个目录/tmp/{aaa,bbb,ccc,ddd,eee}

    [root@pubserver ansible]# vim loop1.yml

    • name: use loop
      hosts: webservers
      tasks:
      • name: create directory
        file:
        path: /tmp/{{item}}
        state: directory
        loop: [aaa,bbb,ccc,ddd,eee] // python的写法,列表[]

    上面写法,也可以改为:


    • name: use loop
      hosts: webservers
      tasks:
      • name: create directory
        file:
        path: /tmp/{{item}}
        state: directory
        loop:
        • aaa // yaml的写法
        • bbb
        • ccc
        • ddd
        • eee

    [root@pubserver ansible]# ansible-playbook loop1.yml

    使用复杂变量。创建zhangsan用户,密码是123;创建lisi用户,密码是456

    item是固定的,用于表示循环中的变量

    循环时,loop中每个-后面的内容作为一个整体赋值给item。

    loop中{}中的内容是自己定义的,写法为key:val

    取值时使用句点表示。如下例中取出用户名就是{{item.uname}}

    [root@pubserver ansible]# vim loop_user.yml

    • name: create users
      hosts: webservers
      tasks:
      • name: create multiple users
        user:
        name: "{{item.uname}}"
        password: "{{item.upass | password_hash('sha512')}}"
        loop:
        • {"uname": "zhangsan", "upass": "123"}
        • {"uname": "lisi", "upass": "456"}
          [root@pubserver ansible]# ansible-playbook loop_user.yml

role角色

  • 为了实现playbook重用,可以使用role角色。作用是代码重用
  • 角色role相当于把任务打散,放到不同的目录中
  • 再把一些固定的值,如用户名、软件包、服务等,用变量来表示
  • role角色定义好之后,可以在其他playbook中直接调用
shell 复制代码
# 使用常规playbook,修改/etc/motd的内容
# 1. 创建motd模板文件
[root@pubserver ansible]# vim motd
Hostname: {{ansible_hostname}}     # facts变量,主机名
Date: {{ansible_date_time.date}}   #  facts变量,日期
Contact to: {{admin}}              # 自定义变量

# 2. 编写playbook
[root@pubserver ansible]# vim motd.yml
---
- name: modifty /tmp/motd
  hosts: webservers
  vars:
    admin: root@123.com            # 自定义名为admin的变量
  tasks:
    - name: modify motd
      template:
        src: motd
        dest: /tmp/motd

[root@pubserver ansible]# ansible-playbook motd.yml
[root@web1 ~]# cat /tmp/motd 
Hostname: web1
Date: 2023-07-20
Contact to: root@123.com


# 创建角色
# 1. 声明角色存放的位置
[root@pubserver ansible]# vim ansible.cfg 
[defaults]
inventory = hosts
roles_path = roles    # 定义角色存在当前目录的roles子目录中

# 2. 创建角色目录
[root@pubserver ansible]# mkdir roles

# 3. 创建名为motd的角色
[root@pubserver ansible]# ansible-galaxy init roles/motd
[root@pubserver ansible]# ls roles/
motd     # 生成了motd角色目录
[root@pubserver ansible]# yum install -y tree
[root@pubserver ansible]# tree roles/motd/
roles/motd/
├── defaults         # 定义变量的目录,优先级最低
│    └── main.yml
├── files            # 保存上传的文件(如copy模块用到的文件)
├── handlers         # handlers任务写到这个目录的main.yml中
│    └── main.yml
├── meta             # 保存说明数据,如角色作者、版本等
│    └── main.yml
├── README.md        # 保存角色如何使用之类的说明
├── tasks            # 保存任务
│    └── main.yml
├── templates        # 保存template模块上传的模板文件
├── tests            # 保存测试用的playbook。可选
│    ├── inventory
│    └── test.yml
└── vars             # 定义变量的位置,推荐使用的位置
     └── main.yml

# 4. 将不同的内容分别写到对应目录的main.yml中
# 4.1 创建motd模板文件
ansibletest]# mv motd roles/motd/templates/
[root@pubserver ansible]# vim roles/motd/templates/motd
Hostname: {{ansible_hostname}}
Date: {{ansible_date_time.date}}
Contact to: {{admin}}

# 4.2 创建变量
[root@pubserver ansible]# echo "admin: test@456.com" >> roles/motd/vars/main.yml  # 追加一行


# 4.3 创建任务
[root@pubserver ansible]# vim roles/motd/tasks/main.yml  # 追加
- name: modify motd
  template:
    src: motd      # 这里的文件,自动到templates目录下查找
    dest: /tmp/motd

# 5. 创建playbook,调用motd角色
[root@pubserver ansible]# vim role_motd.yml
---
- name: modify motd with role
  hosts: webs
  roles:
    - motd

# 6. 执行playbook
[root@pubserver ansible]# ansible-playbook role_motd.yml 
[root@db1 ~]# cat /tmp/motd 
Hostname: db1
Date: 2023-07-20
Contact to: test@456.com

role练习

  1. 创建名为pkgs的角色。用于装包。包名使用变量pkg代表
  2. 创建inst_nginx.yml,调用pkgs角色,安装nginx
  3. 创建inst_mysql.yml,调用pkgs角色,安装mysql
shell 复制代码
# 1. 创建名为pkgs的角色。
# 1.1 创建角色目录
[root@pubserver ansible]# ansible-galaxy init roles/pkgs
# 1.2 创建装包的任务,包名使用变量pkg代表
[root@pubserver ansible]# vim roles/pkgs/tasks/main.yml 
---
# tasks file for roles/pkgs
- name: install rpm pkg
  yum:
    name: "{{pkg}}"
    state: present
# 1.3 定义变量
[root@pubserver ansible]# vim roles/pkgs/defaults/main.yml 
---
# defaults file for roles/pkgs
pkg: nginx

ansibletest]# cat inst_nginx.yml 
---
- name: install nginx
  hosts: db1
  roles:
    - pkgs
ansibletest]# ansible-playbook inst_nginx.yml 



ansibletest]# cat inst_mysql.yml 
---
- name: install mysql
  hosts: db1
  vars:
    pkg: mysql
  roles:
    - pkgs
ansibletest]# ansible-playbook inst_mysql.yml 
java 复制代码
ansibletest]# mkdir -p roles/svrs/{tasks,defaults}
ansibletest]# cat roles/svrs/tasks/main.yml
---
- name: start and enable
  service:
    name: "{{svr}}"
    state: started
    enabled: yes
ansibletest]# cat roles/svrs/defaults/main.yml
---
svr: nginx
ansibletest]# cat inst_nginx.yml
---
- name: install nginx
  hosts: db1
  roles:
    - pkgs
    - svrs
ansibletest]# ansible-playbook inst_nginx.yml 
ansibletest]# cat inst_mysql.yml 
---
- name: install mysql
  hosts: db1
  vars:
    pkg: mysql-server
    svr: mysqld
  roles:
    - pkgs
    - svrs

ansible加解密文件 ansible-vault

直接加解密

  • ansible-vault 动作参数 文件路径:加解密该文件。
    • 常用动作参数:
      • encrypt:加密。
      • decrypt:解密(需知密码)。
      • rekey:重设密码(需知密码)。
      • view:不解密查看(需知密码)。
java 复制代码
// ansible-vault
ansibletest]# echo "for dinner" > /tmp/vault.txt		// 创建一个需要加密的文件
ansibletest]# cat /tmp/vault.txt
	for dinner
// 加密文件,encrypt
ansibletest]# ansible-vault encrypt /tmp/vault.txt
    New Vault password: 			// 新设密码
    Confirm New Vault password: 	// 确认密码
    Encryption successful
ansibletest]# cat /tmp/vault.txt
    $ANSIBLE_VAULT;1.1;AES256
    66643337396139336230303461313066326664646664666636636331663731323863336535356333
    3733643164363338396436666662353532623964323830360a336331313262306330653336323532
    62383332333735623662636562653466353637646333323032333130383137656465633265656231
    3239623536633534630a623638653039316534323235346637623632656562366137386133333839
    3361
// 知道旧密码重设密码,rekey
ansibletest]# ansible-vault rekey /tmp/vault.txt
    Vault password: 				// 旧密码
    New Vault password: 			// 新设密码
    Confirm New Vault password: 	// 确认密码
    Rekey successful
ansibletest]# cat /tmp/vault.txt
    $ANSIBLE_VAULT;1.1;AES256
    31653239643133313637633030336463383035313433666331363764643838326165633563353636
    3835666561393566616530633135653631343031656537620a613539373933363830343637356331
    30616661353461396234313834386536613362333165613233383564653032656431626538663962
    3737323537343063640a393233373538633966373363656339386535313066626239633835353432
    6366
// 知道密码查看文件,view
ansibletest]# ansible-vault view /tmp/vault.txt
    Vault password: 
    for dinner
ansibletest]# ansible-vault view /tmp/vault.txt > /tmp/vault2.txt 	// 不会解密加密文件
	Vault password: 
ansibletest]# cat /tmp/vault2.txt
	for dinner
ansibletest]# cat /tmp/vault.txt
    $ANSIBLE_VAULT;1.1;AES256
    31653239643133313637633030336463383035313433666331363764643838326165633563353636
    3835666561393566616530633135653631343031656537620a613539373933363830343637356331
    30616661353461396234313834386536613362333165613233383564653032656431626538663962
    3737323537343063640a393233373538633966373363656339386535313066626239633835353432
    6366
// 解密文件,decrypt
ansibletest]# ansible-vault decrypt /tmp/vault.txt
    Vault password: 
    Decryption successful
ansibletest]# cat /tmp/vault.txt
	for dinner

使用密码文件加解密 --vault-id

  • ansible-vault 动作参数 --vault-id=密码文件A路径 文件B路径:使用密码文件A来加解密文件B。
    • 常用动作参数:
      • encrypt:加密。
      • decrypt:解密。
      • view:不解密查看。
java 复制代码
// 使用密码文件进行加解密,--vault-id=密码文件
ansibletest]# echo "for dinner" > /tmp/vault.txt					// 创建一个需要加密的文件
ansibletest]# cat /tmp/vault.txt
	for dinner
ansibletest]# echo "asddgfqf.adsbfaaaagaa.afsdf" > /tmp/pass.txt	// 创建密码文件
// 将文件/tmp/pass.txt中的内容作为密码加密/tmp/vault.txt,encrypt
ansibletest]# ansible-vault encrypt --vault-id=/tmp/pass.txt /tmp/vault.txt
	Encryption successful
ansibletest]# cat /tmp/vault.txt
    $ANSIBLE_VAULT;1.1;AES256
    63333935636364306263656332396234636661616334633163303561626331316339643666363330
    6635636134646534343232623135653632646330623936630a656334396137343062373137333137
    35316134306232363364663333353566373038626461653230633139616237356165313233326466
    6533363330306464380a373362396534373636623036303639363830373339663937633665313262
    3030
// 将文件/tmp/pass.txt中的内容作为密码查看/tmp/vault.txt,view
ansibletest]# ansible-vault view --vault-id=/tmp/pass.txt /tmp/vault.txt
	for dinner
// 将文件/tmp/pass.txt中的内容作为密码解密/tmp/vault.txt,decrypt
ansibletest]# ansible-vault decrypt --vault-id=/tmp/pass.txt /tmp/vault.txt
	Decryption successful
ansibletest]# cat /tmp/vault.txt
	for dinner

执行加密的剧本文件 --ask-vault-password

  • 执行加密的剧本文件:需要使用选项 --ask-vault-password 来输入密码。
  • ansible-playbook --ask-vault-password 剧本文件路径:执行该剧本文件时询问密码。
java 复制代码
// 执行加密的剧本文件
// 创建一个剧本文件,加密该剧本文件
ansibletest]# cat user_zhangsan.yml			
    ---
    - name: create a user
      hosts: db1
      tasks:
        - name: create user zhangsan
          user:
            name: zhangsan
            password: "{{'123'| password_hash('sha512')}}"
ansibletest]# ansible-vault encrypt user_zhangsan.yml
	New Vault password: 
	Confirm New Vault password:
	Encryption successful

// 直接执行剧本文件,报错
ansibletest]# ansible-playbook user_zhangsan.yml
	ERROR! Attempting to decrypt but no vault secrets found		// 报错

// 使用选项--ask-vault-password执行剧本文件
ansibletest]# ansible-playbook --ask-vault-password user_zhangsan.yml
	Vault password: 
	......省略一万字(执行任务)
ansibletest]# cat user_zhangsan.yml		// 不会解密文件	
    $ANSIBLE_VAULT;1.1;AES256
    62363439326161623261643961666533376361363062636566353232353638643832623163613066
    6161323564383136636530343638393730633130356437390a653030666535313863646666316232
    32633337356462396131383031616466383730353939616564383865613865386138623065653731
    6465613066653866380a316461313333343135646161386336303236656363623066323963613437
    39306538356537353863313566613663303439393037393034383537323263343165376438313962
    32656564636232326430323435373431633337666638623030653737383062653239643962333437
    36626134396265326533333936376561373264353835323138343763303938386332303961323437
    34313362343166386664356231353862386631396638396231613936643734386362386365663466
    31666634363839653531333139313537316335393536353535646330373639346237326331373866
    38343534393634386564313432623230336538346531663764396530323230653765666264303064
    63386662643965323035643238303263383838356135616561346235356239343565343537356633
    63653761333564666131633533333533643530343461356436323933356364633262356237303163
    6130

sudo命令

  • 一般用于普通用户执行需要root权限的命令
  • 在web1上配置zhangsan拥有sudo权限
java 复制代码
// sudo
// 赋权给zhangsan
[root@db1 ~]# visudo   		// 使用vi方式打开/etc/sudoers,在最后追加一行信息
	zhangsan        ALL=(ALL)       ALL
    /* zhangsan位置是用户名,最后的ALL位置是命令。ALL表示zhangsan可以执行所有命令
     * 第一个ALL是主机名。ALL表示所有主机集中认证的域环境中才有效,单机忽略即可
     * 第二个ALL是sudo后的用户身份。
	 * 第三个ALL是赋权的命令
     */

// 切换成zhangsan用户,执行命令
[root@db1 ~]# su - zhangsan
[zhangsan@db1 ~]$ useradd wangwu   		// 失败,无权限
	useradd: Permission denied.
	useradd: cannot lock /etc/passwd; try again later.
[zhangsan@db1 ~]$ sudo useradd wangwu  	// 以管理员身份执行
	......省略一万字
	[sudo] password for zhangsan: 		// 输入zhangsan的密码,不是root
	// 输入zhangsan密码后有5分钟缓冲时间不用再输密码。

// 赋权给lisi,并免密sudo,NOPASSWD
[root@db1 ~]# visudo    				// 在最后追加一行信息
	lisi    ALL=(ALL)       NOPASSWD: ALL

// 切换成zhangsan用户,执行命令
[root@db1 ~]# su - lisi
[lisi@db1 ~]$ ls /root/   				// 失败,无权限
	ls: cannot open directory '/root/': Permission denied
[lisi@db1 ~]$ sudo ls /root/   			// 以管理员身份执行,无需输入密码
	a3.txt  anaconda-ks.cfg

特殊的主机清单变量

  • 如果远程主机没有使用免密登陆,如果远程主机ssh服务不是默认的22端口,
    可以在控制端设置特殊的Ansible主机清单变量 (与该主机写在同一行):
    • ansible_ssh_user:指定登陆远程主机的用户名。
    • ansible_ssh_pass:指定登陆远程主机的密码。
    • ansible_ssh_port:指定登陆远程主机的端口号。
  • 如果没有在 /etc/hosts 中配置主机的名称解析,可以使用主机清单变量 ansible_host
    • 主机名 ansible_host=IP地址
java 复制代码
// ssh,密码、端口号
// 控制端upserver(192.168.88.240)、被控端web1(88.11)、被控端web2(88.12)、被控端db1(88.13)
控制端upserver(192.168.88.240):
// 删除被控远程主机接收的公钥(/root/.ssh/authorized_keys),恢复通过密码登陆
[root@pubserver ansible]# ansible all -m file -a "path=/root/.ssh/authorized_keys state=absent"
// 创建新的Ansible工作目录myansible
[root@pubserver ~]# mkdir myansible
[root@pubserver ~]# cd myansible
[root@pubserver myansible]# vim ansible.cfg
	[defaults]
	inventory=inventorytest
	host_key_checking=no
[root@pubserver myansible]# cat inventorytest
    [group1]
    web1
    web2
    db1
[root@pubserver myansible]# vim /etc/hosts		 // 新增三行名称解析
    192.168.88.11 web1
    192.168.88.12 web2
    192.168.88.13 db1
[root@pubserver myansible]# ansible all -m ping  // 报错,Permission denied。无法免密远程管理
	// 注意:ping模块检查是否可以远程管理目标主机,不同于ping命令

主机db1(192.168.88.13):
// 修改ssh服务的端口为220
[root@db1 ~]# systemctl stop firewalld
[root@db1 ~]# echo 'Port 220' >> /etc/ssh/sshd_config
[root@db1 ~]# systemctl restart sshd.service
    /* 如果是其它终端远程登陆db1主机,需要指定端口号:-p220
     * [root@myhost ~]# ssh -p220 192.168.88.13
     */

控制端upserver(192.168.88.240):
// 主机db1修改ssh服务端口号后,控制端无法连接该主机
[root@pubserver myansible]# ansible all -m ping
    db1 | UNREACHABLE! => {			// 无法连接ssh默认端口22
        "changed": false,				
        "msg": "Failed to connect to the host via ssh: ssh: connect to host db1 port 22: Connection refused",
        "unreachable": true
    }
    web2 | UNREACHABLE! => {		// 可连接但无法免密远程管理
        "changed": false,
        "msg": "Failed to connect to the host via ssh: root@web2: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
        "unreachable": true
    }
    web1 | UNREACHABLE! => {
        "changed": false,
        "msg": "Failed to connect to the host via ssh: root@web1: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
        "unreachable": true
    }
// 配置ssh通过用户名、密码管理远程主机,通过220端口连接db1
[root@pubserver myansible]# cat inventorytest
    [group1]
    web1 ansible_ssh_user=root ansible_ssh_pass=123
    web2 ansible_ssh_user=root ansible_ssh_pass=123
    db1 ansible_ssh_user=root ansible_ssh_pass=123 ansible_ssh_port=220
[root@pubserver myansible]# ansible all -m ping	 // 全部SUCCESS
// 删除/etc/hosts中的"192.168.88.13 db1"
[root@pubserver myansible]# ansible all -m ping	 // 无法识别db1
[root@pubserver myansible]# cat inventorytest
    [group1]
    web1 ansible_ssh_user=root ansible_ssh_pass=123
    web2 ansible_ssh_user=root ansible_ssh_pass=123
    db1 ansible_ssh_user=root ansible_ssh_pass=123 ansible_ssh_port=220 ansible_host=192.168.88.13
[root@pubserver myansible]# ansible all -m ping	 // 全部SUCCESS

blockinfile模块??

  • blockinfile模块用于对目标文件写入内容块。
  • 常用参数:
    • path:指定被操作的文件路径。
    • block:设置写入该文件的内容块(严格匹配)。
    • statepresent表示创建,absent表示删除。省略默认为present
    • insertbefore:指定在哪一行之前插入内容。支持正则表达式。BOF表示文档开头。
    • insertafter:指定在哪一行之后插入内容。支持正则表达式。EOF表示文档结尾。
    • marker:开始与结束标记语句(标记语句也算插入内容,对state有影响)。#{mark}字符串
    • backup参数 :是否在修改文件之前对文件进行备份。
    • create参数 :当要操作的文件并不存在时,是否创建对应的文件。

archive模块

  • archive模块用于在远程主机上创建和提取压缩包。
  • 常用参数:
    • path:指定要压缩的源数据路径。
    • exclude_path:指定排除的数据路径。
    • src:指定要提取的压缩包路径。
    • dest:指定要创建的目标压缩包路径。
    • format:指定要使用的压缩包格式,如tar、tar.gz、tar.bz2、zip等。
    • mode:指定要创建的目标压缩包的权限。
    • force:强制创建或提取压缩包,即使目标压缩包已存在。
    • remove:是否删除源数据。

unarchive模块

  • unarchive模块用于。

  • 常用参数:

    • src:指定要解压的压缩包路径。本地路径或远程路径。
    • dest:指定解压后的目标路径。可以是本地路径或者远程主机上的路径。
    • remote_src:压缩包是否在远程主机,省略默认为否 no
    • mode:指定解压后数据的权限(8进制或字符串表示),省略默认保持与原文件一致"preserve"
    • owner:指定解压后数据的所有者(用户名或GID)。默认为文件或目录的当前所有者。
    • group:指定解压后文件或目录的所属组。可以使用组名或组ID。默认为文件或目录的当前所属组。
    • extra_opts:额外的解压缩选项,作为字符串传递。
    • creates:指定一个路径,如果该路径已经存在,表示文件已经被提取,将不会再次执行解压缩。

https://blog.csdn.net/weixin_48814356/article/details/129636506?ops_request_misc=\&request_id=\&biz_id=102\&utm_term=archive模块\&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb\~default-8-129636506.nonecase\&spm=1018.2226.3001.4187#t24

synchronize模块

  • synchronize模块基于rsync命令批量同步文件。使用这个模块须保证被控端存在rsync命令。
  • 常用参数:
    • src:指定源数据路径。
    • dest:指定目标数据路径。
    • modepush表示从控制端同步到被控端,pull表示从被控端同步到控制端。省略默认为push
    • archive:是否采用归档模式同步,保证源数据和目标数据属性一致。
    • delete:是否删除不同的文件。省略默认为no
    • rsync_opts:使用rsync参数。
      • rsync_opts=--exclude=*.log:忽略.log结尾的数据。
java 复制代码
// synchronize模块??
]# ansible node1 -m synchronize -a 'src=/n1/ dest=/n1 mode=pull'
]# ansible node1 -m synchronize -a 'src=/n1/ dest=/n1 mode=push'
]# ansible node1 -m synchronize -a 'src=/n1/ dest=/n1 mode=push delete=yes archive=yes'

async和poll

shell 复制代码
+ 在Ansible的剧本(playbook)中,要实现跳过一个任务的进度条或将一个任务放入后台执行并继续执行下一个任务,可以采用以下方法:使用 async 和 poll
+ Ansible 允许通过 async 参数将任务放入后台执行。async 参数定义了任务在后台运行的最长时间(以秒为单位)。同时,你可以使用 poll 参数来控制 Ansible 对异步任务的检查频率。将 poll 设置为 0 会让 Ansible 启动任务后立即继续执行下一个任务,而不等待该任务完成。

示例:
- name: Run a long running task in background
  command: /path/to/long/running/command
  async: 3600 # 运行时间最长为1小时
  poll: 0 # 立即继续到下一个任务
- name: Continue with the next task
  debug:
    msg: "这个任务会在后台任务开始后立即执行"

+ 处理异步任务的结果
+ 当你在后台执行一个任务时,可能还需要在某个时间点检查该任务的完成情况。为此,你可以使用 async_status 模块来轮询任务的状态。
示例:
- name: Run a long running task in background
  command: /path/to/long/running/command
  async: 3600
  poll: 0
  register: my_background_job
- name: Other tasks can be done here
  debug:
    msg: "执行其他任务"
- name: Check the status of the background job
  async_status:
    jid: "{{ my_background_job.ansible_job_id }}"
  register: job_result
  until: job_result.finished
  retries: 30
  delay: 10
+ 在这个示例中,async_status 用于检查后台任务的完成情况,通过循环和延迟来实现。
+ 注意事项
	使用 async 时,确保定义的最长运行时间适用于你的任务。
	当使用 poll: 0 时,你不会得到任务执行的即时反馈。如果任务失败,你需要通过日志或其他方式来诊断问题。
	确保在 playbook 的后面部分或在适当的时机检查异步任务的结果。
	这些方法可以帮助你在 Ansible playbook 中有效地管理和控制异步任务的执行。

delegate_to

shell 复制代码
delegate_to是Ansible中的一个关键字,用于指定任务将在哪台主机上运行。通过使用delegate_to,您可以指定一个任务在目标主机以外的其他主机上执行,这对于执行一些特定操作或检查来说可能非常有用。

以下是一个示例,演示了如何在Ansible中使用delegate_to:

---
- name: Copy file to a different host
  hosts: host1
  tasks:
    - name: Copy file to host2
      copy:
        src: /path/to/source/file
        dest: /path/to/destination/file
      delegate_to: host2
在这个示例中,任务Copy file to host2指定了delegate_to: host2,表示这个任务将在host2上执行。因此,文件将从控制端拷贝到host2。

使用delegate_to关键字有几个常见的用途,比如:

在目标主机之外执行一些额外的操作,比如在跳板机上执行一些操作。
在特定的主机上执行一些与目标主机无关的任务,比如监控、日志收集等。
在需要在不同主机上执行的情况下,可以通过delegate_to指定任务的执行主机。

end

相关推荐
leo__5202 天前
自动化运维:使用Ansible简化日常任务
运维·自动化·ansible
风清再凯7 天前
自动化工具ansible,以及playbook剧本
运维·自动化·ansible
IT乌鸦坐飞机7 天前
ansible部署数据库服务随机启动并创建用户和设置用户有完全权限
数据库·ansible·centos7
遇见火星20 天前
如何使用Ansible一键部署MinIO集群?
ansible
粥周粥20 天前
ANSIBLE
ansible
码农101号20 天前
Linux中ansible模块补充和playbook讲解
linux·运维·ansible
码农101号20 天前
Linux的Ansible软件基础使用讲解和ssh远程连接
ansible
烟雨书信21 天前
ANSIBLE运维自动化管理端部署
运维·自动化·ansible
碎碎-li21 天前
ANSIBLE(运维自动化)
运维·自动化·ansible
@donshu@24 天前
Linux运维-ansible-python开发-获取inventroy信息
linux·运维·ansible