MENU

自动化运维工具Ansible入门

2017 年 09 月 04 日 • 杂乱文章

先介绍一下,Ansible是什么。Ansible是一款自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible的应用场景是在服务器不超过200台的情况下,如果超过200台,ansible驾驭起来会有点吃力,如果超了200建议使用Saltstack,现在来玩玩Ansible吧,是一些入门级别的东西,包括批量执行命令,批量传文件,批量执行脚本,批量yum安装软件,批量服务管理,批量编写计划任务,及Ansible剧本功能,这些功能玩熟了就可以轻松很多了,哈哈哈,开撸。

先说一下本文用到的环境吧,一共6台服务器,包括一个Ansible控制端,其他5个都是受控端,没必要弄太多,用的是本地的测试服务器,操作系统全部采用Centos6.9,对应关系如下。

控制端
Ansible 192.168.1.213 ssh端口22
受控端
主机名:mysql-master IP:192.168.1.166 ssh端口22
主机名:mysql-slave IP:192.168.1.251 ssh端口22
主机名:openvpn IP:192.168.1.141 ssh端口22
主机名:zentao IP:192.168.1.208 ssh端口22
主机名:zookeeper2IP:192.168.1.248 ssh端口22

服务端配置SSH

先不要着急安装Ansible软件,因为Ansible是基于ssh协议,来管理服务器,现在要做的是让控制端免密码登陆到受控端,需要用到秘钥,首先在控制端生成秘钥,确保控制端可以不用密码登录到受控端,具体控制端操作如下。

1.创建秘钥对
[root@ansible ~]# ssh-keygen -t dsa -f /root/.ssh/id_dsa -P ""
2.分发公钥
[root@ansible ~]# ssh-copy-id -i ~/.ssh/id_dsa.pub root@192.168.1.166
3.测试远程执行命令
[root@ansible ~]# ssh 192.168.1.166 "hostname"
mysql-master

因为我的ssh服务并没有修改过,一切都是默认的,如果你改端口了可以使用一下命令进行分发

[root@ansible ~]# ssh-copy-id -i ~/.ssh/id_dsa.pub "-p 24680 root@192.168.1.213"

在刚刚分发完公钥的服务器看一下.ssh/authorized_keys文件,会有控制端的公钥。

批量分发公钥

如果受控端很多,一个一个的分发会很麻烦,可以批量进行分发公钥,借助脚本+sshpass命令即可。前提是你服务器密码必须一样,否则用for循环会有问题,如果yum找不到该软件包,请使用阿里云的常规源及扩展源。

