Ansible 教程
1. 介绍
1.1. Ansible 发展和起源
Ansible 是一款开源的 IT 配置管理工具,常被 IT 界的小伙伴们用于服务部署、配置管理等工作。配置文件采用最常见的 yaml 格式,学习起来也是比较容易,并且不像 SaltStack,Ansible 并不需要也没有 agent,只有一个控制端。该工具使用简单但功能非常强大,可以解决众多工作中繁琐的服务安装、配置等问题。
Ansible 的第一个版本是 0.0.1,发布于 2012 年 3 月 9 日,其作者兼创始人是 Michael DeHaan。迄今为止已经发展到了 2.9 版本。并且它的关注度、Star 数以及 Fork 的次数都位居榜首。就连强大的 SaltStack 也只能排到第二。
Michael DeHaan 在配置管理和架构设计方面有丰富的经验,曾就职于 RedHat 公司,在 RedHat 任职期间主要开发了 Cobble。在他尝试了各种自动化工具 Puppet、Chef 之后,决定自己打造一款能够结合众多优点的自动化工具。由此,便有了 Ansible 这款易理解、易上手、受众人喜爱的自动化工具。
1.2. 为什么需要 Ansible
前面说过,ansible 通常用于自动化的场景,多用在服务部署、配置管理方面。随着时间推移和公司发展,项目越来越多,团队日益壮大,各种公司内部开发的应用、第三方开源的中间件等服务越来越多,那么管理起来就相对比较困难,人肉操作已经完全满足不了传统的运维工作,需要消耗相当多的时间来进行变更,进而阻碍了开发人员的速度,极大的降低了工作效率。显然可考又高效的部署和管理成为了公司的一大难点与挑战。那么一款高效且可靠的服务部署和管理工具就显得尤为重要。而在很长一段时间里,Docker 容器与 kubernetes 容器编排系统没有被广泛的普及之前,有很大一部分人在使用 Jenkins + Ansible 进行 CICD。
1.3. Ansible 的主要功能
批量执行远程命令:可以对任意多台主机同时进行命令的执行。
批量配置软件服务:可以进行自动化的方式部署、配置及管理服务。
编排高级的 IT 任务:Ansible 可以使用 yaml 来编写一套完整的 Playbook,用来部署维护一套完全的基础架构。
1.4. Ansible 的相关特性
Ansible 是基于每个模块进行工作,自身并没有批量部署的能力,ansible 自身只是提供了一种框架。
Ansible 由 Python 语言开发,没有 agent,不需要在被管理节点安装任何客户端;
模块化:基于模块工作,秩序调用特定的模块来完成特定工作;
基于 SSH 协议;
三大关键组成模块:Paramiko, PyYAML, Jinja2;
幂等性:一个任务执行 1 遍和执行 n 遍效果一样,不因重复执行带来意外情况;
可以使用命令行 ad-hoc 方式来执行批量任务,也可以使用 yaml 格式的文件来定制 Playbook 剧本实现批量任务;
可以使用 Role 组织批量任务
1.5. Ansible 的优点
容易学习且轻量:无需在被控制节点安装 agent,做批量操作时只需要在操作机操作即可(前提:需要配置好免密登录);
- 操作灵活:具有众多的模块,可使用命令行 ad-hoc 方式或者 Playbook 剧本的方式来实现批量任务执行;
- 可移植性高:可以基于 yaml 文件编写一套 Playbook,只要做好逻辑判断,就可以在多种操作系统上拿来即用;
- 幂等性:一个任务执行 1 遍和执行 n 遍效果一样,不因重复执行带来意外情况;
- 支持普通用户 sudo 提权。
但是任何事物都具有两面性。SSH 虽好,但如果被管理的机器数量众多的话,执行的速度就会比较慢,就需要进行一定的优化和分批任务来缓解速度问题。
1.6. Ansible 的架构
Ansible 由以下几个核心工具组成:
- INVENTORY:Ansible 管理主机的清单/etc/anaible/hosts;
- MODULES:Ansible 执行命令的功能模块,多数为内置核心模块,也可自定义;
- PLUGINS:模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等;
- APl:供第三方程序调用的应用程序编程接口。
在日常工作中,我们大多数用到的且使用比较频繁的主要是:Inventory 和 Modules。通常我们会根据项目的需求来定制化我们的 Inventory,不会将它放在默认的/etc/anaible/hosts 文件中。
2. 运维自动化和 Ansible 架构介绍
2.1. 运维自动化发展历程及技术应用
2.1.1. 云计算运维工程师核心职能
- 平台架构组建
负责参与并审核架构设计的合理性和可运维性, 搭建运维平台技术架构, 通过开源解决方案,以确保在产品发布之后能高效稳定的运行,
保障并不断提升服务的可用性, 确保用户数据安全, 提升用户体验. - 日常运营保障
负责用运维技术或者运维平台确保产品可以高效的发布上线, 负责保障产品 7*24H 稳定运行, 在此期间对出现的各种问题可以快速的定位并解决; 在日常工作中不断优化系统架构和部署的合理性, 以提升系统服务的稳定性. - 性能, 效率优化
用自动化的工具/平台提升软件在研发声明周期中的工作效率. 优化资源利用率支持产品的不断迭代, 需要不断的进行架构优化调整, 以确保整个产品能够在功能不断丰富和复杂的条件下, 同时保持高可用性.
2.1.2. 软件开发阶段
计划=>编码=>打包=>测试=>发布=>部署=>运维=>监控
2.1.2.1. 相关工具
- 代码管理(SCM): GitHub, GitLab, BitBucket, SubVersion
- 构建工具: maven, Ant, Gradle
- 自动化部署: Capistrano, CodeDeploy
- 持续集成(CI): jenkins, Travis
- 配置管理: Ansible, SaltStack, Chef, Puppet
- 容器: Docker, Podman, LXC, 第三方厂商如 AWS
- 编排: Kubernetes, Cor, Apache Mesos
- 服务注册与发现: Zookeeper, etcd, Consul
- 脚本语言: python, ruby, shell
- 日志管理: ELK, Logentries
- 系统监控: Prometheus, Zabbix, Datadog, Graphite, Ganglia, Nagios
- 性能监控: AppDynamics, New Relic, Splunk
- 压力测试: JMeter, Blaze meter, loader.io
- 应用服务器: Tomcat, jBoss, IIS
- Web 服务器: Apache, Nginx
- 数据库: MySQL, Oracel, PostgreSQL 等关系型数据库; mongoDB, Redis 等 NoSQL 数据库.
- 项目管理(PM): Jira, Asana, Taiga, Trello, Basecamp, Pivotal Tracker
2.1.3. 运维工程师的发展路线
基础运维=>监控运维=>系统运维=>应用运维=>自动化运维=>架构师=>总监或 CTO
2.1.3.1. 运维的未来是什么?
- 一切皆自动化
“运维的未来是, 让开发人员借助工具, 自动化和流程, 并且让他们能够在运维干预极少的情况下部署和运维服务, 从而实现自助服务, 每一个角色都应该努力使工作实现自动化.” — <<运维的未来>>
2.1.3.2. 企业实际应用场景
2.1.3.2.1. Dev 开发环境
使用者: 程序员
功能: 程序员个人的办公电脑或项目的开发测试环境, 部署开发软件, 测试个人或项目整体的 BUG 的环境
管理者: 程序员
2.1.3.2.2. 测试环境
使用者: QA 测试工程师
功能: 测试经过 Dev 环境测试通过的软件的功能和性能, 判断是否达到项目的预期目标, 生成测试报告.
管理者: 运维
说明: 测试环境往往有多套, 测试环境满足测试功能即可, 不易过多
- 测试人员希望测试环境多套, 公司的产品多产品线并发, 即多个版本, 意味着多个版本同步测试.
- 通常测试环境有多套和产品线数量保持一样
2.1.3.2.3. 预发布环境
使用者: 运维
功能: 使用和生产环境一样的数据库, 缓存服务等配置, 测试是否正常
2.1.3.2.4. 发布环境
包括代码发布机, 有些公司为堡垒机(安全屏障)
使用者: 运维
功能: 发布代码至生产环境
管理者: 运维
发布机: 往往需要有 2 台(主备)
2.1.3.2.5. 生产环境
使用者: 运维, 少数情况开放权限给核心开发人员, 极少数公司将权限完全开放给开发人员并维护
功能: 对用户提供公司产品的服务
2.1.3.2.6. 灰度环境
属于生产环境的一部分
使用者: 运维
功能: 在全量发布代码前将代码的功能面向少量精准用户发布的环境, 可基于主机或用户执行灰度发布
案例: 供 100 台生产服务器, 先发布其中 10 台服务器, 这 10 台服务器就是灰度服务器
管理者: 运维
灰度环境: 往往该版本功能变更较大, 为了保险起见特意先让一部分用户优化体验该功能, 待这部分用户使用没有重大问题的时候, 再全量发布至所有服务器
2.1.3.3. 程序发布
程序发布要求:
不能导致系统故障或造成系统完全不可用
不能影响用户体验
预发布验证:
新版本的代码发布到服务器(跟线上环境配置完全相同, 只是未接入到调度器)
灰度发布:
基于主机, 用户, 业务
正式发布
发布过程:
- 在调度器上下线一批主机标记为 mainttenance 状态
- 关闭服务
- 部署新版本的应用程序
- 启动服务
- 在调度器上启用这一批服务器
自动化灰度发布:
脚本
发布平台
2.1.3.3.1. 自动化运维应用场景
文件传输
应用部署
配置管理
任务流编排
2.1.3.4. 常用自动化运维工具
- Ansible: python, Agentless, 中小型应用环境
- Saltstack: python, 一般需要部署 Agent, 执行效率更高
- Puppet: Ruby, 功能强大, 配置复杂, 重型, 适合大型环境
- Fabric: python, agentless
- Chef: ruby, 国内应用少
- Cfengine
- func
2.1.4. Ansible 介绍和架构
2.1.4.1. Ansible 发展史
作者: Michael DeHaan(Cobbler 与 Func 作者)
ansible 的名字来自<<安德的游戏>>中跨越时空的即时通信工具
2012-03-09, 发布 0.0.1 版, 2015-10-17, Red Hat 宣布 1.5 亿美金收购
官网: http://www.ansible.com/
官方文档: https://docs.ansible.com/
2.1.4.2. Ansible 特性
- 模块化: 调用特定的模块, 完成特定任务
- Paramiko(python 对 ssh 的实现), PyYAML, jinja2(模板语言) 三个关键模块
- 支持自定义模块, 可使用任何编程语言写模块
- 基于 Python 语言实现
- 部署简单, 基于 python 和 SSH(默认已安装), agentless, 无需代理不依赖 PKI(无需 ssl)
- 安全, 基于 OpenSSH
- 幂等性: 一个任务执行 1 遍和 n 遍效果一样, 不因重复执行带来意外情况
- 支持 playbook 编排任务, YAML 格式, 支持丰富的数据结构
- 较强的多层解决方案 role
2.1.4.3. Ansible 架构
2.1.4.3.1. Ansible 组成
Inventory, API, Modules, Plugin 的绿框, 可以理解为是 Ansible 命令工具,
其为核心执行工具.
- Inventory: Ansible 管理主机的清单/etc/ansible/hosts
- Modules: Ansible 执行命令的功能模块, 多数为内置核心模块, 也可自定义
- Plugins: 模块功能的补充, 如连接类型插件, 循环插件, 变量插件, 过滤插件等, 该功能不常用
- API: 供第三方程序调用的应用程序接口
2.1.4.3.2. Ansible 命令执行来源
- User 普通用户, 即 System Administrator
- Playbooks: 任务剧本(任务集), 编排定义 Ansible 任务集的配置文件, 由 Ansible 顺序依次执行, 通常是 Json 格式的 YML 文件
- CMDB(配置管理数据库) API 调用
- PUBLIC/PRIVATE Cloud API 调用
- User => Ansible Playbook => Ansible
2.1.4.3.3. 注意事项
- 执行 ansible 的主机一般称为主控端, 中控, master 或堡垒机
- 主控端 Python 版本需要 2.6 或以上
- 被控端 Python 版本小于 2.4 需要安装 python-simplejson
- 被控端如开启 SELinux 需要安装 libselinux-python
- Windows 不能作为主控端
3. Ansible 的安装和使用
3.1. Ansbile 安装
ansible 的安装方法有多种
3.1.1. EPEL yum 源安装
1 | yum install ansible |
3.1.2. 编译安装
1 | yum -y install python-jinja2 PyYAML python-paramiko python-babel \ |
3.1.3. Git 方式
1 |
|
3.1.4. pip 安装
pip 是安装 Python 包的管理器, 类似 yum
1 |
|
3.1.5. 确认安装
1 | ansible --version |
3.1.6. Ansible 相关文件
3.1.6.1. 配置文件
/etc/ansible/ansible.cfg 主配置文件, 配置 Ansible 工作特性
/etc/ansible/hosts 主机清单
/etc/ansible/roles/ 存放角色的目录
3.1.6.2. Ansbile 主配置文件
Ansible 的配置文件/etc/ansible/ansbile.cfg 其中大部分的配置内容无需进行修改
1 | [defaults] |
3.1.6.3. ansible.cfg 文件的优先级顺序
ansible 获取 ansible.cfg 文件的优先级顺序
ansible 运行时会先检查 ansible 命令的目录中是否有 ansible.cfg 文件,如果不存在该文件,则检查用户的主目录(~/)中是否有 ansible.cfg 文件,在找不到其他配置文件时,使用全局/etc/ansible/ansible.cfg 文件,如果都不存在,ansible 包含它使用的默认值。
使用 ANSIBLE_CONFIG 环境变量指定配置文件位置,而此时指定的任何文件将覆盖所有其他配置文件
3.1.6.4. Inventory 主机清单
ansible 的主要功用在于批量主机操作, 为了便捷地使用其中的部分主机, 可以在 inventory file 中将其分组命名默认的 inventory file 为/etc/ansible/hosts
inventory file 可以有多个, 且也可以通过 Dynamic Inventory 来动态生成
3.1.6.4.1. 主机清单文件格式
inventory 文件遵循 INI 文件风格, 中括号中的字符为组名, 可以将同一个主机
同时归并到多个不同的组中,
此外, 当如若目标主机使用了非默认的 SSH 端口, 还可以在主机名称之后使用冒号加端口号来标明如果主机名称遵循相似的命名模式, 还可以使用列表的方式标识各主机
1 |
|
3.1.6.5. Ansible 相关工具
/usr/bin/ansible 主程序, 临时命令执行工具
/usr/bin/ansible-doc 查看配置文档, 模块功能查看工具
/usr/bin/ansible-galaxy 下载/上传优秀代码或 Roles 模块的官网平台
/usr/bin/ansible-playbook 定制自动化任务, 编排剧本工具
/usr/bin/ansible-pull 远程执行命令的工具
/usr/bin/ansible-vault 文件加密工具
/usr/bin/ansible-console 基于 Console 界面与用户交互的执行工具
3.1.6.6. 利用 ansible 实现管理的主要方式
Ad-Hoc 即利用 Ansible 命令, 主要用于临时命令使用场景
Ansible-playbook 主要用于长期规划好的, 大型项目的场景, 需要有前期的规划过程
3.1.6.7. ansible-doc
此工具用来显示模块帮助
格式
1 | ansible-doc [options] [module...] |
范例:
1 | # 列出所有模块 |
3.1.6.8. ansible 命令
此工具通过 ssh 协议, 实现对远程主机的配置管理, 应用部署, 任务执行等功能
建议: 使用此工具前, 先配置 ansible 主控端能基于密钥认证的方式联系各个被管理节点
范例: 利用 sshpass 批量实现基于 key 验证
1 | ssh-keygen -f /root/.ssh/id_rsa -P '' |
格式:
1 |
|
选项说明
1 |
|
3.1.6.9. ansible-pull
此工具会推送 ansible 的命令至远程, 效率无限提升, 对运维要求较高.
3.1.6.10. ansible-playbook
此工具用于执行编写好的 playbook 任务
范例:
1 | ansible-playbook hello.yml |
3.1.6.11. ansible-valt
此工具可用于加密解密 yml 文件
格式:
1 | ansible-vault [create|decrypt|edit|encrypt|rekey|view] |
范例
1 |
|
3.1.6.12. ansible-console
此工具是可交互执行命令, 支持 tab, ansible 2.0+新增
提示符格式:
执行用户@当前操作的主机组(当前的主机数量)[f:并发数]$
常用子命令:
设置并发数: forks n 例如: forks 10
切换组: cd 主机组 例如: cd web
列出当前组主机列表: list
列出所有的内置命令: ?或 help
范例:
1 |
|
3.1.7. Ansible 常用模块
2015 年底 270 多个模块, 2016 年达到 540 个, 2018 年 01 月 12 日 1378 个模块, 2018 年 07 月 15 日 1852 个模块, 2019 年 5 月 25 日(ansible 2.7.10)时 2080 个, 2020 年 0302 日有 3387 个模块
虽然模块众多, 但常用的模块也就 2,30 个而已, 针对特定业务只有 10 几个模块
常用模块帮助文档参考:
https://docs.ansible.com/ansible/latest/modules/modules_by_category.html
3.1.7.1. Command 模块
功能: 在远程主机执行命令, 此为默认模块, 可忽略-m 选项
注意: 此命令不支持 $VARNAME <> | ; & 等, 用 shell 模块实现
范例:
1 |
|
3.1.7.2. shell 模块
功能: 和 command 相似, 用 shell 执行命令
范例:
1 |
|
注意: 调用 bash 执行命令, 类似 cat /tmp/test/md | awk -F ‘|’ ‘{print 1,2}’ &> /tmp/example.txt 这些复杂命令, 即使使用 shell 也可能会失效, 解决办法: 写到脚本时, copy 到远程, 执行, 再把需要的结果拉回执行命令的机器
范例: 将 shell 模块代替 command, 设为默认模块
1 | vim /etc/ansible/ansible.cfg |
3.1.7.3. script 模块
功能: 再远程主机上运行 ansible 服务器上的脚本
范例:
1 | ansible websrvs -m script -a /data/test.sh |
3.1.7.4. copy 模块
功能: 从 ansible 服务器主控端复制文件到远程主机
1 | # 如目标存在, 默认覆盖, 此处指定先备份 |
3.1.7.5. fetch 模块
功能: 从远程主机拷贝文件到 ansible 的主控端, 与 copy 相反, 目前不支持目录
范例:
1 | ansible srv -m fetch -a "src=/root/test.sh dest=/data/scripts" |
3.1.7.6. File 模块
功能: 设置文件属性
范例:
1 | # 创建空文件 |
3.1.7.7. unarchieve 模块
功能: 解包解压缩
实现有两种用法:
- 将 ansible 主机上的压缩包传到远程主机后解压缩至特定目录, 设置 copy=yes
- 将远程主机上的某个压缩包解压缩到指定路径下, 设置 copy=no
常见参数:
copy: 默认为 yes, 当 copy=yes, 拷贝的文件是从 ansible 主机复制到远程主机上, 如果没有设置为 copy=no, 会在主机上寻找 src 源文件
remote_src: 和 copy 功能一样且互斥, yes 表示在远程主机, 不在 ansible 主机, no 表示文件在 ansible 主机上
src: 源路径, 可以是 ansible 主机上的路径, 也可以是远程主机上的路径, 如果是远程主机上的路径, 则需要设置 copy=no
范例:
1 | ansible srv -m unarchive -a "" |
3.1.7.8. archive 模块
功能: 打包压缩
范例:
1 |
|
3.1.7.9. Hostname 模块
功能: 管理主机名
范例:
1 |
|
3.1.7.10. Cron 模块
功能: 计划任务
支持时间: minute, hour, day, month, weekday
范例:
1 | # 备份数据库脚本 |
3.1.7.11. Yum 模块
功能: 管理软件包
范例:
1 |
|
3.1.7.12. Service 模块
功能: 管理服务
范例:
1 | ansible srv -m service -a 'name=httpd state=started enable=yes' |
3.1.7.13. User 模块
功能: 管理用户
范例:
1 |
|
3.1.7.14. Group 模块
功能: 管理组
范例:
1 |
|
3.1.7.15. Lineinfile 模块
ansible 在使用 sed 进行替换时, 经常会遇到需要转义的问题, 而且 ansible 在遇到特殊符号进行替换时, 存在问题, 无法正常进行替换, 其实在 ansible 自身提供了两个模块: lineinfile 模块和 replace 模块, 可以方便地进行替换
功能: 相当于 sed, 可以修改文件内容
范例:
1 | ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX=' line='SELINUX=enforcing'" |
3.1.7.16. Replace 模块
该模块有点类似于 sed 命令, 主要也是基于正则进行匹配和替换
范例:
1 |
|
3.1.7.17. Setup 模块
功能: setup 模块来收集主机的系统信息, 这些 facts 信息可以直接以变量的形式使用, 但是如果主机较多, 会影响执行速度, 可以使用 gather_facts: no 来禁止收集 facts 信息
范例:
1 |
|
import_tasks 模块
Ansible 支持将任务分解到不同的文件中,这样可以提高 playbook 的可读性和可维护性。通过将相关的任务组织到同一个文件中,可以实现任务的重用。
import_tasks 是静态地包含任务文件,这会在 playbook 解析阶段就将任务文件加载进来。由于这种加载方式,import_tasks 不支持变量在文件名中的使用,且所有任务都会在 playbook 的解析阶段被加载,这可能导致一些变量在条件判断时已经被覆盖,从而影响任务的执行。
范例:
1 | - hosts: all |
在这个例子中,other_tasks.yml 是一个包含任务的文件,它在 playbook 解析时就被加载。apply 部分可以用来为包含的任务应用特定的标签。
include_tasks 模块
include_tasks 模块允许动态地包含任务列表,这意味着它在运行时解析包含的文件。这使得可以根据变量或条件来决定包含哪些任务。
范例:
1 |
|
在这个例子中,some_tasks.yml 是一个包含任务的文件,而 task_file_to_include 是一个变量,它在运行时被解析,从而动态地决定包含哪个任务文件。
assert 模块
断言给定的表达式为真。
示例:
1 |
|
that: 可以传递给’when’语句的相同形式的字符串表达式列表。
fail_msg: 用于失败断言的自定义消息。这个参数在 Ansible 2.7 之前被称为’msg’,现在它被重命名为’fail_msg’,别名’msg’
success_msg: 用于成功断言的自定义消息。
quiet: 将此设置为 yes 以避免冗长的输出。
4. Playbook
4.1. playbook 介绍
playbook 剧本是由一个或多个 play 组成的列表
play 的主要功能在于将预定义的一组主机, 装扮成事先通过 ansible 中的 task 定义好的角色. Task 实际是用 ansible 的一个 module, 将多个 play 组织在一个 playbook 中, 即可以让它们联合起来, 按事先编排的机制执行预定义的动作
playbook 文件是采用 YAML 语言编写的
4.2. YAML 语言
4.2.1. YAML 语言介绍
YAML 是一个可读性高的用来表达资料序列的格式. YAML 参考了其他多种语言,包括: XML, C 语言, Python, Perl 以及电子邮件格式 RFC2822 等. Clark Evans 在 2001 年首次发表了这种语言, 另外 Ingy dot net 与 Oren Ben-kiki 是这种语言的共同设计者, 目前很多软件中采用此格式的文件, 如 ubuntu, ansible, docker, k8s 等.
YAML: YAML aint markup language, 即 YAML 不是标记语言, 不过, 在开发这种语言时, YAML 的意思其实是: “Yet Another Markup Language” (仍是一种标记语言)
YAML 官方网站: http://www.yaml.org
4.2.2. YAML 语言特性
YAML 的可读性好
YAML 和脚本语言的交互性好
YAML 使用实现语言的数据类型
YAML 有一个一致的信息模型
YAML 易于实现
YAML 可以基于流来处理
YAML 表达能力强, 扩展性好
4.2.3. YAML 语法简介
在单一文件第一行, 用连续三个连字号”-“开始, 还有选择性的连续三个点号(…)用来表示文件的结束
次行开始正常写 playbook 的内容, 一般建议写明该 playbook 的功能
使用#号注释代码
缩进必须是统一的, 不能空格和 tab 混合使用
缩进的级别也必须是一致的, 同样的缩进代表同样的级别, 程序判别配置的级别是通过缩进结合换行来实现的, YAML 文件内容是区分大小写的, key/value 的值均需要大小写敏感
多个 k/v 可同行写也可换行写, 同行使用,分割
v 可是个字符串, 也可是另一个列表
一个完整的代码块功能需最少元素需包括 name 和 task
一个 name 只能包括一个 task
YAML 文件扩展名通常为 yml 或 yaml
YAML 的语法和其他高阶语言类似, 并且可以简单表达清单, 散列表, 标量等数据结构, 其结构(structure)通过空格来展示, 序列(sequence)里的项用”-“来代表, Map 里的键值对用”:”分割, 下面介绍常用的数据结构.
4.2.3.1. List 列表
列表由多个元素组成, 且所有元素前均使用”-“打头
范例:
1 | # A list of tasty fruits |
4.2.3.2. Dictionary 字典
字典通常由多个 key 与 value 构成
范例:
1 | # An example record |
4.3. Playbook 核心元素
Hosts 执行的远程主机列表
Tasks 任务集
Variable 内置变量或自定义变量在 playbook 中调用
Templates 模板, 可替换模板文件中的变量并实现一些简单逻辑的文件
Handler 和 Notify 结合使用, 由特定条件触发的操作, 满足条件方才执行, 否则不执行
tags 标签, 指定某条任务执行, 用于选择运行 playbook 中的部分代码, ansible 具有幂等性, 因此会自动跳过没有变化的部分, 即便如此, 有些代码为测试其确实没有发生变化的时间依然会非常地长, 此时如果确信没有变化, 就可以通过 tags 跳过此些代码片段
4.3.1. hosts 组件
Hosts: playbook 中的每一个 play 的目的都是为了让特定主机以某个指定的用户身份执行任务. hosts 用于指定要执行指定任务的主机, 须事先定义在主机清单中
案例
1 | - hosts: websrvs:appsrvs |
4.3.2. remote_user 组件
remote_user: 可用于 host 和 task 中, 也可以通过指定其通过 sudo 的方式在远程主机上执行任务, 其可用于 play 全局或某个任务; 此外, 甚至可以在 sudo 时使用 sudo_user 指定 sudo 时切换的用户
1 | - hosts: websrvs |
4.3.3. task 列表和 action 组件
play 的主体部分是 task list, task list 中有一个或多个 task, 各个 task 按次序逐个在 hosts 中指定的所有主机上执行, 即在所有主机上完成第一个 task 后, 再开始第二个 task.
task 的目的是使用指定的参数执行模块, 而再模块参数中可以使用变量. 模块执行是幂等的, 这意味着多次执行是安全的, 因为其结果均一致.
每个 task 都应该有其 name, 用于 playbook 的执行结果输出, 建议其内容能清晰地描述任务执行步骤. 如果未提供 name, 则 action 的结果将用于输出
task 两种格式
(1) action: moudule arguments
(2) module: arguments 建议使用
注意: shell 和 command 模块后面跟命令, 而非 key=value
范例:
1 |
|
4.3.4. 其它组件
某任务的状态在运行后为 changed 时, 可以通过 notify 通知给相应的 handlers 任务可以通过 tags 打标签, 可在 ansible-playbook 命令上使用-t 指定进行调用
4.3.5. ShellScript VS Playbook 案例
1 | # SHELL脚本实现 |
playbook 实现
1 |
|
4.4. playbook 命令
格式
1 | ansible-playbook <filename.yml> ... [options] |
常见选项:
1 |
|
范例
1 |
|
4.5. Playbook 初步
4.5.1. 利用 playbook 创建 mysql 用户
范例: mysql_user.yml
1 | - hosts: dbsrvs |
4.5.2. 利用 playbook 安装 nginx
范例: install_nginx.yml
1 | # install nginx |
4.5.3. 利用 playbook 安装和卸载 httpd
范例: install_httpd.yml
1 |
|
范例: remove_httpd.yml
1 |
|
4.5.4. 利用 playbook 安装 mysql
范例: 安装 mysql-5.6.46-linux-glibc2.12
1 | - hosts: websrvs |
4.6. Playbook 中使用 handlers 和 notify
Handlers 本质是 task list, 类似于 mysql 中的触发器触发行为, 其中的 task 与前述的 task 并没有本质上的不同, 主要用于当关注的资源发生变化时, 才会采取一定的操作, 而 Notify 对应的 action 可用于在每个 play 的最后触发, 这样可以避免多次有改变发生时每次都执行指定的操作, 尽在所有的变化发生完成后一次性地执行指定操作. 在 notify 中列出的操作称为 handler, 也即 notify 中调用 handler 中定义的操作
案例:
1 |
|
4.7. playbook 中使用 tags 组件
在 playbook 文件中, 可以利用 tags 组件, 为特定 task 指定标签, 当在执行 playbook 时, 可以只执行特定 tags 的 task, 而非整个 playbook 文件
案例:
httpd.yml
1 |
|
执行指定的 tags
1 |
|
4.8. playbook 中使用变量
变量名: 仅能由字母, 数字和下划线, 且只能以字母开头
变量定义
1 |
|
范例:
1 | http_port=80 |
变量调用方式:
通过 调用变量, 且变量名前后建议加空格, 有时用”“ 才生效
变量来源:
- ansible 的 setup facts 远程主机的所有变量都可直接调用
- 通过命令行指定变量, 优先级最高
4.8.1. 在 playbook 文件中定义变量
范例: var2.yml
1 |
|
4.8.2. 在 playbook 文件中定义变量
范例:
1 | - hosts: websrvs |
1 |
|
4.8.3. 使用变量文件
可以在一个独立的 playbook 文件中定义变量, 在另一个 playbook 文件中引用变量文件中的变量,比 playbook 中定义的变量优先级更高
vars.yml
1 | package_name: vsfpd |
install_app.yml
1 | # install app and configure |
4.8.4. 主机清单中定义变量
主机变量
在 inventory 主机清单文件中为指定的主机定义变量以便于在 playbook 中使用
范例:
1 |
|
组(公共)变量
在 inventory 主机清单文件中赋予给指定组内所有主机上的在 playbook 中可用的变量
范例:
1 | [websrvs] |
4.9. template 模板
模板是一个文本文件, 可以作为生成文件的模板, 并且模板文件中可以嵌套 jinja2 语法
4.9.1. jinja2 语法
jinja2 语言使用字面量, 有下面形式
字符串: 使用单引号或双引号
数字: 整数, 浮点数
列表: [item1, item2, …]
元组: (item1, item2, …)
字典: {key1:value1, key2:value2}
布尔型: true/false
算术运算: +,-,*,/,//,%,**
比较操作: ==, != >, >=, <,>=
逻辑运算: and, or, not
流表达式: For, IF, When
字面量:
表达式最简单的形式是字面量, 字面量表示诸如字符串和数值的 python 对象, 如”hello world”, 双引号或单引号中间的一切都是字符串. 无论何时你需要在模板中使用一个字符串(比如函数调用,过滤器或只是包含或继承一个模板的参数), 如 42, 42.23
数值可以为整数和浮点数, 如果有小数点, 则为浮点数, 否则为整数, 在 python 里, 42 和 42.0 是一样的
jinja 语法详细语法可参考https://doc.yonyoucloud.com/doc/jinja2-docs-cn/index.html
4.9.2. template
template 功能: 可以根据和参考模块文件, 动态生成相似的配置文件
template 文件必须存放于 template 目录下, 且命名为.j2 结尾
yaml/yml 文件需和 template 目录平级, 目录结构如下:
./
|—temnginx.yml
|—templates
|___nginx.conf.j2
范例: 利用 template 同步 nginx 配置文件
1 | 准备templates/nginx.conf.j2文件 |
template 模块只能在 playbook 中使用,不能在 ansible 命令中单独使用
template 的作用根据模板生成文件并拷贝到目标位置
执行:
1 | ansible-playbook temnginx.yml |
template 变更替换
范例:
修改文件 nginx.conf.j2
vim templates/nginx.conf.j2
1 |
|
变量来源:
- setup 模块的变量(系统变量)
- 主机清单中的变量
- 变量文件中的变量
- yaml 文件中定义的变量
- ansible-playbook 中使用-e 选项传递的变量
- 角色中定义的变量
vim temnginx2.yml
1 |
|
1 | ansible-playbook temnginx2.yml |
4.10. playbook 使用 when
when 语句,可以实现条件测试,如果需要根据变量,facts 或此前任务的执行结果来作为某 task 执行与否的前提时,
要用到条件测试,通过在 task 后添加 when 子局即可使用条件测试,jinja2 的语法格式
范例:
1 |
|
范例:
1 |
|
4.11. playbook 使用迭代 with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为”item”
要在 task 中使用 with items 给定要迭代的元素列表
列表元素格式:
- 字符串
- 字典
范例:
1 |
|
范例:
1 |
|
5. Roles 角色
角色是 Ansible 自 1.2 版本引入的新特性, 用于层次性, 结构化地组织 playbook, roles 能够根据层次型结构自动装载变量文件, tasks 以及 handlers 等, 要使用 roles 只需要在 playbook 中使用 include 指令即可, 简单来讲, roles 就是通过分别将变量, 文件, 任务, 模板以及处理器放置于单独的目录中, 并可以便捷地 include 它们的一种机制, 角色一般用于基于主机构建服务的场景中, 但也可以用于构建守护进程等场景中
运维复杂的场景: 建议使用 roles, 代码复用度高
roles: 多个角色的集合, 可以将多个的 role, 分别放至 roles 目录下的独立目录中
roles/
mysql/
httpd/
nginx/
redis/
5.1. Ansible Roles 目录编排
Roles 目录结构如下所示
roles/project/: 项目名称, 有以下子目录
files/: 存放由 copy 或 script 模块等调用的文件
templates/: template 模块查找所需要模板文件的目录
tasks/: 定义 task, role 的基本元素, 至少应该包含一个名为 main.yml 的文件; 其它的文件需要在此文件中通过 include 进行包含
handlers/: 至少应该包含一个名为 main.yml 的文件; 其它的文件需要在此文件中通过 include 进行包含
vars/: 定义变量, 至少应该包含一个名为 main.yml 的文件; 其它的文件需要在此文件中通过 include 进行包含
meta/: 定义当前角色的特殊设定及其依赖关系, 至少应该包含一个名为 main.yml 的文件, 其它文件需要在此文件中通过 include 进行包含
default/: 设定默认变量时使用此目录中的 main.yml 文件, 比 vars 的优先级低
5.2. 创建 role
创建 role 的步骤
(1) 创建以 role 命名的目录
(2) 在 roles 目录中分别创建以各角色名称命名的目录, 如 webservers 等
(3) 在每个角色命名的目录中分别创建 files, handlers, met, tasks, templates 和 vars 目录; 用不到的目录可以创建为空目录, 也可以不创建
(4) 在 playbook 文件中, 调用各角色
针对大型项目使用 Roles 进行编排
范例: roles 的目录结构
1 | nginx-role.yml |
5.3. playbook 调用角色
调用角色方法 1:
1 |
|
调用角色方法 2:
键 role 用于指定角色名称, 后续的 k/v 用于传递变量给角色
1 |
|
调用角色方法 3:
1 |
|
5.4. roles 中的 tags 使用
1 | - hosts: websrvs |
1 | # ansible-playbook可以挑选择标签执行 |
5.5. 实战案例
5.5.1. 案例 1: 实现 httpd 角色
1 |
|
在 playbook 中调用 httpd 角色
vim /data/ansible/role_httpd.yml
1 |
|
5.5.2. 案例 2:实现 nginx 角色
1 |
|
在 playbook 中调用 nginx 角色
vim /data/ansible/role_nginx.yml
1 |
|
5.5.3. 案例 3:实现 mysql 角色
40”51’
1 | cat /data/ansible/roles/mysql/files/my.conf |
1 | cat /data/ansible/roles/mysql/files/secure_mysql.sh |