Ansible
运维自动化平台,集群管理工具,通过管理机SSH远程管理N台服务器;
- 批量管理,分组管理,单独管理
- 命令模式:相对简单,适合简单任务
- 剧本(playbook)模式:实现复杂任务编排,一键启动部署整个集群
安装部署Ansible
-
准备工作
| 主机名称 |
IP地址 |
| manage01 |
192.168.25.50/24 |
| node1 |
192.168.25.51/24 |
| node2 |
192.168.25.52/24 |
| node3 |
192.168.25.53/24 |
- 时间同步
- 关防火墙,SELinux
- 配置系统hosts文件
- 免密登陆
- 配置yum源/apt源
- Manage 上安装ansible
#配置系统hosts文件(所有服务器操作)
vim /etc/hosts
127.0.0.1 localhost
::1 localhost
192.168.25.50 manage01
192.168.25.51 node1
192.168.25.52 node2
192.168.25.53 node3
#免密登陆 (manage01 上操作)
#生成公私钥
ssh-keygen
#将公钥传给node1
ssh-copy-id -i .ssh/id_rsa.pub root@node1
#将公钥传给node2
ssh-copy-id -i .ssh/id_rsa.pub root@node2
#将公钥传给node3
ssh-copy-id -i .ssh/id_rsa.pub root@node3
#公钥传过去后,先在主机上手动连接一下监控机
ssh root@192.168.25.51
ssh root@192.168.25.52
ssh root@192.168.25.53
#manage端安装 ansible(manage01 上操作)
sudo apt update
sudo apt install ansible
#编辑部署主机列表,定义被监控机
mkdir /etc/ansible/
cd /etc/ansible
touch hosts
vim /etc/ansible/hosts
[group1] #名字可以随便起 后面跟上业务机器的IP地址或者域名
192.168.25.51
192.168.25.52
192.168.25.53
#ping 模块测试网络连接是否正常
ansible -m ping all
#结果是绿色的就代表正常连接
ansible 常用模块
#格式
ansible -m 模块名 -a '参数1=值1 参数2=值2' 主机名/组名/all/ip
ping模块:测试服务器网络是否正常
ansible -m ping all
hostname模块:修改主机名
ansible -m hostname -a 'name=zuolaoshi_node3' 192.168.25.53
file模块:远程文件与权限操作
- 包含touch,rm,mkdir,ln,chmod,chown 命令=
| 参数 |
说明 |
| path |
文件绝对路径 |
| state |
操作(touch文件新建、absent删除、link软连接、hard硬链接、directory目录创建) |
| owner |
设置所有者 |
| group |
设置所属的组 |
| mode |
权限 0000 |
| recurse |
递归 yes or no |
#批量创建文件 001
ansible -m file -a 'path=/root/001 state=touch owner=root group=root mode=777' group1
#批量删除文件 001
ansible -m file -a 'path=/root/001 state=absent' group1
#批量创建软连接
ansible -m file -a 'src=/tmp/zuolaoshi path=/tmp/zuolaoshi_com state=link' group1
#批量修改文件权限,所有者,所属组
ansible -m file -a 'path=/tmp/zuolaoshi owner=sko group=nobody mode=0600' 192.168.25.52
#批量创建一个目录
ansible -m file -a 'path=/tmp/zuolaoshi123 state=directory' group1
#批量修改目录及子文件权限
ansible -m file -a "path=/tmp/zuolaoshi123 owner=sko mode=2755 recurse=yes" group1
copy模块:远程复制
| 参数 |
说明 |
| src |
文件源路径 |
| dest |
目标路径 |
| content |
往目标文件输入内容 |
| force |
强制 yes or no |
| backup |
是否备份有冲突的源文件[文件名相同,内容不同] yes or no |
| checksum |
拷贝完整性校验,使用sha1sum生成校验码 |
| owner |
目标文件所有者 |
| group |
目标文件所属组 |
| mode |
目标文件权限 |
#拷贝manage01机器/root/001文件到group1组的机器
#生成校验码
sha1sum 001
ansible -m copy group1 -a "src=/root/001 dest=/opt checksum=f8182e9ccdbe6efd13eb36a056a7db203fe66e40 owner=sko group=sko mode=0400"
#copy模块拷贝时要注意拷贝目录后面是否带"/"符号,加/ 复制的是目录里的东西,不加/ 复制的是目录本身
#/etc/yum.repos.d后面不带/符号,则表示把/etc/yum.repos.d整个目录拷贝到/tmp/目录下
ansible group1 -m copy -a 'src=/etc/yum.repos.d dest=/tmp/'
#/etc/yum.repos.d/后面带/符号,则表示把/etc/yum.repos.d/目录里的所有文件拷贝到/tmp/目录下
ansible group1 -m copy -a 'src=/etc/yum.repos.d/ dest=/tmp/'
#使用content参数直接往远程文件里写内容(会覆盖原内容)
ansible -m file group1 -a "path=/tmp/zuolaoshi_333 state=touch"
ansible -m copy group1 -a "content='baism\nhello world\n' dest=/tmp/zuolaoshi_333"
#注意:ansible中-a后面的参数里也有引号时,记得要单引双引交叉使用,如果都为双引会出现问题
#使用force参数控制是否强制覆盖
#如果目标文件已经存在,则不覆盖
ansible group1 -m copy -a "src=/tmp/zuolaoshi_222 dest=/tmp/zuolaoshi_333 force=no"
#如果目标文件已经存在,则会强制覆盖
ansible group1 -m copy -a "src=/tmp/zuolaoshi_222 dest=/tmp/zuolaoshi_333 force=yes"
#使用backup参数控制是否备份文件
#backup=yes表示如果拷贝的文件内容与原内容不一样,则会备份一份
#如果拷贝过来的文件本机存在,group1的机器上会将/tmp/333备份一份(备份文件命名加上时间),再远程拷贝新的文件为/tmp/333
ansible group1 -m copy -a "src=/etc/fstab dest=/tmp/zuolaoshi_333 backup=yes"
fetch模块:从node节点下载文件到Manage节点
#远程下载文件
ansible -m fetch group1 -a "src=【远程路径】 dest=【本地路径】"
user模块:用于管理用户账号和用户属性
| 常用参数 |
说明 |
| name="" |
指定用户名 |
| password="" |
指定密码,必须是密文 |
| state= absent|present |
删除|创建 |
| system= yes|no |
是否为系统用户 |
| shell="" |
指定登陆shell |
| generate_ssh_key= yes|no |
是否创建秘钥对 |
| uid= |
指定用户的uid |
| append= yes|no |
用户是否追加到其他组 |
| group= |
用户属组 |
| groups= |
将现有用户加入到某个组,空值就会把该用户从所有所属组中删除 |
| create_home= yes|no |
是否建立家目录 |
| remove= yes|no |
删除家目录 |
#创建一个用户sky,密码是123,要求是系统用户,非交互式登陆,要求生成自己的秘钥对,不创建家目录
echo 123|openssl passwd -1 -stdin
ansible -m user -a 'name=sky password="$1$5V.qzSEd$Yr08MU8K.vXeBZcmavypk1" state=present system=yes shell=/sbin/nologin generate_ssh_key=yes create_home= no' group1
#创建用户zhangsan 密码为123456
echo "123456"|openssl passwd -1 -stdin
ansible -m user group1 -a 'name=zhangsan password="$1$BMPgiHeV$GskMFnvqBL17gTe/us5yK." uid=4423'
#用户删除
ansible -m user 192.168.8.21 -a "name=baishuming1 state=absent remove=yes"
group模块:用于管理用户组和用户组属性
| 参数 |
说明 |
| name= |
组名 |
| state= persent|absent |
创建|删除 |
| system= yes|no |
是否为系统组 |
| gid |
gid |
#组创建
ansible -m group group1 -a "name=admin gid=4444 state=present"
#删除组
ansible -m group group1 -a "name=admin state=absent"
cron模块:用于管理周期性时间任务
| 参数 |
说明 |
| name=“” |
计划任务的名称 |
| user |
执行计划任务的用户 |
| job=“” |
计划任务命令 |
| minute |
执行计划任务的分 默认为* |
| hour |
执行计划任务的时 默认为* |
| day |
执行计划任务的日 默认为* |
| month |
执行计划任务的月 默认为* |
| week |
执行计划任务的周 默认为* |
| state=absent |
删除计划任务 |
#创建一个cron任务,不指定user的话,默认就是root(因为我这里是用root操作的)。 如果minute,hour,day,month,week不指定的话,默认都为*
#每天10:23 执行echo “haha”>/tmp/test
ansible -m cron group1 -a 'name="cron test" user=root job="echo haha > /tmp/test" minute=23 hour=10'
#删除cron任务
ansible -m cron group1 -a 'name="cron test" state=absent'
yum_repository模块:用于配置yum仓库
| 参数 |
说明 |
| name |
仓库名 name.repo 源的名称 [name] |
| description |
描述 |
| baseurl |
包下载路径 |
| gpgcheck= 1 or 0 |
包gpg验证 |
| enabled = yes|no |
是否开启本源 |
| state= absent |
删除源 |
#增加一个/etc/yum.repos.d/dvd.repo配置文件
ansible -m yum_repository group1 -a "name=dvd description=BaseOS baseurl=file:///media/cdrom gpgcheck=0 enabled=yes"
#删除某个yum源
ansible -m yum_repository group1 -a "name=dvd state=absent"
apt_repository模块:管理 APT 仓库
| 参数 |
说明 |
| repo |
指定要添加的仓库字符串 |
| filename |
指定生成的 APT 配置文件的名称(不包括 .list 扩展名) |
| state |
指定仓库的状态,present 表示添加仓库,absent 表示删除仓库 |
#本地主机上(或远程主机)添加一个名为 myrepo 的 APT 仓库
ansible localhost -m ansible.builtin.apt_repository -a "repo='deb http://example.com/repo stable main' filename='myrepo' state=present"
#删除myrepo仓库
ansible localhost -m ansible.builtin.apt_repository -a "repo='deb http://example.com/repo stable main' filename='myrepo' state=absent"
#添加一个带有 GPG 密钥的仓库,可以在添加仓库的同时指定密钥文件路径,或者在添加仓库后单独添加密钥
# 添加仓库
ansible localhost -m ansible.builtin.apt_repository -a "repo='deb https://packages.cloud.google.com/apt cloud-sdk main' filename='google-cloud-sdk' state=present update_cache=yes"
# 添加 GPG 密钥
ansible localhost -m ansible.builtin.apt_key -a "url=https://packages.cloud.google.com/apt/doc/apt-key.gpg state=present"
yum/apt模块:软件包的安装与卸载
| 参数 |
说明 |
| name |
需要安装软件包的名称 |
| list= installed, updates, available and repos |
列出已安装 需要更新 可获得的 和 yum源 |
| state= absent removed installed present latest |
删除、删除、安装确认、安装确认、安装最新版本 |
#使用yum安装一个软件
ansible -m yum/apt group1 -a "name=vsftpd"
#list:列出包信息
ansible -m yum/aptgroup1 -a "list=repos"
#删除软件包
ansible -m yum/apt 192.168.8.21 -a "state=absent name=vsftpd"
service模块:用于控制服务的启动,关闭,开机自启动等
| 参数 |
说明 |
| name |
服务名称 |
| state=reloaded, restarted, started, stopped |
服务管理 |
| enabled=on|false / yes|no |
开启是否开机自启动 |
#启动vsftpd服务,并设为开机自动启动
ansible -m service 192.168.8.22 -a "name=vsftpd state=started enabled=on"
#关闭vsftpd服务,并设为开机不自动启动
ansible -m service 192.168.8.22 -a "name=vsftpd state=stopped enabled=false"
script模块: 远程执行管理机上的脚本
#在manage01上创建脚本,通过ansible将脚本分发到被管理端
cat ansible_test.sh
#!/bin/bash
#ansible script module test script
mkdir /opt/log
find / -name "*.log" -exec cp -rpf {} /opt/log \;
#脚本不用给执行权限
ansible -m script group1 -a "/root/ansible_test.sh"
command模块/shell模块/raw模块:远程执行linux命令
- command模块:
- command模块用于在给的的节点上运行系统命令,比如echo hello
- 本质是调用Python模块执行Linux命令,客户端要有Python才能执行
- 它不会通过shell处理命令,因此不支持像
$HOME这样的变量和,以及<, >, |, ;和&等都是无效的。也就是在command模块中无法使用管道符
| 名称 |
必选 |
备注 |
| chdir |
no |
运行command命令前先cd到这个目录 |
| creates |
no |
如果这个参数对应的文件存在,就不运行command |
| free_form |
yes |
需要执行的脚本(没有真正的参数为free_form) |
| executable |
no |
改变用来执行命令的shell,应该是可执行文件的绝对路径。 |
| removes |
no |
如果这个参数对应的文件不存在,就不运行command,与creates参数的作用相反 |
| stdin(2.4后新增) |
no |
将命令的stdin设置为指定的值 |
ansible -m command 192.168.8.21 -a "ls /root"
ansible -m command 192.168.8.21 -a "echo 'baism hello' > /tmp/baism_123"
ansible -m command 192.168.8.21 -a "cat /tmp/baism_123"
- shell模块:
- 让远程主机在shell进程下执行命令,从而支持shell的特性,如管道等
- 本质是调用Python模块执行Linux命令,客户端要有Python才能执行
| 名称 |
必选 |
备注 |
| chdir |
no |
运行command命令前先cd到这个目录 |
| creates |
no |
如果这个参数对应的文件存在,就不运行command |
| executable |
no |
改变用来执行命令的shell,应该是可执行文件的绝对路径。 |
| free_form |
yes |
需要执行的脚本(没有真正的参数为free_form) |
| removes |
no |
如果这个参数对应的文件不存在,就不运行command,与creates参数的作用相反 |
| stdin(2.4后新增) |
no |
将命令的stdin设置为指定的值 |
ansible -m shell 192.168.8.21 -a "ls /root"
ansible -m shell 192.168.8.21 -a "echo 'hello world' > /tmp/baishuming"
ansible -m shell 192.168.8.21 -a "cat /tmp/baishuming"
- raw模块:最原始的方式运行命令(不依赖python,仅通过ssh实现)
| 名称 |
必选 |
备注 |
| executable |
no |
改变用来执行命令的shell,应该是可执行文件的绝对路径。 |
| free_form |
yes |
需要执行的脚本(没有真正的参数为free_form) |
| 案列:清除yum缓存 |
|
|
#案列:清除yum缓存
ansible 192.168.8.21 -m raw -a "yum clean all"
setup模块:用于收集远程主机的基本信息(如操作系统类型,主机名,ip,cpu信息,内存信息等)
#打印192.168.8.21机器的所有信息
ansible -m setup 192.168.8.21
#使用filter过滤输出,打印192.168.8.21机器的CPU信息
ansible -m setup 192.168.8.21 -a "filter='ansible_processor'"
#打印192.168.8.21机器的内核信息
ansible -m setup 192.168.8.21 -a "filter='ansible_kernel'"
#打印192.168.8.21机器的主机名
ansible -m setup 192.168.8.21 -a "filter='ansible_hostname'"
#打印192.168.8.21机器的网卡信息
ansible -m setup 192.168.8.21 -a "filter='ansible_ens*'"
# 其它常见的过滤条件
ansible_all_ipv4_addresses:显示ipv4的信息。
ansible_devices:显示磁盘设备信息。
ansible_distribution_major_version:显示是系统主版本。
ansible_distribution_version:仅显示系统版本。
ansible_machine:显示系统类型,例:32位,还是64位。
ansible_lvm:显示lvm相关信息。
ansible_memtotal_mb:显示系统总内存。
ansible_memfree_mb:显示可用系统内存。
ansible_memory_mb:详细显示内存情况。
ansible_swaptotal_mb:显示总的swap内存。
ansible_swapfree_mb:显示swap内存的可用内存。
ansible_mounts:显示系统磁盘挂载情况。
ansible_processor:显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus:显示cpu个数(只显示总的个数)。
stat模块:用于获取文件的状态信息
#获取/etc/fstab文件的状态信息
ansible -m stat 192.168.8.21 -a "path=/etc/fstab"
blockinfile模块和lineinfile模块
- blockinfile模块:在文件中插入文本块,插入的文本块会有一个标记,方便修改和删除
| 参数名 |
描述信息 |
| path |
操作的文件对象 |
| block |
也可用content,指定内容。 |
| marker |
使用marker参数自定义”标记”,方便我们通过对应的标记找到对应的内容 |
| state |
默认是present,state=absent,则表示从文件中删除对应标记的内容。 |
| backup |
在修改文件之前是否对文件进行备份,默认是no. |
| create |
当要操作的文件并不存在时,是否创建对应的文件。 |
#创建/tmp/test文件,并初始化文件内容hello world
ansible group1 -m raw -a 'echo "hello world">/tmp/test'
ansible group1 -m raw -a 'cat tmp/test'
#使用marker插入文本“start httpd、stop httpd \restart httpd”,插入文本内容使用 httpd server进行标记
ansible group1 -m blockinfile -a 'path=/tmp/test block="start httpd \n stop ttpd \n restart httpd " marker="#{mark} httpd server
#查看
ansible group1 -m raw -a 'cat tmp/test'
#删除http server标记的文本内容
ansible group1 -m blockinfile -a 'path=/tmp/test state=absent marker="#{mark} httpd server" '
- lineinfile模块:对文件行进行操作,默认添加文件是在行尾
| 参数名 |
描述信息 |
| path |
操作的文件对象 |
| line |
指定行内容。 |
| state |
默认值为present,state=absent表示删除。 |
| backup |
是否在修改文件之前对文件进行备份。 |
| insertbefore |
插在匹配值之前 |
| insertafter |
插在匹配值之后,在该该选项不写的情况下默认插在文本最后 |
| create |
当要操作的文件并不存在时,是否创建对应的文件。 |
#添加"这是测试行"到/tmp/test文件中,如果不指定位置,默认是在末尾添加
ansible group1 -m lineinfile -a 'path=/tmp/test line="这是测试行" '
#查看
ansible test -m raw -a 'cat tmp/test'
#使用insertbefore指定插入到"hello world"行之前,insertafter则相反
ansible test -m lineinfile -a 'path=/tmp/test line="这是测试行-行首" insertbefore="hello world" '
#查看
ansible test -m raw -a 'cat tmp/test'
Playbook剧本
- YAML格式
- 格式要求:
- 严格区分大小写
- 缩进统一,同一级别配置要对齐
- 不允许使用制表符,只能使用空格
基础结构模板
---
- name: 剧本名称(描述这个剧本的用途,比如“安装Nginx”)
hosts: 目标主机/组(比如 group1、192.168.1.100,需在inventory中定义)
become: 是否提权(true 表示用sudo执行,安装软件/管理服务必须设为true)
tasks: # 任务列表(核心!按顺序执行)
- name: 任务1描述(比如“安装Nginx包”)
模块名: # 用什么模块完成任务(比如 apt、service、copy等)
参数1: 值1 # 模块的具体参数(比如 name: nginx)
参数2: 值2 # 比如 state: present(确保安装)
- name: 任务2描述(比如“启动Nginx服务”)
模块名:
参数1: 值1
Ansible-role 角色
- 将剧本根据功能拆分成不同的组件;
- 每个组件只完成一项简单任务;
- 复杂任务通过组合多个组件来实现;
- 优点:灵活、低耦合、高复用;
- 缺点:编写的复杂性高,对技术要求高;
roles的目录结构
- files:用来存放由copy模块或script模块调用的文件。
- tasks:至少有一个main.yml文件,定义各tasks。
- handlers:有一个main.yml文件,定义各handlers。
- templates:用来存放jinjia2模板。
- vars:有一个main.yml文件,定义变量。
- meta:有一个main.yml文件,定义此角色的特殊设定及其依赖关系。
作业
- Ansible剧本配置 yum 源、APT 源
- Ansible剧本修改 IP 地址与主机名
- Ansible剧本实现系统优化:设置时区、时间同步、更新软件、关闭防火墙、SELinux
- Ansible剧本安装单机 LNMP、LNMT
- Ansible剧本安装集群:MySQL 主从、Redis 哨兵
- 将大剧本拆分成角色