Ansible自动化运维

人工运维时代

运维人员早期需要维护数量众多的机器,因此需要执行反复,重复的劳动力。很多机器需要部署相同的服务或是执行相同的命令,还得反复的登录不同的机器。

自动化运维时代

早期运维人员会结合ssh免密登录和shell脚本来完成自动化的部署操作。

系统管理员早期面临的问题主要是,配置管理系统,远程执行命令,批量安装服务,启停服务等。

后来也就诞生了众多开源的软件,自动化运维软件。

  • fabric
  • puppet
  • saltstack
  • chef
  • Ansible

自动化运维趋势

人肉运维 > 人力运维 > 自动化运维 > 数据化运维 > 可视化运维 > AI智能运维

自动化运维的好处

  • 提高工作效率吧 减少重复性的劳动新操作
  • 大大的减少了人为出错的可能性
  • ansible支持数据化管理,数据化追源,找到问题的源点

image-20231107201445823

ansible介绍

ansible是一个同时管理多个远程主机的软件,必须是任意可以同股票ssh登录的机器

  • 远程虚拟机
  • 物理机
  • 也可以直接管理本地机器

ansible通过ssh协议实现了,管理节点(老板),被管理节点(员工)的通信。

只要是通过ssh协议登录的主机,就可以完成ansible自动化部署操作

  • 批量文件分发
  • 批量数据复制
  • 批量数据修改、删除
  • 批量自动化安装软件服务
  • 批量服务启动停止
  • 脚本话,自动化批量服务器部署

ansible的特点

ansible的编排引擎可以出色的完成各种任务配置管理,ansible在流程控制,资源部署等方便很强大,并且ansible无需安装客户端软件,管理简洁,使用yaml配置文件语法,功能强大,便于维护。

ansible基于python语言开发的,主要由python的两个ssh处理模块,paramiko,以及PyYAML模块

  • 安装部署简单
  • 管理主机边界,支持多台主机并行管理
  • 无需安装被管理节点的客户端 (no agent),且无需占用客户端的其它端口,仅仅使用ssh服务即可
  • 不仅仅支持python,还支持其它语言的二次开发
  • 不用root用户也可以执行,降低系统权限

Ansible实践部署

准备好虚拟机

三个虚拟机 一个为ansible server 两个为客户端

Rocky1  10.10.10.101	Rocky1.skills.com.		管理机器(安装了ansible的服务端)
Rocky2 10.10.10.102 Rocky2.skills.com. 被管理机器(配置好ssh服务,以及关闭防火墙)
Rocky3 10.10.10.103 Rocky3.skills.com. 被管理机器

准备ansible管理机器

(1)安装ansible管理工具

[root@Rocky1 ~]# yum install -y ansible* libselinux

(2)查看ansible的版本

ansible --version

准备ansible被管理机器 (客户端)

(1)安装一下软件

[root@Rocky2 ~]# yum install -y ansible* libselinux*
[root@Rocky3 ~]# yum install -y ansible* libselinux*

Ansible管理方式

ansible批量管理主机的方式主要有两种

  • 传统的输入密钥验证
  • 密钥管理
配置好ansible的配置文件,添加被管理主机的ip地址,或者主机名
1. 备份现有的配置文件
# cp /etc/ansible/hosts{,.ori}

# ls /etc/ansible/
ansible.cfg hosts hosts.ori roles
2. 添加被管理主机的IP地址
[root@Rocky1 ~]# vim /etc/ansible/hosts //在末行添加以下内容
[client]
10.10.10.102
10.10.10.103

SSH密码认证方式管理及其

ansible是直接利用linux本地的ssh服务,以及一些远程的ssh操作们一般情况下客户端的ssh服务都是默认开启的,无需额外配置

1.在Rocky1上执行如下命令  
-m 指定功能模块
-a 需要执行的指定参数
-k 询问连接密码
-u 指定远程主机以哪个用户去运行
在Rocky1机器上,告诉其它被管理的机器,你要执行什么命令,以及用什么用户去执行
ansible 主机列表 -m command -a 'hostname' -k -u root

2.如下操作一般会出现问题,需要手动SSH对主机进行一次连接,即可使用ansible命令操作

[root@Rocky1 ~]# ssh 10.10.10.102
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
root@10.10.10.102's password:
Last login: Mon Jan 8 11:42:42 2024 from 192.168.100.101
[root@Rocky2 ~]#

