一、Ansible时代

在人工运维时代,需要在多台设备上部署相同的服务、执行相同的命令;人工运维效率很低。
在早期时代运维人员结合ssh免密登录以及shell脚本来完成自动化的部署操作,但是不是每个人写的代码都是代码;所以迎来了自动化运维时代。
在自动化运维时代,许多开源自动化运维软件诞生了。其中saltstack、ansible都是基于python编写的可以进行二次开发。
自动化运维好处:

  1. 1. 提供工作效率,减少重复性的劳动力操作
  2. 1. 大大的减少人为出错的可能性
  3. 1. 数据化管理、数据化汇报、问题可追溯

二、Ansible软件架构

Ansible是一个同时管理多个远程主机的软件(必须是任意可以ssh登录的机器),通过ssh协议实现,管理节点(安装了ansible服务的机器)、被管理节点间的通信。只要是能通过ssh协议登录的主机,就可以完成ansible自动化部署操作。比如:批量文件分发、数据复制、数据修改,删除、自动化安装软件服务、批量服务启停、脚本化,自动批量服务部署。
Ansible是基于python语言开发的,主要由python的两个ssh模块处理,paramiko以及PyYAML模块;并且ansible无需安装客户端软件,管理简洁,使用yaml配置文件语法,功能强大,易于维护。特点如下:

  • 安装部署简单
  • 管理主机便捷,支持多台主机并行管理
  • 无需安装被管理节点的客户端,且无需占用其他端口,使用ssh默认端口即可。
  • 支持二次开发,使用非root权限也可以执行,减低系统权限。

Ansible是基于模块工作的,本身没有批量部署的能力。真正执行具有批量部署的是Ansible运行的模块,Ansible只是提供一种框架。
Anbsible - 图1

三、实践操作