1.安装sshpass命令
[root@ansible ~]# yum -y install sshpass
2.编写脚本
#!/bin/bash
rm -rf /root/.ssh/*
ssh-keygen -t dsa -f /root/.ssh/id_dsa -P "" &>/dev/null

for ip in 166 251 141 208 248
  do
    sshpass -pSowhat? ssh-copy-id -i /root/.ssh/id_dsa.pub "-o StrictHostKeyChecking=no root@192.168.1."$ip"" >/dev/null 2>&1
done

在生成之前先把.ssh目录清空,否则会抛错,需要主机的两个点,一是密码需要换成自己的,for循环的变量需要该一下即可,执行这个脚本。

3.检查是否分发成功

不用一个一个的去查,写个简单的for循环脚本即可,这个是又改过的,加了点echo的东西,下面的图片可能和这个脚本实际输出不符,忽略。

#!/bin/bash
for ip in 166 251 141 208 248
  do
    echo ======================192.168.1.$ip=================
       ssh 192.168.1.$ip $1
    echo ====================================================    
  echo ""
done

我执行一下hostname命令,五台受控端都可以看到,说明木有问题。这也是一个最简单的批量管理脚本了。

[root@ansible ~]# sh check.sh hostname
mysql-master
mysql-slave
openvpn
zentao
zookeeper2

其实也可以使用密码进行管理,但是建议还是使用秘钥,如果使用密码,请修改hosts文件,主机IP后添加上用户名密码信息,必须安装sshpass软件包,栗子:

192.168.1.208 ansible_ssh_user=root ansible_ssh_pass=Sowhat?

安装Ansible服务端及客户端软件

1.控制端安装
[root@ansible ~]# yum -y install ansible

2.更换受控端yum源

我现在不敢确定我的受控端是不是已经配置好yum源了,保险起见先配置yum源吧,也不用一台一台的去弄了,用刚刚写的那个脚本就可以了。

[root@ansible ~]# sh check.sh "mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup"
[root@ansible ~]# sh check.sh "curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo"
[root@ansible ~]# sh check.sh "mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup"
[root@ansible ~]# sh check.sh "mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup"
[root@ansible ~]# sh check.sh "wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo"
3.受控端安装软件包

先看一下哈,要安装的现在有没有。

木有,装一下吧,这个脚本安装是一个一个的装,并不是所有服务器同时安装,最后看一下结果就阔以了。

[root@ansible ~]# sh check.sh "yum -y install libselinux-python"

4.添加要Ansible要管理的主机
[root@ansible ~]# vim /etc/ansible/hosts 
[rj-bai]
192.168.1.166
192.168.1.251
192.168.1.141
192.168.1.208
192.168.1.248

rj-bai为模块名,下面是要管理的主机ip地址,模块名随便写,现在Ansible就可以使用了,下面会介绍一些模块,最后,看一下python-chardet的软件包版本是不是 >= 3.0.2, < 3.1.0,如果不是,请更新一下。命令如下。检查通过后就可以使用Ansible了。

[root@ansible ~]# wget https://pypi.python.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz#md5=7dd1ba7f9c77e32351b0a0cfacf4055c
[root@ansible ~]# tar zxf chardet-3.0.4.tar.gz
[root@ansible chardet-3.0.4]# pip install chardet --upgrade

Ansible命令模块-command(默认模块)

此为Ansible的命令模块,也是默认模块,下面通过这条命令执行一条命令。查看系统版本信息

实例
[root@ansible ~]# ansible rj-bai -m command -a "lsb_release -a"

返回文字的颜色在这里说一下,执行后没有变化返回绿色,配置发生变化返回黄色,出现异常返回红色,这个模块可以执行绝大多数命令,有的涉及到管道之类的他就不支持了,一会再说,现在可以看到除了141都没有安装这个命令,下面安装一下。

[root@ansible ~]# ansible rj-bai -m command -a "yum -y install redhat-lsb"

用ansible执行命令是全部服务器同时进行,可以去看进程,这里我就不截被控端的图了。只看最后返回的结果,下图可以看到所有的都安装成功了。

参数

-m MODULE_NAME相对应的模块被执行,默认command模块,-m后解模块名
-a MODULE_ARFS 模块信息参数,-a后代表要执行的命令,也可以写一个IP

只针对某一个主机执行

[root@ansible ~]# ansible 192.168.1.166 -m command -a "lsb_release -a"

在这里也直接说了,我刚写hosts文件,只是写了一个模块,名字是rj-bai,如果有多个模块,同时全部要执行命令,把模块名换为all即可。

Ansible复制模块-copy

也就是批量传输文件,将控制端的文件批量传给受控端,栗子,将本地/root/nginx.1.12.1.tar.gz传到受控端的/usr/local/src目录下。

[root@ansible ~]# ansible rj-bai -m copy -a "src=/root/nginx-1.12.1.tar.gz dest=/usr/local/src/nginx-1.12.1.tar.gz"

141是绿的,说明这个文件在src目录下已经存在了,看一下都在不在。

[root@ansible ~]# ansible rj-bai -m command -a "ls /usr/local/src/nginx-1.12.1.tar.gz"

参数。
backup在替换之前先备份
owner 指定文件属主
group 指定文件属组
mode 指定文件权限
实例

重新传nginx.1.12.1.tar.gz文件,将文件属主组改为rj-bai,权限改为755,看上图现在是属主属组为root,权限是644,开撸。

1.添加用户,并制定uid及gid,其实不用指定uid及gid

[root@ansible ~]# ansible rj-bai -m command -a "useradd -u 888 rj-bai"

2.重新传送文件,并制定以上参数

[root@ansible ~]# ansible rj-bai -m copy -a "src=/root/nginx-1.12.1.tar.gz dest=/usr/local/src/nginx-1.12.1.tar.gz backup=yes  owner=rj-bai group=rj-bai mode=755"

3.最后看结果即可,可以和上面的对比一下。

替换之前备份

备份的条件是在文件发生变化后才会备份,是在远程主机上进行备份,而不是在本地,试试,先创建文件

[root@ansible ~]# ansible rj-bai -m command -a "mkdir /tmp/test"
[root@ansible ~]# ansible rj-bai -m copy -a "src=/etc/hosts dest=/tmp/test/hosts"
[root@ansible ~]# ansible rj-bai -m command -a "ls /tmp/test"

修改文件,不要纠结那个shell是什么鬼,马上就说了

[root@ansible ~]# ansible rj-bai -m shell -a " > /tmp/test/hosts"
[root@ansible ~]# ansible rj-bai -m copy -a "src=/etc/hosts dest=/tmp/test/hosts backup=yes"

[root@ansible ~]# ansible 192.168.1.208 -m command -a "cat /tmp/test/hosts.27881.2017-09-04@15:54:12~"
192.168.1.208 | SUCCESS | rc=0 >>

事实证明也可以。copy模块结束。

修改文件属性信息-file模块

这么模块可以用来操作文件或目录,像是修改属主属组,创建文件,删除文件。

实例

将/etc/hosts文件软连接到/tmp目录

[root@m01 ~]# ansible rj-bai -m file -a "src=/etc/hosts dest=/tmp/hosts state=link"
参数。
state
directory 如果目录不存在就创建
file 如果文件不存在,也不会被创建
link 创建软连接
hard 创建硬链接
touch 如果文件不存在,汇创建新文件,如果存在更新时间戳
absent 删除目录文件或取消连接文件
force 强制创建软连接,如果链接存在,先取消再创建,选项yes&no
group 定义文件&文件夹的属组
mode 定义文件&文件夹的权限
owner 定义文件&文件夹的属主
path 定义文件&目录的路径
recurse 递归设置文件的属性,对目录有效

实例
创建/rj-bai目录,属主组为rj-bai,权限为700

[root@ansible ~]# ansible rj-bai -m file -a "path=/rj-bai state=directory owner=rj-bai group=rj-bai mode=700"
[root@ansible ~]# ansible rj-bai -m shell -a "ls -ld /rj-bai"
192.168.1.248 | SUCCESS | rc=0 >>
drwx------ 2 rj-bai rj-bai 4096 Sep  5 06:49 /rj-bai

删除rj-bai目录

[root@ansible ~]# ansible rj-bai -m file -a "path=/rj-bai state=absent"
[root@ansible ~]# ansible rj-bai -m shell -a "ls -ld /rj-bai"
192.168.1.208 | FAILED | rc=2 >>
ls: cannot access /rj-bai: No such file or directory

就这些吧,这个比较简单。

shell模块,远程执行脚本

这个模块分为两个,一个是shell,一个是script,下面会分别介绍

1.shell模块

这个模块需要将要运行的脚本传到受控端才可以执行,就用上面所提到的copy模块完成传送,注意,传送的时候脚本要加上x权限,否则会爆出权限拒绝。

[root@ansible ~]# cat ./sh/echo.sh 
#!/bin/bash
echo "在人间有谁活着不像是一场鲶鱼"
[root@ansible ~]# ansible rj-bai -m copy -a "src=/root/sh/echo.sh dest=/tmp/echo.sh mode=755"
[root@ansible ~]# ansible rj-bai -m command -a "ls -l /tmp/echo.sh"

已经传送过去了,开始执行,看最终效果。

其实这个shell模块除了执行脚本还可执行命令,command模块执行命令,如果命令里带有管道之类的就会有问题,看下图,所以建议执行命令使用shell模块即可。

2.script模块

他的用法和shell一样,但是不能执行命令,他的优点是执行脚本不需要将脚本文件复制到远程服务器,就可以将脚本的执行过程在远程服务器上进行执行,看一下就知道了。

[root@ansible sh]# cat script.sh 
#!/bin/bash
echo "一曲肝肠断,何处觅知音"
[root@ansible sh]# ansible rj-bai -m script -a "/root/sh/script.sh"

总结一下script模块与shell的区别,shell需要将脚本文件传送到远程服务器,然后再执行脚本,注意要有x权限,shell模块也可以执行命令,script模块不需要将脚本复制到远程服务器,就可以将脚本的执行过程在远程服务器上进行执行,远程执行脚本模块结束。

yum安装模块-yum

实例

这个就比较简单了,就装一个httpd吧,好像除了141全都没装,现在批量装一下。

[root@ansible ~]# ansible rj-bai -m yum -a "name=httpd state=installed"
[root@ansible ~]# ansible rj-bai -m shell -a "service httpd status"
[root@ansible ~]# ansible rj-bai -m shell -a "chkconfig --list | grep httpd"

现在已经安装好了,并且不是启动状态,下一个模块就是服务批量管理,那这个试试,installed表示安装,removed表示卸载,具体的用ansible-doc -s 加模块名看帮助吧,yum模块结束。

批量服务管理模块-service

实例

现在要批量启动httpd服务,操作如下。

[root@ansible ~]# ansible rj-bai -m service -a "name=httpd state=started enabled=no"

208的nginx跑着禅道,也有访问,所以没把它关了,其他四个启动正常。

参数
name服务名字,必须是能在chkconfig里面找到的
state 要执行的状态,包含running,started,stopped,restarted,reloaded
enabled 是否可以开机启动no表示禁止
现在httpd用不到了,删了吧,今天就写到这里吧,有点晕。
[root@ansible ~]# ansible rj-bai -m yum -a "name=httpd state=removed"

计划任务模块-cron

实例

这个是针对用户添加的计划任务,而不是系统计划任务,下面添加一个实例,每天的零点零分执行/tmp/下的echo.sh脚本,这个是昨天用copy模块传过去的。

[root@ansible ~]# ansible rj-bai -m cron -a 'name="echo" minute=0 hour=0 job="/bin/bash /tmp/echo.sh &>/dev/null"'

说明:name计划任务名称,分钟使用minute表示,小时用hour表示,job定义计划任务要做的事情。

注释或删除计划任务

建议不要删除,要进行注释,而且ansibile只能管理它添加的计划任务,你手动添加的ansible是无法管理的。下面是注释的实例,如果要开启将disabled改为no

[root@ansible ~]# ansible rj-bai -m cron -a 'name="echo" minute=0 hour=0 job="/bin/bash /tmp/echo.sh &>/dev/null" disabled=yes'

如果要删除请执行这个。

[root@ansible ~]# ansible rj-bai -m cron -a 'name="echo" minute=0 hour=0 job="/bin/bash /tmp/echo.sh &>/dev/null" state=absent'

参数
minute分钟时间信息,编写方式0-59、*、*/2等
hour 小时时间信息,编写方式0-23、* 、*/2等
day 日期时间信息,编写方式1-31、* 、*/2等
month 月份时间信息,编写方式1-12,*、*/2等
weekday 星期时间信息,编写方式0代表周日,6代表周六
job执行响应的操作或命令
name 计划任务描述信息
state 删除计划任务选项
disabled 开启或关闭计划任务,只影响开启状态的条目
user 指定修改与编写定时任务的用户信息