[root@Rocky1 ~]# ssh 10.10.10.103
root@10.10.10.103's password:
[root@Rocky3 ~]#
3.这个时候我们再执行刚刚那个命令
# ansible client -m command -a 'hostname' -k -u root //让两个被管理的机器,执行我们想要的结果

image-20231108115816845

  • 所以我们需要添加客户端机器的密钥

配置免密登录

每次执行ansible的命令的时候,都需要输入ssh的认证密码,也就是root密码,如果不同的主机密码不一致,那你还得输入多次才行,因此我们可以配置如下的快捷登录方式

1.ansible自带的密码认证参数

可以再 /etc/ansible/hosts文件中,定义好密码即可实现快速的认证,远程管理主机

参数
ansible_host 主机地址
ansible-port 端口,默认端口是22
ansible_user 认证的用户
ansible_ssh_pass 用户认证的密码

1.将/etc/ansible/hosts文件下 添加以下内容 来快速实现快速的认证
# vim /etc/ansible/hosts
[client]
192.168.123.102 ansible_user=root ansible_ssh_pass=1
192.168.123.103 ansible_user=root ansible_ssh_pass=1
# 保存并退出

2.使用以下命令执行命令看看是否可以不需要密码
[root@Rocky1 ~]# ansible client -m command -a 'hostname' //将-k -u root 取消
192.168.123.103 | CHANGED | rc=0 >>
Rocky3.skills.com
192.168.123.102 | CHANGED | rc=0 >>
Rocky2

2.ssh密钥方式批量管理主机

这个方式比起hosts文件的参数来的更加安全放心

1. 在Rocky1机器上创建密钥对
[root@Rocky1 ~]# ssh-keygen //此时密钥对就会自动创建到/root/.ssh/id_rsa下面

2.此时检查公私钥文件
[root@Rocky1 ~]# cd ~/.ssh/
[root@Rocky1 .ssh]# ls
id_rsa id_rsa.pub known_hosts known_hosts.old

编写公钥分发脚本

# [root@Rocky1 .ssh]# mkdir /myssh
# [root@Rocky1 .ssh]# cd /myssh/
# [root@Rocky1 myssh]# touch ssh_key_send.sh
# [root@Rocky1 myssh]# vim ssh_key_send.sh
---------------------------------------------------------------------------------------------------------
#!/bin/bash
rm -f ~/.ssh/id_rsa*
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" > /dev/null 2>&1
SSH_Pass=1
Key_Path=~/.ssh/id_rsa.pub
for ip in 102 103
do
sshpass -p $SSH_Pass ssh-copy-id -i $Key_Path -o StrictHostKeyChecking=no 192.168.123.$ip
done
---------------------------------------------------------------------------------------------------------
# [root@Rocky1 myssh]# sh ssh_key_send.sh // 此时Rocky1这台机器上就可以免密的执行ansible的命令
# [root@Rocky1 myssh]# ansible client -m command -a 'uname -a'
192.168.123.103 | CHANGED | rc=0 >>
Linux Rocky3.skills.com 5.14.0-162.6.1.el9_1.0.1.x86_64 #1 SMP PREEMPT_DYNAMIC Mon Nov 28 18:44:09 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
192.168.123.102 | CHANGED | rc=0 >>
Linux Rocky2 5.14.0-162.6.1.el9_1.0.1.x86_64 #1 SMP PREEMPT_DYNAMIC Mon Nov 28 18:44:09 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

3.总结

                            **在生产环境中,ansible的连接方式可以二选一。推荐使用ssh密钥管理来实现ansible的执行**

ansible模式与命令

ansible实现批量化主机管理的模式,主要有两种

  • 利用ansible的纯命令行实现的批量化管理,ad-hoc模式———比较简单的shell命令管理
  • 利用ansible的playbook剧本来实现批量管理,playbook ————比较复杂的shell脚本管理

1. ad-hoc模式

ansible的ad-hoc模式是ansible的命令行形式,也就是处理一些临时的,简单的任务,可以直接使用ansible的命令行来操作

比如

  • 临时批量查看被管理机器的内存清空,cpu负载情况,网络情况
  • 临时的分发配置文件等等

2. Playbook模式

ansible的playbook模式是针对比较具体,且比较大的任务,那么你就得实现写好剧本

  • 一键部署rsync备份服务器
  • 一键部署lnmp环境

