Ansible是一款开源的资源管理工具,是目前运维自动化工具中最简单、容易上手的优秀软件。用户可以通过它自动化的部署应用程序来实现IT基础架构,例如对服务器进行初始化配置、安全基线配置、更新和打补丁都是简单容易的。
[EPEL]
name=EPEL
baseurl=https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/
enabled=1
gpgcheck=0
添加yum源,以安装Ansible。
dnf install -y ansible
ansible –version #查看ansible版本
Ansible配置文件优先级
主机清单:
/etc/ansible/hosts
[dev] #分组
192.168.10.20 #主机
[test]
192.168.10.21
[prod]
192.168.10.22
192.168.10.23
[balancers]
192.168.10.24
[webservers:children] #webservers:组名称,children:参数,表示包含子组。
prod #组
[all:vars] #all:所以主机 vars:ansible变量
ansible_user=root #账号
ansible_password=redhat #密码
主机清单文件修改后的是会立即生效的,一般常用“ansible-inventory --graph”命令以结构化的方式显示出受管节点主机信息,对于有层级的分组来讲是非常利于阅读的:
[root@linuxprobe ~]# ansible-inventory --graph
@all:
|–@balancers:
| |–192.168.10.24
|–@dev:
| |–192.168.10.20
|–@prod:
| |–192.168.10.22
| |–192.168.10.23
|–@test:
| |–192.168.10.21
|–@ungrouped:
将Ansible主配置文件中的第71行设置成默认不需要SSH协议的指纹验证,以及第107行设置成默认执行Playbook时所使用的管理员名称为root
[root@linuxprobe ~]# vim /etc/ansible/ansible.cfg
69
70 # uncomment this to disable SSH key host checking
71 host_key_checking = False
72
………………省略部分输出信息………………
104
105 # default user to use for playbooks if user is not specified
106 # (/usr/bin/ansible will use current user as default)
107 remote_user = root
108
运行临时命令
ansible-doc 模块名称 #查询命令格式
ansibe-doc -l #列出所有模块信息
常用模块
ansible是用于执行临时任务的命令,也就是执行后即结束,不同于Playbook剧本文件的可重复性。使用ansible命令时必须指明受管主机节点的信息,如果已经设置过主机清单文件(/etc/ansible/hosts)则可以写all参数来代指全体受管节点,或用dev、test等主机组名称来代指某一组的主机节点。
ansible 受管主机节点 -m 模块名称 [-a 模块参数]
“-a”是要传递给模块的参数,大多情况下“-m”与“-a”参数都会同时出现。
示例 : ansible all -m ping
返回值若为SUCCESS则代表主机当前在线。
ansible-doc -l #列举出当前Ansible服务所支持的所有模块信息
ansible-doc a10_server #显示出这个模块的作用、可用参数及实例等等信息
yum_repository模块的作用是管理主机的软件仓库,能够添加、修改及删除软件仓库的配置信息。
参数相对比较复杂。遇到这种情况建议先用ansible-doc命令对其进行了解
ansible all -m yum_repository -a ‘name=“EX294_BASE” description=“EX294 base software” baseurl=“file:///media/cdrom/BaseOS” gpgcheck=yes enabled=1 gpgkey=“file:///media/cdrom/RPM-GPG-KEY-redhat-release”’
命令执行成功后,可以到主机清单中任意服务器上查看到新建成功的软件仓库配置文件。
剧本文件(playbook)
Ansible服务的Playbook剧本文件采用YAML语言编写,有着强制性的格式规范,通过空格将不同信息分组,因此有时会因一两个空格错位而导致报错,需要万分小心。YAML文件开头需要先写三个减号—,多个分组信息需要间隔一致才能执行,上下也要对齐,后缀名一般为.yml。在执行后会在屏幕上输出运行界面,内容会依据不同工作而变化,但绿色均代表成功,黄色代表执行成功并进行了修改,而红色则代表执行失败。
Playbook剧本文件的结构由四部分组成——target、variable、task、handler。target部分用于定义要执行剧本的主机节点范围、variable部分用于定义剧本执行时要用的变量、task部分用于定义将在远程主机上执行的任务列表、handler部分用于定义执行完成后需要调用的后续任务。
YAML语言编写的Ansible剧本文件会按照从上至下的顺序自动运行。
其中name字段代表此项Play(动作)的名字,可自行命名,没有限制,用于在执行过程中提示用户执行到了那一步,以及帮助管理员日后阅读时回忆起这段代码的作用。hosts字段代表要在哪些主机节点上执行该剧本,多个主机组之间用逗号间隔,若需要对全部主机进行操作则用all参数。tasks字段用于定义要执行的任务,每个任务都要有一个独立的name字段进行命名,并且每个任务的name字段和模块名称都要严格上下对齐,参数要单独缩进。正确的写法应该是:
[root@linuxprobe ~]# vim packages.yml
- name: 安装软件包
hosts: dev,test,prod
tasks:
- name: one #任务名称
yum: #模块名称
name: mariadb #安装名称
state: latest #表示最新版
[root@linuxprobe ~]#
要严格按照标准格式进行写入
RHEL 8系统自带的Vim编辑器会自动进行缩进。
ansible-playbook packages.yml #运行刚刚写好的剧本文件
执行成功后主要观察最下方的输出信息,ok和changed代表执行及修改成功。如遇到unreachable或failed大约0的情况,建议手动检查下剧本是否在所有主机中都正确运行了,以及有无安装失败的情况。正确执行过packages.yml文件后,随机切换到dev、test、prod组中任意一台节点主机上,再次安装mariadb软件包则会提示已经存在,刚刚的操作一切顺利~
创建及使用角色(role)
角色功能通过分别把变量、文件、任务、模块及处理器配置放在各个独立的目录中,然后对其进行便捷加载的一种机制。简单来说,角色功能是把常用的一些功能“类模块化”,然后用的时候加载即可。
使用RHEL系统内置角色,是一种不需要联网就能实现的功能。用户只需要配置好软件仓库的配置文件,然后安装包含系统角色的软件包rhel-system-roles,随后便可以在系统中找到它们了,以及能够使用Playbook剧本文件进行调用。
dnf install -y rhel-system-roles
安装完毕后,使用ansible-galaxy list命令查看RHEL 8系统中有哪些自带的角色可用
ansible-galaxy list
Playbook剧本模板文件存放在/usr/share/doc/rhel-system-roles/目录中,可以复制过来修改使用:
[root@linuxprobe ~]# cp /usr/share/doc/rhel-system-roles/timesync/example-timesync-playbook.yml timesync.yml
NTP服务器是用于计算机时间同步的一种协议,提供高精度的时间校准服务,帮助计算机校对系统时钟。目前常用的是由国际快速授时服务提供的pool.ntp.org,也是稳定性比较好的。在复制来的剧本模板文件中,删除掉多余的代码,将NTP服务器的地址填写到timesync_ntp_servers变量的hostname字段中即可,变量参数含义可参考表格6-6所示,稍后timesync角色就会自动为用户配置参数信息了。
[root@linuxprobe ~]# vim timesync.yml
- hosts: all
vars: #自定义变量
timesync_ntp_servers:
- hostname: pool.ntp.org
iburst: yes
roles:- rhel-system-roles.timesync
从外部获取角色
Ansible Galaxy是Ansible的官方社群服务,用于共享角色和功能代码,用户可以自由的在网站上共享和下载Ansible角色,是管理和使用角色的不二之选。
“ansible-galaxy install 角色名称”的命令格式进行自动获取
ansible-galaxy install nginxinc.nginx
ansible-galaxy list #查看系统中已有角色
用“-r”参数进行加载手动编写外部角色文件
上传一个叫做nginx_core的角色软件包,是用于对nginx网站进行保护的插件功能,编写yml配置文件如下:
[root@linuxprobe ~]# cat nginx.yml
- rhel-system-roles.timesync
- src: https://www.linuxprobe.com/Software/nginxinc-nginx_core-0.3.0.tar.gz
name: nginx-core
随后使用ansible-galaxy命令的“-r”参数加载这个文件,即可查看到新角色信息了
[root@linuxprobe ~]# ansible-galaxy install -r nginx.yml - downloading role from https://www.linuxprobe.com/nginxinc-nginx_core-0.3.0.tar.gz
- extracting nginx to /etc/ansible/roles/nginx
- nginx was installed successfully
[root@linuxprobe ~]# ansible-galaxy list
/etc/ansible/roles
- nginx-core, (unknown version)
- nginxinc.nginx, 0.19.1
/usr/share/ansible/roles
创建新的角色
除了能够使用系统镜像自带和Ansible Galaxy中获取的外部角色,也可以自行创建符合工作需求的新角色信息,定制化的编写工作能够更好的贴合生产环境实际情况,但难度也会稍高一些。接下来将会创建一个名称为apache的新角色信息,它能够帮助我们自动的安装、运行httpd网站服务,设置防火墙允许规则及根据每个主机生成独立的index.html首页文件,让用户调用后就能享受到一条龙的部署网站服务。
根据主配置文件第68行所定义的角色保存路径,如果用户新建的角色信息不在规定目录内,使用ansible-galaxy list命令则是无法找到的。因此需要手动填写下新角色目录的路径,或是进入到/etc/ansible/roles目录内再进行创建,为了避免后期角色信息过于分散导致不好管理,还是决定在默认目录下进行创建,不再修改。
[root@linuxprobe roles]# vim /etc/ansible/ansible.cfg
66
67 # additional paths to search for roles in, colon separated
68 #roles_path = /etc/ansible/roles
69 #roles_path = /etc/ansible/roles:新的角色路径 #以:相隔路径
创建一个新的角色信息使用“init”参数,且建立成功后便会在当前目录下生成出一个新的目录:
[root@linuxprobe ~]# cd /etc/ansible/roles
[root@linuxprobe roles]# ansible-galaxy init apache
- Role apache was created successfully
[root@linuxprobe roles]# ls
apache nginx nginxinc.nginx
创建新的角色最关键的便是对目录结构的理解,通俗来说就是要把正确的信息放入到正确的目录中,这样调用角色时才能有正确的效果。角色信息对应的目录结构及含义如表16-8所示。
第1步:打开编写用于定义角色任务的tasks/main.yml文件。该文件中不需要定义要执行的主机组列表,因为后面会单独编写Playbook剧本进行调用,此时应先对apache角色能做的事情有个明确的思路,调用角色后yml文件会按照从上至下的顺序自动执行。
1:安装httpd网站服务。
2:运行httpd网站服务,并加入到开机启动项中。
3:配置防火墙放行http网站协议。
4:根据每台主机的变量值,生成不同的主页文件。
先写出第一个任务,使用yum模块安装httpd网站服务程序,注意格式:
[root@linuxprobe apache]# vim tasks/main.yml
- name: one
yum:
name: httpd
state: latest
第2步:使用service模块启动httpd网站服务程序,并加入到启动项中,保证能够一直为用户提供服务。初次使用模块前先用ansible-doc命令查看下帮助和实例信息吧,但由于书籍出版的限制,信息会做删减,仅保留有用的段落内容。
[root@linuxprobe apache]# ansible-doc service
………………省略部分输出信息………………
EXAMPLES:
-
name: Start service httpd, if not started
service:
name: httpd
state: started -
name: Enable service httpd, and not touch the state
service:
name: httpd
enabled: yes
通过输出信息可得知启动服务为“state: started”参数,而加入到开机启动项则是“enabled: yes”参数。继续编写:
[root@linuxprobe apache]# vim tasks/main.yml
- name: one
yum:
name: httpd
state: latest - name: two
service:
name: httpd
state: started
enabled: yes
第3步:配置防火墙放行允许策略,让其他主机可以正常访问。配置防火墙使用firewalld模块,同样也先看下帮助示例吧:
[root@linuxprobe defaults]# ansible-doc firewalld
EXAMPLES:
-
firewalld:
service: https
permanent: yes
state: enabled -
firewalld:
port: 8081/tcp
permanent: yes
state: disabled
immediate: yes
依据输出信息可得知,firewalld模块设置防火墙策略中,指定协议名称为“service: http”参数,放行该协议为“state: enabled”参数,设置为永久生效为“permanent: yes”参数,当前也能立即生效为“immediate: yes”参数。参数虽然多了一些,但是基本与在第8章节学习的一致,并不需要担心。继续编写:
[root@linuxprobe apache]# vim tasks/main.yml
- name: one
yum:
name: httpd
state: latest - name: two
service:
name: httpd
state: started
enabled: yes - name: three
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes
第4步:让每个主机显示的首页内容均不同。常规的模块都是这样查一个、写一个就能搞定,为了增加难度再提出个新需求,能否让每个主机上运行的httpd网站服务都有不同的内容,例如显示当前服务器的主机名及IP地址呢?这样的话就要用到template模块及Jinja2技术了。
template模块的使用方法依然用ansible-doc命令进行查询,示例部分有很大帮助:
[root@linuxprobe apache]# ansible-doc template
EXAMPLES: - name: Template a file to /etc/files.conf
template:
src: /mytemplates/foo.j2
dest: /etc/file.conf
owner: bin
group: wheel
mode: ‘0644’
从template模块的输出信息中可得知,这是一个用于复制文件模板的模块,能够把文件从Ansible服务器复制到受管主机上,“src”参数用于定义本地文件的路径,“dest”参数用于定义复制到受管主机的文件路径,而owner、group、mode参数可选择性的设置文件归属及权限信息。
正常来说复制文件的操作是直接进行的,受管主机节点上会获取到一个与Ansible服务器上一摸一样的文件,但有些时候想让每台客户端根据自身系统情况产生不同的文件信息,这样就需要使用到Jinja2技术了,文件后缀是.j2结尾。继续编写:
[root@linuxprobe apache]# vim tasks/main.yml
- name: one
yum:
name: httpd
state: latest - name: two
service:
name: httpd
state: started
enabled: yes - name: three
firewalld:
service: http
permanent: yes
state: enabled
immediate: yes - name: four
template:
src: index.html.j2
dest: /var/www/html/index.html
Jinja2是Python语言中一个被广泛使用的模板引擎,最初的设计思想来源是Django的模块引擎,基于此发展了其语法和一些列强大的功能,能够让受管主机根据自身变量而产生出不同的文件内容。话句话说,正常情况下的复制操作会让新旧文件一摸一样,但Jinja2技术不会在原始文件中直接写入文件内容,而是一系列的变量名称,在使用template模块进行复制的过程中,由Ansible服务负责在受管主机上收集这些变量名称所对应的值,最后再逐一填写到目标文件中,能够让每台主机的文件都根据自身系统情况来独立生成。
例如想要让每个网站的输出信息值为“Welcome to 主机名 on 主机地址”,也就是用每个主机自己独有的名称和IP地址替换文本中的内容,这样就有趣太多了。这种实验的难点主要是查询到对应的变量名称,主机名及地址所对应的值保存在哪里?可以用setup模块进行查询。
setup模块的作用是自动收集受管主机上的变量信息,用-a参数追加filter指令可以对收集来的进行进行二次过滤,语法格式为ansible all -m setup -a ‘filter=“关键词”’ ,其中*号是第三章节学习的通配符,进行关键词查询。例如想搜索各个主机的名称,即用通配符搜索所有包含fqdn关键词的变量值信息。Fully Qualified Domain Name即完全限定主机名,简称FQDN,用于在逻辑上准确表示出主机的位置,也常常被作为主机名的完全表达形式,比/etc/hostname文件中所定义的主机名更加严谨和准确。通过输出信息可得知,ansible_fqdn变量保存有主机名称,随后再进行下一步操作:
[root@linuxprobe ~]# ansible all -m setup -a ‘filter=“fqdn”’
192.168.10.20 | SUCCESS => {
“ansible_facts”: {
“ansible_fqdn”: “linuxprobe.com”,
“discovered_interpreter_python”: “/usr/libexec/platform-python”
},
“changed”: false
}
………………省略部分输出信息………………
用于定制主机地址的变量可以用“ip”作为关键词进行检索,能够看到在ansible_all_ipv4_addresses变量中的值是我们想要的信息。如果想输出IPV6级别的地址则可用ansible_all_ipv6_addresses变量。
[root@linuxprobe ~]# ansible all -m setup -a ‘filter=“ip”’
192.168.10.20 | SUCCESS => {
“ansible_facts”: {
“ansible_all_ipv4_addresses”: [
“192.168.10.20”,
“192.168.122.1”
],
“ansible_all_ipv6_addresses”: [
“fe80::d0bb:17c8:880d:e719”
],
“ansible_default_ipv4”: {},
“ansible_default_ipv6”: {},
“ansible_fips”: false,
“discovered_interpreter_python”: “/usr/libexec/platform-python”
},
“changed”: false
}
………………省略部分输出信息………………
在确认了主机名与IP地址所对应的具体变量名称后,在角色所对应的templates目录内新建一个与上面template模块参数相同的文件名称(index.html.j2)。Jinja2在调用变量值时,格式为在变量名称的两侧格加两个大括号,编写完成即:
[root@linuxprobe apache]# vim templates/index.html.j2
Welcome to {{ ansible_fqdn }} on {{ ansible_all_ipv4_addresses }}
进行到了这里,任务基本就算完成了。最后要做的就是编写一个用于调用apache角色的yml文件,以及执行它。
[root@linuxprobe apache]# cd ~
[root@linuxprobe ~]# vim roles.yml
- name: 调用自建角色
hosts: all
roles:
- apache
[root@linuxprobe ~]# ansible-playbook roles.yml
PLAY [调用自建角色] **************************************************************************
TASK [Gathering Facts] **********************************************************************
执行完毕后,在浏览器中随机输入几个主机的IP地址,即可访问到包含有主机FQDN完全限定主机名和IP地址的网页了,自此实验完美实现,如图16-7、图16-8及图16-9所示。
图16-7 随机访问一台主机节点的网站首页
图16-8 随机访问一台主机节点的网站首页
创建和使用逻辑卷
使用Ansible剧本方式要比使用Shell脚本优势大很多,主要有两点原因。其一,Ansible模块化的功能让操作更标准,只要在执行过程中无报错,那么便会依据远程主机的系统版本及配置自动做出判断和操作,不用担心受到系统变化而导致命令失效的问题。其二,Ansible服务在执行剧本文件时会进行判断,如果该文件或该设备已经被创建过,或是某个动作(Play)已经被执行过,则绝对不会再重复的执行,而使用Shell脚本有可能导致设备被重复格式化,导致数据丢失。
创建一个能批量、自动管理LVM逻辑卷设备的Playbook,能够大大提高对硬盘设备的管理效率,不仅如此,更能避免由于手动创建所带来的错误。例如想要在每个受管主机上都创建出一个名称叫做data的逻辑卷设备,大小为150M,归属于research卷组。如果创建成功,则进一步用ext4文件系统进行格式化操作,若创建失败,则给用户输出一条报错提醒,以便排查原因。
通过回忆第7章节所学习过的LVM逻辑卷的知识,我们应该让Playbook剧本文件依次创建PV物理卷、VG卷组及LV逻辑卷。先需要使用lvg模块让设备支持逻辑卷技术,并创建出一个名为research的卷组,帮助信息如下:
[root@linuxprobe ~]# ansible-doc lvg
EXAMPLES:
-
name: Create a volume group on top of /dev/sda1 with physical extent size = 3>
lvg:
vg: vg.services
pvs: /dev/sda1
pesize: 32 -
name: Create a volume group on top of /dev/sdb with physical extent size = 12>
lvg:
vg: vg.services
pvs: /dev/sdb
pesize: 128K
通过输出信息可得知,创建PV和VG卷组的lvg模块总共有三个必备参数。其中“vg”参数用于定义卷组的名称,“pvs”参数用于指定硬盘设备名称,而“pesize”参数用于确定最终卷组的容量大小,可以用PE个数亦可用容量值进行指定。这样的话先创建出一个由/dev/sdb设备组成的名称为research,大小为150M的卷组设备吧。
[root@linuxprobe ~]# vim lv.yml
-
name: 创建和使用逻辑卷
hosts: all
tasks:
- name: one
lvg:
vg: research
pvs: /dev/sdb
pesize: 150M
接下来便是用lvol模块来创建出LVM逻辑卷设备了,先查看下模块帮助信息吧:
[root@linuxprobe ~]# ansible-doc lvol
EXAMPLES: -
name: Create a logical volume of 512m
lvol:
vg: firefly
lv: test
size: 512 -
name: Create a logical volume of 512m with disks /dev/sda and /dev/sdb
lvol:
vg: firefly
lv: test
size: 512
pvs: /dev/sda,/dev/sdb
通过输出信息可得知,lvol确定是用于创建LVM逻辑卷设备的模块,其中“vg”参数用于指定卷组名称,“lv”参数用于指定逻辑卷名称,而“size”参数则用于指定最终逻辑卷设备的容量大小,不加单位默认为M。填写好参数,创建出一个大小为150M,归属于research卷组,名称为data的逻辑卷设备:
[root@linuxprobe ~]# vim lv.yml
-
name: 创建和使用逻辑卷
hosts: all
tasks:
- name: one
lvg:
vg: research
pvs: /dev/sdb
pesize: 150M
- name: two
lvol:
vg: research
lv: data
size: 150M
这样还不够好,如果能再将创建出的/dev/research/data逻辑卷设备自动用ext4文件系统进行格式化操作,则又能帮助运维管理员减少了一些工作量。对于设备的文件系统格式化操作使用filesystem模块完成,帮助信息如下:
[root@linuxprobe ~]# ansible-doc filesystem
EXAMPLES: -
name: Create a ext2 filesystem on /dev/sdb1
filesystem:
fstype: ext2
dev: /dev/sdb1
filesystem模块的参数真是简练,参数“fstype”用于指定文件系统的格式化类型,“dev”参数用于指定要格式化的设备文件路径。继续编写:
[root@linuxprobe ~]# vim lv.yml
- name: 创建和使用逻辑卷
hosts: all
tasks:
- name: one
lvg:
vg: research
pvs: /dev/sdb
pesize: 150M
- name: two
lvol:
vg: research
lv: data
size: 150M
- name: three
filesystem:
fstype: ext4
dev: /dev/research/data
如果无法按照既定模块顺利完成,这时要用类似于第4章节学习过的if条件句的方式进行一次判断——如果失败…则怎么样…。
首先将上述的三个模块命令用block操作符作为一个整体,相当于是对这三个模块执行结果作为一个整体判断。然后使用rescue操作符进行救援,只有block块中的模块执行失败了才会调用rescue中的救援模块。其中debug模块的msg参数的作用是如果block中的模块执行失败则输出一条信息到屏幕,给予用户一定的提醒作用。完成编写后是这个样子的:
[root@linuxprobe ~]# vim lv.yml
- name: 创建和使用逻辑卷
hosts: all
tasks:
- block:
- name: one
lvg:
vg: research
pvs: /dev/sdb
pesize: 150M
- name: two
lvol:
vg: research
lv: data
size: 150M
- name: three
filesystem:
fstype: ext4
dev: /dev/research/data
rescue:
- debug:
msg: “Could not create logical volume of that size”
YAML语言对于格式有着硬性的要求,既然rescue是对block内的模块进行救援的功能代码,因此两个操作符必须严格对齐,错开一个空格都会导致Playbook执行失败。确认无误后,执行lv.yml剧本文件检阅下效果吧:
[root@linuxprobe ~]# ansible-playbook lv.yml
PLAY [创建和使用逻辑卷] *********************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.10.20]
ok: [192.168.10.21]
--------------省略部分信息----------------------------
TASK [one] *********************************************************************
fatal: [192.168.10.20]: FAILED! => {“changed”: false, “msg”: “Device /dev/sdb not found.”}
fatal: [192.168.10.21]: FAILED! => {“changed”: false, “msg”: “Device /dev/sdb not found.”}
changed: [192.168.10.22]
changed: [192.168.10.23]
fatal: [192.168.10.24]: FAILED! => {“changed”: false, “msg”: “Device /dev/sdb not found.”}
--------------省略部分信息----------------------------
TASK [debug] *******************************************************************
ok: [192.168.10.20] => {
“msg”: “Could not create logical volume of that size”
}
ok: [192.168.10.21] => {
“msg”: “Could not create logical volume of that size”
}
ok: [192.168.10.24] => {
“msg”: “Could not create logical volume of that size”
}
PLAY RECAP *********************************************************************
192.168.10.20 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
192.168.10.21 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
192.168.10.22 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.10.23 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.10.24 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
在Playbook运行完毕后的执行记录(PLAY RECAP)中可以很清晰的看出只有192.168.10.22及192.168.10.23两台prod组中的主机执行成功了,其余三台主机均触发了rescue救援功能。登录到任意一台prod组的主机节点上,找到新建的逻辑卷设备信息:
[root@linuxprobe ~]# lvdisplay
— Logical volume —
LV Path /dev/research/data
LV Name data
VG Name research
LV UUID EOUliC-tbkk-kOJR-8NaH-O9XQ-ijrK-TgEYGj
LV Write Access read/write
LV Creation host, time linuxprobe.com, 2021-04-23 11:00:21 +0800
LV Status available
open 0
LV Size 5.00 GiB
Current LE 1
Segments 1
Allocation inherit
Read ahead sectors auto
-
currently set to 8192
Block device 253:2
………………省略部分输出信息………………
判断主机组名
在上面Playbook剧本实验中,我们可以让不同的主机根据自身不同的变量信息而生成出独特的网站首页文件,但却无法对某个主机组进行针对性操作。其实在每个客户端中都会有一个叫做“inventory_hostname”的变量,用于定义着每个节点主机所对应的Ansible服务主机组名称,也就是在/etc/ansible/hosts文件中所对应的分组信息,例如dev、test、prod、balancers。
“inventory_hostname”是Ansible服务中的魔法变量,意味着无法用setup模块直接进行查询,诸如“ansible all -m setup -a ‘filter=“关键词”’”的命令将对它失效。魔法变量需要在执行Playbook剧本文件时的[Gathering Facts]阶段进行搜集,直接查询是看不到的,而只能在剧本文件中进行调用。
获得了存储主机组名称的变量名称,接下便开始实践,需求如下:
若主机节点在dev分组中,则修改/etc/issue文件内容为“Development”;
若主机节点在test分组中,则修改/etc/issue文件内容为“Test”;
若主机节点在prod分组中,则修改/etc/issue文件内容为“Production”。
第1步:Ansible服务常用模块名称,依据上文所提及的表格16-5新建、修改及复制文件需要用的copy模块,此时便派上了用场。先查询下copy模块的帮助信息:
[root@linuxprobe ~]# ansible-doc copy
………………省略部分输出信息………………
EXAMPLES: -
name: Copy file with owner and permissions
copy:
src: /srv/myfiles/foo.conf
dest: /etc/foo.conf
owner: foo
group: foo
mode: ‘0644’ -
name: Copy using inline content
copy:
content: ‘# This file was moved to /etc/other.conf’
dest: /etc/mine.conf
在输出信息中列举了两种管理文件内容的示例,第一是对于文件的复制行为,第二是通过“content”参数定义内容,“dest”参数指定新建文件的名称,显然第二种更加符合当前的实验场景。编写剧本文件如下:
[root@linuxprobe ~]# vim issue.yml
- name: 修改文件内容
hosts: all
tasks:
- name: one
copy:
content: ‘Development’
dest: /etc/issue
- name: two
copy:
content: ‘Test’
dest: /etc/issue
- name: three
copy:
content: ‘Production’
dest: /etc/issue
但按照这种顺序执行下去,每一台主机节点的/etc/issue文件都会被重复修改三次,最终定格在“Production”字样,显然缺少了一些东西。我们应该依据“inventory_hostname”变量中的值进行判断,若主机为dev组则执行第一个Play,若主机为test组则执行第二个Play,若主机为prod组则执行第三个Play,因此要进行三次判断。
when是进行判断的语法,需要在每个Play下方进行判断,只有满足条件才会执行:
[root@linuxprobe ~]# vim issue.yml
- name: 修改文件内容
hosts: all
tasks:
- name: one
copy:
content: ‘Development’
dest: /etc/issue
when: “inventory_hostname in groups.dev”
- name: two
copy:
content: ‘Test’
dest: /etc/issue
when: “inventory_hostname in groups.test”
- name: three
copy:
content: ‘Production’
dest: /etc/issue
when: “inventory_hostname in groups.prod”
执行Playbook剧本文件,过程中可清晰的看出由于when语法的作用,未在指定主机组中的节点将被skipping(跳过):
[root@linuxprobe ~]# ansible-playbook issue.yml
-----------------省略部分内容-------------------
PLAY RECAP ********************************************************************************
192.168.10.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
192.168.10.21 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
192.168.10.22 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
192.168.10.23 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
192.168.10.24 : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
登录到dev组的192.168.10.20主机节点上,查看文件内容:
[root@linuxprobe ~]# cat /etc/issue
Development
登录到test组的192.168.10.21主机节点上,查看文件内容:
[root@linuxprobe ~]# cat /etc/issue
Test
登录到prod组的192.168.10.22/23主机节点上,查看文件内容:
[root@linuxprobe ~]# cat /etc/issue
Production
管理文件属性
文件管理常用的功能都合并到了file模块中
[root@linuxprobe ~]# ansible-doc file
………………省略部分输出信息………………
EXAMPLES:
-
name: Change file ownership, group and permissions
file:
path: /etc/foo.conf
owner: foo
group: foo
mode: ‘0644’ -
name: Create a symbolic link
file:
src: /file/to/link/to
dest: /path/to/symlink
owner: foo
group: foo
state: link -
name: Create a directory if it does not exist
file:
path: /etc/some_directory
state: directory
mode: ‘0755’ -
name: Remove file (delete file)
file:
path: /etc/foo.txt
state: absent
通过上面的输出示例,读者们已经能够了解到file模块的基本参数了,“path”参数定义文件的路径、“owner”参数定义文件所有者、“group”参数定义文件所有组、“mode”参数定义文件权限、“src”参数定义源文件的路径、“dest”参数定义目标文件的路径、“state”参数则定义了文件类型。
请创建出一个名为/linuxprobe的新目录,所有者及所有组均为root管理员身份;
设置所有者和所有组拥有对文件的完全控制权,而其他人则只有阅读和执行权限;
给予SBIT特殊权限;
仅在dev主机组主机节点实施。
第二条要求是算术题,将权限描述转换为数字法,即可读为4、可写为2、可执行为1,请读者先自行默默算一下答案。此前在编写Playbook剧本文件时“hosts”参数一直对应的是all,即全体主机节点,而这次也改为仅对dev主机组成员生效,请小心谨慎。编写模块代码如下:
[root@linuxprobe ~]# vim chmod.yml
- name: 管理文件属性
hosts: dev
tasks:
- name: one
file:
path: /linuxprobe
state: directory
owner: root
group: root
mode: ‘2775’
请将新创建的目录做一个快捷方式到/linuxcool目录。这样用户在访问两个文件时都能有相同的内容了,使用file模块做快捷方式时,不需要再单独创建目标文件,Ansible服务会帮咱们完成的:
[root@linuxprobe ~]# vim chmod.yml
- name: 管理文件属性
hosts: dev
tasks:
- name: one
file:
path: /linuxprobe
state: directory
owner: root
group: root
mode: ‘2775’
- name: two
file:
src: /linuxprobe
dest: /linuxcool
state: link
Playbook剧本文件执行过程:
[root@linuxprobe ~]# ansible-playbook chmod.yml
-----------------省略部分内容----------------------
PLAY RECAP ***********************************************************************
192.168.10.20 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.10.22 : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
192.168.10.22 : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
192.168.10.22 : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
192.168.10.22 : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
进入到dev组的主机中,查看到/linuxprobe目录及/linuxcool快捷方式均已经被顺利创建,实验完成:
[root@linuxprobe ~]# ls -ld /linuxprobe
drwxrwsr-x. 2 root root 6 Apr 20 09:52 /linuxprobe
[root@linuxprobe ~]# ls -ld /linuxcool
lrwxrwxrwx. 1 root root 11 Apr 20 09:52 /linuxcool -> /linuxprobe
管理密码库文件
Ansible服务自1.5版本发布后,“Vault”作为一项新功能进入到了运维人员的视野,它不仅实现对密码、剧本等敏感信息进行加密,甚至可以加密变量名称和变量值,保护了数据不会被别人轻易的阅读到。使用ansible-vault命令可以实现对内容的新建(create)、加密(encrypt)、解密(decrypt )、修改口令(rekey)及查看(view)等等功能。
第1步:例如创建出一个名为locker.yml的配置文件,其中保存有两个变量值:
[root@linuxprobe ~]# vim locker.yml
pw_developer: Imadev
pw_manager: Imamgr
第2步:使用ansible-vault命令对文件进行加密,需要每次输入密码比较麻烦,因此还应新建出一个用于保存密码值的文本文件,让ansible-vault进行自动调用。为了保证数据的安全性,新建密码文件后将权限设置为600,仅管理员可读可写:
[root@linuxprobe ~]# vim /root/secret.txt
whenyouwishuponastar
[root@linuxprobe ~]# chmod 600 /root/secret.txt
在Ansible服务的主配置文件中进行调用,在第140行的“vault_password_file”参数后指定密码值保存的文件路径:
[root@linuxprobe ~]# vim /etc/ansible/ansible.cfg
137
138 # If set, configures the path to the Vault password file as an alternative to
139 # specifying --vault-password-file on the command line.
140 vault_password_file = /root/secret.txt
141
第3步:设置好了密码文件路径,Ansible服务便会自动进行加载,用户不再需要每次加密或解密时都重复输入密码值了。例如加密刚刚创建的locker.yml文件时,只需要使用“encrypt”参数即可:
[root@linuxprobe ~]# ansible-vault encrypt locker.yml
Encryption successful
加密过后的文件将使用AES 256格式进行加密,也就是意味着2256就是256位AES密钥空间的组合数2256>2(10*25)>10(3*25)=1075>>>3×1023,以天河4号超级计算机为例,每秒进行20亿亿次破解计算,也无法在我们有生之年搞定这串密码值。查看到加密后的内容为:
[root@linuxprobe ~]# cat locker.yml
$ANSIBLE_VAULT;1.1;AES256
38653234313839336138383931663837333533396161343730353530313038313631653439366335
3432346333346239386334663836643432353434373733310a306662303565633762313232663763
38366334316239376262656230643531656665376166663635656436363338626464333430343162
6664643035316133650a333331393538616130656136653630303239663561663237373733373638
62383234303061623865633466336636363961623039343236356336356361613736333739623961
6334303865663838623363333339396637363061626363383266
那如果不想用原始密码了呢,也可以手动对文件进行“rekey”修改密码操作,同时应结合“–ask-vault-pass”参数进行修改,否则Ansible服务会因接收不到用户输入的旧密码值,而拒绝新的密码变更请求:
[root@linuxprobe ~]# ansible-vault rekey --ask-vault-pass locker.yml
Vault password: 输入旧的密码
New Vault password: 输入新的密码
Confirm New Vault password: 再输入新的密码
Rekey successful
第4步:那如果想查看和修改加密文件中的内容呢。对于已经加密过的文件,需要使用ansible-vault命令的“edit”参数进行修改,随后用“view”参数即可查看到修改后的内容。编辑操作默认使用Vim编辑器作为修改工具,请修改完毕后记得wq保存退出:
[root@linuxprobe ~]# ansible-vault edit locker.yml
pw_developer: Imadev
pw_manager: Imamgr
pw_production: Imaprod
最后,再用“view”参数进行查看,便是最新的内容了:
[root@linuxprobe ~]# ansible-vault view locker.yml
Vault password: 输入密码后敲击回车确认
pw_developer: Imadev
pw_manager: Imamgr
pw_production: Imaprod