本文详细介绍了Ansible自动化运维工具的基本概念与使用方法。作为一种基于Python的自动化工具,Ansible可通过单个控制节点管理多个被管理节点,实现批量文件配置、部署和命令执行。文章涵盖了Ansible的安装步骤、主机环境准备、inventory文件配置以及执行ad-hoc命令的实用示例,是运维人员和开发者快速掌握Ansible的入门指南。
安装
Ansible 是一种自动化运维工具,可以在单个主机(控制节点 control node)上管理多个主机(被管理节点 managed node),比如批量文件配置,批量部署,批量运行命令等,在运维或者部署服务集群时很有用。
由于 Ansible 是用 Python 实现的,所以安装也很简单:
1 | pip install ansible |
当然也有其它很多种安装方式,比如通过源码安装,或者通过系统包管理器安装,最简单的就是使用 Pip。
主机的环境准备
基于 Red Hat Enterprise Linux 5.14 x86_64 系统
ansible 通过 ssh 实现主机间的通信,所以首先要保证主机间能相互"看得见",假设有两个主机: host1, host2
设置 hostname
在部署服务集群的时候,为了方便可以将各个机器进行命名。修改/etc/hostname文件,将相应的主机名改为如:node1,node2。修改
/etc/hosts文件,比如当有两个主机时,在每个主机的/etc/hosts文件中增加如下内容:
1 | 172.31.89.117 node1 |
每个 IP 与相应的主机名对应
配置 ssh 公私钥在每个主机上执行
ssh-keygen命令,产生 rsa 类型密钥,然后执行ssh-copy-id将每个主机上的公钥传给另一个主机,
也可以手动在 ~/.ssh/authorized_keys 中添加。这样每个主机上就能不输入密码,通过 ssh 命令进入另一个主机。
Ansible 基本概念
安装完成后,系统新增一系列命令,我们主要使用这三个:ansible, ansible-inventory, ansible-playbook
1. inventory 文件
主机变量配置文件,可以理解为主机清单,主机库存文件。主要是在一个主节点上统一集中配置各个主机(节点)系统信息,网络位置等信息。
ansible 的默认主机配置文件在 /etc/ansible/hosts,如果在该默认路径下没有,则需要手动指定。
这个配置文件可以是 INI,或者 YML 格式。
如果是 INI 文件,配置如下:
inventory.ini
1 | [myhosts] |
这里 myhosts 是组名(group name),这里即 host 组,作为 key 值需要是唯一的,且大小写敏感。
同样如果是 YML 文件,配置如下:
inventory.yml
1 | myhosts: |
这里的 ansible_host 是 ansible 的默认主机变量, 相应的还有 http_port 用来指定端口。
如果它们有共同的变量,可以这么写:
1 | myhosts: |
其中 vars 与 hosts 同级,表示 vars 下面定义的变量是 host 间共用的。
如果是 ini 文件,则是:
1 | [myhosts] |
可以嵌套其它组的组叫做元组(metagroup),例如以下示例文件:
inventory-demo.yml
1 | leafs: |
其中 network 是一个 metagroup,它的子组包含另外两个组:leafs, spines。
而 datacenter 也是一个 metagroup,它包含 network, webservers 这两个组。
所以这个配置文件是一个 data center 的主机配置文件。
可以用 ansible-inventory 命令来校验一下配置文件。(特别对于 .yml 文件,可以看是否有语法错误)
1 | ansible-inventory -i inventory.yml --list |
同样可以使用 ansible 命令来 ping 一下 配置文件中的 host 组:
1 | ansible myhosts -m ping -i inventory.ini |
这里的 -m 指定了 ansible 内置的 ping 命令模块来执行通过 -i 指定的主机清单文件。
到这里为止,在介绍 playbook 之前,我们可以做一些好玩的事情:
使用 ansible 的方式除了使用写 playbook “剧本”(or 脚本)来编排大量复杂的任务之外,还可以在命令行直接执行,在 ansible 中这叫做 ad-hoc 命令。
刚刚执行的 ansible myhosts -m ping -i inventory.ini 就是这种方式。
为了方便,我们将主机的 inventory 文件放到 /etc/ansible/hosts,默认会去这里找配置文件,因此不再需要使用 -i 手动指定了。
1. 批量管理主机
举个例子 🙋♀️🌰,假如手上有 20 台主机,想批量 reboot 它们,配置好主机清单之后:
1 | ansible myhosts -a "/sbin/reboot" -f 10 |
选项 -f 10 f 表示 forks,表示并行任务数,这里是每次重启 10 个。
tips: ansible 可以并发执行任务,默认的并发数是 5
2. 批量处理文件
比如将本机的配置文件批量复制到所有主机,使用 copy 命令模块:
1 | ansible myhosts -m copy -a "src=/etc/ansible/hosts dest=/tmp/hosts" |
如果再重复执行一遍,并不会再次传输文件,除非之后文件的内容改变了,这个时候其 checksum 也变了。
重复执行的时候,不再是 CHANGED 状态,而是 SUCCESS, "changed": false。
tips: ansible 执行任务是幂等的,同一个操作可以重复执行,不影响结果。
可以查看一下,使用 shell 命令模块:
1 | [root@node1 ]$ ansible myhosts -m shell -a 'cat /tmp/hosts' |
也可以删除掉:
1 | [root@node1 /home ]$ ansible myhosts -m shell -a 'rm /tmp/hosts' |
rc = 0 表示 shell 命令执行结果返回值为 0,执行成功
3. 批量包管理
ansible 有专门的包管理模块,支持 apt, yum, dnf, dpkg,以及其它通用的包管理器。
当我要确定每个主机上已经安装了某个软件包,同时不想去升级它们:
1 | ansible myhosts -m yum -a "name=python state=present" |
预期状态 state 是 present,所以当安装了这个包,就是符合预期,返回成功 SUCCESS。
如果要确认一个包还没安装:
1 | [root@node1 ]$ ansible myhosts -m yum -a "name=acme state=absent" |
因为没有安装,与预期状态 state=absent 相符合,所以也返回 SUCCESS。
4. 批量管理服务
在 RHEL 系统里,这里的服务包含 systemd 服务,init 服务等。
比如修改了网络配置文件后,需要确认网络服务已经重新 reload,加载新的配置文件了,则执行:
1 | [root@node1 ]$ ansible myhosts -m service -a "name=NetworkManager state=reloaded" |
这相当于在每个主机上执行了这个命令:systemctl reload NetworkManager.service。这里的 state 可以是 reloaded, restarted, started, stopped,对应着 systemd 服务的 reload, restart, start, stop 操作。
5. 批量配置 cron 定时任务
1 | ansible all -m cron -a 'name="ntp update every 5 min" minute=*/5 job="/sbin/ntpdate 172.17.0.1 &> /dev/null"' |
这里 -a 指定的参数有 name, minute, job,分别是任务名称,任务定时器,任务脚本。
照例查看一下设置的任务:
1 | ansible myhosts -m shell -a "crontab -l" |
以上都用到了 ansible 的内置命令模块,我们可以使用 ansible-doc 命令查看这些命令模块:
1 | ansible-doc -l # 获取全部模块的信息(包括内置的和第三方的) |
2. playbook 文件
Playbook
inventory 文件指定了主机的各种配置信息,确定了每个节点的角色。而 playbook 文件就是指定要在主机上执行什么批量任务,比如安装集群,更新集群,卸载集群等等,或者只是批量执行某个命令。
简单讲,playbook 文件就是任务编排文件,可以类比理解为 Docker 中的 Dockerfile 文件。
在实际项目中,要执行的任务包含一系列的复杂的步骤,它们组成一系列任务(play)。
Play
playbook 文件中的,由一系列按顺序排列的任务(task)组成的有序任务列表。
Task
某个任务中,某项单独的操作,一般通过使用 ansible 定义的某个的命令模块(module)来执行操作。
Module
模块就是一些命令或者可执行文件的抽象,在 Task 中通过调用某个模块来执行具体的命令。
以下是一个 playbook 文件的示例:
1 | - name: My first play |
这个一个 playbook 文件,里面很简单只有一个 play,因为只有一个 tasks,而这个 tasks 包含两个 task:
第一个 task 调用了 ansible 内置的 ping 命令模块,执行 ping 命令。
另一个 task 调用了 ansible 内置的 debug 命令模块,打印 debug 信息,将模拟 debug 信息传递给 msg 变量。
最后我们用 ansible-playbook 命令执行一下这个 playbook。
1 | ansible-playbook -i inventory.ini playbook.yml |
其中 Gathering Facts 任务是默认执行的,在实际任务开始前用来收集主机的信息,在这里是读取 inventory.ini 文件。
最后 PLAY RECAP 总结了本次执行任务的总体情况,它们都是 ok 状态的。
以上就完成了 ansible playbook 的 hello world 过程。
常用的 module
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html
子任务类
ansible.builtin.import_playbook
ansible.builtin.include_role
ansible.builtin.include_tasks
ansible.builtin.import_tasks
命令类
ansible.builtin.shell
ansible.builtin.command
ansible.builtin.raw
ansible.builtin.script
ansible.builtin.win_shell
文件管理类
ansible.builtin.file
ansible.builtin.tempfile
ansible.builtin.lineinfile
ansible.builtin.copy
ansible.builtin.stat
ansible.builtin.find
ansible.builtin.git
包管理类
ansible.builtin.pip
ansible.builtin.yum
ansible.builtin.apt
服务管理类
ansible.builtin.service
ansible.builtin.service_facts
ansible.builtin.systemd_service
ansible.builtin.sysvinit
具体使用可以看官方文档,或者使用 ansible-doc -s [module] 查阅。
以上。