mount 模块

因为今天要批量挂载nfs,所以查了一下mount模块,记录一下

参数
fstype挂载文件的类型
name挂载点
opts传给mount的参数
src挂载源
statepresent 只处理fstab中的配置
stateabsent 删除挂载点
statemounted 自动挂载
stateumounted 卸载
实例,挂载nfs文件系统

在挂载之前需要通过yum模块装一下nfs的两个包,不多BB了

[root@ansible ~]# ansible server -m mount -a "name=/nfs-server src=172.24.89.240:/nfs-server fstype=nfs state=mounted"

20180718121102.png

systemd模块

这个也是管理服务的模块,但是是在centos7上用的,在centos6上用的是service,今天用到了,记录一下。
栗子:启动服务zabbix-agent,并加入开机启动

[root@ansible ~]# ansible server -m systemd -a "state=started name=zabbix-agent enabled=yes"
一些常用参数
参数
daemon_reload运行daemon-reload
name服务的名称
enabledyes or no,是否开机启动
state要执行的操作,reloaded,restarted,started,stopped

一些基础的模块及使用到这里就介绍完了。下面介绍一下ansible的剧本功能。

剧本功能

实例1:计划任务

这个所谓的剧本其实就是类似shell脚本,我要干嘛写到一个文件里执行即可,很适合批量安装服务,综合上面所介绍的一些模块,其实现在已经可以批量搭建服务了,一会就来一个练练手,先说一下剧本的基础语法吧,给个模板,注意空格,不要用table键,这个语法要求很严格的,如果用tables键了,会提示语法不正确,很蛋疼,编写剧本使用的是yml语法。

