Linux运维--Ansible

学习资源

Ansible自动化运维的简单介绍

人工运维:维护多台机器,需要在不同机器部署相同的服务,执行相同的命令。(效率较低)

自动化运维:结合SSH免密登录以及shell脚本来完成自动化的部署操作。

Ansible是基于python开发的一款自动化运维软件,可以同时管理多个远程主机(必须是任意可以通过ssh登录的机器)。

Ansible通过ssh协议实现了 管理节点(安装了ansible服务的机器)、被管理节点(被管理的机器)的通信。

ansible可以管理的机器:远程虚拟机、物理机、本机机器;

主要特点:

  • 安装部署简单
  • 无须安装被管理机器的客户端,且无须占用其他端口
  • 不用root也可操作,降低系统权限
  • 不仅仅支持python,还支持其他语言的二次开发

部署测试环境

准备虚拟机

准备3个虚拟机,配置在一个局域网内,并设置好静态IP

hadoop101 192.168.10.101 被管理机器

hadoop102 192.168.10.102 被管理机器(配置好ssh服务,以及关闭防火墙等)

CentOSByCC 192.168.10.100 管理机器(安装好ansible的服务端)

部署管理机器

选择yum自动化安装,阿里云yum源、epel源(配置yum源相关操作请看这篇文章—-后面补地址———)

1
2
3
4
5
6
7
8
# 配置epel源
sudo yum install epel-release
# 安装 ansible 服务以及依赖
yum install ansible libselinux-python -y
# 检查 ansible 软件安装情况
rpm -ql ansible | grep -E '^/etc|^/usr/bin'
# 查看 ansible 版本
ansible --version

部署被管理机器

1
2
# 安装依赖
yum install epel-release libselinux-python -y

批量管理主机

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

  • 传统的ssh密码验证
  • 密钥管理
1
2
3
4
5
6
7
8
9
10
11
12
# 管理机器(CentOSByCC)
# 备份现有的配置文件
cp /etc/ansible/hosts{,.ori}
# 修改hosts文件,添加ansible需要管理的机器地址 (配置域名解析后,添加主机名也可)
[root@CentOSByCC ansible]# tail -3 /etc/ansible/hosts
[chaoge]
192.168.10.101
192.168.10.102

# 主机列表也可写成以下形式
192.168.10.[101:102]
host[1:2]

ssh密码认证方式管理机器

1
2
3
4
5
6
# 在管理机器上,告诉其它被管理的机器,你要执行什么命令,以及什么用户去执行
# -m 指定功能模块,默认就是 command 模块
# -a 告诉模块需要执行的参数
# -k 询问密码验证
# -u 指定运行的用户
ansible chaoge -m command -a 'hostname' -k -u root # 显示被管理机器的主机名

执行上面的命令时,默认情况下会有错误提示,需要手动ssh对主机进行一次连接

ssh root@192.168.10.101

ssh root@192.168.10.102

exit 退出远程连接

cat ~/.ssh/known_hosts 查看ssh连接信息

然后再执行命令即可

批量免密管理机器

每次执行ansible命令,需要输入ssh密码,因此配置免密登录,更加方便远程管理,有以下几种方式可以实现。

ansible自带的密码认证参数

在 /etc/ansible/hosts文件中,定义好密码即可,即可实现快速认证

1
2
3
4
5
6
# 修改 hosts 文件
[chaoge]
192.168.10.101 ansible_user=root ansible_ssh_pass=root ansible_ssh_port="2222" # 依次为 登录用户、登录密码、默认端口(可更改)
192.168.10.102 ansible_user=root ansible_ssh_pass=root
# 此时不需要指定用户,也不需要输入密码即可通过认证
ansible chaoge -m command -a "ifconfig ens33"
ssh密钥批量管理

上面那种方式明文暴露了密码,不安全,这种方式更加安全放心。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1.在管理机器上创建 ssh密钥对
ssh-keygen -f ~/.ssh/id_rsa -P "" > /dev/null 2>&1

# 2.检查公私钥文件
[root@CentOSByCC cc]# cd ~/.ssh/
[root@CentOSByCC .ssh]# ls
id_rsa id_rsa.pub known_hosts

