功能特性介绍
Ansible主要有以下特点:
- 无代理架构,通过避免在 IT 基础设施上安装额外软件来降低维护开销。
- 简单性,自动化剧本使用简单的 YAML 语法,代码就像文档一样易于阅读。Ansible 也是分散式的,使用 SSH 和现有的操作系统凭据来访问远程机器。
- 可扩展性和灵活性,通过模块化设计轻松快速地扩展您自动化的系统,该设计支持各种操作系统、云平台和网络设备。
- 幂等性和可预测性,当系统处于您的剧本描述的状态时,即使多次运行剧本,Ansible 也不会更改任何内容。
Ansible大致框架如图:
原理:控制节点生成可执行的python文件发送给受控节点,之后受控节点执行python脚本
安装
在客户机上安装ansible(注意需提前安装python环境版本3.7+)
`yum 安装:`
yum install epel-release.noarch -y
yum install ansible -y
pip install ansible
pip3 install ansible
`查看版本:`
[root@7-3 ~]# ansible --version
ansible 2.9.27
`查看配置文件:`
[root@7-3 ~]# rpm -qc ansible
/etc/ansible/ansible.cfg //这个基本上不需要改
/etc/ansible/hosts //主机清单,很重要⭐
配置主机清单
下面为ini格式的主机清单设置
[host] //组名
111.111.111.111 //主机号
[host2] //第二个组名
112.112.112.112
[all] //组名也可以嵌套
host1
host1
对于复杂的应用场景,可以使用结构更加清晰合理的yaml格式,如:
myhosts:
hosts:
my_host_01:
ansible_host: 192.0.2.50
my_host_02:
ansible_host: 192.0.2.51
my_host_03:
ansible_host: 192.0.2.52
下面是一个数据中心的基础结构设置:
leafs:
hosts:
leaf01:
ansible_host: 192.0.2.100
leaf02:
ansible_host: 192.0.2.110
spines:
hosts:
spine01:
ansible_host: 192.0.2.120
spine02:
ansible_host: 192.0.2.130
network:
children:
leafs:
spines:
webservers:
hosts:
webserver01:
ansible_host: 192.0.2.140
webserver02:
ansible_host: 192.0.2.150
datacenter:
children:
network:
webservers:
配置完成后验证清单
ansible-inventory -i inventory.ini --list
Ping清单中的某组进行测试
ansible myhosts -m ping -i inventory.ini
容易报错的地方:
- 目标主机未安装python会报错
- 目标主机的python版本不能低于3.7
- 如果目标主机有多个python版本,需指定
- 需提前进行ssh密钥认证,ssh-keygen -t rsa -b 4096生成密钥 ssh-copy-id root@xxx,将密钥复制到目标主机
成功后如图:
创建剧本
剧本是 Ansible 用于部署和配置受管节点的自动化蓝图,采用 YAML 格式。
- 剧本一系列定义 Ansible 执行操作顺序的剧目,自上而下,以实现总体目标。
- 剧目一个有序的任务列表,映射到清单中的受管节点。
- 任务对单个模块的引用,定义 Ansible 执行的操作。
- 模块,Ansible 在受管节点上运行的代码或二进制单元。Ansible 模块按集合分组,每个模块都有一个完全限定的集合名称 (FQCN)。
在项目文件夹中创建playbook.yaml文件,输入:
- name: My first play
hosts: myhosts
tasks:
- name: Ping my hosts
ansible.builtin.ping:
- name: Print message
ansible.builtin.debug:
msg: Hello world
运行剧本:ansible-playbook -i inventory.ini playbook.yaml
运行效果如图:
通过上面输出可以看到:
- 剧本中的命名name会在输出中显示,因此name尽量使用易于理解的描述
- Gathering Facts任务没在剧本中描述但出现在运行结果中,该任务是隐式运行的,它主要是收集主机信息
- 任务下面的ok代码任务已成功运行
- play recap为总结摘要,总结每个主机上所有任务的执行结果,本示例中的有三个任务,所以ok=3代表任务全部执行成功
其他功能
在掌握清单和剧本后我们便可以进行基础的自动化管理了,不过Ansible的一些其他功能可以帮助我们实现更复杂的需求。碍于篇幅,这里只是简单介绍下,想了解更多可以查询官方文档:Ansible文档
模块和扩展
模块(也称为“任务插件”或“库插件”)是可以从命令行或在 playbook 任务中使用的离散代码单元。Ansible 通常在远程托管节点上执行每个模块,并收集返回值。
下面是yaml文件中使用模块的一个示例:
- name: restart webserver
service:
name: httpd
state: restarted
集合
集合是 Ansible 内容的一种分发格式,其中可以包含剧本、角色、模块和插件。可以理解为编程中的函数,将众多模块等打包为一个函数方法,提供输入参数
- name: Run a play using the collections keyword
hosts: all
collections:
- my_namespace.my_collection
tasks:
- name: Import a role
ansible.builtin.import_role:
name: role1
- name: Run a module not specifying FQCN
my_module:
option1: value
- name: Run a debug task
ansible.builtin.debug:
msg: '{{ lookup("my_namespace.my_collection.lookup1", "param1")| my_namespace.my_collection.filter1 }}'
数据保护Ansible vault
Ansible Vault能够为变量和文件进行加密保护,帮助您安全地存储密码、密钥等敏感信息,避免这些内容以明文形式暴露在Playbook或角色文件中。要使用该功能,您需要预先设置一个或多个加密密码用于数据的加解密操作。如果您选择将密码存放在第三方密钥管理工具中,则需编写脚本实现密码的自动调用。
通过ansible-vault命令行工具,您可以便捷地管理加密内容:无论是创建加密变量、生成加密文件,还是对现有文件进行加密、编辑、重新加密或解密等操作,都能轻松完成。加密后的文件可直接纳入版本控制系统进行妥善托管,团队成员也能更安全地协作共享。
在实际使用场景中,您只需在执行临时命令或运行Playbook时提供对应的加密密码,即可正常调用这些受保护的内容。此外,通过修改ansible.cfg配置文件预设密码文件路径,或是选择在执行时手动输入密码,都能灵活适配不同的安全策略需求。
实际应用场景
下面提出一个实际应用场景并使用ansible进行自动化运行。
场景一:假设现在开发人员在测试库提交了代码,代码编译后程序打包在客户机某目录下,现在需要将文件传输到受控主机指定项目文件夹中,在传输前将项目打包备份到备份目录,传输完成后解压缩并重启服务
---
- name: Deploy application update
hosts: myhosts # 指定目标主机组,按实际情况修改
gather_facts: yes # 设置为no,不收集主机信息,以提升运行速度,这里因为需要时间数据所以打开
#become: yes # 使用特权权限执行任务
vars:
# 控制节点上的软件包路径
local_package_path: "your_dir/publish.zip"
# 目标主机上的项目部署路径
remote_project_dir: "/your_dir"
# 目标主机上的备份根目录
backup_root: "/your_dir"
# 服务名称
service_name: "your_service_name"
tasks:
# 获取时间戳用于创建唯一备份目录
- name: Create timestamp
ansible.builtin.set_fact:
timestamp: "{{ ansible_date_time.date }}_{{ ansible_date_time.time }}"
# 设置备份路径变量
- name: Set backup path
ansible.builtin.set_fact:
backup_path: "{{ backup_root }}/{{ timestamp }}"
# 创建备份目录
- name: Create backup directory
ansible.builtin.file:
path: "{{ backup_path }}"
state: directory
mode: 0755
# 检查项目目录是否存在
- name: Check project directory existence
ansible.builtin.stat:
path: "{{ remote_project_dir }}"
register: dir_stat
# 此处可增加一步,先停止服务再备份
# 备份现有项目(仅当项目目录存在时执行)
- name: Backup existing project
ansible.builtin.archive:
path: "{{ remote_project_dir }}"
dest: "{{ backup_path }}/backup.tar.gz"
format: zip
when: dir_stat.stat.exists
# 传输新软件包到目标主机临时目录
- name: Transfer new package
ansible.builtin.copy:
src: "{{ local_package_path }}"
dest: "{{ remote_project_dir }}/publish.zip"
mode: 0644
# 解压新软件包到项目目录
- name: Deploy new package
ansible.builtin.unarchive:
src: "{{ remote_project_dir }}/publish.zip"
dest: "{{ remote_project_dir }}"
remote_src: yes # 表示源文件在目标主机上
owner: "root" # 按实际情况修改用户
group: "root" # 按实际情况修改用户组
mode: 0755
# 重启应用服务
- name: Restart application service
ansible.builtin.systemd:
name: "{{ service_name }}"
state: restarted
enabled: yes
daemon_reload: yes
# 清理临时文件
- name: Cleanup temporary package
ansible.builtin.file:
path: "{{ remote_project_dir }}/publish.zip"
state: absent
执行命令ansible-playbook -i inventory.ini playbook.yaml运行
场景二:需要对受控服务集群统一更新某项目中的配置文件Appsetting.json
---
- name: Update Appsetting.json
hosts: all # 目标主机组,按实际情况修改
become: yes # 使用特权权限执行任务
vars:
# 本地 Appsetting.json 文件路径
local_config_path: "/path/on/controller/Appsetting.json"
# 目标主机上的项目配置文件路径
remote_config_path: "/opt/your_project/Appsetting.json"
# 备份目录
backup_root: "/backup/your_project"
# 服务名称
service_name: "your_service"
tasks:
# 获取时间戳用于创建唯一备份目录
- name: Create timestamp
ansible.builtin.set_fact:
timestamp: "{{ ansible_date_time.date }}_{{ ansible_date_time.time }}"
# 设置备份路径变量
- name: Set backup path
ansible.builtin.set_fact:
backup_path: "{{ backup_root }}/{{ timestamp }}"
# 创建备份目录
- name: Create backup directory
ansible.builtin.file:
path: "{{ backup_path }}"
state: directory
mode: 0755
# 检查配置文件是否存在
- name: Check if Appsetting.json exists
ansible.builtin.stat:
path: "{{ remote_config_path }}"
register: config_stat
# 备份现有配置文件(仅当文件存在时执行)
- name: Backup existing Appsetting.json
ansible.builtin.copy:
src: "{{ remote_config_path }}"
dest: "{{ backup_path }}/Appsetting.json"
remote_src: yes # 表示源文件在目标主机上
when: config_stat.stat.exists
# 传输新的 Appsetting.json 文件到目标主机
- name: Transfer new Appsetting.json
ansible.builtin.copy:
src: "{{ local_config_path }}"
dest: "{{ remote_config_path }}"
owner: "www-data" # 按实际情况修改用户
group: "www-data" # 按实际情况修改用户组
mode: 0644
# 重启服务(视情况增加这步,有些服务配置文件更改不需要重启)
- name: Restart application service
ansible.builtin.systemd:
name: "{{ service_name }}"
state: restarted
enabled: yes
daemon_reload: yes