跟我学Devops之工具篇(Ansbile)


声明:这是我在大学毕业后进入第一家互联网工作学习的内容


我从自动化运维入门开始,第一个学习的自动化工具就是ansible。

百度解释

ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。

ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:

  • 连接插件connection plugins:负责和被监控端实现通信;
  • host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
  • 各种模块核心模块、command模块、自定义模块;
  • 借助于插件完成记录日志邮件等功能;
  • playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。

个人理解

用通俗的话来解释,ansbile可以分组,每个组里添加目标机器ip,通过密钥或者密码连接成功组里的机器后,你就可以用ansbile命令操作每个组的机器了。对于大规模的机器群来说,ansbile是必不可少的运维工具。

ansbile的特点:

  • 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;
  • 默认使用SSH协议对设备进行管理;
  • 有大量常规运维操作模块,可实现日常绝大部分操作;
  • 配置简单、功能强大、扩展性强;
  • 支持API及自定义模块,可通过Python轻松扩展;
  • 通过Playbooks来定制强大的配置、状态管理;
  • 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
  • 提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。

当然你可能不需要用到ansbile所有功能,以下是我认为实战中ansbile用的最爽的几个点:

  • 配置管理:将配置文件批量放到你指定组的机器某一目录下,或者指定路径后一次性修改指定组的机器该路径下的配置文件
  • 应用部署:如java应用编译好成jar包,ansbile直接将jar包分发到指定组的机器某一目录下,执行启动命令
  • 滚动发布:有人可能会问了,ansible也能滚动发布?其实只要了解滚动发布的原理,用ansbile一样可以做到。例如在生产环境利用负载均衡分发流量到底层存在多个运行java应用的实例中,那么滚动更新就是先控制一台组里的机器,杀进程,启动新的jar包,监控jar包启动成功等,如果这台组里的机器成功,则让后续组里的机器继续更新,否则终止。

开始ansible之旅

安装ansible

两种安装方式都行

  • pip安装

yum install python-pip

pip install ansible

  • yum安装

yum install epel-release -y

yum install ansible –y

安装完成后执行ansible --version

[root@localhost ~]# ansible --version
ansible 2.9.7
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]

配置ansible

默认配置文件

配置文件路径在/etc/ansible

[root@localhost ansible]# pwd
/etc/ansible
[root@localhost ansible]# ll
total 24
-rw-r--r--. 1 root root 19985 Apr 19 05:24 ansible.cfg
-rw-r--r--. 1 root root  1016 Apr 19 05:24 hosts
drwxr-xr-x. 2 root root     6 Apr 19 05:24 roles

修改ansible.cfg
将以下几个参数的注释去掉并修改

host_key_checking= False   
timeout = 30  增加ssh的超时时间
log_path = /var/log/ansible.log	 存日志

主机清单

ansible有2种连接主机清单的方式

基于密码连接
[root@localhost ansible]# vim /etc/ansible/hosts
#添加两个组dev、test
[dev]
172.31.22.31  ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.22.33  ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.22.35  ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"

[test]
172.31.24.31  ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.24.33  ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.24.35  ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"

修改完后ping下该组主机是否都能连上

[root@localhost ansible]# ansible dev -m ping
172.31.22.33 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.31.22.31 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.31.22.35 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
基于秘钥连接
[root@localhost ansible]# ssh-keygen
[root@localhost ansible]# for i in {1,3,5}; do ssh-copy-id -i 172.31.22.3$i ; done
[root@localhost ansible]# for i in {1,3,5}; do ssh-copy-id -i 172.31.24.3$i ; done
[root@localhost ansible]# vim /etc/ansible/hosts
#添加两个组dev、test
[dev]
172.31.22.31  
172.31.22.33  
172.31.22.35  

[test]
172.31.24.31  
172.31.24.33  
172.31.24.35  

修改完后ping下该组主机是否都能连上

[root@localhost ansible]# ansible test -m ping
172.31.24.33 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.31.24.31 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.31.24.35 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

ansbile常用模块

下面举几个日常用的比较多的模块,没有列举完所有的,下列模块掌握之后日常对付批量操作虚拟机的任务是没问题的。

ping模块

测试主机连通性

ansible $1 -m ping

$1:组名    eg:dev

command模块

这个模块可以直接在远程主机上执行命令,并将结果返回本主机。