# 3.编写公钥分发脚本 并执行
#!/bin/bash
rm -rf ~/.ssh/id_rsa*
ssh-keygen -f ~/.ssh/id_rsa -P "" > /dev/null 2>&1
SSH_Pass=root
Key_Path=~/.ssh/id_rsa.pub
for ip in 101 102
do
sshpass -p $SSH_Pass ssh-copy-id -i $Key_Path "-o StrictHostKeyChecking=no" 192.168.10.$ip
done
# 非交互式分发密钥命令需要用 sshpass 指定SSH密码,通过 -o StrictHostKeyChecking=no 跳过ssh连接确认信息

此时管理机器连接被管理机器时就无需输入密码了

1
ansible chaoge -m command -a "uname -a"

组变量

给主机组统一赋值变量

1
2
3
4
5
6
7
8
9
10
vim /etc/ansible/hosts

[webserver]
host1
host2
host3
host4
[webserver:vars]
ansible_user=root
ansible_ssh_pass=root

子分组

管理多个主机组

1
2
3
4
5
6
7
8
9
10
11
vim /etc/ansible/hosts

[webserver1]
host1
host2
[webserver2]
host3
host4
[webserver:children]
webserver1
webserver2

自定义主机列表

我们可以在任何位置使用自己创建的主机列表文件进行连接,用 -i 选项实现

1
2
3
4
5
6
7
8
9
10
11
12
# 创建主机列表文件
vim hostlist

[webserver]
host1
host2
[webserver:vars]
ansible_user=root
ansible_ssh_pass=root

# 使用此文件连接主机列表
ansible -i hostlist webserver -m ping

模式与命令

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

  • 利用ansible的纯命令行实现的批量管理(简单的shell命令管理)
  • 利用ansible的playbook剧本来实现批量管理(复杂的shell脚本管理)

ad-hoc模式

直接使用ansible的命令行,处理一些临时的、简单的任务,比如

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

playbook模式

主要针对比较具体的任务,比如

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

ansible模块

ansible-doc命令

1
2
3
4
# 列出所有的ansible支持的模块
ansible-doc -l
# 查看某个模块的具体用法以及参数
ansible-doc -s 模块名

command模块

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

command模块是ansible的默认基本模块,也可以省略不写。

使用command模块时,不得出现 $name,> < | ; & 等shell变量和特殊符号,因为command模块无法识别。

参数:

  • chdir 在执行命令之前,先进入该参数指定的目录
  • creates 在执行命令之前,判断该文件是否存在,如果存在则跳过,如果不存在则执行
  • removes 在执行命令之前,判断该文件是否存在,如果存在则执行,如果不存在则跳过
  • free-form 该参数可以输入任何的系统命令,实现远程执行和管理
  • warn 是否提供告警信息
1
2
3
4
5
6
# 执行命令前切换目录
ansible chaoge -m command -a 'pwd chdir=/tmp/'
# 存在该目录执行则执行命令
ansible chaoge -m command -a 'pwd removes=/tmp/'
# 关闭告警信息
ansible chaoge -m command -a 'chmod 000 /etc/hosts warn=false'

shell模块

作用:在远程机器上执行复杂的命令

参数:

  • chdir 在执行命令之前,先进入该参数指定的目录
  • creates 在执行命令之前,判断该文件是否存在,如果存在则跳过,如果不存在则执行
  • removes 在执行命令之前,判断该文件是否存在,如果存在则执行,如果不存在则跳过
  • free-form 该参数可以输入任何的系统命令,实现远程执行和管理
  • warn 是否提供告警信息
1
2
3
4
5
6
# 批量创建写入文件信息
ansible -m shell -a 'echo 哈哈哈哈 > /tmp/haha.txt'

# 批量远程执行脚本
# !!! 需要执行的脚本,必须在客户端机器上存在,否则会报错文件不存在
ansible chaoge -m shell -a "mkdir -p /server/myscripts;echo 'hostname' > /server/myscripts/hostname.sh;chmodl+x /server/myscripts/hostname.sh;bash /server/myscripts/hostname.sh warn=False"

