运维之Ansible
- 未分类
- 2024-09-24
- 976热度
- 0评论
运维自动化之ANSIBLE
课程内容
- 运维自动化发展历程及技术应用
- Ansible命令使用
- Ansible常用模块详解
- YAML语法简介
- Ansible playbook基础
- Playbook变量、tags、handlers使用
- Playbook模板templates
- Playbook条件判断 when
- Playbook字典 with_items
- Ansible Roles
运维自动化发展历程及技术应用
IAAS、PAAS 和 SAAS 是三种云计算服务模型,每种模型提供的服务层次不同。
1. IAAS (Infrastructure as a Service) - 基础设施即服务
IAAS 提供的是虚拟化的计算资源,比如服务器、存储和网络。它使用户能够管理底层基础设施,同时具备更高的控制灵活性,但需要自行管理操作系统、中间件和应用程序。
- 使用场景: 当用户需要更多定制和控制权,且希望自己管理服务器的配置和网络设置时,IAAS 是不错的选择。
- 例子: AWS EC2、Microsoft Azure、Google Cloud、阿里云 ECS。
2. PAAS (Platform as a Service) - 平台即服务
PAAS 提供的是一个用于开发、测试、部署和管理应用程序的平台。用户不需要关心底层的基础设施(服务器、存储、网络等),而是专注于应用程序的开发和部署。
- 使用场景: 当用户希望快速构建应用程序而不想管理底层基础设施时,PAAS 是理想选择。
- 例子: Google App Engine、Microsoft Azure App Service、Heroku、阿里云的SAE(Serverless App Engine)。
3. SAAS (Software as a Service) - 软件即服务
SAAS 提供的是一种通过互联网直接访问的软件应用服务,用户无需安装和维护应用程序,只需通过浏览器或API访问即可。底层基础设施、平台和应用程序都由服务提供商完全管理。
- 使用场景: 当用户需要现成的应用程序解决方案并且不想处理底层的维护和更新时,SAAS 是最好的选择。
- 例子: Google Workspace (Gmail, Google Docs)、Microsoft Office 365、Salesforce、阿里云的钉钉。
总结:
- IAAS: 提供基础设施,用户管理操作系统和应用。
- PAAS: 提供平台,用户专注于应用开发。
- SAAS: 提供现成的软件应用,用户只需使用。
运维工程师核心职能
1、平台架构组件 负责参与并审核架构设计的合理性和可运维性,搭建运维平台技术架构,通过开源解决方案,以确保产品在发布之后能高效稳定的运行,保障并不断提升服务的可用性,确保用户数据安全,提升用户体验。
2、日常运营保障 负责用运维技术或运维平台确保产品可以高效的发布上线,负责保障产品7*24小时稳定运行,在此期间对出现的各种问题可以快速定位并解决;在日常工作中不断优化系统架构和部署的合理性,以提升系统服务的稳定性。
3、性能、效率优化 用自动化的工具/平台提升软件在研发生命周期中的工程效率。不断优化系统架构,提升部署效率、优化资源利用率支持产品的不断迭代,需要不断的进行架构优化调整。以确保整个产品能够在功能不断丰富和复杂的条件下,同时保持高可用性。
运维相关工具
- 代码管理(SCM):GitHub、GitLab、BitBucket、SubVersion
- 构建工具:maven、Ant、Gradle
- 自动部署:Capistrano、CodeDeploy
- 持续集成(CI):Jenkins、Travis
- 配置管理:Ansible、SaltStack、Chef、Puppet
- 容器:Docker、Podman、LXC、第三方厂商如AWS
- 编排:Kubernetes、Core、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、Oracle、PostgreSQL等关系型数据库;mongoDB、redis等NoSQL数据库
- 项目管理(PM):Jira、Asana、Taiga、Trello、Basecamp、Pivotal Tracker
企业实际应用场景分析
1、Dev开发环境:
使用者:程序员
功能:程序员开发软件,测试BUG的环境
管理者:程序员
2、测试环境
使用者:QA测试工程师
功能:测试经过Dev环境测试通过的软件的功能
管理者:运维
说明:测试环境往往有多套,测试环境满足测试功能即可,不宜过多。测试人员希望测试环境有多套,公司的产品多产品线并发,即多个版本,意味着多个版本同步测试。通常测试环境有多少套和产品线数量保持一样。
3、发布环境:代码发布机,有些公司为堡垒机(安全屏障)
使用者:运维
功能:发布代码至生产环境
管理者:运维(有经验)
发布机:往往需要有2台(主备)
4、生产环境
使用者:运维,少数情况开放权限给核心开发人员,极少数公司将权限完全开放给开发人员并其维护
功能:对用户提供公司产品的服务
管理者:只能是运维
说明:生产环境服务器数量:一般比较多,且应用非常重要。往往需要自动工具协助部署配置应用
5、灰度环境(生产环境的一部分)
使用者:运维
功能:在全量发布代码前将代码的功能面向少量精准用户发布的环境,可基于主机或用户执行灰度发布
案例:共100台生产服务器,先发布其中的10台服务器,这10台服务器就是灰度服务器
管理者:运维
说明:灰度环境:往往该版本功能变更较大,为保险起见特意先让一部分用户优化体验该功能,待这部分用户使用没有重大问题的时候,再全量发布至所有服务器
程序发布
程序发布要求:不能导致系统故障或造成系统完全不可用,不能影响用户体验
预发布验证:新版本的代码先发布到服务器(跟线上环境配置完全相同,只是未接入到调度器)
灰度发布:基于主机,用户,业务
发布过程:在调度器上下线一批主机(标记为maintanance状态) --> 关闭服务 -->部署新版本的应用程序(软链接实现/金丝雀) --> 启动服务 --> 在调度器上启用这一批服务器
自动化灰度发布:脚本、发布平台
运维自动化发展历程及技术应用
运维自动化是 IT 运维领域的重要趋势,旨在通过自动化工具和技术减少人工干预,提高系统可靠性、稳定性和效率。其发展历程与技术应用经历了几个重要阶段:
1. 初期:手动操作和脚本化
在运维自动化的早期,IT 运维主要依赖手动操作。运维工程师通过登录服务器执行命令、配置文件管理和人工监控系统。为了减少重复性工作,运维人员逐渐开始编写脚本(如 Shell、Perl、Python)来实现任务自动化。
- 技术特点: 手工编写脚本,脚本缺乏标准化、难以维护。
- 应用场景: 主要用于自动化执行批量任务,比如批量部署应用、配置环境、执行简单监控。
2. 中期:配置管理工具和集中式管理
随着 IT 基础设施的规模扩展,手动编写脚本难以应对复杂环境,运维自动化开始进入工具化阶段。出现了专门的配置管理工具,如 Puppet、Chef、Ansible、SaltStack,它们帮助团队更好地管理和自动化大规模服务器的配置、部署和维护。
- 技术特点: 引入“基础设施即代码”(Infrastructure as Code,IaC)的理念,使用集中化的配置文件和模板进行环境管理。
- 代表工具: Puppet、Chef、Ansible、SaltStack。
- 应用场景: 大规模服务器的批量配置、环境一致性保证、自动化部署和运维。
3. 云时代:容器化与微服务
随着云计算的发展,运维自动化进入了一个新的阶段。云平台提供了弹性计算、存储和网络服务,容器化技术(如 Docker)和容器编排工具(如 Kubernetes)的出现,使得运维自动化得到了进一步的提升。应用程序被打包成独立的容器,便于部署、扩展和管理。同时,微服务架构使应用程序更易于管理和自动化。
- 技术特点: 自动化的部署、扩展和自愈能力,容器编排平台大大简化了运维工作。
- 代表技术: Docker、Kubernetes、OpenShift、Rancher。
- 应用场景: 微服务架构下的应用自动化部署、弹性扩展、故障恢复。
4. 现代阶段:DevOps 和持续集成/持续部署 (CI/CD)
DevOps 文化推动了开发与运维的深度整合,进一步推动了运维自动化的发展。CI/CD 工具(如 Jenkins、GitLab CI、CircleCI)帮助开发和运维团队在代码开发、测试、部署和监控环节实现了自动化流水线,减少了人工干预,提升了软件交付的速度和质量。
- 技术特点: 自动化的代码构建、测试、部署和监控,缩短开发到生产的周期,提升系统的稳定性和可恢复性。
- 代表工具: Jenkins、GitLab CI、Travis CI、CircleCI。
- 应用场景: DevOps 流水线自动化,持续交付和部署,版本控制与自动回滚。
5. 未来方向:AI 运维 (AIOps)
随着机器学习和大数据技术的发展,AI 运维(AIOps)逐渐成为新的趋势。AIOps 利用机器学习模型分析海量的运维数据(如日志、监控指标等),自动识别潜在问题,预测系统故障,优化资源使用,实现自我修复和智能化的运维管理。
- 技术特点: 大数据分析、机器学习、智能监控和问题诊断。
- 代表工具: Splunk、Datadog、Moogsoft、Dynatrace。
- 应用场景: 自动化故障排查、智能告警优化、预测性维护。
自动化运维应用场景
自动化运维在文件传输、应用部署、配置管理、任务流编排等多个场景中具有重要的应用。
1. 文件传输
自动化文件传输是指在不同系统之间进行文件交换时,通过自动化工具或脚本来替代手动操作,以提高效率和可靠性。
-
应用场景:
- 定期备份文件或数据库到远程服务器。
- 在应用系统间自动传输日志、配置文件、数据文件。
- 跨系统的文件同步、备份与恢复。
-
技术与工具:
- SCP、SFTP: 通过 SSH 加密的文件传输,常用于安全的文件传输任务。
- Rsync: 用于同步和备份,支持增量传输和差异化文件传输。
- 自动化工具: 如 Ansible 或 SaltStack,可以用 playbook 和 state file 来自动化跨系统文件传输。
- 文件传输自动化平台: 使用专门的文件传输自动化工具,如 MFT(Managed File Transfer),可以提供更高级的传输管理和安全性。
2. 应用部署
应用部署是运维自动化的重要环节,涉及从代码编译、打包、测试到部署的全流程。自动化工具帮助减少人工干预,提升部署的速度、可靠性和一致性。
-
应用场景:
- 在不同环境(如开发、测试、生产)之间自动化部署应用程序。
- 在多个服务器或容器中实现批量化和一致化的应用部署。
- 支持多版本部署、自动回滚、零停机更新等操作。
-
技术与工具:
- CI/CD 流水线: 使用 Jenkins、GitLab CI、Travis CI 等工具,实现自动构建、测试、部署的流水线。
- 容器化部署: 利用 Docker 将应用打包为容器,通过 Kubernetes 实现大规模集群管理和自动化部署。
- Ansible、Chef、Puppet: 使用配置管理工具编写自动化部署任务,实现应用的版本发布、配置更新等操作。
- Helm: 针对 Kubernetes 集群的应用部署管理工具,用于简化容器化应用的配置和部署。
3. 配置管理
配置管理通过自动化工具实现 IT 基础设施和软件的标准化配置与一致性管理,确保不同服务器或环境中的配置保持同步和一致。
-
应用场景:
- 在大规模服务器集群中,确保系统配置的一致性和安全性。
- 对配置变更进行版本控制、审计与自动化分发。
- 在多个环境中保持应用程序和系统配置的可重复性。
-
技术与工具:
- Ansible: 无代理(Agentless)配置管理工具,使用 YAML 格式的 Playbook 管理服务器配置、软件安装等任务。
- Puppet: 基于声明式配置模型,通过编写配置文件来自动化管理和监控基础设施。
- Chef: 采用 Ruby 语言编写的自动化配置管理工具,提供强大的脚本编写能力。
- SaltStack: 高效的并发管理,适用于大规模分布式系统的配置管理。
-
常见应用:
- 系统软件安装、配置文件同步、操作系统补丁更新。
- 安全策略、网络配置管理。
4. 任务流编排
任务流编排是指将多个自动化任务串联起来,形成完整的工作流,保证按顺序或并行执行。它涉及自动化调度任务的定义、依赖管理和结果处理。
-
应用场景:
- 持续集成和部署(CI/CD)过程中,将构建、测试、部署等环节编排为自动化流程。
- 在数据处理场景中,编排数据提取、转换、加载(ETL)等任务。
- 定时自动执行定制化的任务流,比如备份、日志清理、资源管理等。
-
技术与工具:
- Jenkins Pipeline: Jenkins 的流水线功能,用于编排复杂的构建、测试、部署任务,支持多步骤、并行化操作。
- Airflow: Apache Airflow 是专门用于编排和调度任务流的工具,适合复杂的 ETL 流程、数据处理和跨系统任务管理。
- Luigi: Python 库,用于构建数据管道和自动化任务流管理,擅长处理依赖关系复杂的任务。
- Kubernetes CronJobs: Kubernetes 中的 CronJobs 可用于定时执行容器化的任务,自动化调度各种任务流。
Ansible企业使用场景
公司由于业务扩展,增加了5台服务器,每台服务器配置KVM,根据需求安装50+的虚拟机,并对虚拟机推送安全基线配置和推送统一的网关配置,如果你作为运维同学,应该使用什么样的思路完成这次的工作任务呢?
Ansible特性
- 模块化:调用特定的模块,完成特定任务
- Paramiko(python对ssh的实现),PyYAML,Jinja2(模板语言)三个关键模块
- 支持自定义模块
- 基于Python语言实现
- 部署简单,基于python和SSH(默认已安装),agentless
- 安全,基于OpenSSH
- 支持playbook编排任务
- 幂等性:一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
- 无需代理不依赖PKI(无需ssl)
- 可使用任何编程语言写模块
- YAML格式,编排任务,支持丰富的数据结构
- 较强大的多层解决方案
Ansible架构
Ansible 的架构设计简洁,采用无代理(agentless)的方式,通过 SSH 连接进行远程管理,旨在简化 IT 自动化任务。其核心组件包括控制节点、管理节点(受管节点)、模块、插件、Inventory、Playbooks 等。下面是 Ansible 架构的详细解析:
1. 控制节点(Control Node)
控制节点是运行 Ansible 命令和 Playbooks 的主机,也是整个 Ansible 操作的中心。它负责发起对受管节点的所有操作任务,包括发送指令、执行模块等。
-
功能:
- 执行 Playbooks 和 Ad-hoc 命令。
- 发送指令给受管节点,处理任务的调度和控制。
- 管理 Inventory 文件,定义目标节点。
-
特点:
- 控制节点可以是任何安装了 Ansible 的主机(通常是管理服务器或运维人员的工作站)。
- 通过 SSH 连接到受管节点进行操作。
2. 管理节点(Managed Nodes / Hosts)
管理节点,也称为受管节点,是 Ansible 执行任务的目标主机。Ansible 不需要在这些主机上安装任何代理软件,而是通过 SSH 或 WinRM(对于 Windows 系统)连接到这些节点。
-
特点:
- 受管节点可以是任何服务器、虚拟机、容器、网络设备等,Ansible 通过 SSH 远程执行任务。
- 不需要额外安装软件,控制节点直接通过标准协议(如 SSH)与之交互。
-
工作方式:
- 控制节点发送任务到受管节点,受管节点执行任务并返回结果。
- 执行结果在本地运行,Ansible 模块通常是临时拷贝到节点上执行,执行完毕后删除。
3. 模块(Modules)
Ansible 模块是用于执行具体任务的单元,可以看作是 Ansible 与受管节点交互的核心组件。Ansible 在执行任务时,将模块临时传输到受管节点上运行,任务完成后模块会被删除。
-
功能:
- 模块可执行各种任务,如安装软件、管理服务、配置文件修改、文件传输等。
- 每个模块都是一个单独的脚本,支持通过参数控制。
-
模块类型:
- 系统模块(system modules):管理操作系统任务,如用户、组、文件权限。
- 云模块(cloud modules):用于管理云资源,如 AWS、Azure、Google Cloud。
- 网络模块(network modules):配置和管理网络设备。
- 定制模块:用户可以根据需求编写自定义模块。
4. 插件(Plugins)
插件用于扩展 Ansible 的功能,是支持某些特定任务的代码片段。插件负责一些常见功能的实现,如日志记录、任务通知、连接管理等。Ansible 插件分为多种类型:
- 常见插件类型:
- Connection Plugins: 管理 Ansible 如何与远程节点通信,如 SSH、WinRM。
- Callback Plugins: 控制 Ansible 执行过程中如何输出结果,如发送通知、生成报告。
- Action Plugins: 用于扩展 Ansible 模块,控制如何执行任务。
- Inventory Plugins: 管理 Inventory 数据源的收集和解析。
- Lookup Plugins: 从外部源获取数据,如从文件、数据库或其他服务中获取变量。
5. Inventory(资产清单)
Inventory 是一个文件或脚本,用于定义受管节点的列表及其分组。Ansible 通过 Inventory 文件了解要操作哪些主机。Inventory 支持静态和动态两种形式。
-
静态 Inventory:
- 以纯文本(通常是 INI 或 YAML 格式)形式定义的主机和组信息,包含主机名、IP 地址、组名等。
- 可以直接在文件中定义主机变量,如主机的 SSH 用户、端口等。
-
动态 Inventory:
- 通过脚本或 API 调用动态生成的主机列表,常用于云平台或容器环境,自动从外部服务获取当前活跃的主机信息。
- 比如从 AWS EC2、OpenStack、Kubernetes 中动态获取节点信息。
6. Playbooks
Playbooks 是 Ansible 的核心配置文件,用于定义要对受管节点执行的任务集合。Playbooks 采用 YAML 格式编写,具有高度可读性和易于维护的特点。
- 结构:
- Plays: 每个 Play 定义一组任务以及这些任务要运行在哪些主机上(通过 Inventory 定义的组或主机名)。
- Tasks: 每个任务定义一个要执行的具体操作,使用某个模块实现。
- Handlers: 处理事件触发的任务,比如在特定条件下重启服务。
- Variables: Playbook 中可以定义变量,以增强灵活性和可重复性。
- Roles: 角色用于组织和重用 Playbooks 中的任务、变量和文件,便于复杂场景下的管理。
7. Roles(角色)
Roles 是用于组织和重用 Playbooks 中任务、变量、文件等的机制,帮助用户更好地组织复杂的自动化任务。通过 Roles,用户可以将相关的任务集合分开管理,从而实现更好的模块化和可维护性。
- 结构:
- Roles 包含任务、变量、模板、文件、处理器等的文件夹,所有的内容都按类别划分存放。
- 用户可以将常用的配置封装为 Role,在不同的 Playbook 中重复使用。
Ansible工作原理
Ansible主要组成部分
Ansible命令执行来源:
- USER,普通用户,即SYSTEM ADMINISTRATOR
- CMDB(配置管理数据库) API 调用
- PUBLIC/PRIVATE CLOUD API调用 (公有私有云的API接口调用)
- USER-> Ansible Playbook -> Ansibile
利用ansible实现管理的方式:
- Ad-Hoc 即ansible单条命令,主要用于临时命令使用场景
- Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程
Ansible-playbook(剧本)执行过程:
- 将已有编排好的任务集写入Ansible-Playbook
- 通过ansible-playbook命令分拆任务集至逐条ansible命令,按预定规则逐条执行
Ansible主要操作对象主要有主机和网络设备
注意事项:
- 执行ansible的主机一般称为主控端,中控,master或堡垒机
- 主控端Python版本需要2.6或以上
- 被控端Python版本小于2.4需要安装python-simplejson
- 被控端如开启SELinux需要安装libselinux-python
- windows不能做为主控端
- ansible不是服务,不会一直启动,只是需要的时候启动
Ansible安装
下面例子为rpm包安装(EPEL源),当然还有其他安装方式,读者可以根据自身的需求选择,此处不再赘述
[root@localhost ~]# yum info ansible
Available Packages
Name : ansible
Arch : noarch
Version : 2.9.27
Release : 1.el7
Size : 17 M
Repo : epel/x86_64
....省略部分输出...
[root@localhost ~]# yum -y install ansible
[root@localhost ~]# ansible --version
ansible 2.9.27
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 14 2020, 14:45:30) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
Ansible相关配置文件
配置文件
/etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性(一般无需修改)
/etc/ansible/hosts 主机清单(将被管理的主机放到此文件)
/etc/ansible/roles/ 存放角色的目录
程序
/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界面与用户交互的执行工具
1、主机清单inventory
Inventory 主机清单:
- ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名
- 默认的主机清单文件路径为/etc/ansible/hosts
- 主机清单可以有多个,且也可以通过Dynamic Inventory来动态生成
/etc/ansible/hosts文件格式:
- inventory文件遵循INI文件风格,中括号中的字符为组名
- 可以将同一个主机同时归并到多个不同的组中
- 若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明
[root@ansible ~]# cat /etc/ansible/hosts
ntp.magedu.com 不分组,直接加,可以使用域名或IP地址
[front] front组
blog.caijx.work:2333 可以指定端口
web.caijx.work
10.10.1.10
[dbservers]
db1.caijx.com
db2.caijx.com
db3.caijx.com
如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
[websrvs]
www[1:100].example.com ip: 1-100
[dbsrvs]
db-[a:f].example.com dba-dbf
2、ansible.cfg
ansible.cfg是 Ansible 的核心配置文件,用于定义 Ansible 的全局行为和设置。它让你可以自定义各种选项,例如主机清单、日志级别、SSH 连接设置等。通过编辑ansible.cfg,可以更方便地控制 Ansible 的运行方式,无需在每个命令中重复指定选项。
Ansible 配置文件/etc/ansible/ansible.cfg (一般保持默认)
vim /etc/ansible/ansible.cfg
[defaults]
#inventory = /etc/ansible/hosts # 主机列表配置文件
#library = /usr/share/my_modules/ # 库文件存放目录
#remote_tmp = $HOME/.ansible/tmp # 临时py命令文件存放在远程主机目录
#local_tmp = $HOME/.ansible/tmp # 本机的临时命令执行目录
#forks = 5 # 默认并发数,同时可以执行5次
#sudo_user = root # 默认sudo 用户
#ask_sudo_pass = True # 每次执行ansible命令是否询问ssh密码
#ask_pass = True # 每次执行ansible命令是否询问ssh口令
#remote_port = 22 # 远程主机的端口号(默认22)
建议优化项:
host_key_checking = False # 检查对应服务器的host_key,建议取消注释
log_path=/var/log/ansible.log # 日志文件,建议取消注释
module_name = command # 默认模块
[defaults]
inventory = ./hosts # 指定主机清单文件的路径
remote_user = ansible # 远程用户
host_key_checking = False # 是否检查主机密钥
retry_files_enabled = False # 禁用重试文件
[privilege_escalation]
become = True # 是否启用权限提升(如 sudo)
become_method = sudo # 使用的权限提升方式
become_user = root # 提升为的用户
Ansible系列命令
Ansible系列命令
ansible ansible-doc ansible-playbook ansible-vault ansible-console
ansible-galaxy ansible-pull
ansible-doc: 显示模块帮助
ansible-doc [options] [module...]
-a 显示所有模块的文档
-l, --list 列出可用模块
-s, --snippet 显示指定模块的playbook片段(简化版,便于查找语法)
示例:
ansible-doc -l 列出所有模块
ansible-doc ping 查看指定模块帮助用法
ansible-doc -s ping 查看指定模块帮助用法
1、Ansible
ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible端能基于密钥认证的方式联系各被管理节点
ansible <host-pattern> [-m module_name] [-a args]
ansible +被管理的主机(ALL) +模块 +参数
--version 显示版本
-m module 指定模块,默认为command
-v 详细过程 –vv -vvv更详细
--list-hosts 显示主机列表,可简写 --list
-k, --ask-pass 提示输入ssh连接密码,默认Key验证
-C, --check 检查,并不执行
-T, --timeout=TIMEOUT 执行命令的超时时间,默认10s
-u, --user=REMOTE_USER 执行远程执行的用户
-b, --become 代替旧版的sudo切换
--become-user=USERNAME 指定sudo的runas用户,默认为root
-K, --ask-become-pass 提示输入sudo时的口令
ansible all --list 列出所有主机
ping模块: 探测网络中被管理主机是否能够正常使用 走ssh协议
如果对方主机网络正常,返回pong
ansible-doc -s ping 查看ping模块的语法
检测所有主机的网络状态
1> 默认情况下连接被管理的主机是ssh基于key验证,如果没有配置key,权限将会被拒绝
因此需要指定以谁的身份连接,输入用户密码,必须保证被管理主机用户密码一致
ansible all -m ping -k
2> 或者实现基于key验证 将公钥ssh-copy-id到被管理的主机上 , 实现免密登录
ansible all -m ping
[root@localhost ~]# vim key.sh
#!/bin/bash
ssh-keygen -f /root/.ssh/id_rsa -P ''
Net=192.168.132
export SSHPASS=123
for i in {175..177};do
sshpass -e ssh-copy-id $Net.$i
done
2、Ansible结合主机清单
匹配主机的列表:
1、All :表示所有Inventory中的所有主机
ansible all –m ping
2、* :通配符
ansible "*" -m ping (*表示所有主机)
ansible 192.168.1.* -m ping
ansible "*svr" -m ping
3、或关系 ":"
ansible "websrvs:appsrvs" -m ping
ansible “192.168.1.10:192.168.1.20” -m ping
4、逻辑与 ":&"
ansible "websrvs:&dbsrvs" –m ping #在websrvs组并且在dbsrvs组中的主机
5、逻辑非 ":!"
ansible 'websrvs:!dbsrvs' –m ping #在websrvs组,但不在dbsrvs组中的主机。注意:此处为单引号
6、综合逻辑或结合正则表达式
ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' –m ping
ansible "~(front|back).*\.caijx\.com" –m ping #匹配以 front 或 back 开头的主机名,并且以 .caijx.com 结尾的主机
3、Ansible命令执行过程
- 加载配置文件:
- Ansible 首先会加载配置文件,默认位置是/etc/ansible/ansible.cfg。如果设置了 ANSIBLE_CONFIG 环境变量,Ansible 会优先使用该路径的配置文件。加载配置文件时,会读取其中的各种设置,例如主机清单、模块路径、日志级别等。
- 加载模块:
- 根据命令行中指定的模块(例如 command),Ansible 会加载对应的模块文件。模块通常以 Python 编写,并存储在 Ansible 的模块目录中。Ansible 也会根据配置文件中的设置,加载自定义的模块路径(如果有的话)。
- 生成临时 Python 文件:
- Ansible 将要执行的模块或命令生成一个临时的 Python 文件。这个文件包含了执行模块所需的代码和逻辑。生成的临时 Python 文件会被传输到目标主机的 $HOME/.ansible/tmp/ansible-tmp-数字/ 目录下,并以 .py 结尾。例如,ansible-tmp-123456789/XXX.py。
- 给临时文件赋予执行权限:
- Ansible 在目标主机上将临时 Python 文件的权限设置为可执行 (chmod +x),以确保文件可以被执行。
- 执行模块并返回结果:
- Ansible 执行临时 Python 文件,并将模块的输出结果返回到控制主机。执行过程中,模块会在目标主机上完成其任务(如文件操作、服务管理等)。
- 删除临时文件:
- 执行完成后,Ansible 会删除临时 Python 文件,以清理目标主机上的临时文件。
- 退出:
- 完成以上步骤后,Ansible 会退出,并返回执行结果给用户。
执行状态:
- 绿色:执行成功并且不需要做改变的操作
- 黄色:执行成功并且对目标主机做变更
- 红色:执行失败
4、ansible使用示例
ansible all -m ping -u caijx -k
ansible all -m ping -u caijx -k -b
ansible all -m ping -u caijx -k -b --become-user=root
ansible 192.168.132.175 -m shell -u caijx -a "ls /root" -b -K -k
ansible 192.168.132.175 -m shell -u caijx -a "ls /root" -bKk --become-user=root
参数 | 含义 |
---|---|
-u | 指定使用caijx用户进行连接。 |
-b | 启用权限提升(sudo) |
-k | 提示输入 SSH 密码 |
-K | 提示输入 SUDO 密码 |
--become-user=root | 指定提升后的用户是root |
5、ansible-galaxy
连接 https://galaxy.ansible.com
下载相应的roles(角色)
列出所有已安装的galaxy
ansible-galaxy list
安装galaxy
ansible-galaxy install geerlingguy.redis
删除galaxy
ansible-galaxy remove geerlingguy.redis
6、ansible-pull
用于从版本控制系统(如 Git)中拉取 Ansible playbook,并在本地节点上执行。这种方法适用于需要集中管理的环境,特别是在某些节点不能直接访问 Ansible 控制节点时
ansible-pull -U https://github.com/example/repo.git -i hosts.ini site.yml
7、ansible-vault
功能:管理加密解密yml文件
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
ansible-vault encrypt hello.yml 加密
ansible-vault decrypt hello.yml 解密
ansible-vault view hello.yml 查看
ansible-vault edit hello.yml 编辑加密文件
ansible-vault rekey hello.yml 修改口令
ansible-vault create new.yml 创建新文件
8、ansible-console
Ansible 提供的一个交互式命令行工具,用于与目标主机进行实时交互。它允许用户直接在 Ansible 的环境中执行模块命令,方便进行快速测试和故障排查。
[root@localhost ~]# ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
#执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$
root@all (6)[f:5]$ cd mysql
root@mysql (1)[f:5]$ cd 192.168.132.175
root@192.168.132.175 (1)[f:5]$ forks 3
root@192.168.132.175 (1)[f:3]$ shell ls /root
192.168.132.175 | CHANGED | rc=0 >>
404.html
anaconda-ks.cfg
client.log
sysconfig.tar.gz
root@192.168.132.175 (1)[f:3]$ yum name=httpd state=present
root@192.168.132.175 (1)[f:3]$ service name=httpd state=started
Ansible常用模块
1、Command模块
Command:在远程主机执行命令,默认模块,可忽略-m选项。注意:此命令不支持 $VARNAME < > | ; & 等
[root@localhost ~]# ansible-doc -s command
- name: Execute commands on targets
command:
argv: # Passes the command as a list rather than a string. Use `argv' to avoid quoting values that would otherwise be interpreted incorrectly (for example "user name"). Only the
string or the list form can be provided, not both. One or the other must be provided.
chdir: # Change into this directory before running the command.
cmd: # The command to run.
creates: # A filename or (since 2.0) glob pattern. If it already exists, this step *won't* be run.
...省略部分输出...
ansible srvs -m command -a 'service vsftpd start'
ansible srvs -m command -a 'echo caijx |passwd --stdin 123456' #请读者验证此命令
2、Shell模块
Shell:和command相似,用shell执行命令。调用bash执行命令,但类似"cat /tmp/stanley.md | awk -F'|' '{print $1,$2}' &> /tmp/example.txt"这些复杂命令,即使使用shell也可能会失败。由于Command模块和Shell模块的功能类似,读者可以修改默认模块为Shell。 解决办法:写到脚本时,copy到远程执行,再把需要的结果拉回执行命令的机器
ansible all -m shell -a 'getenforce' #查看SELINUX状态
ansible all -m shell -a "sed -i 's/SELINUX=.*/SELINUX=disabled/' /etc/selinux/config" -b
ansible srv -m shell -a 'echo caijx |passwd –stdin 123'
3、Script模块
Script:在远程主机上运行ansible服务器上的脚本
ansible websrvs -m script -a /data/test.sh
4、Copy模块
Copy:从主控端复制文件到远程主机
src : 源文件 指定拷贝文件的本地路径 (要复制到远程服务器的文件的本地路径。可以是绝对路径,也可以是相对路径。如果路径是目录,则会递归复制。在这种情况下,如果路径以/结尾,则仅将该目录内的内容复制到目标。如果路径不以/结尾,则会复制目录本身及其所有内容。)
dest: 指定目标路径
mode: 设置权限
backup: 备份源文件
content: 代替src,指定本机文件内容,生成目标主机文件
ansible mysql -m copy -a "src=/root/test1.sh dest=/tmp/test2.sh owner=caijx mode=600 backup=yes" #如果目标存在,默认覆盖,此处指定先备份
ansible mysql -m copy -a "content='test content\nxxx' dest=/tmp/test.txt" #指定内容,直接生成目标文件
5、Fetch模块
Fetch:从远程主机提取文件至主控端,copy相反,目前不支持目录,可以先打包,再提取文件。会生成每个被管理主机不同编号的目录,不会发生文件名冲突
ansible websrvs -m fetch -a 'src=/root/test.sh dest=/data/scripts'
ansible all -m shell -a 'tar jxvf test.tar.gz /root/test.sh'
ansible all -m fetch -a 'src=/root/test.tar.gz dest=/data/'
6、File模块
File:设置文件属性
path: 要管理的文件路径 (强制添加)
recurse: 递归,文件夹要用递归
src: 创建硬链接,软链接时,指定源目标,配合'state=link' 'state=hard' 设置软链接,硬链接
state: 状态
absent 缺席,删除
ansible websrvs -m file -a 'path=/app/test.txt state=touch' #创建文件
ansible websrvs -m file -a "path=/data/testdir state=directory" #创建目录
ansible websrvs -m file -a "path=/root/test.sh owner=wang mode=755" #设置权限755
ansible websrvs -m file -a 'src=/data/testfile dest=/data/testfile-link state=link' #创建软链接
7、unarchive模块
unarchive:解包解压缩,有两种用法: 1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes. 2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数:
copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,
如果设置为copy=no,会在远程主机上寻找src源文件
src: 源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,
如果是远程主机上的路径,则需要设置copy=no
dest:远程主机上的目标路径
mode:设置解压缩后的文件权限
ansible websrvs -m unarchive -a 'src=foo.tgz dest=/var/lib/foo'
# 默认copy为yes ,将本机目录文件解压到目标主机对应目录下
ansible websrvs -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'
# 解压被管理主机的foo.zip到data目录下, 并设置权限777
ansible websrvs -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'
8、Archive模块
Archive:打包压缩
将远程主机目录打包
path: 指定路径
dest: 指定目标文件
format: 指定打包格式
owner: 指定所属者
mode: 设置权限
ansible all -m archive -a 'path=/etc/sysconfig dest=/data/sysconfig.tar.bz2 format=bz2 owner=wang mode=0777'
ansible all -m archive -a 'path=/etc/sysconfig dest=/root/sysconfig.tar.gz format=gz mode=0777'
9、Hostname模块
Hostname:管理主机名
ansible appsrvs -m hostname -a "name=app.adong.com" 更改一组的主机名
ansible 192.168.38.103 -m hostname -a "name=app2.adong.com" 更改单个主机名
10、Cron模块
Cron:计划任务。支持时间:minute,hour,day,month,weekday
ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.16.0.1 &>/dev/null' name=Synctime" #创建任务
ansible websrvs -m cron -a 'state=absent name=Synctime' #删除任务
ansible websrvs -m cron -a 'minute=*/10 job='/usr/sbin/ntpdate 172.30.0.100" name=synctime disabled=yes' #注释任务,不在生效
11、Yum模块
Yum:管理包。可以同时安装多个程序包
ansible websrvs -m yum -a 'list=httpd' 查看程序列表
ansible websrvs -m yum -a 'name=httpd state=present' 安装
ansible websrvs -m yum -a 'name=httpd state=absent' 删除
ansible websrvs -m yum -a "name=https://mirrors.aliyun.com/zabbix/zabbix/4.2/rhel/7/x86_64/zabbix-agent-4.2.3-2.el7.x86_64.rpm state=latest"
12、Service模块
Service:管理服务
ansible srv -m service -a 'name=httpd state=stopped' 停止服务
ansible srv -m service -a 'name=httpd state=started enabled=yes' 启动服务,并设为开机自启
ansible srv -m service -a 'name=httpd state=reloaded' 重新加载
ansible srv -m service -a 'name=httpd state=restarted' 重启服务
13、User模块
User:管理用户
home 指定家目录路径
system 指定系统账号
group 指定组
remove 清除账户
shell 指定shell类型
ansible websrvs -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'
ansible websrvs -m user -a 'name=sysuser1 system=yes home=/app/sysuser1'
ansible websrvs -m user -a 'name=user1 state=absent remove=yes' #清空用户所有数据
ansible websrvs -m user -a 'name=app uid=88 system=yes home=/app groups=root shell=/sbin/nologin password="$1$zfVojmPy$ZILcvxnXljvTI2PhP2Iqv1"' 创建用户
ansible websrvs -m user -a 'name=http generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa'
ansible websrvs -m user -a 'name=app state=absent' #不会删除家目录
ansible websrvs -m user -a 'name=ding state=absent remove=yes' #删除用户及家目录等数据
安装mkpasswd
yum insatll expect
mkpasswd 生成口令
openssl passwd -1 生成加密口令
14、Group模块
Group:管理组
ansible srv -m group -a "name=testgroup system=yes" 创建组
ansible srv -m group -a "name=testgroup state=absent" 删除组
15、get_url模块
get_url:从指定的 URL 下载文件
ansible mysql -m get_url -a 'url=https://blog.caijxlinux.work/404.html dest=/root/404.html'
ansible mysql -m get_url -a "url=http://blog.caijxlinux.work/404.html dest=/var/www/html/ checksum=md5:7b86f423757551574a7499f0aae"
16、Cron模块
cron:定时任务
ansible mysql -m cron -a "name=job1 job='ls >/dev/null'"
ansible mysql -m cron -a "name=job2 minute=0 hour=5,2 job='ls >/dev/null'"
ansible mysql -m cron -a "name=job2 minute=0 hour=5,2 job='ls >/dev/null' disabled=yes"
17、mount模块
mount:挂载
ansible localhost -m yum -a 'name=nfs-utils state=present'
ansible localhost -m file -a 'path=/ops state=directory'
ansible localhost -m copy -a 'content="/ops 172.16.1.0/24(rw,sync)" dest=/etc/exports'
ansible localhost -m service -a "name=nfs state=restarted"
#示例一、挂载nfs存储至本地的/opt目录,并实现开机自动挂载
ansible oldboy -m mount -a "src=172.16.1.61:/ops path=/opt fstype=nfs opts=defaults state=mounted"
#示例三、永久卸载nfs的挂载,会清理/etc/fstab
ansible webservers -m mount -a "src=172.16.1.61:/ops path=/opt fstype=nfs opts=defaults state=absent"
Ansible playbook
- playbook是由一个或多个"play"组成的列表
- play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。
- Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
- Playbook采用YAML语言编写
用户通过ansible命令直接调用yml语言写好的playbook,playbook由多条play组成。每条play都有一个任务(task)相对应的操作,然后调用模块modules,应用在主机清单上,通过ssh远程连接从而控制远程主机或者网络设备
YAML语法简介
- 在单一档案中,可用连续三个连字号(——)区分多个档案。另外,还有选择性的连续三个点号( ... )用来表示档案结尾
- 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能
- 使用#号注释代码
- 缩进必须是统一的,不能空格和tab混用。缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的
- YAML文件内容是区别大小写的,k/v的值均需大小写敏感
- 多个k/v可同行写也可换行写,同行使用:分隔。v可是个字符串,也可是另一个列表[]
- 一个完整的代码块功能需最少元素需包括 name 和 task
- 一个name只能包括一个task
- YAML文件扩展名通常为yml或yaml
- 短横线表示列表项,使用一个短横杠加一个空格。多个项使用同样的缩进级别作为同一列表。
List:列表,其所有元素均使用“-”打头
列表代表同一类型的元素
示例:
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
Dictionary:字典,通常由多个key与value构成 键值对
示例:
---
# An employee record
name: Example Developer
job: Developer
skill: Elite
也可以将key:value放置于{}中进行表示,用,分隔多个key:value
示例:
---
# An employee record
{name: Example Developer, job: Developer, skill: Elite} 有空格
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔
示例
name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age: 37
gender: Female
children:
- name: Jimmy Smith
age: 17
gender: Male
- name: Jenny Smith
age 13
gender: Female
Playbook
1、核心元素
Hosts 执行的远程主机列表(应用在哪些主机上)
Tasks 任务集
Variables 内置变量或自定义变量在playbook中调用
Templates模板 可替换模板文件中的变量并实现一些简单逻辑的文件
Handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
tags标签 指定某条任务执行,用于选择运行playbook中的部分代码。
ansible具有幂等性,因此会自动跳过没有变化的部分,
即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。
此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
ansible-playbook -t tagsname useradd.yml
2、基础组件
Hosts:
> playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。
hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
> 可以是如下形式:
one.example.com
one.example.com:two.example.com
192.168.1.50
192.168.1.*
> Websrvs:dbsrvs 或者,两个组的并集
> Websrvs:&dbsrvs 与,两个组的交集
> webservers:!phoenix 在websrvs组,但不在dbsrvs组
示例: - hosts: websrvs:dbsrvs
remote_user:
可用于Host和task中。
也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;
此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root (可省略,默认为root) 以root身份连接
tasks: 指定任务
- name: test connection
ping:
remote_user: magedu
sudo: yes 默认sudo为root
sudo_user:wang sudo为wang
task列表和action
任务列表task:由多个动作,多个任务组合起来的,每个任务都调用的模块,一个模块一个模块执行
1> play的主体部分是task list,task list中的各任务按次序逐个在hosts中指定的所有主机上执行,
即在所有主机上完成第一个任务后,再开始第二个任务
2> task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。
模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
3> 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。
如果未提供name,则action的结果将用于输出
tasks:任务列表
两种格式:
(1) action: module arguments
(2) module: arguments 建议使用 模块: 参数
注意:shell和command模块后面跟命令,而非key=value
某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers
任务可以通过"tags"打标签,可在ansible-playbook命令上使用-t指定进行调用
示例:
tasks:
- name: disable selinux 描述
command: /sbin/setenforce 0 模块名: 模块对应的参数
如果命令或脚本的退出码不为零,可以使用如下方式替代
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
转错为正 如果命令失败则执行 true
或者使用ignore_errors来忽略错误信息
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True 忽略错误
3、运行Playbook
运行playbook的方式
ansible-playbook <filename.yml> ... [options]
常见选项
--check -C 只检测可能会发生的改变,但不真正执行操作
(只检查语法,如果执行过程中出现问题,-C无法检测出来)
(执行playbook生成的文件不存在,后面的程序如果依赖这些文件,也会导致检测失败)
--list-hosts 列出运行任务的主机
--list-tags 列出tag (列出标签)
--list-tasks 列出task (列出任务)
--limit 主机列表 只针对主机列表中的主机执行
-v -vv -vvv 显示过程
示例
ansible-playbook hello.yml --check 只检测
ansible-playbook hello.yml --list-hosts 显示运行任务的主机
ansible-playbook hello.yml --limit websrvs 限制主机
4、Playbook VS ShellScripts
安装httpd
SHELL脚本
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl start httpd
systemctl enable httpd
Playbook定义
---
- hosts: all
remote_user: root
tasks:
- name: "安装Apache"
yum: name=httpd yum模块:安装httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/ copy模块: 拷贝文件
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes service模块: 启动服务
5、示例:Playbook 创建用户
[root@localhost ansible]# cat create_user.yaml
---
# create user
- hosts: front
remote_user: root
gather_facts: yes
tasks:
- name: create group
group: name=mysql system=yes gid=822
- {name: create user, user: name=mysql group=mysql system=yes shell=/sbin/nologin create_home=no uid=822}
6、示例:Playbook示例 安装httpd服务
示例:httpd.yml
- hosts: websrvs
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
- name: start service
service: name=httpd state=started enabled=yes
7、示例:Playbook 安装mysql服务
# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
- hosts: dbsrvs
remote_user: root
gather_facts: no
tasks:
- name: install packages
yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
- name: create mysql group
group: name=mysql gid=306
- name: create mysql user
user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
- name: copy tar to remote host and file mode
unarchive: src=/data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ owner=root group=root
- name: create linkfile /usr/local/mysql
file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
- name: data dir
shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
tags: data
- name: config my.cnf
copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
- name: enable service
shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on
tags: service
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
- name: secure script
script: /data/ansible/files/secure_mysql.sh
tags: script
[root@localhost ansible]# cat files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid
[client]
port=3306
socket=/tmp/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
[root@localhost ansible]# cat files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF
y
123
123
y
y
y
y
EOF
8、示例:Playbook安装Nginx服务
[root@localhost ansible]# vim nginx.yaml
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: add group nginx
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: Modify index
copy: src=files/index.html dest=/usr/share/nginx/html/index.html
- name: Start Nginx
service: name=nginx state=started enabled=yes
9、示例:Playbook安装NFS服务
案例一、使用ansible安装并配置nfs服务
服务端: 10.0.0.7
1.安装nfs
2.配置nfs
3.根据配置创建目录,创建用户,授权
4.启动并加入开机自启
客户端: 10.0.0.8
1.准备一个空目录
2.挂载10.7 上共享的目录即可
[root@m01 project1]# cat nfs.yaml
- hosts: 172.16.1.7
tasks:
- name: Install NFS Server
yum: name=nfs-utils state=present
- name: Configure NFS Server
copy: src=./exports.j2 dest=/etc/exports backup=yes
- name: Create NFS Group
group: name=www gid=666
- name: Create NFS User
user: name=www uid=666 group=666 shell=/sbin/nologin create_home=no
- name: Create NFS Data
file: path=/data state=directory owner=www group=www recurse=yes
- name: Service NFS Server
service: name=nfs state=started enabled=yes
- hosts: 172.16.1.8
tasks:
- name: Client Create NFS Data
file: path=/nfs_tt state=directory
- name: Client Mount NFS Server
mount:
src: 172.16.1.7:/data
path: /nfs_tt
fstype: nfs
opts: defaults
state: mounted
10、handlers&¬ify
1、handlers和notify结合使用触发条件
Handlers 实际上就是一个触发器是task列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作
Notify此action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。
在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
2、Playbook中handlers使用
- hosts: websrvs
remote_user: root
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
notify: restart httpd
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
- hosts: websrvs
remote_user: root
tasks:
- name: add group nginx
tags: user
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: config
copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
notify:
- Restart Nginx
- Check Nginx Process
handlers:
- name: Restart Nginx
service: name=nginx state=restarted enabled=yes
- name: Check Nginx process
shell: killall -0 nginx > /tmp/nginx.log
3、Playbook中tags使用
tags: 添加标签 。可以指定某一个任务添加一个标签,添加标签以后,想执行某个动作可以做出挑选来执行。多个动作可以使用同一个标签
[root@localhost ansible]# vim http.yaml
- hosts: front
remote_user: root
gather_facts: no
tasks:
- name: Install httpd
yum: name=httpd state=present
tags: install
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags: conf
- name: start service
service: name=httpd state=started enabled=yes
tags: service
[root@localhost ansible]# ansible-playbook -t install,conf http.yaml --limit=192.168.132.175
- hosts: testsrv
remote_user: root
tags: inshttpd 针对整个playbook添加tage
tasks:
- name: Install httpd
yum: name=httpd state=present
- name: Install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags: rshttpd
notify: restart httpd
handlers:
- name: restart httpd
service: name=httpd status=restarted
ansible-playbook –t rshttpd httpd2.yml
11、Playbook中变量的使用
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量来源:
1> ansible setup facts 远程主机的所有变量都可直接调用 (系统自带变量)
ansible mysql -m setup -a 'filter=ansible_nodename'
ansible mysql -m file -a 'path=/root/{{ ansible_nodename }}.log state=touch'
setup模块可以实现系统中很多系统信息的显示
可以返回每个主机的系统信息包括:版本、主机名、cpu、内存
ansible all -m setup -a 'filter="ansible_nodename"' 查询主机名
ansible all -m setup -a 'filter="ansible_memtotal_mb"' 查询主机内存大小
ansible all -m setup -a 'filter="ansible_distribution_major_version"' 查询系统版本
ansible all -m setup -a 'filter="ansible_processor_vcpus"' 查询主机cpu个数
2> 在/etc/ansible/hosts(主机清单)中定义变量
普通变量:主机组中主机单独定义,优先级高于公共变量(单个主机 )
公共(组)变量:针对主机组中所有主机定义统一变量(一组主机的同一类别)
3> 通过命令行指定变量,优先级最高
ansible-playbook –e varname=value
4> 在playbook中定义
vars:
- var1: value1
- var2: value2
5> 在独立的变量YAML文件中定义
6> 在role中定义
变量命名:
变量名仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:key=value
示例:http_port=80
变量调用方式:
1> 通过{{ variable_name }} 调用变量,且变量名前后必须有空格,有时用“{{ variable_name }}”才生效
2> ansible-playbook –e 选项指定
ansible-playbook test.yml -e "hosts=www user=magedu"
在主机清单中定义变量,在ansible中使用变量
vim /etc/ansible/hosts
[appsrvs]
192.168.38.17 http_port=817 name=www
192.168.38.27 http_port=827 name=web
调用变量
ansible appsrvs -m hostname -a'name={{name}}' 更改主机名为各自被定义的变量
针对一组设置变量
[appsrvs:vars]
make="-"
ansible appsrvs -m hostname -a 'name={{name}}{{mark}}{{http_port}}'
将变量写进单独的配置文件中引用
[root@localhost ansible]# cat vars.yaml
pack_name: vsftpd
service_name: vsftpd
[root@localhost ansible]# cat vsftpd.yaml
- hosts: mysql
remote_user: root
gather_facts: no
vars_files:
- vars.yaml
tasks:
- name: install vsftpd
yum:
name={{ pack_name }}
- name: start service
service:
name={{ service_name }}
state=started
enabled=yes
Ansible基础元素
Facts:是由正在通信的远程目标主机发回的信息,这些信息被保存在ansible变量中。
要获取指定的远程主机所支持的所有facts,可使用如下命令进行
ansible websrvs -m setup
通过命令行传递变量
在运行playbook的时候也可以传递一些变量供playbook使用
示例:
ansible-playbook test.yml -e "hosts=www user=magedu"
register
把任务的输出定义为变量,然后用于其他任务
示例:
[root@localhost ~]# vim out.yaml
- hosts: all
gather_facts: false
tasks:
- name: 执行命令并保存输出到变量
command: "uptime"
register: uptime_output
- name: 输出 uptime 的结果
debug:
msg: "系统运行时间: {{ uptime_output.stdout }}"
1、示例:使用setup变量
示例:var.yml
- hosts: websrvs
remote_user: root
tasks:
- name: create log file
file: name=/var/log/ {{ ansible_fqdn }} state=touch
ansible-playbook var.yml
2、示例:-e参数指定变量
示例:var.yml
- hosts: websrvs
remote_user: root
tasks:
- name: install package
yum: name={{ pkname }} state=present
ansible-playbook –e pkname=httpd var.yml
3、示例:playbook文件内定义变量
示例:var.yml
- hosts: websrvs
remote_user: root
vars:
- username: user1
- groupname: group1
tasks:
- name: create group
group: name={{ groupname }} state=present
- name: create user
user: name={{ username }} state=present
ansible-playbook var.yml
ansible-playbook -e "username=user2 groupname=group2” var2.yml
4、inventory文件内定义变量
主机变量
可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用
示例:
[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909
组变量
组变量是指赋予给指定组内所有主机上的在playbook中可用的变量
示例:
[websrvs]
www1.magedu.com
www2.magedu.com
[websrvs:vars]
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com
普通变量
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
公共(组)变量
[websvrs:vars]
http_port=808
mark="_"
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
ansible websvrs –m hostname –a ‘name={{ hname }}{{ mark }}{{ http_port }}’
命令行指定变量:
ansible websvrs –e http_port=8000 –m hostname –a'name={{ hname }}{{ mark }}{{ http_port }}'
cat vars.yml
var1: httpd
var2: nginx
cat var.yml
- hosts: web
remote_user: root
vars_files:
- vars.yml
tasks:
- name: create httpd log
file: name=/app/{{ var1 }}.log state=touch
- name: create nginx log
file: name=/app/{{ var2 }}.log state=touch
hostname app_81.magedu.com hostname 不支持"_",认为"_"是非法字符
hostnamectl set-hostname app_80.magedu.com 可以更改主机名
组嵌套
inventory中,组还可以包含其它的组,并且也可以向组中的主机指定变量。
这些变量只能在ansible-playbook中使用,而ansible命令不支持
示例:
[apache]
httpd1.magedu.com
httpd2.magedu.com
[nginx]
ngx1.magedu.com
ngx2.magedu.com
[websrvs:children]
apache
nginx
[webservers:vars]
ntp_server=ntp.magedu.com
5、invertory参数
invertory参数:用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量
ansible_ssh_host
ansible_ssh_port
ansible_ssh_user
ansible_ssh_pass
ansbile_sudo_pass
示例:
cat /etc/ansible/hosts
[websrvs]
192.168.0.1 ansible_ssh_user=root ansible_ssh_pass=magedu
192.168.0.2 ansible_ssh_user=root ansible_ssh_pass=magedu
inventory参数
ansible基于ssh连接inventory中指定的远程主机时,还可以通过参数指定其交互方式;
这些参数如下所示:
ansible_ssh_host
The name of the host to connect to, if different from the alias you wishto give to it.
ansible_ssh_port
The ssh port number, if not 22
ansible_ssh_user
The default ssh user name to use.
ansible_ssh_pass
The ssh password to use (this is insecure, we strongly recommendusing --ask-pass or SSH keys)
ansible_sudo_pass
The sudo password to use (this is insecure, we strongly recommendusing --ask-sudo-pass)
ansible_connection
Connection type of the host. Candidates are local, ssh or paramiko.
The default is paramiko before Ansible 1.2, and 'smart' afterwards which
detects whether usage of 'ssh' would be feasible based on whether
ControlPersist is supported.
ansible_ssh_private_key_file
Private key file used by ssh. Useful if using multiple keys and you don't want to use SSH agent.
ansible_shell_type
The shell type of the target system. By default commands are formatted
using 'sh'-style syntax by default. Setting this to 'csh' or 'fish' will cause
commands executed on target systems to follow those shell's syntax instead.
ansible_python_interpreter
The target host python path. This is useful for systems with more
than one Python or not located at "/usr/bin/python" such as \*BSD, or where /usr/bin/python
is not a 2.X series Python. We do not use the "/usr/bin/env" mechanism as that requires the remote user's
path to be set right and also assumes the "python" executable is named python,where the executable might
be named something like "python26".
ansible\_\*\_interpreter
Works for anything such as ruby or perl and works just like ansible_python_interpreter.
This replaces shebang of modules which will run on that host.
模板templates
文本文件,嵌套有脚本(使用模板编程语言编写) 借助模板生成真正的文件
Jinja2语言,使用字面量,有下面形式
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1, item2, ...]
元组:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布尔型:true/false
算术运算:+, -, *, /, //, %, **
比较操作:==, !=, >, >=, <, <=
逻辑运算:and,or,not
流表达式:For,If,When
1、Jinja2
Jinja2 是 Ansible 用来处理模板的引擎,它允许你在 Playbook、模板文件、变量、循环和条件表达式中使用动态内容。以下是 Jinja2 在 Ansible 中常见的应用场景。
(1)变量插值
Jinja2 最常见的用法是通过 {{ 变量名 }}
的形式引用变量。例如:
- hosts: all
tasks:
- name: 输出主机名
debug:
msg: "主机名是 {{ inventory_hostname }}"
这里的 {{ inventory_hostname }}
是一个内置变量,代表当前主机的名称。
(2)条件表达式
可以使用 Jinja2 进行条件判断。例如:
- hosts: all
tasks:
- name: 根据变量值执行任务
debug:
msg: "变量 foo 是 {{ foo }}"
when: foo is defined
Jinja2 支持多种条件表达式,如 if
, else
, and
, or
, in
, is defined
, 等等。
(3)循环
可以通过 Jinja2 来遍历列表或字典。例如:
- hosts: all
tasks:
- name: 遍历用户列表
debug:
msg: "用户 {{ item }}"
loop:
- alice
- bob
- charlie
对于复杂的字典或列表,Jinja2 提供了 with_items
或 with_dict
语法。
(4)模板文件
Jinja2 也常用于编写模板文件,特别是在配置文件中。例如,nginx.conf.j2
:
server {
listen 80;
server_name {{ server_name }};
root {{ document_root }};
location / {
try_files $uri $uri/ =404;
}
}
然后在 Playbook 中使用:
- hosts: web
tasks:
- name: 部署 nginx 配置
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
在这个例子中,server_name
和 document_root
是在 Playbook 或 Inventory 文件中定义的变量,Jinja2 会自动将它们渲染到模板中。
(5)过滤器
Jinja2 提供了多种过滤器来操作数据。常见的过滤器有:
default
: 如果变量未定义,使用默认值length
: 计算列表或字符串的长度join
: 将列表转换为字符串to_json
: 将数据转换为 JSON 格式replace
: 替换字符串中的内容
例如:
- name: 使用过滤器
debug:
msg: "用户名长度是 {{ username | length }}"
(6)运算
Jinja2 支持数学运算、逻辑运算等:
- name: 打印变量 foo 的两倍
debug:
msg: "foo 的两倍是 {{ foo * 2 }}"
(7) 设置默认值
使用 default
过滤器可以在变量未定义时设置默认值:
- name: 显示变量值或默认值
debug:
msg: "{{ some_variable | default('默认值') }}"
(8) Jinja2 宏和自定义函数
可以通过宏定义一组重复的模板代码,并在模板中调用它:
{% macro print_user(name) %}
用户名是 {{ name }}
{% endmacro %}
{{ print_user('Alice') }}
通过使用 Jinja2 的这些功能,Ansible 可以实现复杂的逻辑和配置自动化,大大增强了 Playbook 的灵活性和可扩展性。
2、Jinja2:算术运算
算术运算
Jinja 允许你用计算值。这在模板中很少用到,但为了完整性允许其存在
支持下面的运算符
+:把两个对象加到一起。
通常对象是素质,但是如果两者是字符串或列表,你可以用这种方式来衔接它们。
无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
-:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1
/:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }}
//:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
%:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
*:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。
也可以用于重 复一个字符串多次。{{ ‘=’ * 80 }} 会打印 80 个等号的横条
**:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8
比较操作符
== 比较两个对象是否相等
!= 比较两个对象是否不等
> 如果左边大于右边,返回 true
>= 如果左边大于等于右边,返回 true
< 如果左边小于右边,返回 true
<= 如果左边小于等于右边,返回 true
逻辑运算符
对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
and
如果左操作数和右操作数同为真,返回 true
or
如果左操作数和右操作数有一个为真,返回 true
not
对一个表达式取反(见下)
(expr)
表达式组
['list', 'of', 'objects']:
一对中括号括起来的东西是一个列表。列表用于存储和迭代序列化的数据。
例如 你可以容易地在 for循环中用列表和元组创建一个链接的列表
<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'), ('downloads.html',
'Downloads')] %}
<li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>
('tuple', 'of', 'values'):
<ul>
<li><a href="index.html">Index</a></li>
<li><a href="about.html">About</a></li>
<li><a href="downloads.html">Downloads</a></li>
</ul>
元组与列表类似,只是你不能修改元组。
如果元组中只有一个项,你需要以逗号结尾它。
元组通常用于表示两个或更多元素的项。更多细节见上面的例子
{'dict': 'of', 'key': 'and', 'value': 'pairs'}:
Python 中的字典是一种关联键和值的结构。
键必须是唯一的,并且键必须只有一个 值。
字典在模板中很少使用,罕用于诸如 xmlattr() 过滤器之类
true / false:
true 永远是 true ,而 false 始终是 false
Template
template功能:根据模块文件动态生成对应的配置文件
> template文件必须存放于templates目录下,且命名为 .j2 结尾
> yaml/yml 文件需和templates目录平级,目录结构如下:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
1、template示例
示例:利用template 同步nginx配置文件
准备templates/nginx.conf.j2文件
vim temnginx.yml
- hosts: websrvs
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
ansible-playbook temnginx.yml
2、Playbook中template变更替换
修改文件nginx.conf.j2 下面行为
worker_processes {{ ansible_processor_vcpus }};
cat temnginx2.yml
- hosts: websrvs
remote_user: root
tasks:
- name: template config to remote hosts
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
ansible-playbook temnginx2.yml
pstree
3、Playbook中template算术运算
算法运算:
示例:
vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**2 }};
worker_processes {{ ansible_processor_vcpus+2 }};
4、when 实现条件判断
条件测试:如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,
通过when语句实现,在task中使用,jinja2的语法格式
when语句
在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法
示例:
tasks:
- name: "shutdown RedHat flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "RedHat" 当系统属于红帽系列,执行command模块
when语句中还可以使用Jinja2的大多"filter",
例如要忽略此前某语句的错误并基于其结果(failed或者success)运行后面指定的语句,
可使用类似如下形式:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
此外,when语句中还可以使用facts或playbook中定义的变量
(1)示例:when条件判断
- hosts: websrvs
remote_user: root
tasks:
- name: add group nginx
tags: user
user: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install Nginx
yum: name=nginx state=present
- name: restart Nginx
service: name=nginx state=restarted
when: ansible_distribution_major_version == "6"
(2)示例:when条件判断
示例:
tasks:
- name: install conf file to centos7
template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "6"
迭代:with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制
> 对迭代项的引用,固定变量名为"item"
> 要在task中使用with_items给定要迭代的元素列表
> 列表格式:
字符串
字典
示例: 创建用户
- name: add several users
user: name={{ item }} state=present groups=wheel #{{ item }} 系统自定义变量
with_items: # 定义{{ item }} 的值和个数
- testuser1
- testuser2
上面语句的功能等同于下面的语句:
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel
with_items中可以使用元素还可为hashes
示例:
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
ansible的循环机制还有更多的高级功能,具体请参见官方文档
http://docs.ansible.com/playbooks_loops.html
示例:将多个文件进行copy到被控端
[root@localhost ansible]# cat rsyncd.yaml
---
- hosts: mysql
remote_user: root
gather_facts: no
tasks:
- name: Create rsyncd config
copy: src={{ item }} dest=/etc/{{ item }}
with_items:
- rsyncd.secrets
- rsyncd.conf
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: src={{ item }} dest=/tmp/{{ item }}
with_items:
- file1
- file2
- file3
- name: yum install httpd
yum: name={{ item }} state=present
with_items:
- apr
- apr-util
- httpd
(1)示例:迭代嵌套子变量
[root@localhost ansible]# cat group.yaml
- hosts: mysql
remote_user: root
tasks:
- name: add some groups
group: name={{ item }} state=present
with_items:
- group1
- group2
- group3
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: 'user1', group: 'group1' }
- { name: 'user2', group: 'group2' }
- { name: 'user3', group: 'group3' }
with_itmes 嵌套子变量
示例
---
- hosts: testweb
remote_user: root
tasks:
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1' , groups: 'wheel'}
- { name: 'testuser2' , groups: 'root'}
(2)Playbook字典 with_items
- name: 使用ufw模块来管理哪些端口需要开启
ufw:
rule: “{{ item.rule }}”
port: “{{ item.port }}”
proto: “{{ item.proto }}”
with_items:
- { rule: 'allow', port: 22, proto: 'tcp' }
- { rule: 'allow', port: 80, proto: 'tcp' }
- { rule: 'allow', port: 123, proto: 'udp' }
- name: 配置网络进出方向的默认规则
ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
state: enabled
with_items:
- { direction: outgoing, policy: allow }
- { direction: incoming, policy: deny }
(3)Playbook中template for if when循环
{% for vhost in nginx_vhosts %}
server { #重复执行server代码
listen {{ vhost.listen | default('80 default_server') }};
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }};
{% endif %}
{% if vhost.root is defined %}
root {{ vhost.root }};
{% endif %}
{% endfor %}
这段 Jinja2 模板代码的作用是为 Nginx 配置生成多个 server
块,它根据 nginx_vhosts
列表中的不同虚拟主机参数动态生成对应的 Nginx 配置。每次循环会生成一个 server
块,并根据条件插入 server_name
和 root
相关配置。
-
{% for vhost in nginx_vhosts %}
:- 这是一个循环语句,遍历
nginx_vhosts
列表中的每个虚拟主机配置项,每个项通过vhost
变量访问。
- 这是一个循环语句,遍历
-
server {
:- 每次循环都会开始生成一个新的
server
块,代表一个新的虚拟主机。
- 每次循环都会开始生成一个新的
-
listen {{ vhost.listen | default('80 default_server') }};
:- 设置
listen
指令。使用vhost.listen
值,如果没有定义listen
,则使用默认值'80 default_server'
。 - Jinja2 中的
| default()
过滤器用于提供一个默认值。
- 设置
-
{% if vhost.server_name is defined %}
:- 检查当前的
vhost
是否定义了server_name
,如果定义了,就生成server_name
指令。 {{ vhost.server_name }}
:插入vhost
中的server_name
。
- 检查当前的
-
{% if vhost.root is defined %}
:- 类似地,检查
vhost
是否定义了root
目录。如果定义了,就生成root
指令。 {{ vhost.root }}
:插入vhost
中的root
值。
- 类似地,检查
-
{% endfor %}
:- 结束循环,表示对每个虚拟主机的配置生成已经完成,进入下一次循环。
假设 nginx_vhosts
列表包含以下内容:
nginx_vhosts:
- listen: 8080
server_name: example.com
root: /var/www/example
- server_name: test.com
root: /var/www/test
- listen: 8081
渲染后的 Nginx 配置文件将如下所示:
server {
listen 8080;
server_name example.com;
root /var/www/example;
}
server {
listen 80 default_server;
server_name test.com;
root /var/www/test;
}
server {
listen 8081;
}
(4)示例
// temnginx.yml
---
- hosts: testweb
remote_user: root
vars: # 调用变量
nginx_vhosts:
- listen: 8080 #列表 键值对
//templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}
生成的结果
server {
listen 8080
}
(5)示例
// temnginx.yml
---
- hosts: mageduweb
remote_user: root
vars:
nginx_vhosts:
- web1
- web2
- web3
tasks:
- name: template config
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
// templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost }}
}
{% endfor %}
生成的结果:
server {
listen web1
}
server {
listen web2
}
server {
listen web3
}
Roles
ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。
简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
复杂场景:建议使用roles,代码复用度高。变更指定主机或主机组。 如命名不规范维护和传承成本大。某些功能需多个Playbook,通过includes即可实现。
角色(roles):角色集合
site.yml
roles/
└── webserver/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── vars/
│ └── main.yml
1、Ansible Roles目录编排
2、Roles目录结构
每个角色,以特定的层级目录结构进行组织
roles目录结构:
playbook.yml 调用角色
roles/
project/ (角色名称)
tasks/
files/
vars/
templates/
handlers/
default/ 不常用
meta/ 不常用
3、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文件
roles/appname 目录结构
tasks目录:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表;
此文件可以使用include包含其它的位于此目录中的task文件
files目录:存放由copy或script等模块调用的文件;
templates目录:template模块会自动在此目录中寻找Jinja2模板文件
handlers目录:此目录中应当包含一个main.yml文件,用于定义此角色用到的各handler;
在handler中使用include包含的其它的handler文件也应该位于此目录中;
vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量;
meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;
ansible1.3及其以后的版本才支持;
default目录:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件
roles/example_role/files/ 所有文件,都将可存放在这里
roles/example_role/templates/ 所有模板都存放在这里
roles/example_role/tasks/main.yml: 主函数,包括在其中的所有任务将被执行
roles/example_role/handlers/main.yml:所有包括其中的 handlers 将被执行
roles/example_role/vars/main.yml: 所有包括在其中的变量将在roles中生效
roles/example_role/meta/main.yml: roles所有依赖将被正常登入
4、创建Role
创建role的步骤
(1) 创建以roles命名的目录
(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等
(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;
用不到的目录可以创建为空目录,也可以不创建
(4) 在playbook文件中,调用各角色
(1)示例: 创建httpd角色
1> 创建roles目录
mkdir -pv roles/httpd/{handlers,files,tasks}
查看目录结构
tree roles/
roles/
├── httpd
│ ├── files
│ ├── handlers
│ └── tasks
2> 创建目标文件
cd roles/httpd/tasks/
touch install.yml config.yml service.yml
3> vim install.yml
- name: install httpd package
yum: name=httpd
vim config.yml
- name: config file
copy: src=httpd.conf dest=/etc/httpd/conf/ backup=yes
vim service.yml
- name: start service
service: name=httpd state=started enabled=yes
4> 创建main.yml主控文件,调用以上单独的yml文件,
main.yml定义了谁先执行谁后执行的顺序
vim main.yml
- include: install.yml
- include: config.yml
- include: service.yml
5> 准备httpd.conf文件,放到httpd单独的文件目录下
cp /app/ansible/flies/httpd.conf ../files/
6> 创建一个网页
vim flies/index.html
<h1> welcome to weixiaodong home <\h1>
7> 创建网页的yml文件
vim tasks/index.yml
- name: index.html
copy: src=index.html dest=/var/www/html
8> 将网页的yml文件写进mian.yml文件中
vim mian.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml
9> 在handlers目录下创建handler文件mian.yml(没有notify触发)
vim handlers/main.yml
- name: restart service httpd
service: name=httpd state=restarted
10> 创建文件调用httpd角色
cd /app/ansidle/roles
vim role_httpd.yml
---
# httpd role
- hosts: appsrvs
remote_user: root
roles: #调用角色
- role: httpd
11> 查看目录结构
tree
.
httpd
├── files
│ ├── httpd.conf
│ └── index.html
├── handlers
│ └── main.yml
└── tasks
├── config.yml
├── index.yml
├── install.yml
├── main.yml
└── service.yml
12> ansible-playbook role_httpd.yml
(2)示例: 创建一个nginx角色
建立nginx角色在多台主机上来部署nginx需要安装 创建账号
1> 创建nginx角色目录
cd /app/ansible/role
mkdir nginx{tesks,templates,hanslers} -pv
2> 创建任务目录
cd tasks/
touch insatll.yml config.yml service.yml file.yml user.yml
创建main.yml文件定义任务执行顺序
vim main.yml
- include: user.yml
- include: insatll.yml
- include: config.yml
- include: file.yml
- include: service.yml
3> 准备配置文件(centos7、8)
ll /app/ansible/role/nginx/templates/
nginx7.conf.j2
nginx8.conf.j2
4> 定义任务
vim tasks/install.yml
- name: install
yum: name=nginx
vim tasks/config.yml
- name: config file
template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version=="7"
notify: restrat
- name: config file
template: src=nginx8.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version=="8"
notify: restrat
vim tasks/file.yml 跨角色调用file.yum文件,实现文件复用
- name: index.html
copy: src=roles/httpd/files/index.html dest=/usr/share/nginx/html/
vim tasks/service.yml
- nmae: start service
service: name=nginx state=started enabled=yes
vim handlers/main.yml
- name: restrat
service: name=nginx state=restarted
vim roles/role_nginix.yml
---
#test rcle
- hosts: appsrvs
roles:
- role: nginx
5> 测试安装
ansible-playbook role_nginx.yml
5、Playbook调用角色
调用角色方法1:
- hosts: websrvs
remote_user: root
roles:
- mysql
- memcached
- nginx
调用角色方法2:
传递变量给角色
- hosts:
remote_user:
roles:
- mysql
- { role: nginx, username: nginx } #不同的角色调用不同的变量
键role用于指定角色名称
后续的k/v用于传递变量给角色
调用角色方法3:还可基于条件测试实现角色调用
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
6、通过Roles传递变量
通过roles传递变量
当给一个主机应用角色的时候可以传递变量,然后在角色内使用这些变量
示例:
- hosts: webservers
roles:
- common
- { role: foo_app_instance, dir: '/web/htdocs/a.com', port: 8080 }
7、条件式地使用Roles
甚至也可以条件式地使用roles
示例:
---
- hosts: webservers
roles:
- { role: some_role, when: "ansible_os_family == 'RedHat'" }
8、Roles playbook tags使用
roles playbook tags使用
ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml 对标签进行挑选执行
// nginx-role.yml
---
- hosts: testweb
remote_user: root
roles:
- { role: nginx ,tags: [ 'nginx', 'web' ] ,when: ansible_distribution_major_version == "6“ }
- { role: httpd ,tags: [ 'httpd', 'web' ] }
- { role: mysql ,tags: [ 'mysql', 'db' ] }
- { role: marridb ,tags: [ 'mysql', 'db' ] }
- { role: php }
(1)实验: 创建角色memcached
memcacched 当做缓存用,会在内存中开启一块空间充当缓存
cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64" # 缓存空间默认64M
OPTIONS=""
1> 创建对用目录
cd /app/ansible
mkdir roles/memcached/{tasks,templates} -pv
2> 拷贝memcached配置文件模板
cp /etc/sysconfig/memcached templates/memcached.j2
vim templates/memcached.j2
CACHESIZE="{{ansible_memtotal_mb//4}}" #物理内存的1/4用做缓存
3> 创建对应yml文件,并做相应配置
cd tasks/
touch install.yml config.yml service.yml
创建main.yml文件定义任务执行顺序
vim main.yml
- include: install.yml
- include: config.yml
- include: service.yml
vim install.yml
- name: install
yum: name=memcached
vim config.yml
- name: config file
template: src=memcached.j2 dets=/etc/sysconfig/memcached
vim service.yml
- name: service
service: name=memcached state=started enabled=yes
4> 创建调用角色文件
cd /app/ansible/roles/
vim role_memcached.yml
---
- hosts: appsrvs
roles:
- role: memcached
5> 安装
ansible-playbook role_memcached.yml
memcached端口号11211
其它功能
委任(指定某一台机器做某一个task)
delegate_to
local_action (专指针对ansible命令执行的机器做的变更操作)
交互提示
prompt
*暂停(java)
wait_for
Debug
debug: msg="This always executes."
Include
Template 多值合并
Template 动态变量配置
Ansible Roles
在 Ansible 中,以下概念和模块可帮助你实现特定的功能和交互方式:
delegate_to
-
用途:将某个任务委派给特定的主机执行,而不是在当前 Playbook 中定义的目标主机上执行。
-
示例:
- name: Execute a task on a specific host command: /path/to/command delegate_to: specific_host
local_action
-
用途:执行本地操作,直接在 Ansible 控制节点上进行,而不是在目标主机上执行。
-
示例:
- name: Run a command locally local_action: command /path/to/local/command
prompt
-
用途:在执行 Playbook 时提示用户输入变量。通常用于需要用户交互的场景。
-
示例:
- name: Prompt for a variable vars: my_var: "{{ lookup('env', 'MY_ENV_VAR') }}" prompt: "Please enter a value for my_var:"
wait_for
-
用途:等待特定条件满足,可以用于暂停任务,直到目标主机处于某种状态(例如,等待端口开放)。
-
示例:
- name: Wait for a port to be open wait_for: port: 8080 delay: 10 timeout: 300
debug
-
用途:输出调试信息,帮助查看变量或状态。
-
示例:
- name: Print a debug message debug: msg: "This always executes."
Include
-
用途:用于将其他 Playbook 或任务文件包含到当前 Playbook 中,便于代码复用和组织。
-
示例:
- import_tasks: other_tasks.yml
Template 多值合并
-
用途:在模板中合并多个值,可以使用 Jinja2 的语法。
-
示例:
{{ variable1 | combine(variable2) }}
Template 动态变量配置
-
用途:在模板中根据上下文动态生成配置。
-
示例:
server { listen {{ port }}; server_name {{ domain }}; }
总结
这些功能和模块使 Ansible 能够灵活处理各种场景,从简单的命令执行到复杂的条件逻辑、用户交互以及调试输出。合理使用这些特性可以提高 Playbook 的可维护性和可读性,帮助实现更复杂的自动化任务。
推荐资料
http://galaxy.ansible.com
https://galaxy.ansible.com/explore#/
http://github.com/
http://ansible.com.cn/
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples
实验: 实现二进制安装mysql的卸载
cat remove_mysql.yml
---
# install mariadb server
- hosts: appsrvs:!192.168.38.108
remote_user: root
tasks:
- name: stop service
shell: /etc/init.d/mysqld stop
- name: delete user
user: name=mysql state=absent remove=yes
- name: delete
file: path={{item}} state=absent
with_items:
- /usr/local/mysql
- /usr/local/mariadb-10.2.27-linux-x86_64
- /etc/init.d/mysqld
- /etc/profile.d/mysql.sh
- /etc/my.cnf
- /data/mysql
ansible-playbook remove_mysql.yml
[root@ansible ~]#cat /data/ansible/roles/mysql/files/my.cnf
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid
[client]
port=3306
socket=/tmp/mysql.sock
[mysqld_safe]
log-error=/var/log/mysqld.log
[root@ansible ~]#cat /data/ansible/roles/mysql/files/secure_mysql.sh
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF
y
magedu
magedu
y
y
y
y
EOF
[root@ansible ~]#chmod +x /data/ansible/roles/mysql/files/secure_mysql.sh
[root@ansible ~]#ls /data/ansible/roles/mysql/files/
my.cnf mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz secure_mysql.sh
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/main.yml
- include: install.yml
- include: group.yml
- include: user.yml
- include: unarchive.yml
- include: link.yml
- include: data.yml
- include: config.yml
- include: service.yml
- include: path.yml
- include: secure.yml
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/install.yml
- name: install packages
yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/group.yml
- name: create mysql group
group: name=mysql gid=306
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/user.yml
- name: create mysql user
user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/unarchive.yml
- name: copy tar to remote host and file mode
unarchive: src=mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ owner=root group=root
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/link.yml
- name: mkdir /usr/local/mysql
file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/data.yml
- name: data dir
shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/config.yml
- name: config my.cnf
copy: src=my.cnf dest=/etc/my.cnf
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/service.yml
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld;chkconfig --add mysqld;chkconfig mysqld on;/etc/init.d/mysqld start
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/path.yml
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/secure.yml
- name: secure script
script: secure_mysql.sh
[root@ansible ~]#tree /data/ansible/roles/mysql/
/data/ansible/roles/mysql/
├── files
│ ├── my.cnf
│ ├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
│ └── secure_mysql.sh
└── tasks
├── config.yml
├── data.yml
├── group.yml
├── install.yml
├── link.yml
├── main.yml
├── path.yml
├── secure.yml
├── service.yml
├── unarchive.yml
└── user.yml
2 directories, 14 files
[root@ansible ~]#cat /data/ansible/mysql_roles.yml
- hosts: dbsrvs
remote_user: root
roles:
- {role: mysql,tags: ["mysql","db"]}
- {role: nginx,tage: ["nginx","web"]}
[root@ansible ~]#ansible-playbook -t mysql /data/ansible/mysql_roles.yml