3. ansible的ad-hoc命令行解析

Rocky1  ansible服务端
Rocky2 被管理的机器
Rocky3 被管理的机器
  1. 让被管理机器返回主机名
[root@Rocky1 ~]# ansible client -m command -a 'hostname' 
192.168.123.102 | CHANGED | rc=0 >>
Rocky2
192.168.123.103 | CHANGED | rc=0 >>
Rocky3

ad-hoc命令解析

  • Ansible —- 自带提供的命令操作
  • Chaoge———/etc/ansible/hosts文件中定义的主机组,还可以谢主机的ip地址 以及通配符 *
  • -m command ansible的指定模块的参数,以及指定了command的模块
  • -a 指定command模块什么参数,hostname,uname -r

ansible-doc命令

列出所有的ansible支持的模块
ansible-doc -l | grep ^command
查看莫格模块的具体用法参数
ansible-doc -s command

Ansible的模块精讲

command模块

作用 在远程节点上执行一个命令

ansible-doc -s command 查看该模块支持的参数

chdir  在执行命令之前,先通过cd进入该参数指定的目录
creates 在创建一个文件之前,判断该文件是否存在,如果存在了,则跳过前面的东西,如果不存在则执行前面的动作

command模块是ansible的默认基本模块,也可以省略不写,但是要注意如下的坑

  • 使用command模块,不得使用sehll变量$name,也不得出现特殊符号> < | ; & 这些符号command模块都不认识,如果你想使用前面指定的模块,特殊符号,请使用shell模块。

command

ansible常用模块

command模块

功能: 在远程主机上执行命令,此为默认模块,可忽略-m选项

- name: Execute commands on targets
command:
argv: # 以列表形式传递命令,而不是字符串。使用`argv'可以避免将某些需要特殊处理的值(例如“用户名”)错误地解释为字符串。只能提>
# 供字符串形式或列表形式的其中一种,不可同时提供两者。必须提供其中之一。
chdir: # 在运行命令之前切换到指定目录。
cmd: # 要运行的命令。
creates: # 文件名或(自2.0版本以来)通配符模式。如果已存在匹配的文件,则不会运行此步骤。在检查`removes'之前进行检查。
free_form: # 命令模块接受自由形式字符串作为要运行的命令。实际上没有名为 'free form' 的参数。
removes: # 文件名或(自2.0版本以来)通配符模式。如果存在匹配的文件,则会运行此步骤。在检查`creates'之后进行检查。
stdin: # 直接将命令的标准输入设置为指定的值。
stdin_add_newline: # 如果设置为 `yes',则在标准输入数据末尾添加换行符。
strip_empty_ends: # 从结果的stdout/stderr末尾删除空行。
warn: # (已弃用)启用或禁用任务警告。此功能已被弃用,并将在2.14版本中移除。从2.1版本开始,默认情况下禁用此选项。

范例:

# ansible client -m command -a "systemctl stop httpd"  //关闭clinet组的httpd服务
# ansible client -m command -a "hostname" //查看client组的用户名

# [root@Rocky1 ~]# ansible client -m command -a 'chdir=/etc creates=/root/1.txt cat httpd/conf/httpd.conf'

# chdir=/etc //执行这个命令前 先进入/etc目录下
# creates=/root/1.txt //如果客户端的主机上有/root/1.txt这个文件 那么后面的命令则不执行了
# cat https/conf/httpd.conf //查看客户端的httpd/conf/httpd.conf这个配置文件

Shell模块

功能:和Command模块差不多 但是支持更多的命令参数 不易报错 所以参数命令跟Command差不多 不再介绍

范例:

# 显示所有管理端的主机名  
· ansible client -m shell -a 'echo $HOSTNAME'
192.168.123.102 | CHANGED | rc=0 >>
Rocky2
# 将管理端机器的/tmp目录下的所有文件删除
· ansible client -m shell -a 'rm -rf /tmp/*'
192.168.123.102 | CHANGED | rc=0 >>
# 修改root用户密码
· ansible client -m shell -a 'echo "pass-123"|passwd --stdin root'
192.168.123.102 | CHANGED | rc=0 >>
更改用户 root 的密码 。
passwd:所有的身份验证令牌已经成功更新。

Script模块

功能:在远程主机上运行ansible脚本

Script对比Shell和Command的好处

  1. Shell上执行命令方便 但是如果你写了脚本的话 你单纯使用Shell命令它不能执行
  2. Script上写了脚本后 你可以将这个脚本传送给所有控制端的所有机器 并执行

范例:

(1) [root@Rocky1 ~]# cat > test.sh
#! /bin/bash
echo "my hostname is 'Rocky'"
^C
(2) 执行测试这个脚本能不能正常工作
[root@Rocky1 ~]# /root/test.sh
my hostname is 'Rocky'
(3) 在控制端使用脚本
[root@Rocky1 ~]# ansible client -m script -a '/root/test.sh'
192.168.123.102 | CHANGED => {
"changed": true, // changed:true 表示操作已成功
"rc": 0,
"stderr": "Shared connection to 192.168.123.102 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.123.102 closed."
],
"stdout": "my hostname is 'Rocky'\r\n",
"stdout_lines": [
"my hostname is 'Rocky'"
]
}

copy模块

功能: 将ansible的文件复制到远程的主机




dest 指定复制文件的目录位置,使用绝对路径。如果是源目录,则目标也要是目录,如果目标文件已存在,会覆盖原有内同
src 指定源文件的路径,可以使用相对路径和绝对路径,支持直接指定路径,如果是源是目录,则目标也要是目录
mode 指出复制时,目标文件的权限,可选
owner 指出复制时,目标文件的属主,可选
group 指出拇指时目标文件的属组,可选
content 指出复制到目标主机上的内容,不能和src一起使用

范例:

[root@Rocky1 ~]# ansible client -m copy -a "content='test line1\n test line2' dest=/tmp/test.txt" 
1)content='test lin1\ntest line2' //指定写入的内容 直接写出要添加的内容 生成文件
2)dest=/tmp/test.txt //指定复制到文件的位置
# [root@Rocky1 ~]# ansible client -m copy -a "content='test line1\ntest line2' dest=/tmp/test.txt"
-----------------------------------------------------------------------------------------------
192.168.123.102 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"checksum": "43791ccbbcf72774b2bbbe6fe8d7ab488359b922",
"dest": "/tmp/test.txt",
"gid": 0,
"group": "root",
"md5sum": "f0e596e1a1a3ef7d278f2dda4d4e6ec8",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 21,
"src": "/root/.ansible/tmp/ansible-tmp-1699611955.979775-3537-224485407617732/source",
"state": "file",
"uid": 0
}
--------------------------------------------------------------------------------------------------
[root@Rocky1 ~]# ansible client -a 'cat /tmp/test.txt' //查看文件内容是否复制到了指定目录
192.168.123.102 | CHANGED | rc=0 >>
test line1
test line2

范例:将ansible服务器的/etc/sysconfig文件拷贝到控制端主机的/data/目录下 并且权限为600 属主为ayaka

# [root@Rocky1 ~]# ansible client -m copy -a 'src=/etc/sysconfig dest=/data/ mode=600 owner=ayaka'
----------------------------------------
192.168.123.102 | CHANGED => {
"changed": true,
"dest": "/data/",
"src": "/etc/sysconfig"
}
----------------------------------------
# [root@Rocky1 ~]# ansible client -m shell -a 'ls -ld /data/*'
192.168.123.102 | CHANGED | rc=0 >>
drwxr-xr-x. 3 ayaka root 4096 11月 10 05:33 /data/sysconfig

Fetch模块

功能:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录

范例:

yamlCopy Code- name: Fetch a file from remote host
fetch:
src: /path/to/src/file.txt
dest: /path/to/dest/file.txt

在此示例中,我们使用fetch模块从远程主机获取位于/path/to/src/file.txt的文件,并将其保存到本地的/path/to/dest/file.txt

File模块

功能:设置文件属性

范例;

# 创建空文件
[root@Rocky1 ~]# ansible client -m file -a 'path=/root/o.txt state=touch' //state=touch touch的意思就是创建文件的意思
#删除文件
[root@Rocky1 ~]# ansible client -m file -a 'path=/root/o.txt state=absent' //state=absent absent就是删除
#设置文件的属性
[root@Rocky1 ~]# ansible client -m file -a 'path=/root/o.txt owner=ayaka mode=777'

#创建目录
[root@Rocky1 ~]# ansible client -m file -a 'path=/data/mysql state=directory'
! 重点参数 state=directory //directory的意思就是创建目录

unarchive模块

