自动化运维
任务背景
公司的服务器越来越多, 维护⼀些简单的事情都会变得很繁琐。⽤shell脚本来管理少量服务器效率还⾏, 服务器多了之后, shell脚本⽆法实现⾼效率运维。这种情况下,我们需要引⼊⾃动化运维⼯具, 对多台服务器实现⾼效运维。
任务要求
通过管理服务器能够按照需求灵活⾼效地管理所有应⽤服务器的运维操作
任务拆解
1, 需要⼀台服务器做管理端, 来连接管理所有的应⽤服务器
2, 考虑如果只针对⼀部分应⽤服务器进⾏运维操作如何实现(服务器分组)
3, 学会将平台烂熟于⼼的linux操作命令转化为⾃动化运维的⽅式(常⻅模块的学习)
4, 如果操作⾮常的冗⻓, 学会使⽤playbook和role的⽅式来管理⾃动化运维主要关注的⾯
假如管理很多台服务器,主要关注以下⼏个⽅⾯:
-
管理机与被管理机的连接(管理机如何将管理指令发送给被管理机)
-
服务器信息收集 (如果被管理的服务器有centos7.5外还有其它linux发⾏版,如suse,ubuntu等。当你要做的事情在不同OS上有所不同,你需要收集信息,并将其分开处理)
-
服务器分组(因为有些时候我要做的事情不是针对所有服务器,可能只针对某⼀个分组)
-
管理内容的主要分类
(1)⽂件⽬录管理(包括⽂件的创建,删除,修改,查看状态,远程拷⻉等)
(2)⽤户和组管理
(3)cron时间任务管理
(4)yum源配置与通过yum管理软件包
(5)服务管理
(6)远程执⾏脚本
(7)远程执⾏命令
常见的开源⾃动化运维工具比较
- puppet(拓展)
基于ruby语⾔,成熟稳定。适合于⼤型架构,相对于ansible和
saltstack会复杂些。
- saltstack(拓展)
基于python语⾔。相对简单,⼤并发能⼒⽐ansible要好, 需要维
护被管理端的服务。如果服务断开,连接就会出问题。
- ansible
基于python语⾔。简单快捷,被管理端不需要启服务。直接⾛
ssh协议,需要验证所以机器多的话速度会较慢。
Ansible的应用
1、概述:
ansible是⼀种由Python开发的⾃动化运维⼯具,集合了众多运维⼯具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运⾏命令等功能。
2、特点:
部署简单;
默认使⽤ssh进⾏管理,基于python⾥的paramiko模块开发
管理端和被管理端不需要启动服务
配置简单,功能强⼤,扩展性强
能过playbook(剧本)进⾏多个任务的编排
3、环境准备
管理机:m0(192.168.2.176)
被管理机:s0(192.168.2.177) s1(192.168.2.178) s2(192.168.2.179)
4、基础配置:
(1)静态ip
(2)主机名及主机名互相绑定
(3)关闭防⽕墙, selinux
(4)时间同步
(5)确认和配置yum源(需要epel源)
5、配置过程
(1)安装并查看版本
[root@m0 ~]# yum list installed|grep epel
epel-release.noarch 7-11 @extras
[root@m0 ~]# yum -y install ansible
[root@m0 ~]# ansible --version
ansible 2.9.27
[root@m0 ~]# find /etc/ -name '*ansible*'
/etc/ansible
/etc/ansible/ansible.cfg
(2)实现master对agent的免密登录,只在master上做。(如果这⼀步不做,则在后⾯操作agent时都要加-k参数传密码;或者在主机清单⾥传密码)做免密(anible通过22端口进行管理)
[root@m0 ~]# ssh-keygen # 一路enter
The key's randomart image is:
+---[RSA 2048]----+
| E+..o.. .ooo=|
| + o. . + . +.|
|o + o o = . . .|
|oo o o.+ o + |
|.. . .S. . . B|
| . .o . . X.|
| . . + . + *|
| . . . oo|
| .oo oo|
+----[SHA256]-----+
[root@m0 ~]# ls ./ssh/
ls: 无法访问./ssh/: 没有那个文件或目录
[root@m0 ~]# ls ./.ssh/
id_rsa id_rsa.pub known_hosts
[root@m0 ~]# cat ./.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDt3ZM422EYl4Xgu7miNDPfbF6AV9D1hQPFLvjHzZTtr0piDZvKhvt2iXpd42eF6XNpTPdEKC1omdSfJS8dlqNE1ipYNXQoX+YAnDK+brinwC6k8JzPK34p+lP9VCEkpaaqFIQTJCe/pVyUhNjw2uViikWIAxkZfGBy/dKSkooNr6dLUaeB80njavCZEXMn73/aGAlwYxH0EPgMiiyRRg5leuuMuZXFl8xLU2YiJ9/B43Q/JQBTDxzeaIXdgb8yiPiCJpYUnVcjVgmhQwEpFh58EGHxr5WA+L3MiXYHjT26JdBzkMirmggBBbjPbHrSvRQg6ZCiRfDrrpGGEZbTic7z root@m0
[root@m0 ~]# ssh-copy-id -i 192.168.2.177
[root@m0 ~]# ssh-copy-id -i 192.168.2.178
(3)定义主机组测试连接性
# 服务器分组
ansible通过⼀个主机清单功能来实现服务器分组。Ansible的默认主机清单配置⽂件为/etc/ansible/hosts。
示例:
示例:
[nginx] 组名
apache[1:10].aaa.com 表示apache1.aaa.com到apache10.aaa.com这10台机器
nginx[a:z].aaa.com 表示nginxa.aaa.com到nginxz.aaa.com共26台机器
192.168.2..[11:15] 表示192.168.2.11到192.168.2.15这5台机器
[nginx]
192.168.2.13:2222 表示10.1.1.13这台,但ssh端⼝为2222
# 定义1 192.168.2.177 、 192.168.2.178 这台服务器的别名为 group01
[root@m0 ~]# vim /etc/ansible/hosts
[group01]
192.168.2.177
192.168.2.178
[group02]
192.168.2.177
192.168.2.178
192.168.2.179
[root@m0 ~]# ansible 192.168.2.177 -m ping
192.168.2.177 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@m0 ~]# ansible group01 -m ping
192.168.2.177 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.2.178 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@m0 ~]# ansible group02 -m ping
The authenticity of host '192.168.2.179 (192.168.2.179)' can't be established.
ECDSA key fingerprint is SHA256:MioezkR2Al25tYmE7gw4La34F5fPGXOIp7+/icCRKjQ.
ECDSA key fingerprint is MD5:5a:c8:de:80:5a:43:e0:9e:6d:52:50:8f:b6:43:3c:13.
Are you sure you want to continue connecting (yes/no)? 192.168.2.178 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.2.177 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
yes # 没做免密
192.168.2.179 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Warning: Permanently added '192.168.2.179' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
(4)利⽤别名来分组,没有做免密登录的服务器可以指定⽤户名与密码
[root@m0 ~]# vim /etc/ansible/hosts
other ansible_ssh_host=192.168.2.179 ansible_ssh_po
rt=22 ansible_ssh_user=root ansible_ssh_password=1
[group02]
192.168.2.177
192.168.2.177
other
[root@m0 ~]# ansible group02 -m ping
192.168.2.178 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.2.177 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
other | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@m0 ~]# ansible other -m ping
other | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
如果要查看ping模块的⽤法,使⽤下⾯命令(其它模块以此类推)
ansible-doc ping
## ⼩结:
主机清单的作⽤: 服务器分组。
主机清单的常⻅功能:
-
可以通过IP范围来分, 主机名名字的范围来分
-
如果ssh端⼝不是22的,可以传⼊新的端⼝。
-
没有做免密登录,可以传密码。
****## 练习:****不论你⽤哪种环境(免密或不免密,端⼝是否22), 请最终将两台被管理机器加⼊到group02组即可
vim /ect/ansible/hosts
web01 ansible_ssh_host=192.168.71.200
ansible_ssh_user=root ansible_ssh_pass=root
ansible_ssh_port=22
web02 ansible_ssh_host=192.168.71.201
ansible_ssh_user=root ansible_ssh_pass=root
ansible_ssh_port=2222
[group1]
web01
web02
Ansbile 主机ip|域名|组名|别名 -m ping|copy|.... '参数'
ansible模块
查看所有支持的模块
[root@m0 ~]# ansible-doc -l
[root@m0 ~]# ansible-doc ping
如果要查看ping模块的⽤法,使⽤下⾯命令(其它模块以此类推)
ansible-doc ping
hostname模块
基本格式为: ansible 操作的机器名或组名 -m 模块名 -a "参数1=值1 参数2=值2"
hostname模块⽤于修改主机名(注意: 它不能修改/etc/hosts⽂件)
[root@m0 ~]# ansible group02 -m hostname -a 'name=ab.huajuan.tangpin'
file模块
字段说明
path 文件的地址 # directory 创建目录 # touch 创建文件 # absent 删除文件
link 创建软连接 # hard创建硬链接 # recure 是否允许递归 # src 文件源
创建目录
[root@s0 ~]#ansible group02 -m file -a 'path=/tmp/abc state=directory'
[root@s0 ~]# ls -l /tmp/
总用量 0
drwxr-xr-x. 2 root root 6 8月 16 11:45 abc
drwx------. 3 root root 17 8月 16 10:25 systemd-private-1d58301c85934a19910d218cdd2c7a70-chronyd.service-6vUQVK
创建文件
[root@m0 ~]# ansible group02 -m file -a 'path=/tmp/abc/def state=touch'
[root@ab ~]# ls -ld /tmp/abc/def
-rw-r--r--. 1 root root 0 8月 16 14:09 /tmp/abc/def
递归修改 owne r、group、mode
[root@m0 ~]# ansible group02 -m file -a 'path=/tmp/abc recurse=yes owner=bin group=daemon mode=1777'
[root@ab ~]# ll /tmp/
总用量 0
drwxrwxrwt. 2 bin daemon 17 8月 16 14:09 abc
drwx------. 3 root root 17 8月 16 10:25 systemd-private-a33925d16cd14fc5bc9b8f0fe5c23f27-chronyd.service-5wcjuI
[root@ab ~]# ll /tmp/abc
总用量 0
-rwxrwxrwt. 1 bin daemon 0 8月 16 14:09 def
删除⽬录(连同⽬录⾥的所有 文件 )
[root@ab ~]#ansible group02 -m file -a 'path=/tmp state=absent'
创建⽂件并指定owner,group,mode等
[root@ab ~]#ansible group1 -m file -a 'path=/tmp/test state=touch owner=bin group=daemon mode=1777'
删除文件
[root@m0 ~]# ansible group02 -m file -a 'path=/tmp/abc state=absent'
[root@ab ~]# ll /tmp/abc
ls: 无法访问/tmp/abc: 没有那个文件或目录
软连接指向硬链接,硬链接指向文件
创建软连接文件
[root@m0 ~]# ansible group02 -m file -a 'src=/etc/fstab path=/tmp/xxx state=link'
[root@ab ~]# ll /tmp/
lrwxrwxrwx. 1 root root 10 8月 16 14:28 xxx -> /etc/fstab
创建硬连接文件
[root@m0 ~]# ansible group02 -m file -a 'src=/etc/fstab path=/tmp/yyy state=hard'
[root@ab ~]# ll /tmp/
-rw-r--r--. 2 root root 501 7月 23 08:58 yyy
state模块 (了解)
获取/etc/fstab文件的状态信息
[root@m0 ~]#ansible group1 -m stat -a 'path=/etc/fstab'
copy模块 (一主两从 )
copy模块⽤于对⽂件的远程拷⻉操作(如把本地 的⽂件拷⻉到远程的机器上)
[root@m0 ~]# ls
anaconda-ks.cfg
mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
soft
改名
[root@m0 ~]# mv mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz mysql57.tar.gz
[root@m0 ~]# ls
anaconda-ks.cfg mysql57.tar.gz soft
上传文件
[root@m0 ~]# ansible group02 -m copy -a 'src=./mysql57.tar.gz dest=~
查看
[root@ab ~]# ls ~/
anaconda-ks.cfg mysql57.tar.gz soft
将master文件拷⻉到group02的所有机器上
[root@m0 ~]#echo master > /tmp/222
[root@m0 ~]#ansible group1 -m copy -a 'src=/tmp/222 dest=/tmp/333'
[root@ab ~]# ls /tmp/
333
使⽤content参数直接往远程 文件 ⾥写内容(会覆盖原内容)
[root@m0 ~]#ansible group02 -m copy -a 'content="haha" dest=/tmp/333'
注意:ansible中-a后⾯的参数⾥也有引号时,记得要单引双引交叉使⽤,如果都为双引会出现问题。
使⽤force参数控制是否强制覆盖,如果⽬标⽂件已经存在,则不覆盖
[root@m0 ~]#ansible group1 -m copy -a 'src=/tmp/222 dest=/tmp/333 force=no'
如果⽬标⽂件已经存在,则会强制覆盖
[root@m0 ~]#ansible group1 -m copy -a 'src=/tmp/222 dest=/tmp/333 force=yes'
使 ⽤backup参数控制是否备份⽂件
backup=yes表示如果拷⻉的⽂件内容与原内容不⼀样,则会备份⼀份
group02的机器上会将/tmp/333备份⼀份(备份⽂件命名加上时间),再远程拷⻉新的⽂件为/tmp/333
[root@m0 ~]#ansible group02 -m copy -a 'src=/etc/fstab dest=/tmp/333 backup=yes owner=daemon group=daemon mode=1777'
copy模块拷⻉时要注意拷⻉⽬录后⾯是否带"/"符号
/etc/yum.repos.d后⾯不带/符号,则表示把/etc/yum.repos.d整个⽬录拷⻉到/tmp/⽬录下
master# ansible group1 -m copy -a
'src=/etc/yum.repos.d dest=/tmp/'
/etc/yum.repos.d/后⾯带/符号,则表示把/etc/yum.repos.d/⽬录⾥的所有⽂件拷⻉到/tmp/⽬录下
在m0上配置好所有的yum源,然后拷⻉到group02的远程机器上(要求⽬录内的内容完全⼀致)
[root@s0~]# ansible group02 -m file -a "path=/etc/yum.repos.d/ state=absent"
[root@s0~]#ansible group02 -m copy -a "src=/etc/yum.repos.d dest=/etc/"
template模块(与copy模块功能⼏乎⼀样)
template模块⾸先使⽤变量渲染jinja2模板⽂件成普通⽂件,然后再复制过去.⽽copy模块不⽀持.(jinja2是⼀个基于python的模板引擎),注意:template模块不能拷⻉⽬录
[root@s0~]# ansible -m template group02 -a "src=/etc/hosts dest=/tmp/hosts"
[root@s0~]#ansible -m template group1 -a "src=/etc/yum.repos.d/ dest=/etc/yum.repos.d/"
fetch模块
fetch模块与copy模块类似,但作⽤相反。⽤于把远程 机器的⽂件拷⻉到本地。
注意 !!!: fetch模块不能从远程拷⻉⽬录到本地
在两台被管理机上分别创建⼀个同名⽂件(但内容不同)
[root@s0~]# echo agent1 > /tmp/1.txt
[root@s1 ~]#echo agent2 > /tmp/1.txt
从m 0 上fecth⽂件(因为group 02 ⾥有2台机器,为了避免同名⽂件⽂件冲突,它使⽤了不同的⽬录)
[root@m0 ~]#ansible group02 -m fetch -a 'src=/tmp/1.txt dest=/tmp/'
[root@m0 ~]#ansible group02 -m fetch -a 'src=/etc/sysconfig/network-scripts/ifcfg-ens33 dest=/tmp'
先删除上⾯fetch过来的, 然后尝试只fetch其中⼀台机器的,也会使⽤名称来做⼦⽬录区分
[root@m0 ~]#rm /tmp/192.168.2..* -rf
[root@m0 ~]#ansible 192.168.2.177 -m fetch -a 'src=/tmp/1.txt dest=/tmp/'
192.168.2.177 | CHANGED => {
"changed": true,
"checksum":
"d2911a028d3fcdf775a4e26c0b9c9d981551ae41",
"dest": "/tmp/192.168.2.177/tmp/1.txt", 只fetch⼀个,也会这样命名
"md5sum": "0d59da0b2723eb03ecfbb0d779e6eca5",
"remote_checksum":
"d2911a028d3fcdf775a4e26c0b9c9d981551ae41",
"remote_md5sum": null
}
yum_repository模块( yum_repository模块⽤于配置yum仓库 )
增加⼀个/etc/yum.repos.d/local.repo配置 文件
[root@m0 ~]# ansible group02 -m yum_repository -a "name=local description=localyum baseurl=file:///mnt/ enabled=yes gpgcheck=no"
注意 !!! ****:****此模块只帮助配置yum仓库,但如果仓库⾥没有软件包,安装⼀样会失败。所以可以手动去挂载光驱到/mnt⽬录
mount /dev/cdrom /mnt
删除/etc/yum.repos.d/local.repo配置 文件
[root@m0 ~]#ansible group02 -m yum_repository -a "name=local state=absent"
user模块
创建账户abc
[root@m0 ~]# ansible group02 -m user -a 'name=abc state=present'
[root@ab ~]# id abc
uid=1002(abc) gid=1002(abc) 组=1002(abc)
创建mysql账户
[root@m0 ~]# ansible group02 -m user -a 'name=mysql state=present system=yes shell="/sbin/nologin"'
[root@ab ~]# grep mysql /etc/passwd
mysql:x:997:994::/home/mysql:/sbin/nologin
[root@m0 ~]# ansible group02 -m file -a 'path=/usr/local/mysql/mysql-files owner=mysql group=mysql mode=750 state=directory'
[root@ab ~]# ll /usr/local/mysql/
drwxr-x---. 2 mysql mysql 6 8月 16 16:09 mysql-files
创建账户并设置uid、密码password
[root@m0 ~]# ansible group02 -m user -a 'name=tom uid=1009 state=present password=tom
[root@ab ~]# grep tom /etc/passwd
tom:x:1009:1009::/home/tom:/bin/bash
[root@ab ~]# grep tom /etc/group
tom:x:1009:
创建⼀个普通⽤户叫hadoop,并产⽣空密码密钥对
[root@m0 ~]# ansible group02 -m user -a 'name=hadoop generate_ssh_key=yes'
[root@ab ~]# ls ./.ssh/
authorized_keys known_hosts
[root@ab ~]# cat ./.ssh/authorized_keys
ssh-rsa
删除账户但家目录还存在,使⽤remove=yes参数让其删除⽤户的同时也删除家⽬录
[root@m0 ~]# ansible group02 -m user -a 'name=hadoop state=absent'
[root@ab ~]# grep had /etc/passwd
[root@ab ~]# tree /home/
/home/
├── abc
├── hadoop
├── juan
├── mysql
├── tom
└── user01
[root@ab ~]# ll /home/
drwx------. 3 1010 1010 74 8月 16 16:20 hadoop
[root@m0 ~]# ansible group02 -m user -a 'name=tom state=absent remove=yes'
[root@ab ~]# ls /home/
abc hadoop juan mysql user01
cron模块
添加计划任务
[root@m0 ~]# ansible group02 -m cron -a 'name="test cron1" user=root job="/usr/sbin/ntpdate cn.ntp.org.cn" hour=2'
[root@ab ~]# crontab -l
#Ansible: test cron1
* 2 * * * /usr/sbin/ntpdate cn.ntp.org.cn
删除计划任务
[root@ab ~]# ansible group1 -m cron -a 'name="test cron1" state=absent'
yum模块
批量安装ntpdate
[root@m0 ~]# ansible group02 -m yum -a 'name=ntpdate state=present'
[root@ab ~]# yum list installed|grep ntpdate
ntpdate.x86_64 4.2.6p5-29.el7.centos.2 @base
[root@ab ~]# ntpdate cn.ntp.org.cn
16 Aug 16:36:38 ntpdate[4952]: adjust time server 203.107.6.88 offset 0.004739 sec
批量安装rsync
[root@m0 ~]# ansible group02 -m yum -a 'name=rsync state=present'
[root@ab ~]# yum list installed|grep rsync
rsync.x86_64 3.1.2-12.el7_9 @updates
service模块
关闭防火墙
[root@m0 ~]# ansible group02 -m service -a 'name=firewalld state=stopped enabled=false'
[root@ab ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon