1.环境准备 (自动化工具,批量操作)
6台 2cpu,1.5G以上内存,20G硬盘,1网卡
1.1 基础环境准备
1)启动6台虚拟机,ansible.sh
2)真机配置yum仓库
]# tar -xf ansible_soft.tar.xz
]# cd ansible_soft/
soft]# mkdir /var/ftp/ansible
soft]# cp * /var/ftp/ansible
soft]# createrepo /var/ftp/ansible
3)修改主机名(容易区分,6台机器都需要修改)这里以ansible主机为例子
]# echo ansible > /etc/hostname
]# hostname ansible
4)配置ip(6台机器都需要配置),这里以ansible主机为例子
]# vim /etc/sysconfig/network-scripts/ifcfg-eth0
# Generated by dracut initrd
DEVICE="eth0"
ONBOOT="yes"
IPV6INIT="no"
IPV4_FAILURE_FATAL="no"
NM_CONTROLLED="no"
TYPE="Ethernet"
BOOTPROTO="static"
IPADDR=192.168.1.51
PREFIX=24
GATEWAY=192.168.1.254
]# systemctl restart network
[root@localhost ~]# ifconfig
...inet 192.168.1.51...
5)配置yum客户端,在管理节点ansible上面配置
ansible ~]# vim /etc/yum.repos.d/local.repo
[local_repo]
name=CentOS-$releasever - Base
enabled=1
gpgcheck=1
[local]
name=local
enabled=1
gpgcheck=0
ansible ~]# yum clean all
ansible ~]# yum repolist
ansible ~]# yum -y install ansible
ansible ~]# ansible --version
ansible 2.4.2.0 //显示版本说明安装成功
6)请在6台主机上面配置/etc/hosts,这里以ansible主机为例子
ansible]# cat /etc/hosts
192.168.1.51 ansible
192.168.1.52 web1
192.168.1.53 web2
192.168.1.54 db1
192.168.1.55 db2
192.168.1.56 cache
2. 主机定义与分组
熟悉ansible配置文件
定义主机,分组和子组练习
自定义文件,多配置路径练习
2.1 ansible.cfg配置文件
ansible]# cd /etc/ansible/
ansible ansible]# ls
ansible.cfg hosts roles
ansible ansible]# vim ansible.cfg
//指定分组文件路径,主机的分组文件hosts
14 inventory = /etc/ansible/hosts
//ssh首次连接的时候,需要取消输入yes
61 host_key_checking = False
[selinux] //组名称,selinux的相关选项在这个下面配置
...
[colors] //组名称,colors的相关选项在这个下面配置
...
2.2 定义主机,分组和子组练习
1)静态主机的定义
ansible]# vim /etc/ansible/hosts
[web]
web1
web2
[db]
db[1:2]
[other]
cache
//1:2为db1到db2两台主机,1:20为db1到db20多台主机
ansible]# ansible web --list-host //显示web组的主机
hosts (2):
web1
web2
ansible]# ansible db --list-host
hosts (2):
db1
db2
ansible]# ansible other --list-host
hosts (1):
cache
[ansible]# ansible all --list-host //显示所有组的主机
hosts (5):
web1
web2
cache
db1
db2
2)直接测试
-m(module) ping(模块)
ansible]# ansible cache -m ping
//测试是否可以连接,若失败颜色为红色
cache | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname cache: Name or service not known\r\n",
"unreachable": true
}
3)修改后测试
ansible]# vim /etc/ansible/hosts
[other]
cache ansible_ssh_user="root" ansible_ssh_pass="123456"
//cache虚拟机的用户名和密码
ansible]# ansible other -m ping //测试成功,颜色为绿色
cache | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible]# vim /etc/ansible/hosts
[web]
web1
web2
[web:vars] //web组:变量(vars不改),web组的多台机器共用一个用户名和密码
ansible_ssh_user="root"
ansible_ssh_pass="123456"
ansible]# ansible web -m ping
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
2.3 定义子组(集合)
ansible]# vim /etc/ansible/hosts
//指定子分组(app可改:children不改),web,db是提前分好的组
[app:children]
web
db
[app:vars](vars 集合内所有成员的公共属性)
ansible_ssh_user="root"
ansible_ssh_pass="123456"
ansible]# ansible app --list-host //查看
hosts (4):
web1
web2
db1
db2
ansible]# ansible app -m ping //测试
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
db1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
db2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
2.4 多路径练习
自定义的ansible文件只在当前路径生效
1)多路径
ansible ~]# mkdir aaa
ansible ~]# cd aaa/
aaa]# vim myhost
[app1]
web1
db1
[app2]
web2
db2
[app:children]
app1
app2
[other]
cache
[app:vars]
ansible_ssh_user="root"
ansible_ssh_pass="123456"
aaa]# touch ansible.cfg
aaa]# grep -Ev "^#|^$" /etc/ansible/ansible.cfg
[defaults]
roles_path = /etc/ansible/roles:/usr/share/ansible/roles
host_key_checking = False
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
aaa]# vim ansible.cfg
[defaults]
inventory = myhost
host_key_checking = False
2)测试结果
aaa]# ansible app1 -m ping
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
db1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
aaa]# ansible app -m ping
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
db1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
db2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
aaa]# ansible app --list-host
hosts (4):
web1
db1
web2
db2
aaa]# cd
ansible ~]# ansible app1 --list-host //切换到别的目录,测试失败
[WARNING]: Could not match supplied host pattern, ignoring: app1
[WARNING]: No hosts matched, nothing to do
hosts (0):
3.动态主机
3.1 脚本输出主机列表
ansible ~]# cd aaa
aaa]# ls
ansible.cfg myhost
aaa]# vim host.py
#!/usr/bin/python (这行也要!)
import json
hostlist = {} //定义主机列表
hostlist["bb"] = ["192.168.1.52", "192.168.1.53"]
hostlist["192.168.1.54"] = {
"ansible_ssh_user":"root","ansible_ssh_pass":"pwd"
}
hostlist["aa"] = {
"hosts" : ["192.168.1.55", "192.168.1.56"],
"vars" : {
"ansible_ssh_user":"root","ansible_ssh_pass":"pwd"
}
}
print(json.dumps(hostlist))
aaa]# chmod 755 ./host.py
2) 脚本输出样例(这样写输出的结果有些乱)
aaa]# ./host.py
{"aa": {"hosts": ["192.168.1.55", "192.168.1.56"], "vars": {"ansible_ssh_user": "root", "ansible_ssh_pass": "a"}}, "192.168.1.54": {"ansible_ssh_user": "root", "ansible_ssh_pass": "a"}, "bb": ["192.168.1.52", "192.168.1.53"]}
3) 可以用shell脚本输出
aaa]# vim my.sh
#!/bin/bash
echo '
{ "aa": {
"hosts":
["192.168.1.55", "192.168.1.56"],
"vars": {
"ansible_ssh_user": "root",
"ansible_ssh_pass": "123456"}
},
}'
aaa]# chmod 755 my.sh
aaa]# ./my.sh
{ "aa": {
"hosts":
["192.168.1.55", "192.168.1.56"],
"vars": {
"ansible_ssh_user": "root",
"ansible_ssh_pass": "123456"}
},
}
aaa]# vim ansible.cfg
[defaults]
inventory = my.sh
host_key_checking = False
aaa]# ansible aa -m ping
192.168.1.55 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.56 | SUCCESS => {
"changed": false,
"ping": "pong"
}
3.2 批量执行
1)查看负载
aaa]# cd /etc/ansible
ansible]# ansible app -m command -a 'uptime'
web2 | SUCCESS | rc=0 >>
19:55:36 up 4:02, 2 users, load average: 0.00, 0.01, 0.01
db1 | SUCCESS | rc=0 >>
19:55:36 up 4:01, 2 users, load average: 0.00, 0.01, 0.02
web1 | SUCCESS | rc=0 >>
19:55:36 up 4:02, 2 users, load average: 0.00, 0.01, 0.01
db2 | SUCCESS | rc=0 >>
19:55:36 up 4:01, 2 users, load average: 0.00, 0.01, 0.03
2)查看时间
ansible]# ansible app -m command -a 'date +%F\ %T'
web1 | SUCCESS | rc=0 >>
2019-02-26 19:56:12
db1 | SUCCESS | rc=0 >>
2019-02-26 19:56:12
db2 | SUCCESS | rc=0 >>
2019-02-26 19:56:12
web2 | SUCCESS | rc=0 >>
2019-02-26 19:56:12
4.批量部署证书文件
创建一对密钥
给所有主机部署密钥
4.1 批量部署证书文件,给所有主机部署密钥
1)创建密钥
ansible]# cd /root/.ssh/
.ssh]# vim /etc/ansible/hosts
[web]
web1
web2
[db]
db[1:2]
[other]
cache
.ssh]# ansible all -m ping //直接ping会报错
.ssh]# ssh-keygen -t rsa -b 2048 -N '' //创建密钥
2)给所有主机部署密钥
.ssh]# ansible all -m authorized_key -a "user=root exclusive=true manage_dir=true key='$(< /root/.ssh/id_rsa.pub)'" -k
SSH password: //输入密码
.ssh]# ansible all -m ping //成功
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
db2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
cache | SUCCESS => {
"changed": false,
"ping": "pong"
}
db1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
.ssh]# ssh web1
//不需要输入密码,可以直接登陆
5. 练习模块
练习使用command , shell , raw, script模块
5.1 练习模块
ansible-doc //模块的手册,相当于man
ansible-doc -l //列出所有模块
ansible-doc 模块名 //查看指定模块的帮助信息
1)ping模块
.ssh]# ansible web1 -m ping
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
2)command模块
.ssh]# ansible web1 -m command -a 'chdir=/tmp touch f1'
//创建成功
web1 ~]# cd /tmp/
tmp]# ls //在web1上面查看
f1
3)shell模块
.ssh]# ansible web1 -m shell -a 'chdir=/tmp touch f2' //创建成功
[root@web1 ~]# cd /tmp/
[root@web1 tmp]# ls //在web1上面查看
f2
4)raw模块
.ssh]# ansible web1 -m raw -a 'chdir=/tmp touch f3'
//文件可以创建,但无法切换目录,文件在用户家目录下生成/root/
web1 ~]# ls //在web1上面查看
f3
5)script模块
对于太复杂的命令,可以写个脚本,然后用script模块执行
在web1主机上创建zhangsan3用户,修改zhangsan3的密码为123456,设置zhangsan3第一次登陆必须修改密码
用命令写:(必须有zhangsan3这个用户)
.ssh]# ansible web1 -m shell -a 'echo 123456 | passwd --stdin zhangsan3'
.ssh]# ssh -l zhangsan3 web1
zhangsan3@web1's password: //输入zhangsan3的密码
web1 ~]$ whoami
zhangsan3
.ssh]# ansible web1 -m shell -a 'chage -d 0 zhangsan3'
(重置zhangsan3的密码)
.ssh]# ssh -l zhangsan3 web1
用脚本写,script模块执行:
[.ssh]# vim user.sh
#!/bin/bash
useradd zhangsan3
echo 123456 | passwd --stdin zhangsan3
chage -d 0 zhangsan3
echo
.ssh]# ansible web1 -m script -a './user.sh'
web1 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to web1 closed.\r\n",
"stdout": "Changing password for user zhangsan3.\r\npasswd: all authentication tokens updated successfully.\r\n\r\n",
"stdout_lines": [
"Changing password for user zhangsan3.",
"passwd: all authentication tokens updated successfully.",
""
]
}
ansible .ssh]# ssh -l zhangsan3 web1
lisi@web1's password:
You are required to...(更改密码)
6. 模块练习
使用copy模块同步数据
使用lineinfile模块编辑文件
使用replace模块修改文件
6.1 模块练习
1)使用copy模块同步数据
src:要复制到进程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync
dest:必选项。进程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no
force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
.ssh]# ansible all -m shell -a 'cat /etc/resolv.conf'
//查看/etc/resolv.conf
db1 | SUCCESS | rc=0 >>
; generated by /usr/sbin/dhclient-script
search vbr
nameserver 192.168.1.254
web1 | SUCCESS | rc=0 >>
; generated by /usr/sbin/dhclient-script
search vbr
nameserver 192.168.1.254
db2 | SUCCESS | rc=0 >>
; generated by /usr/sbin/dhclient-script
search vbr
nameserver 192.168.1.254
web2 | SUCCESS | rc=0 >>
; generated by /usr/sbin/dhclient-script
search vbr
nameserver 192.168.1.254
cache | SUCCESS | rc=0 >>
; generated by /usr/sbin/dhclient-script
search vbr
nameserver 192.168.1.254
.ssh]# cat /etc/resolv.conf
nameserver 176.233.0.227
.ssh]# ansible all -m copy -a 'src=/etc/resolv.conf dest=/etc/resolv.conf'
//复制本机的resolv.conf到其他主机
.ssh]# ansible all -m shell -a 'cat /etc/resolv.conf'
//查看都有nameserver 176.233.0.227
ansible ~]# mkdir aa
ansible ~]# echo "654321" > aa/1.txt
ansible ~]# ansible all -m copy -a 'src=/root/aa dest=/root/a.log'
//复制本机的目录/root/aa到其他机器的/root/a.log目录下,复制目录只能少数批量执行同步
ansible ~]# ansible all -m shell -a 'ls -ld /root/*''
web2 | SUCCESS | rc=0 >>
drwxr-xr-x 3 root root 16 2月 26 20:30 /root/a.log
db1 | SUCCESS | rc=0 >>
drwxr-xr-x 3 root root 16 2月 26 20:30 /root/a.log
web1 | SUCCESS | rc=0 >>
drwxr-xr-x 3 root root 16 2月 26 20:30 /root/a.log
cache | SUCCESS | rc=0 >>
drwxr-xr-x 3 root root 16 2月 26 20:30 /root/a.log
db2 | SUCCESS | rc=0 >>
drwxr-xr-x 3 root root 16 2月 26 20:30 /root/a.log
web1 ~]# ls a.log/aa/1.txt
a.log/aa/1.txt
2)使用lineinfile模块编辑文件
以行为基础,整行修改(整行被替换掉)
ansible ~]# ansible cache -m lineinfile \
-a 'path=/etc/sysconfig/network-scripts/ifcfg-eth0 \
regexp="^ONBOOT=" line="ONBOOT=\"no\""' (" “ ‘)
cache | SUCCESS => {
"backup": "",
"changed": true,
"msg": "line replaced"
}
3)使用replace模块修改文件
修改文件的某一部分(替换一行中匹配的内容),以正则表达式匹配为基础修改
ansible ~]# ansible cache -m replace -a \
'path=/etc/sysconfig/network-scripts/ifcfg-eth0 \
regexp="^(ONBOOT=).*" replace="\1\"yes\""'
cache | SUCCESS => {
"changed": true,
"msg": "1 replacements made"
}
7. 综合练习
安装Apache并修改监听端口为8080
修改ServerName配置,执行apachectl -t命令不报错
设置默认主页hello world
启动服务并设开机自启
7.1 步骤一:熟悉模块
1)yum模块
ansible ~]# ansible other -m yum -a 'name="lrzsz" state=removed'
//lrzsz软件包名,removed=absent删除
ansible ~]# ansible other -m yum -a 'name="lrzsz,lftp" state=installed'
//安装多个软件包,不写state默认为安装
2)service模块
ansible ~]# ansible other -m service -a 'name="sshd" enabled="yes" state="started"'
//sshd服务名,开机启动同时启动这个服务
3)setup模块
filter 过滤指定的关键字(可以过滤到我们需要的信息)
ansible ~]# ansible cache -m setup -a 'filter=os'
cache | SUCCESS => {
"ansible_facts": {},
"changed": false
}
ansible ~]# ansible cache -m setup -a 'filter=ansible_distribution'
cache | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "CentOS"
},
"changed": false
}
7.2 安装Apache
1)安装Apache服务设置开机自启
ansible ~]# ansible cache -m yum -a 'name=httpd state=installed'
ansible ~]# ansible cache -m service -a 'name=httpd enabled=yes state=started'
2)修改端口号为8080
ansible ~]# ssh cache
cache ~]# cat /etc/httpd/conf/httpd.conf | grep ^Listen
Listen 80
ansible ~]# ansible cache -m lineinfile -a 'path="/etc/httpd/conf/httpd.conf" regexp="^Listen " line="Listen 8080"'
cache | SUCCESS => {
"backup": "",
"changed": true,
"msg": "line replaced"
}
ansible ~]# ssh cache
cache ~]# cat /etc/httpd/conf/httpd.conf | grep ^Listen
Listen 8080
7.3 修改ServerName配置,执行apachectl -t命令不报错
1)没有修改之前
cache ~]# apachectl -t //有报错
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.1.56. Set the 'ServerName' directive globally to suppress this message
Syntax OK
2)修改之后
ansible ~]# ansible cache -m lineinfile -a 'path="/etc/httpd/conf/httpd.conf" regexp="^ServerName " line="ServerName 0.0.0.0"'
cache | SUCCESS => {
"backup": "",
"changed": true,
"msg": "line added"
}
ansible ~]# ssh cache
cache ~]# apachectl -t
Syntax OK
7.4 设置默认主页为hello world
ansible ~]# echo "Hello World" > /root/index.html
ansible ~]# ansible cache -m copy -a 'src=/root/index.html dest=/var/www/html/index.html'
cache | SUCCESS => {
"changed": true,
"checksum": "22596363b3de40b06f981fb85d82312e8c0ed511",
"dest": "/var/www/html/index.html",
"gid": 0,
"group": "root",
"md5sum": "6f5902ac237024bdd0c176cb93063dc4",
"mode": "0644",
"owner": "root",
"size": 12,
"src": "/root/.ansible/tmp/ansible-tmp-1536219767.29-30682157793478/source",
"state": "file",
"uid": 0
}
*****************
ansible.sh
#!/bin/bash
func_zj(){
cd /var/lib/libvirt/images/
for i in ansible web1 web2 db1 db2 cache
do
qemu-img create -f qcow2 -b node.qcow2 $i.img 20G
sed "s,node,$i," /etc/libvirt/qemu/node.xml > /etc/libvirt/qemu/$i.xml
virsh define /etc/libvirt/qemu/$i.xml
virsh start $i
for j in {3..0}
do
echo $j
sleep 1
done
done
}
func_spawn(){
expect <<EOF
spawn virsh console $1
expect " " {send "\r"}
expect "login" {send "root\r"}
expect "Password" {send "123456\r"}
expect "#" {send "export LANG=en_US\r"}
expect "#" {send "growpart /dev/vda 1\r"}
expect "#" {send "xfs_growfs /\r"}
expect "#" {send "lsblk\r"}
expect "#" {send "echo $1 > /etc/hostname\r"}
expect "#" {send "ip a s\r"}
expect "#" {send "exit\r"}
EOF
}
func_sj(){
for k in ansible web1 web2 db1 db2 cache
do
func_spawn $k
done
}
echo "开始"
func_zj
for j in {60..0}
do
echo $j
sleep 1
done
func_sj
echo "结束"
##################################
知识点整理:
01:ansible概述
基于Python开发,IT自动化和DevOps软件,实现了批量操作系统配置,批量程序部署,批量运行命令等功能,只要有SSH和Python即可使用。
02:ad-hoc 主机管理模式/playbook 两种模式
01:主机集合:inventory=/etc/ansible/hosts
host_key_checking=False 首次ssh不输入yes
]# ansible 集合/主机 -m(module) xxx -a(模块的参数) 'xxx' (- k 密码)
常用模块都有哪些:
command --> id(查看用户),uptime,date 默认模块,不支持"|" "<" ">" "&"(bash提供)
authorized_key --> ssh-key-id命令
shell(跟command差不多,可执行任意模块 远程的时候注意转义,否则是本地)
raw(跟shell一样,可执行任意模块,unix,不支持cd 即 -a chdir=/dir touch xxx)
script -a 'xx.sh' --> 执行脚本模块 远程批量执行本地脚本(复杂的任务)
copy -a 'src=xx dest=xx' --> 拷贝文件和文件夹,不适合批量操作(打包校验机制,麻烦)
lineinfile -a 'path=xxx regexp=“^xx"(匹配整行,替换整行) line(修改为)="XXX" -->修改行内容
replace 跟lineinfile一样,但只修改匹配的部分
replace -a 'path=xxx regexp=“^xx"(匹配整行,替换整行) replace(修改为)="^XXX" -->修改行内容
yum -a 'name=aa,bb,.. state=installed' --> yum 装包 (removed 卸载)
service -a 'name=a,b,...state=started(stoppd restarted) enabled=yes' -->启服务
setup | grep os(返回字符串) -->获取主机信息,不写参数获取所有
setup -a 'filter="ansible_os_family"'(返回标准格式) 获取主机名
查看所有模块:]# ansible-doc -l(1300多)
02:动态主机分组(脚本、程序,返回给ansible Json主机数据就行)
(只要哪个程序有主机群组的配置文件+SSH就可以用ansible批量管理,如zabbix)
Json:数组 字典
数组:[ "a","b","c" ]
字典:{ A:a,B:b,...键值对的集合 }
#######################################