功能:解包解压缩

实现有两种方法:

1、将ansible主机上的压缩包传到远程主机后解压缩所至特定目录,设置copy=yes

2、将远程主机上的莫格压缩包解压缩到指定路径下、设置copy=no

远程解压缩:

# 文件打包
tar zcvf toto.tar.gz /etc/*

# 远程解压缩
[root@Rocky1 ~]# ansible client -m unarchive -a 'src=/root/toto.tar.gz dest=/data/ owner=ayaka'

# 检查远程是否解压缩了文件
[root@Rocky1 ~]# ansible client -m shell -a 'ls -ld /data/*'
192.168.123.102 | CHANGED | rc=0 >>
drwxr-xr-x. 135 ayaka root 8192 11月 10 06:08 /data/etc //可以看到是以及解压缩了的

本地解压缩:(如果要在本地解包 一定要指定源文件的位置是其压缩包的位置 并且最后面一定要加上copy=no 表示本地压缩包)

[root@Rocky1 ~]# ansible client -m unarchive -a 'src=/data/toto.tar.xz dest=/opt/ mode=777 copy=no'

hostname模块

功能:管理主机名

范例:

  • ansible -m hostname -a ‘需要修改的主机名名称’
[root@Rocky1 log]# ansible client -m hostname -a 'name=Rocky2.skills.com'

Cron模块

功能:计划任务

支持时间:minute,hour,day,month,weekday

范例:

# 备份数据库脚本
mysqldump -A -F --single_trancaction --master-data=2 -q -uroot | gzip > /data/mysql_`date+%F_%T`.sql.gz

# 创建任务
[root@Rocky1 log]# ansible 192.168.123.102 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'

# 观察计划任务
[root@Rocky1 log]# ansible client -m shell -a 'crontab -l'

192.168.123.102 | CHANGED | rc=0 >>
#Ansible: backup mysql
30 2 * * 1-5 /root/mysql_backup.sh

# 禁用计划任务
[root@Rocky1 log]# ansible 192.168.123.102 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disabled=yes'

# 启用计划任务
[root@Rocky1 log]# ansible 192.168.123.102 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh disabled=no'

# 删除计划任务
[root@Rocky1 log]# ansible 192.168.123.102 -m cron -a ' name="backup mysql" state=absent'

Yum模块

功能:管理软件包,支持RHEL,Centos,fedora,不支持Ubuntu

常用参数:

name:     指定要操作的软件包的名称,可以是单个软件包的名称,也可以是多个软件包的列表

state: 指定软件包的状态 常见的取值有present(安装软件包) absent(删除软件包)latest(更新软件包)

update_cache:可以是yes或no 控制是否在执行任务前更新yum缓存

范例:安装与删除samba软件包

# 安装samba软件包
[root@Rocky1 log]# ansible client -m yum -a 'name=samba state=present'
# 卸载samba软件包
[root@Rocky1 log]# ansible client -m yum -a 'name=samba state=absent'

service服务

功能:管理服务的状态

常见参数:

state=? ?即为以下这些参数

- started 开启

- stopped 关闭

- enabled 自启动

- reloaded/restarted 重启

范例:

# 启动httpd的服务
[root@Rocky1 log]# ansible client -m service -a 'name=httpd state=started'
# 停止httpd的服务
[root@Rocky1 log]# ansible client -m service -a 'name=httpd state=stopped'

Users模块

功能:管理用户

常用命令参数:

- name      指定要操作的用户名
- comment 用于设置用户的注释信息
- group 将用户添加的指定的用户组
- groups 指定用户的所属的用户组列表
- password 指定用户的密码
- shell 指定用户登录的shell
- home 指定用户的家目录

范例:

# 创建用户
[root@Rocky1 log]# ansible client -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
# 删除用户及家目录登数据
[root@Rocky1 log]# ansible client -m user -a 'name=user1 state=absent remove=yes'

Group模块

功能:管理用户的用户组

范例:

# 添加用户组nginx 并指定gid88
[root@Rocky1 log]# ansible client -m group -a 'name=nginx gid=88 system=yes'
# 删除用户组nginx
[root@Rocky1 log]# ansible client -m group -a 'name=nginx state=absent'

Lineinfile模块

ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行提更换时,存在问题,无法进行替换。其实ansible自身提供了两个模块:lineinfile和replace模块

功能:相当于sed 可以修改文件内容

常用参数:

1. state: 指定行应当存在还是不存在。常见取值包括“present(存在)”和absent(不存在)
2. path: 指定目标文件的路径
3. regexp: 用于匹配需要操作的行的正则表达式模式
4. line: 指定要插入或替换的文本内容

范例:

# 将/etc/httpd/conf/httpd.conf中的listen=80换成listen8080
ansible client -m lineinfile -a 'path=/etc/httpd/conf/httpd.conf regexp='^listen=' line='listen=8080''
# 将/etc/httpd/conf/httpd.conf中的#注释删除
[root@Rocky1 log]# ansible client -m lineinfile -a 'dest=/etc/httpd/conf/httpd.conf state=absent regexp="#"'

修改默认模块

范例:将shell模块代替command,设为默认模块

[root@Rocky1 ~]# vim /etc/ansible/ansible.cfg 
# 修改下面一行
module_name = shell

playbook

playbook介绍

image-20231110150314139

playbook剧本是由一个或多个”play”组成的列表

play的主要功能在于将预定的一组主机,装扮成实现通过ansible的task定义好的角色,task实际是调用ansible的一个module,将多个playbook中,即可以让它们列和起来,按事先编排的机制执行预定义的动作

Playbook文件采用YAML语言编写。

YAML语言

YAML语言介绍

YAML是一个可读性高的用来表达资料序列的格式,它参考了很多其它语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822登。不过在开打的这种语言时,YAML的意思其实是”Yet Anothemarkup Language” 仍是一种标记语言。

YAML语言的特性

  • YAML的可读性好
  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML易于实现
  • YAML可以基于流来处理

YAML语言简介

  • 在单一文件第一行,用连续三个字号”—-“开始,还有选择性的连续三个点号(…)用来表示文件的结尾
  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
  • 使用#号注释代码
  • 缩进必须是一直的,同样的缩进代表同样的级别,程序判别的级别是通过缩进结合换行来实现的YAML文件内容是区分大小写的,key/value的值俊需大小写敏感
  • 多个k/v可同行也可以换行写,同行使用,分隔。
  • v可是个字符串,也可以是另一个列表。
  • 一个完整的代码块功能需要最少元素需包括name和task
  • 一个name只能包括一个task
  • YAML文件的扩展名通常为yml和yaml

List列表

列表由多个元素组成,且所有元素前均使用“-”打头

范例:

image-20231110154206094

Directory字典

字典通常由多个key和value组成

范例:

image-20231110202455557

三种常见的数据形式

XML:Extensible Markup Languuage,可扩展标记语言,可用于数据交换和配置

JSON:JavaScript Object Notation,JavaScript对象标记法,主要用来数据交换或配置,不支持注释

YAML:YAML Ain’t Markup Language YAML不是一种标记语言,主要用来配置,大小写敏感,不支持tab

image-20231110202706638

Playbook核心元素

  • Hosts 执行的远程主机列表
  • Tasks 任务集
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates模板,可替换模板文件中的变量并实现一些简单的逻辑文件
  • Handlers和notify结合使用,由特定条件出发的操作,满足条件方才执行,覅则不执行

hosts组件

Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中。

案例:

vim /etc/ansible/hosts
[client]
192.168.123.101
192.168.123.102
hosts: client

remote_user组件

remote_user:可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户

image-20231110204047276

task列表和action组件

play的主体部分时task list,task list中有一个或多个task,各个task按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,在开始第二个task。

task的目的时使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行时安全的,因为其结果均一致

每个task都应该由其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果输出都一致。

task两种格式:

(1)action:module argument

(2)module:arguments

注意:shell和command模块后面跟命令 而非key=value

范例:

---
- hosts: 192.168.123.102
remote_user: root
tasks:
- name: install httpd
yum:
name: httpd
- name: start httpd
service:
name: start httpd
service: httpd
state: started

ShellScripts VS Playbook案例

# Shell脚本实现
#!/bin/bash
#安装apache
yum install --quiet -y httpd
#复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp /tmp/vhosts.conf /etc/httpd/conf.d/
#启动Apache服务
systemctl enable --now httpd

#Playbook实现
---
- hosts: client
remote_user: root
tasks:
- name: "安装httpd服务"
yum:
name: httpd
- name: "复制httpd文件"
copy:
src: /tmp/httpd/httpd.conf
dest: /etc/httpd/conf/httpd.conf
- name: "复制httpd文件"
copy:
src: /tmp/vhosts.conf
dest: /etc/httpd/conf.d
- name: "启动Apache服务"
service:
name: httpd
state: started

playbook命令

格式:

ansible-playbook <filename.yaml> ... [options]

常见选项:

-c --check      #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--lists-tags #列出tag
--lists-tasks #列出tasks
--limit 主机列表 #只针对主机列表中的主机执行
-v -vv -vvv #显示过程

范例:

[root@Rocky1 ~]# ansible-playbook instalhttpd.yaml --check  //只检测

[root@Rocky1 ~]# ansible-playbook instalhttpd.yaml --limit 192.168.123.101 //只针对其中一台主机执行

playbook初步

利用playbook创建mysql用户

范例:mysql_user,yml

---
- hosts: client
remote_user: root
tasks:
- name: "创建用户组mysql"
group:
name: mysql
system: yes
gid: 306
- name: "创建用户mysql"
user:
name: mysql
shell: /sbin/nologin
system: yes
group: mysql
uid: 306
home: /data/mysql
create_home: no

利用playbook安装和启用Nginx服务

---
- hosts: client
remote_user: root
tasks:
- name: "安装Nginx服务"
yum:
name: nginx
- name: "停止Apache服务"
service:
name: httpd
state: stopped
- name: "开启Nginx服务"
service:
name: nginx
state: started

利用playbook安装和启用Apache服务并设置网页内容

---
- hosts: 192.168.123.101
remote_user: root
tasks:
- name: "复制index文件到web1上"
copy:
src: /root/index1.html
dest: /var/www/html/index.html
- hosts: 192.168.123.102
remote_user: root
tasks:
- name: "复制index文件到web2上"
copy:
src: /root/index2.html
dest: /var/www/html/index.html
- hosts: client
remote_user: root
tasks:
- name: "停止Nginx服务"
service: name=nginx state=stopped
- name: "重启httpd服务"
service: name=httpd state=restarted

测试:

[root@Rocky1 ~]# curl 192.168.123.101
WebA
[root@Rocky1 ~]# curl 192.168.123.102
WebB

实操

安装部署nginx服务

  1. 编辑yaml文件
---
- hosts: client
remote_user: root
tasks:
- name: install nginx
yum:
name: nginx
state: present
- name: copy index.html
copy:
src: /root/index.html
dest: /usr/share/nginx/html/
- name: start nginx
service:
name: nginx
state: started
  1. 准备主页内容文件
echo "Hello Nginx" > index.html
  1. 运行yaml
[root@host-10-10-110-101 ~]# ansible-playbook nginx.yaml 

PLAY [client] **********************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [linux3.skills.com]
ok: [linux2.skills.com]
ok: [linux4.skills.com]
ok: [linux5.skills.com]

TASK [install nginx] ***************************************************************************************************
changed: [linux2.skills.com]
changed: [linux3.skills.com]
changed: [linux4.skills.com]
changed: [linux5.skills.com]

TASK [copy index.html] *************************************************************************************************
changed: [linux2.skills.com]
changed: [linux5.skills.com]
changed: [linux4.skills.com]
changed: [linux3.skills.com]

TASK [start nginx] *****************************************************************************************************
changed: [linux2.skills.com]
changed: [linux4.skills.com]
changed: [linux3.skills.com]
changed: [linux5.skills.com]

PLAY RECAP *************************************************************************************************************
linux2.skills.com : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
linux3.skills.com : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
linux4.skills.com : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
linux5.skills.com : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

  1. 访问网站
[root@host-10-10-110-101 ~]# ansible client -m shell -a "curl localhost"
linux5.skills.com | CHANGED | rc=0 >>
Hello Nginx % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12 100 12 0 0 6000 0 --:--:-- --:--:-- --:--:-- 6000
linux2.skills.com | CHANGED | rc=0 >>
Hello Nginx % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12 100 12 0 0 12000 0 --:--:-- --:--:-- --:--:-- 12000
linux4.skills.com | CHANGED | rc=0 >>
Hello Nginx % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12 100 12 0 0 6000 0 --:--:-- --:--:-- --:--:-- 12000
linux3.skills.com | CHANGED | rc=0 >>
Hello Nginx % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12 100 12 0 0 6000 0 --:--:-- --:--:-- --:--:-- 6000