script模块

作用:把管理机器上的脚本远程传输到远程机器上去执行(远程机器上不需要有该脚本)

参数:

chdir、creates、removes

1
2
# 在管理机器上执行,被管理机器返回结果
ansible chaoge -m script -a '/script.sh'

拷贝模块

作用:复制文件到到远程机器的某个位置

1
2
3
4
5
6
7
# src 要复制的文件 
# des 要复制去的位置
# owner 所属用户
# group 所属组
# mode 权限分配
# backup 如果目标文件存在,是否在覆盖前创建一个备份
ansible chaoge -m copy -a 'src=/etc/hosts dest=/tmp/2.txt owner=root group=bin mode=777'

用户模块

作用:可以批量为远程机器创建用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建用户
# name 用户名
# state # 设置帐号状态,不指定为创建,指定值为absent表示删除
# group 指定基本组
# password 指定用户密码
# shell 指定默认shell
ansible chaoge -m user -a 'name=testUser state=present'

# 生成加密密码并修改
echo '123456' | openssl passwd -1 -stdin # 会生成对应的加密密码
ansible chaoge -m user -a 'name=testUser state=present password="$1$oUWbRo3r$mwVPTEXn3fGuvPC9VLpBp."'

# 测试
ssh testUser@192.168.10.101 # 输入密码 123456

yum模块

作用:批量进行软件的安装

1
2
3
# name 包名,值为 * 代表对所有软件进行升级
# state 操作(present--->安装, latest--->安装最新的,absent---> 卸载软件)
ansible chaoge -m yum -a 'name="httpd" state="latest"'

服务模块

作用:服务状态控制

1
2
3
4
# name 服务名
# state started--->启动服务, stopped--->停止服务, restarted--->重启服务, reloaded--->重载配置
# enabled 设置开机启动
ansible chaoge -m service -a 'name=httpd state=started enabled=yes'

文件模块

作用:操作文件

1
2
3
4
# path 文件/文件夹路径
# state directory--->如果目录不存在,就创建目录 file--->即使文件不存在,也不会被创建 link--->创建软链接 hard--->创建硬链接 touch--->如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间 absent--->删除目录、文件或者取消链接文件
# mode 文件/文件夹权限
ansible chaoge -m file -a 'path=/tmp/77.txt mode=777 state=touch'

收集模块

作用:显示主机相关信息

1
2
3
# filter 过滤出相关信息
ansible chaoge -m setup
ansible chaoge -m setup -a 'filter=ansible_processor'

fetch模块

作用:用于从远程某主机获取(复制)文件到本地

1
2
3
# src  在远程拉取的文件,并且必须是一个file,不能是目录
# dest 用来存放文件的目录
ansible host1 -m fetch -a 'src=/data/test dest=/data'

cron模块

作用:管理cron计划任务

1
2
3
4
5
6
7
8
9
10
11
12
# day 日应该运行的工作( 1-31, *, */2, )
# hour 小时 ( 0-23, *, */2, )
# minute 分钟( 0-59, *, */2, )
# month 月( 1-12, *, /2, )
# weekday 周 ( 0-6 for Sunday-Saturday,, )
# job 指明运行的命令是什么
# name 定时任务描述
# reboot 任务在重启时运行,不建议使用,建议使用special_time
# special_time 特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)
# state 指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务
# user 以哪个用户的身份执行
ansible host1 -m cron -a 'name="ntp update every 5 min" minute=*/5 job="/sbin/ntpdate 172.17.0.1 &> /dev/null"'

group模块

作用:主要用于添加或删除组

1
2
3
4
5
# gid	设置组的GID号
# name 指定组的名称
# state 指定组的状态,默认为创建,设置值为absent为删除
# system 设置值为yes,表示创建为系统组
ansible chaoge -m group -a 'name=hhh state=present'

unarchive模块

作用:解压缩包

1
2
3
4
# src 要解压的包名
# dest 解压到哪个目录下
# remote_src yes--->解压远程主机上的包 no--->将管理机上的包传到远程主机上解压
ansible host1 -m unarchive -a 'src=/root/11.tar dest=/home'