注意,该命令不支持| 管道命令

ansible $1 -m command -a $2

$1:组名    eg:dev

$2:命令    eg:'ip add'

shell模块

shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。

ansible $1 -m shell -a $2

$1:组名    eg:dev

$2:命令    eg:'ps -aux|grep java'

shell模块 vs command模块

这两个模块在很多情况下都能完成同样的工作,以下是两个模块之前的区别:

  • command 模块命令将不会使用 shell 执行。

  • 因此, 像 $HOME 这样的变量是不可用的。还有像<, >, |, ;, &都将不可用。

  • shell 模块通过shell程序执行, 默认是/bin/sh, <, >, |, ;, & 可用,但这样有潜在的 shell 注入风险。

  • command 模块更安全,因为他不受用户环境的影响。 也很大的避免了潜在的 shell 注入风险。

copy模块

这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。

ansible $1 -m copy -a $2

$1:组名    eg:dev

$2:命令    eg:'src=/data/test.sh dest=/data mode=777 '

参数详解

src      #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
content   #用于替换"src",可以直接指定文件的值
dest     #必选项,将源文件复制到的远程主机的绝对路径
backup    #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息
mode     #递归设定目录的权限,默认为系统默认权限
force    #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
others    #所有的 file 模块中的选项可以在这里使用

fetch模块

该模块用于从远程某主机获取(复制)文件到本地。

ansible $1 -m fetch -a $2

$1:组名    eg:dev

$2:命令    eg:'src=/data/test.sh dest=/data '

dest:用来存放文件的目录
src:在远程拉取的文件,并且必须是一个file,不能是目录

文件保存的路径是我们设置的接收目录下的被管制主机ip目录下

[root@localhost data]# ansible dev -m fetch -a 'src=/data/test.sh dest=/data'
172.31.22.33 | CHANGED => {
    "changed": true, 
    "checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00", 
    "dest": "/data/172.31.22.33/data/test.sh", 
    "md5sum": "2da6c61e985bf3cece7ece373c3976b0", 
    "remote_checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00", 
    "remote_md5sum": null
}
172.31.22.31 | CHANGED => {
    "changed": true, 
    "checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00", 
    "dest": "/data/172.31.22.31/data/test.sh", 
    "md5sum": "2da6c61e985bf3cece7ece373c3976b0", 
    "remote_checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00", 
    "remote_md5sum": null
}
172.31.22.35 | CHANGED => {
    "changed": true, 
    "checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00", 
    "dest": "/data/172.31.22.35/data/test.sh", 
    "md5sum": "2da6c61e985bf3cece7ece373c3976b0", 
    "remote_checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00", 
    "remote_md5sum": null
}
[root@localhost data]# ll
total 28
drwxr-xr-x.  3 root root 4096 May 15 10:08 172.31.22.31
drwxr-xr-x.  3 root root 4096 May 15 10:08 172.31.22.33
drwxr-xr-x.  3 root root 4096 May 15 10:08 172.31.22.35
[root@localhost data]# cd 172.31.22.31/data
[root@localhost data]# ll
total 4
-rwxr-xr-x. 1 root root 352 May 15 10:08 test.sh

yum模块

该模块主要用于软件的安装

ansible $1 -m yum -a $2

$1:组名    eg:dev

$2:命令    eg:'name=tree  state=present'

name=  #所安装的包的名称
state=  #present 安装, latest 安装最新的, absent 卸载软件。

[root@localhost ~]# ansible dev -m yum -a 'name=tree  state=present'
172.31.22.31 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "tree-1.6.0-10.el7.x86_64 providing tree is already installed"
    ]
}
172.31.22.35 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "installed": [
            "tree"
        ]
    }, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * elrepo: mirrors.tuna.tsinghua.edu.cn\n * epel: mirrors.tuna.tsinghua.edu.cn\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package tree.x86_64 0:1.6.0-10.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package        Arch             Version                   Repository      Size\n================================================================================\nInstalling:\n tree           x86_64           1.6.0-10.el7              base            46 k\n\nTransaction Summary\n================================================================================\nInstall  1 Package\n\nTotal download size: 46 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : tree-1.6.0-10.el7.x86_64                                     1/1 \n  Verifying  : tree-1.6.0-10.el7.x86_64                                     1/1 \n\nInstalled:\n  tree.x86_64 0:1.6.0-10.el7                                                    \n\nComplete!\n"
    ]
}
172.31.22.33 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "installed": [
            "tree"
        ]
    }, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * elrepo: mirrors.tuna.tsinghua.edu.cn\n * epel: mirrors.tuna.tsinghua.edu.cn\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package tree.x86_64 0:1.6.0-10.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package        Arch             Version                   Repository      Size\n================================================================================\nInstalling:\n tree           x86_64           1.6.0-10.el7              base            46 k\n\nTransaction Summary\n================================================================================\nInstall  1 Package\n\nTotal download size: 46 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : tree-1.6.0-10.el7.x86_64                                     1/1 \n  Verifying  : tree-1.6.0-10.el7.x86_64                                     1/1 \n\nInstalled:\n  tree.x86_64 0:1.6.0-10.el7                                                    \n\nComplete!\n"
    ]
}