#play-book
- hosts: rj-bai
  tasks:
    - name: cron task
      cron: name=rj-bai minute=0 hour=1 job='/bin/bash /tmp/echo.sh  /dev/null'
    - name: shell task
      shell: echo "$HOSTNAME" >>/tmp/hostname.txt

第一行为注释,host那行为那个组要执行这个剧本,tasks代表要做的事情,-name为输出提示信息,cron代表使用计划任务模块,冒号后只写要做什么就可以了,不要像之前那样ansible rj-bai -m cron -a 这样写了,全部的都是,用哪个模块把模块名写上就可以了,上面写的就是添加一个计划任务,然后echo主机名到/tmp/hostname.txt文件,执行之前要检查一下语法是否正确,模拟执行一下。

检查语法是否正确

[root@ansible ~]# ansible-playbook --syntax-check playbook.yml 

playbook: playbook.yml

如果正确会看到上面的结果

模拟执行

模拟执行只是测试能不能正常执行,并不会对受控端进行操作。

[root@ansible ~]# ansible-playbook -C playbook.yml

没看到红的说明没有问题,可以继续了

开始执行

下面开始执行,看最终的结果,剧本里写的两个东西全部执行成功。卧槽我才发现计划任务脚本后面忘加>>了,忽略,下面就用这个剧本功能去搞点事情吧,搭个服务出来。