1、安装

  1. 准备三台Linux机器;nginx(管理机器)、rsyncnfs(被管理机器)
  1. 1.配置管理机器,由于没有过多参数配置,所以采用yum安装
  2. [root@nginx ~]# yum install epel-release -y
  3. [root@nginx ~]# yum install ansible libselinux-python -y #安装
  4. 2.检查ansible软件的安装情况,查询配置文件,可执行命令,版本等情况
  5. [root@nginx ~]# rpm -ql ansible |grep -E '^/etc|^/usr/bin' #通过yum安装的一般都安装在/etc目录中
  6. [root@nginx ~]# ansible --version #查看一下版本信息
  7. ansible 2.9.17
  8. config file = /etc/ansible/ansible.cfg
  9. configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  10. ansible python module location = /usr/lib/python2.7/site-packages/ansible
  11. executable location = /usr/bin/ansible
  12. python version = 2.7.5 (default, Aug 4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
  13. 3.被管理机器安装ansible所需要的系统模块
  14. [root@rsync ~]# yum install epel-release libselinux-pyhthon -y
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。

Options:
  -a MODULE_ARGS, --args=MODULE_ARGS    
             #module arguments
             #指定执行模块使用的参数  
  --ask-vault-pass      
             #ask for vault password
             #加密playbook文件时提示输入密码
  -B SECONDS, --background=SECONDS
             #run asynchronously, failing after X seconds(default=N/A)
             #后台运行超时时间,异步运行,X秒之后失败
  -C, --check           
             #don't make any changes; instead, try to predict some of the changes that may occur
             #模拟执行,不会真正在机器上执行(查看执行会产生什么变化)
  -D, --diff            
             #when changing (small) files and templates, show the differences in those files; works great with --check
             #当更新的文件数及内容较少时,该选项可显示这些文件不同的地方,该选项结合-C用会有较好的效果
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS
             #set additional variables as key=value or YAML/JSON
             #执行命令时添加额外参数变量
  -f FORKS, --forks=FORKS
             #specify number of parallel processes to use(default=5)
             #并行任务数。FORKS被指定为一个整数,默认是5
  -h, --help            
             #show this help message and exit
             #打开帮助文档API
  -i INVENTORY, --inventory-file=INVENTORY
             #specify inventory host path(default=/etc/ansible/hosts) or comma separated host list.
             #指定要读取的Inventory文件
  -l SUBSET, --limit=SUBSET
             #further limit selected hosts to an additional pattern
             #限定执行的主机范围
  --list-hosts          
             #outputs a list of matching hosts; does not execute anything else
             #列出执行匹配到的主机,但并不会执行
  -m MODULE_NAME, --module-name=MODULE_NAME
             #module name to execute (default=command)
             #指定执行使用的模块,默认使用 command 模块
  -M MODULE_PATH, --module-path=MODULE_PATH
             #specify path(s) to module library (default=None)
             #要执行的模块的路径
  --new-vault-password-file=NEW_VAULT_PASSWORD_FILE
             #new vault password file for rekey
             #    
  -o, --one-line        
             #condense output
             #压缩输出,摘要输出.尝试一切都在一行上输出
  --output=OUTPUT_FILE  
             #output file name for encrypt or decrypt; use - for stdout
             #
  -P POLL_INTERVAL, --poll=POLL_INTERVAL
             #set the poll interval if using -B (default=15)
             #设置轮询间隔,每隔数秒。需要- B
  --syntax-check        
             #perform a syntax check on the playbook, but do not execute it
             #检查Playbook中的语法书写
  -t TREE, --tree=TREE  
             #log output to this directory
             #将日志内容保存在该输出目录,结果保存在一个文件中在每台主机上
  --vault-password-file=VAULT_PASSWORD_FILE
             #vault password file
             #
  -v, --verbose         
             #verbose mode (-vvv for more, -vvvv to enable connection debugging)
             #执行详细输出
  --version             
             #show program's version number and exit
             #显示版本


  Connection Options:
    control as whom and how to connect to hosts


    -k, --ask-pass      
             #ask for connection password
             #
    --private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE
             #use this file to authenticate the connection
             #
    -u REMOTE_USER, --user=REMOTE_USER
             #connect as this user (default=None)
             #指定远程主机以USERNAME运行命令
    -c CONNECTION, --connection=CONNECTION
             #connection type to use (default=smart)
             #指定连接方式,可用选项paramiko (SSH)、ssh、local,local方式常用于crontab和kickstarts
    -T TIMEOUT, --timeout=TIMEOUT
             #override the connection timeout in seconds(default=10)
             #SSH连接超时时间设定,默认10s
    --ssh-common-args=SSH_COMMON_ARGS
             #specify common arguments to pass to sftp/scp/ssh (e.g.ProxyCommand)
             #
    --sftp-extra-args=SFTP_EXTRA_ARGS
             #specify extra arguments to pass to sftp only (e.g. -f, -l)
             #
    --scp-extra-args=SCP_EXTRA_ARGS
             #specify extra arguments to pass to scp only (e.g. -l)
             #
    --ssh-extra-args=SSH_EXTRA_ARGS
             #specify extra arguments to pass to ssh only (e.g. -R)
             #


  Privilege Escalation Options:
    control how and which user you become as on target hosts


    -s, --sudo          
             #run operations with sudo (nopasswd) (deprecated, use become)
             #相当于Linux系统下的sudo命令
    -U SUDO_USER, --sudo-user=SUDO_USER
             #desired sudo user (default=root) (deprecated, use become)
             #使用sudo,相当于Linux下的sudo命令
    -S, --su            
             #run operations with su (deprecated, use become)
             #
    -R SU_USER, --su-user=SU_USER
             #run operations with su as this user (default=root) (deprecated, use become)
             #
   -b, --become        
             #run operations with become (does not imply password prompting)
             #
    --become-method=BECOME_METHOD
             #privilege escalation method to use (default=sudo),valid choices: [ sudo | su | pbrun | pfexec | doas |dzdo | ksu | runas ]
             #
    --become-user=BECOME_USER
             #run operations as this user (default=root)
             #
    --ask-sudo-pass     
             #ask for sudo password (deprecated, use become)
             #
    --ask-su-pass       
             #ask for su password (deprecated, use become)
             #
    -K, --ask-become-pass
             #ask for privilege escalation password
             #

2、管理方式

ansible批量管理主机的方式主要有两种:传统的输入ssh密码验证、密钥管理

配置ansible的配置文件,添加被管理的主机的IP地址或者主界面
1.备份现有的配置文件
[root@nginx ~]# cp /etc/ansible/hosts{,.ori}            #快捷备份

2.在hosts文件中添加被管理机器的IP地址信息
[root@nginx ~]# tail -3 /etc/ansible/hosts
[test-ansible]
192.168.0.175
192.168.0.174

3.ssh密码认证批量管理主机
ansible是直接利用Linux本地的ssh服务,来进行远程管理操作,一般情况下ssh都是默认开启的无需配置
//-m    指定功能模块,默认就是command模块    //-a    告诉模块需要执行的参数        //-k    询问密码验证    //-u    指定运行的用户
[root@nginx ~]# ansible test-ansible -m command -a 'hostname' -k -u root    #向被管理主机发送执行命令并返回给服务器
SSH password:
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to
see details
192.168.0.175 | CHANGED | rc=0 >>
rsync
192.168.0.174 | CHANGED | rc=0 >>
nfs

报错如下,需要手动先ssh链接一次被管理机器让该 ~/.ssh/known_hosts下存在被管理机器的密钥信息
Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host.

4.免密操作,在执行ansible操作时无需输入密码(配置ssh免密登录或者修改/etc/ansible/hosts文件)
#可以在/etc/ansible/hosts中,定义好密码即可,实现快速认证,远程管理主机,配置如下:
[root@nginx ~]# !tail
tail -3 /etc/ansible/hosts
[test-ansible]
192.168.0.175 ansible_user=root ansible_ssh_pass=123456            #ip地址、端口默认是22(ansible_port=22)、用户、密码
192.168.0.174 ansible_user=root ansible_ssh_pass=123456
#测试运行
[root@nginx ~]# ansible test-ansible -m command -a 'hostname'        #无需添加后面部分参数
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to
see details
192.168.0.174 | CHANGED | rc=0 >>
nfs
192.168.0.175 | CHANGED | rc=0 >>
rsync
针对ssh免密登录,机器少可以通过ssh-copy-id上传,机器多就走脚本如下:
1.脚本配置
[root@nginx myscripts]# cat ssh_key_send.sh
#!/bin/bash
rm -rf ~/.ssh/id_rsa*
ssh-keygen -f ~/.ssh/id_rsa -P "" > /dev/null 2>&1
SSH_Pass=123456
Key_Path=~/.ssh/id_rsa.pub
for ip in 174 175
do
    sshpass -p$SSH_Pass ssh-copy-id -i $Key_Path "-o StrictHostKeyChecking=no" 192.168.0.$ip
done
# 非交互式分发公钥命令需要用sshpass指定SSH密码,通过-o StrictHostKeyChecking=no 跳过SSH连接确认信息
# 需要注意密码和循环条件

[root@nginx myscripts]# sh ssh_key_send.sh        #运行脚本批量免密                
[root@nginx myscripts]# ssh -o ' StrictHostKeyChecking=no' '192.168.0.175'        #测试免密登录
[root@nginx myscripts]# ansible test-ansible -a 'ifconfig'            #测试ansible执行命令

四、ansible模式与命令

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

  • 利用ansible的纯命令实现的批量管理,ad-doc模式
  • 利用ansible的playbook剧本来实现批量管理,playbook剧本模式

ansible的ad-doc模式是ansible的命令行模式,也就是处理一些临时的简单的任务;如临时查看被管理机器的内存、CPU等
ansible的playbook模式是针对比较具体的,且比较大的任务,需要提前写好剧本。

ad-hoc命令行解析:
[root@nginx ~]# ansible-doc -l         #查看你ansible的所有的模块信息
[root@nginx ~]# ansible-doc -s command            #查看某个模块的用法

五、ansible模块

命令操作的模块:command模块、shell模块、script模块

1、command模块

在远处的主机上执行一个命令,通过ansible-doc -s command 查看改模块支持的参数

  • chdir 在执行命令之前,先通过cd进入该参数指定的目录
  • creates 在创建一个文件之前,判断该文件是否存在;存在则跳过前面的动作,不存在在执行前面的动作
  • free-form 该参数可以输入任何的系统命令,实现远程执行和管理
  • removes 定义一个文件是否存在,如果存在了则执行前面的动作,如果不存在则跳过动作

command模块是ansible的默认基本模块,也可以省略不写;但是要注意是该模块时不能出现变量$name,或者特殊符号(<>|;)如果需要用到变量请使用shell模块

[root@nginx ~]# ansible test-ansible -a 'uptime'        #获取机器的负载情况
[root@nginx ~]# ansible test-ansible -a 'pwd chdir=/tmp'        #进入/tmp目录,打印路径,利用chdir在进入/tmp目录

[root@nginx ~]# ansible 192.168.0.174 -m command -a 'pwd creates=/xxx'        #在执行命令之前判断xxx文件是否存在,存在则不执行,不存在则执行
192.168.0.174 | CHANGED | rc=0 >>
/root
[root@nginx ~]# ansible 192.168.0.174 -m command -a 'pwd creates=/opt'        #存在不执行,removes与之相反
192.168.0.174 | SUCCESS | rc=0 >>
skipped, since /opt exists

2、shell模块

一般在远程的机器上执行复杂的命令,支持变量和特殊符号;参数和command的参数解释一致。

[root@nginx ~]# ansible ylin -m shell -a 'ps -ef|grep 'vim''    #通过shell命令查询vim进程信息    
[root@nginx ~]# ansible ylin -m shell -a 'echo 'love' >> /opt/love.txt'        #ehco也好使

3、script模块

把管理节点机器上的脚本远程的传输到被管理节点上去执行;参数和解释与上面类似。

[root@nginx ~]# ansible ylin -m script -a '/myscripts/host.sh' #需要在管理机器上有该脚本,有执行权限才行

文件操作的模块:copy模块

4、copy模块

复制文件到远程的主机,只能推送不能拉去数据。

1.创建拷贝之后文件的属主、属组
[root@nginx ~]# ansible ylin  -m shell -a "useradd ylin && id ylin"    

2、拷贝文件
[root@nginx ~]# ansible ylin -m copy -a "src=/root/ylin.txt dest=/root/ owner=ylin group=ylin mode=0666 backup=yes"
//owner    拷贝之后文件的属主    //group    拷贝之后文件的属组    //mode 拷贝之后文件的权限信息    //backup    拷贝中如果存在目标文件,先备份在拷贝

3.修改被管理主机上文件的内容,覆盖修改
[root@nginx ~]# ansible ylin -m copy -a 'content='evol' dest=/root/ylin.txt backup=yes'

5、file模块

创建、修改文件,修改目录、文件的属性,参数如下:group、owner、mode、path、src、dest
state参数:

  • file 如果目标文件不存在,那么不会创建该文件
  • touch 如果文件不存在,则创建一个新的文件;如果文件存在,修改文件最后的修改时间
  • directory 如果目录不存在,则创建目录
  • link 用于创建软连接
  • absent 删除目录,文件或者取消连接
    ``` 1.远程批量创建文件夹 [root@nginx ~]# ansible ylin -m file -a “dest=/root/dir/ state=directory” #在创建的时候如果没有指定参数,默认采取如下 192.168.43.177 | CHANGED => { “ansible_facts”: { “discovered_interpreter_python”: “/usr/bin/python” }, “changed”: true, “gid”: 0, “group”: “root”, “mode”: “0755”, “owner”: “root”, “path”: “/root/dir/“, “secontext”: “unconfined_u:object_r:admin_home_t:s0”, “size”: 6, “state”: “directory”, “uid”: 0 }

2.远程创建文件的操作,修改属组信息 [root@nginx ~]# ansible ylin -m file -a “dest=/root/ylin.txt group=root state=touch”

3.远程创建软连接 [root@nginx ~]# ansible ylin -m file -a “src=/etc/passwd dest=/root/psd state=link” #创建软连接时,必须要指定src目录和dest目录

<a name="EmN65"></a>
#### 6、yum模块
state参数:installed、remove、absent(卸载)、latest(升级、下载更新    )

1.批量通过yum安装wget [root@nginx ~]# ansible ylin -m yum -a “name=wget state=installed” #name=软件的名字 state=安装(installed)还是卸载(remove|absent)

<a name="fAoHk"></a>
#### 7、服务管理模块
通过ansible yum模块安装的软件,可以通过ansible远程批量化服务管理的模块,进行批量的启停操作。

1.远程查看crond服务是否正常 [root@nginx ~]# ansible ylin -m shell -a “systemctl status crond” |grep Active Active: active (running) since 六 2021-02-27 06:26:13 CST; 8min ago Active: active (running) since 六 2021-02-27 06:26:10 CST; 8min ago

2.检查crond服务是否配置了开启自启 [root@nginx ~]# ansible ylin -m shell -a “systemctl list-unit-files” |grep crond crond.service enabled crond.service enabled

3.通过系统模块重启crond服务 [root@nginx ~]# ansible ylin -m systemd -a “name=crond state=restarted” #restarted、start、stopped 、reloaded,enabled=yes开机自启

<a name="hGdQE"></a>
#### 8、cron模块
cron模块主要是管理Linux的定时任务模块,分 时 日 月 周

1.添加定时任务,没五分钟进行时间同步 [root@nginx ~]# ansible ylin -m cron -a “name=update_cron job=’/usr/bin/ntpdate ntp.aliyun.com > /dev/null 2>&1’ minute=*/5”

将正确和错误的信息都输入到/dev/null中,时间配置minute,hour,day,mouth,weekday

2.查看定时任务是否配置成功 [root@nginx ~]# ansible ylin -m shell -a “crontab -l” 192.168.43.8 | CHANGED | rc=0 >>

Ansible: update_cron

/5 * /usr/bin/ntpdate ntp.aliyun.com > /dev/null 2>&1 192.168.43.177 | CHANGED | rc=0 >>

Ansible: update_cron

/5 * /usr/bin/ntpdate ntp.aliyun.com > /dev/null 2>&1

3.删除定时任务 [root@nginx ~]# ansible ylin -m cron -a “name=update_cron state=absent” #删除时只能删除ansible创建的定时任务

<a name="f67G4"></a>
### 六、playbook剧本
剧本编写复杂的运行环境,ansible需要编写playbook剧本需要遵循yaml语法。<br />ansible的剧本由两个最基本的部分组成:

   - hosts定义被管理的主机列表信息
   - tasks关键词定义的被管理主机需要执行的动作

yaml基本语法:大小写敏感、使用缩进表示层级关系、禁止使用tab键、相同元素只需要对齐即可。<br />yaml语法支持的数据结构:对象(key: value)、数组、

使用剧本批量安装nginx服务 [root@nginx ansible]# cat my_first.yaml

install nginx yaml and copy

  • hosts: all #定义操作的范围可以是all、某个模块的主机、IP地址、主机名(需要能DNS解析) tasks: #定义任务的集合
    - name: install nginx service                    #第一个任务的名字
      yum: name=nginx state=installed            #第一个任务的模块:语法
    - name: copy /root/yy.txt to all            #这种方式也可以
      copy: 
          src:/root/yy.txt 
        dest:/root/
    
在ansible程序中,加载模块的功能可以直接使用ansible adhoc命令去执行;加载剧本的功能,可以使用ansible-playbook命令去执行。

[root@nginx ~]# ansible-playbook /etc/ansible/my_first.yaml -C #模拟执行剧本 [root@nginx ~]# ansible-playbook /etc/ansible/my_first.yaml —syntax-check #语法检测 [root@nginx ~]# ansible-playbook /etc/ansible/my_first.yaml —list-hosts #查看影响的机器 [root@nginx ~]# ansible-playbook /etc/ansible/my_first.yaml —verbose #安装查看进度 ```