注意:已安装目标软件的机器不会再执行安装

ansible playbook

playbook 是 ansible 用于配置,部署,和管理被控节点的剧本。即写好一个剧本后,根据组的不同可以使用一个剧本来批量操作服务器,比如这个剧本制作好了后,可以给dev组安装java环境,安装完成后,还可以给test组安装,有点模板的意思。

格式

创建一个带.yml结尾的文本,文本内容应该遵循下面几点

  • 文件的第一行应该以 “—” (三个连字符)开始,表明文件的开始。
  • 在同一行中,#之后的内容表示注释。
  • YML中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
  • 同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
  • play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":“分隔表示,”:"后面还要增加一个空格。

Playbook的核心元素:

  • Hosts:主机组
  • Tasks:任务列表
  • Variables:变量,设置方式有四种
  • Templates:包含了模板语法的文本文件——Jinja是一种现代且设计友好的Python模板语言,以Django的模板为模型。借助可选的沙盒模板执行环境,它可以快速,广泛地使用并且安全
  • Handlers:由特定条件触发的任务

Playbooks配置文件的基础组件:

  • Hosts:运行指定任务的目标主机
  • remoute_user:在远程主机上执行任务的用户
  • tasks:任务列表
格式:
     tasks:
     – name: TASK_NAME   
      module: arguments
      notify: HANDLER_NAME
   handlers:
     – name: HANDLER_NAME
      module: arguments
      
handlers:任务,在特定条件下触发;接收到其它任务的通知时被触发;   
   (1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
  (2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
  
ansible-playbook命令的命令行中的-e vars=VARS,这样就可以直接把自定义的变量传入。

例如下面的playbook 
你需要改http_port 端口可以这样执行

ansible-playbook ansible_httpd.yml -e http_port=81 

你需要定向执行tag:startapache的方法

ansible-playbook ansible_httpd.yml -t startapache

官网的第一个的playbook

[root@localhost ~]# vim ansible_httpd.yml
---
- hosts: dev       #ansbile定义的组名
  vars:            #变量,可以传到template里的httpd.j2里,也可以直接在yml文件里利用
    http_port: 80   
    max_clients: 200
#远程执行的用户
  remote_user: root  
  tasks:
  - name: ensure apache is at the latest version   #方法名
#基础模块:参数
    yum: pkg=httpd state=latest                   
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
#执行name为restart apache的方法
    notify:         
    - restart apache  
  - name: ensure apache is running
    service: name=httpd state=started 
    tag:startapache
#这里的restart apache和上面的触发是配对的。这就是handlers的作用。相当于tag
  handlers:          
    - name: restart apache
      service: name=httpd state=restarted   #重启服务器

总结

ansible最基本的知识就梳理到这了,其实对于大部分场景已经够用了。如果需要定制化长期使用ansible编排,推荐用ansbile-playbook的模式,这样对于大型集群维护更方便,例如改脚本、配置更新、重启等。如果是偶尔用ansbile可以直接使用普通命令。本文展示的ansible只是一个入门教程,实际使用中对于更多丰富模块的利用、以及优化ansible的性能的方法可以看下面参考资料的官方文档。

下期通过ansible配合jenkins展现实战中ansbile的可用性。

参考资料

ansible官方文档

jinja2官方文档

自动化运维工具——ansible详解(一)


版权声明:

原创不易,洗文可耻。除非注明,本博文章均为原创,转载请以链接形式标明本文地址。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值