[root@ansible ~]# ansible-playbook playbook.yml

使用剧本功能搭建服务

实例2:批量安装tomcat8.5

就批量安装tomcat8.5吧,把248,及208去了,他俩之前已经配置好java环境变量及tomcat了,暂时还不能动,就用剩下的三个吧,新建一个模块,名字是tomcat

1.添加模块

[root@ansible ~]# vim /etc/ansible/hosts
[tomcat]
192.168.1.166
192.168.1.251
192.168.1.141

2.编写剧本

将jdk,tomcat8.5软件包上传到控制端,建议将修改好的配置文件也传进来,远程传过去就用了,我传的包含tomcat软件包,jdk,server.xml配置文件及catalina.sh启动脚本,因为配置java环境变量的参数用shell写会有问题,所以也是用文本方式传过去,然后追加到profile文件,大概就这么多吧,我软件存放位置为/root/soft,开撸。

#install tomcat
- hosts: tomcat
  tasks:
    - name: transfer jdk1.8
      copy: src=/root/soft/jdk-8u131-linux-x64.tar.gz dest=/usr/local/src/
    - name: transfer tomcat8.5
      copy: src=/root/soft/apache-tomcat-8.5.15.tar.gz dest=/usr/local/src/
    - name: transfer java.txt
      copy: src=/root/soft/java.txt dest=/usr/local/src/
    - name: Unzip jdk1.8
      shell: tar zxf /usr/local/src/jdk-8u131-linux-x64.tar.gz -C /usr/local/
    - name: revise profile file
      shell: cat /usr/local/src/java.txt >> /etc/profile
    - name: Unzip tomcat8.5
      shell: tar zxf /usr/local/src/apache-tomcat-8.5.15.tar.gz -C /usr/local/
    - name: mv tomcat
      shell: mv /usr/local/apache-tomcat-8.5.15 /usr/local/tomcat
    - name: transfer server.xml
      copy: src=/root/soft/server.xml dest=/usr/local/tomcat/conf/server.xml backup=yes
    - name: transfer catalina.sh
      copy: src=/root/soft/catalina.sh dest=/usr/local/tomcat/bin/catalina.sh backup=yes mode=755
    - name: start tomcat
      shell: nohup /usr/local/tomcat/bin/catalina.sh start 

简单的写了一下,大概就是这样,试着测试执行一下,没有出错。

[root@ansible ~]# ansible-playbook -C tomcat.yml

最后开始正式执行,先看看现在有没有tomcat运行着。

[root@ansible ~]# ansible tomcat -m shell -a "ps aux | grep tomcat | grep -v grep"
[root@ansible ~]# ansible tomcat -m shell -a "netstat -lntp | grep 8080"

3.执行剧本

[root@ansible ~]# ansible-playbook tomcat.yml
[root@ansible ~]# ansible tomcat -m shell -a "netstat -lntp | grep 8080"
[root@ansible ~]# ansible tomcat -m shell -a "ps aux | grep tomcat | grep -v grep"

完美,全部正常启动,试试能不能正常访问到

[root@ansible ~]# for ip in 141 166 251
> do
>   curl -I 192.168.1.$ip:8080
> done

全部返回200,可以正常访问

说一下在启动tomcat时候遇到的问题,一个是找不到$JAVA_HOME,解决办法就是改一下启动脚本,加一条东西。

[root@ansible ~]# vim soft/catalina.sh
source /etc/profile

还有就是执行启动脚本在要加上nohup,别的就没啥了。大概就这些,以后有再加。。。。

最后编辑于: 2018 年 12 月 10 日
返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码