剧本实战

了解 YAML 语言

语法

1
2
3
4
5
6
7
8
9
10
# 列表
fruits:
- Apple
- Orange
- Mangp
# 字典
John:
name:John James
job:doctor
sex:man

web服务器的部署配置

准备工作,在管理机器上操作

1
2
3
4
5
6
7
# ansible 管理机器
yum install -y httpd
mkdir apache
cd apache
cp -rf /etc/httpd/conf/httpd.conf .
vim httpd.conf
Listen 8080 #修改为监听 8080 端口

编写剧本 , vim apache.yaml

1
2
3
4
5
6
7
8
- hosts: host1
tasks:
- name: install apache package
yum: name=httpd state=present
- name: copy apache conf
copy: src=./httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: ensure apache is running
service: name=httpd state=started enabled=yes

测试编写的剧本

1
2
3
4
5
6
7
8
9
10
# 检验语法是否正确
ansible-playbook apache.yaml --syntax-check
# 列出任务
ansible-playbook apache.yaml --list-tasks
# 列出主机
ansible-playbook apache.yaml --list-hosts
# 执行
ansible-playbook apache.yaml
# 在被管理机器上访问 ip:8080
https://192.168.10.101:8080

如果我们更改再次端口,并重新执行剧本,虽然配置文件已推送,但目标主机服务并不会重新启动,所以无法立即用更改后的端口进行访问。

对于这个问题,我们可以用handlers触发器解决,在剧本文件里修改

1
2
3
4
5
6
7
8
9
10
11
12
- hosts: host1
tasks:
- name: install apache package
yum: name=httpd state=present
- name: copy apache conf
copy: src=./httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: restart apache service
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart apache service
service: name=httpd state=restarted

当 copy 模块发生变化时,就会执行对应的 handlers 模块

部署并配置Nginx

准备目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mkdir roles/nginx/{files,handlers,tasks.templates,vars} -p
touch roles/site.yaml roles/nginx/{handlers,tasks,vars}/main.yaml
echo 1234 > roles/nginx/files/index.html
yum install -y nginx && cp /etc/nginx/nginx.conf roles/nginx/templates/nginx.conf.j2

# 使用 tree 命令查看目录结构
roles/
├── nginx
│   ├── files
│   │   └── index.html
│   ├── handlers
│   │   └── main.yaml
│   ├── tasks
│   │   └── main.yaml
│   ├── templates
│   │   └── nginx.conf.j2
│   └── vars
│   └── main.yaml
└── site.yaml

# nginx 角色名
# files 普通文件
# handlers 触发器文件
# tasks 主任务
# templates 金甲模板(有变量)
# vars 自定义变量

编写剧本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# vim roles/nginx/tasks/main.yaml     主任务
- name: install epel-release packge
yum: name=epel-release state=latest
- name: install nginx packge
yum: name=nginx state=latest
- name: copy index.html
copy: src=index.html dest=/usr/share/nginx/html/index.html
- name: copy nginx.conf template
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: make sure nginx service running
service: name=nginx state=started enabled=yes

# vim roles/nginx/templates/nginx.conf.j2 金甲模板
worker_processes {{ ansible_processor_cores }} # 内置变量
worker_connections {{ worker_connections }} # 自定义变量

# vim roles/nginx/vars/main.yaml 自定义变量
worker_connections: 10234

# vim roles/nginx/handlers/main.yaml 触发器
- name: restart nginx
service: name=nginx state=restarted

# vim roles/site.yaml
- hosts: host1
roles:
- nginx

在金甲模板中,可以将某些值替换为内置变量,可以用setup模块查出变量的值

1
>ansible host1 -m setup -a 'filter=ansible_processor_cores'

执行剧本并验证

1
2
3
4
cd roles
ansible-playbook site.yaml --syntax-check
ansible-playbook site.yaml
# 访问IP进行验证

通过IP访问失败,通过定位发现是前端目录文件路径不对

1
2
3
# server块
root /data/web # 修改为
root /usr/share/nginx/html # 之前在主任务剧本里定义过的