Ansible 编码最佳实践与高级应用
1. 版本控制与代码协作
在代码协作方面,Git 是一个非常实用的工具。其他协作者可以像我们在第一步那样克隆你的代码。如果他们已经有仓库的工作副本,可以使用以下命令更新:
$ git pull
虽然 Git 有一些高级主题和用例超出了这里的范围,但大约 80% 的情况下,上述命令就是你所需的全部 Git 命令行知识。此外,还有许多 Git 的图形前端,以及集成了 Git 仓库的代码编辑器和集成开发环境(IDE),能帮助你更好地利用它们。
2. 处理操作系统和发行版差异
在自动化编码中,即使我们努力标准化技术环境,操作系统和发行版的差异仍然不可避免。例如,不可能一次性对所有服务器进行重大升级,新的操作系统版本发布时,必然有些机器会保留旧版本。在编写 Ansible playbook 时,尤其是角色,目标是使其尽可能广泛适用于整个环境。以安装 Apache 2 网络服务器为例,在支持 Ubuntu 和 CentOS 时,不仅要处理不同的包管理器(yum 和 apt),还要处理不同的包名(httpd 和 apache2)。
下面通过一个实际例子展示如何根据 Ansible 事实对主机进行分组,让操作系统发行版决定 playbook 中哪个 play 被执行。
假设使用以下简单的库存文件,其中有两个主机在名为 app 的组中:
[app]
app01.dev.example.com
app02.dev.example.com
创建一个名为 osvariants.yml 的 playbook,步骤如下:
1. 创建一个新的 playbook,包含以下 play 定义和单个任务:
---
- name: Play to demonstrate group_by module
hosts: all
tasks:
- name: Create inventory groups based on host facts
group_by:
key: os_{{ ansible_facts['distribution'] }}
这里使用了 group_by 模块,它根据指定的键动态创建新的库存组。原始库存组结构保持不变,但所有主机也会根据其事实添加到新创建的组中。例如,如果主机基于 Ubuntu,会被添加到 os_Ubuntu 组;如果基于 CentOS,则会被添加到 os_CentOS 组。
2. 添加以下 play 定义,在 CentOS 上安装 Apache:
- name: Play to install Apache on CentOS
hosts: os_CentOS
become: true
tasks:
- name: Install Apache on CentOS
yum:
name: httpd
state: present
- 添加第三个 play 定义,在 Ubuntu 上使用 apt 模块安装 apache2 包:
- name: Play to install Apache on Ubuntu
hosts: os_Ubuntu
become: true
tasks:
- name: Install Apache on Ubuntu
apt:
name: apache2
state: present
- 如果环境基于 CentOS 服务器,运行这个 playbook 的结果如下:
$ ansible-playbook -i hosts osvariants.yml
PLAY [Play to demonstrate group_by module] *********************
TASK [Gathering Facts] *****************************************
ok: [app02.dev.example.com]
ok: [app01.dev.example.com]
TASK [Create inventory groups based on host facts]
ok: [app01.dev.example.com]
ok: [app02.dev.example.com]
PLAY [Play to install Apache on CentOS] ************************
TASK [Gathering Facts] *****************************************
ok: [app01.dev.example.com]
ok: [app02.dev.example.com]
TASK [Install Apache on CentOS] ********************************
changed: [app02.dev.example.com]
changed: [app01.dev.example.com]
[WARNING]: Could not match supplied host pattern, ignoring: os_Ubuntu
PLAY [Play to install Apache on Ubuntu] ************************
skipping: no hosts matched
PLAY RECAP *****************************************************
app01.dev.example.com : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
app02.dev.example.com : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以看到,安装 CentOS 上 Apache 的任务被执行,因为 group_by 模块创建了 os_CentOS 组,而第二个 play 只在该组的主机上运行。由于库存中没有运行 Ubuntu 的服务器,os_Ubuntu 组未创建,第三个 play 被跳过。
3. Ansible 版本间的移植
Ansible 是一个快速发展的项目,随着版本发布和新功能添加,会有新模块发布,软件中的 bug 也会被修复。你可能会遇到编写的代码需要在不同 Ansible 版本上运行的情况。
为确保 playbook、角色、模块和插件在更新 Ansible 安装后仍能正常工作,首先要确定你当前使用的 Ansible 版本。例如,查询 Ansible 版本:
$ ansible [core 2.15.0]
config file = None
configured module search path = ['/Users/danieloh/Library/Python/3.11/bin/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /Users/danieloh/Library/Python/3.11/lib/python/site-packages/ansible
ansible collection location = /Users/danieloh/Library/Python/3.11/bin/collections:/usr/share/ansible/collections
executable location = /Users/danieloh/Library/Python/3.11/bin/ansible
python version = 3.11.3 (main, Apr 7 2023, 20:13:31) [Clang 14.0.0 (clang-1400.0.29.202)] (/opt/homebrew/opt/python@3.11/bin/python3.11)
jinja version = 3.1.2
libyaml = True
可以知道你从 Ansible 2.15.0 版本开始。然后,应查看 Ansible 版本的移植指南,通常每个主要版本都会有移植指南。例如,Ansible 8 的移植指南可在 这里 找到。
此外,变更日志也是了解版本间变化的重要信息来源,每个小版本都会发布和更新变更日志,可在官方 Ansible GitHub 仓库的稳定分支中找到。例如,查看 Ansible 2.15 的所有变更日志,可访问 这里 。
4. 高级 Ansible 主题概述
在大规模自动化中,会遇到一些特殊情况,需要使用 Ansible 的高级功能来控制 playbook 流程和错误处理。以下是一些高级主题:
- 异步与同步操作
- 控制滚动更新的 play 执行
- 配置最大失败百分比
- 设置任务执行委托
- 使用 run_once 选项
- 本地运行 playbook
- 使用代理和跳转主机
- 配置 playbook 提示
- 在 play 和任务中放置标签
- 使用 Ansible Vault 保护数据
5. 异步与同步操作
Ansible play 默认按顺序执行,每个任务完成后才开始下一个任务。但有时特定任务运行时间可能超过配置的 SSH 连接超时时间,这就需要使用异步任务。
异步任务可以在目标主机的后台运行,并定期轮询状态,与同步任务(保持与目标主机的连接直到任务完成,有超时风险)形成对比。
以下是一个模拟长时间运行任务的例子,假设库存文件中有两个服务器:
[frontends]
frt01.example.com
frt02.example.com
创建一个 playbook 来演示异步任务:
---
- name: Play to demonstrate asynchronous tasks
hosts: frontends
become: true
tasks:
- name: A simulated long running task
shell: "sleep 20"
async: 30
poll: 5
这里的 async 参数告诉 Ansible 该任务应异步运行,最长运行 30 秒;poll 参数表示每隔 5 秒检查一次异步任务的状态。如果 poll 设为 0,任务将在后台运行且不会自动检查,需要手动编写任务检查状态。
如果要稍后检查任务状态,可以添加第二个任务:
---
- name: Play to demonstrate asynchronous tasks
hosts: frontends
become: true
tasks:
- name: A simulated long running task
shell: "sleep 20"
async: 30
poll: 0
register: long_task
- name: Check on the asynchronous task
async_status:
jid: "{{ long_task.ansible_job_id }}"
register: async_result
until: async_result.finished
retries: 30
运行这个 playbook 会得到类似以下的输出:
$ ansible-playbook -i hosts async2.yml
PLAY [Play to demonstrate asynchronous tasks] ***********************
TASK [Gathering Facts] **********************************************
ok: [frt01.example.com]
ok: [frt02.example.com]
TASK [A simulated long running task] ********************************
changed: [frt02.example.com]
changed: [frt01.example.com]
总结
在 Ansible 自动化中,遵循一些最佳实践可以让管理变得轻松,为技术基础设施带来真正的好处。通过处理操作系统差异、利用版本控制工具、掌握 Ansible 版本间的移植方法,以及运用高级功能处理特殊情况,你可以更高效地完成自动化任务。希望这些内容能帮助你在 Ansible 自动化旅程中取得更好的成果。
6. 控制滚动更新的 play 执行
在更新大量服务器时,滚动更新是一种常用的策略,它可以确保服务的可用性。通过控制每次更新的服务器数量,可以避免因同时更新过多服务器而导致服务中断。
例如,我们有一个包含多个服务器的组,要对它们进行滚动更新。可以使用 serial 参数来控制每次更新的服务器数量。以下是一个示例 playbook:
---
- name: Rolling update playbook
hosts: all
serial: 2
become: true
tasks:
- name: Update packages
apt:
name: "*"
state: latest
在这个示例中, serial: 2 表示每次只对 2 个服务器进行更新。当这 2 个服务器更新完成后,再对下一组 2 个服务器进行更新,直到所有服务器都更新完毕。
7. 配置最大失败百分比
在更新大量服务器时,可能会有少数服务器出现故障。为了避免因为少数服务器的故障而导致整个更新过程失败,可以配置最大失败百分比。
可以使用 max_fail_percentage 参数来配置最大失败百分比。以下是一个示例 playbook:
---
- name: Playbook with max fail percentage
hosts: all
max_fail_percentage: 20
become: true
tasks:
- name: Update packages
apt:
name: "*"
state: latest
在这个示例中, max_fail_percentage: 20 表示如果失败的服务器数量超过总服务器数量的 20%,则整个 playbook 失败;否则,继续执行。
8. 设置任务执行委托
有时,我们需要在一台服务器上执行任务,但该任务的结果会影响其他服务器。这时,可以使用任务执行委托。
使用 delegate_to 参数可以将任务委托给指定的服务器执行。以下是一个示例 playbook:
---
- name: Playbook with task delegation
hosts: all
become: true
tasks:
- name: Check disk space on a specific server
shell: "df -h"
delegate_to: server01.example.com
在这个示例中, delegate_to: server01.example.com 表示将 Check disk space on a specific server 任务委托给 server01.example.com 服务器执行。
9. 使用 run_once 选项
当一个任务只需要在一组服务器中的一台服务器上执行时,可以使用 run_once 选项。
以下是一个示例 playbook:
---
- name: Playbook with run_once option
hosts: all
become: true
tasks:
- name: Generate a unique ID
shell: "uuidgen"
run_once: true
在这个示例中, run_once: true 表示 Generate a unique ID 任务只在组中的一台服务器上执行一次。
10. 本地运行 playbook
有时,我们需要在本地机器上运行 playbook,而不是在远程服务器上。可以使用 hosts: localhost 来指定在本地运行。
以下是一个示例 playbook:
---
- name: Local playbook
hosts: localhost
connection: local
tasks:
- name: Create a local directory
file:
path: /tmp/my_directory
state: directory
在这个示例中, hosts: localhost 和 connection: local 表示 playbook 将在本地机器上运行。
11. 使用代理和跳转主机
在安全环境或核心网络配置中,可能需要使用代理和跳转主机来访问目标服务器。
可以在 ansible.cfg 文件中配置代理和跳转主机。以下是一个示例配置:
[ssh_connection]
proxy_command = ssh -W %h:%p jump_server.example.com
在这个示例中, proxy_command 指定了通过 jump_server.example.com 跳转主机来访问目标服务器。
12. 配置 playbook 提示
在运行 playbook 时,可以配置提示信息,让用户输入一些必要的参数。
可以使用 vars_prompt 来配置提示信息。以下是一个示例 playbook:
---
- name: Playbook with prompts
hosts: all
vars_prompt:
- name: username
prompt: "Enter your username"
private: false
- name: password
prompt: "Enter your password"
private: true
tasks:
- name: Login with provided credentials
debug:
msg: "Logging in with username: {{ username }} and password: {{ password }}"
在这个示例中,运行 playbook 时会提示用户输入用户名和密码。
13. 放置标签在 plays 和 tasks 中
为了方便选择要执行的任务或 play,可以在 plays 和 tasks 中放置标签。
可以使用 tags 参数来添加标签。以下是一个示例 playbook:
---
- name: Playbook with tags
hosts: all
tasks:
- name: Task with tag
debug:
msg: "This is a task with a tag"
tags:
- example_tag
运行 playbook 时,可以使用 --tags 选项来指定要执行的标签对应的任务。例如:
$ ansible-playbook playbook.yml --tags example_tag
14. 保护数据使用 Ansible Vault
在 Ansible 中,敏感数据(如密码、密钥等)需要进行保护。可以使用 Ansible Vault 来加密这些数据。
以下是使用 Ansible Vault 的步骤:
1. 创建一个加密的文件:
$ ansible-vault create secret.yml
- 输入密码并编辑文件内容,例如:
password: my_secret_password
- 在 playbook 中使用加密文件:
---
- name: Playbook using encrypted data
hosts: all
vars_files:
- secret.yml
tasks:
- name: Use encrypted data
debug:
msg: "The password is {{ password }}"
- 运行 playbook 时,需要提供 Vault 密码:
$ ansible-playbook playbook.yml --ask-vault-pass
总结
Ansible 的高级功能为处理大规模自动化中的特殊情况提供了强大的支持。通过掌握异步与同步操作、控制滚动更新、配置最大失败百分比等功能,可以更好地控制 playbook 流程和错误处理。同时,使用代理和跳转主机、保护数据使用 Ansible Vault 等功能,也能提高自动化的安全性和可靠性。希望这些内容能帮助你在 Ansible 自动化中应对各种复杂情况。
流程图示例
graph TD;
A[开始] --> B[异步任务执行];
B --> C{任务完成?};
C -- 是 --> D[结束];
C -- 否 --> E[轮询任务状态];
E --> C;
表格示例
| 高级功能 | 描述 |
|---|---|
| 异步与同步操作 | 处理长时间运行任务,避免 SSH 连接超时 |
| 控制滚动更新 | 确保服务可用性,避免同时更新过多服务器 |
| 配置最大失败百分比 | 允许少数服务器故障,避免整个更新过程失败 |
| 设置任务执行委托 | 在一台服务器上执行任务,影响其他服务器 |
| 使用 run_once 选项 | 任务只在一组服务器中的一台上执行 |
| 本地运行 playbook | 在本地机器上运行 playbook |
| 使用代理和跳转主机 | 访问受限制的服务器 |
| 配置 playbook 提示 | 让用户输入必要的参数 |
| 放置标签在 plays 和 tasks 中 | 方便选择要执行的任务 |
| 保护数据使用 Ansible Vault | 加密敏感数据 |
超级会员免费看
73

被折叠的 条评论
为什么被折叠?



