运维Linux之Ansible详解学习(更新中)
什么是Ansible
Ansible 是一款新出现的自动化运维工具,基于 Python 开发。以下是对它的详细介绍:
- 功能特点:集合了众多运维工具的优点,能实现批量系统配置、批量程序部署、批量运行命令等功能。它是基于模块工作的,本身没有批量部署能力,而是提供一种框架,真正具有批量部署能力的是其运行的模块。
- 工作原理:通过 SSH 或 Windows 远程管理机制建立临时远程连接,控制节点在大多数安装了 Python 的类 Unix 系统上执行,包括安装了 WSL 的 Windows 系统。系统配置部分通过其自己的声明式语言定义。
- 主要组件:
- 连接插件:负责和被监控端实现通信。
- host inventory:指定操作的主机,是一个配置文件,里面定义了监控的主机。
- 各种模块:包括核心模块、command 模块、自定义模块等。
- 插件:借助于插件完成记录日志邮件等功能。
- playbook:剧本,执行多个任务时可让节点一次性运行多个任务,非必需。
- 设计目标:本质上为最小、一致性、安全和可靠的。如果小心撰写程序,Ansible playbook 脚本文件可以是幂等的,以防止对受控系统产生意外的副作用。Playbook 使用基于 YAML 和 Jinja 模板的简单叙述性语言,仅需要最少的学习。
- 平台支持:控制机器必须是 Linux/Unix 主机,并且需要 Python 2.7 或 3.5。托管节点(如果是类 Unix)必须具有 Python 2.4 或更高版本。从 1.7 版本开始,Ansible 也可以管理 Windows 节点,使用 WS - Management 协议支持的本机 PowerShell 远程处理,而不是 SSH。Ansible 可以部署到裸机主机、虚拟机和云环境。
官网文档地址:
https://docs.ansible.com/ansible/latest/
配置文件
rpm -qc ansible-core
在没下载之前查询不到,q是query(查询),c是configfile(配置文件)/etc/ansible/ansible.cfg # 主配置文件
/etc/ansible/hosts # 主机清单文件
概念
主机清单
官方文档:
https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.
html
[web-servers]
webserver1.example.com
webserver2.example.com
[database-servers]
dbserver1.example.com
dbserver2.example.com
连接插件
官方文档:
https://docs.ansible.com/ansible/latest/plugins/connection.html
[web-servers]
webserver1.example.com ansible_connection=ssh
webserver2.example.com ansible_connection=ssh
[database-servers]
dbserver1.example.com ansible_connection=ssh
dbserver2.example.com ansible_connection=winrm
模块
模块(Modules)是 Ansible 的核心组件,用于在远程主机上执行任务。
Ansible 提供了丰富的内置模块,涵盖了各种任务,如文件操作、软件包管理、服务管理、用
户管理等。还能通过在剧本中调用模块,可以实现自动化任务的执行。
常用模块有:
ping:检测远程主机的连通性。
command/shel:在目标主机上执行命令或命令字符串。
copy:将文件从控制节点复制到远程主机。
file:创建、修改或删除文件和目录。
template:使用 jinja2 模板生成文件,并将其复制到远程主机。
apt/yum:在基于 Debian/RedHat 的系统上安装、升级或移除软件包。
service:启动、停止、重新启动或重载系统服务。
user/group:创建、修改或删除用户和用户组。
lineinfile:在文中添加、修改或删除一行文本。
raw:在目标主机上执行原始命令,绕过模块系统。
wait_for:等待一定时间或直到某个条件为真。
script:在在目标主机上执行本地脚本。
git:克隆或更新 Git 代码库。
debug:打印调试信息。
Playbook
- name: Install and start Nginx #描述 Playbook 或任务的简短名称
hosts: web_servers #指定要执行任务的目标主机或主机组
become: yes #可选参数,用于指定是否以管理员权限执行任务及执行任务的用户。
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
- name: Start Nginx service
service:
name: nginx
state: started
playbook基本格式及用法:
一、Playbook 基础结构
Playbook 由一个或多个 Play(剧本) 组成,每个 Play 定义了一组 主机 和 任务。基本框架如下:
--- # YAML 文件起始标记(必须存在)
- name: <Play 的名称> # 描述性名称(建议明确任务目的,如 "Install Nginx")hosts: <主机或主机组> # 目标主机(必填)gather_facts: <是否收集主机信息> # 可选(默认值为 yes)become: <是否提权> # 可选(默认值为 no)vars: # 定义变量(可选)- var1: value1- var2: value2tasks: # 任务列表(必填)- name: <任务名称> # 描述性名称(建议明确操作,如 "Install nginx package")<模块名>: # 模块名称(如 yum、apt、copy 等)<参数1>: value1 # 模块参数<参数2>: value2when: <条件判断> # 条件执行(可选)tags: <标签> # 标记任务(可选,用于选择性执行)register: <变量名> # 注册任务结果到变量(可选)handlers: # 处理程序(可选,用于响应 notify 事件)- name: <处理程序名称><模块名>: # 通常用于重启服务等操作<参数>: valueroles: # 引入角色(可选,用于模块化管理)- <角色名称>
二、关键组成部分详解
1. Play 级别参数
参数 | 说明 | 示例 |
---|---|---|
name | Play 的描述性名称(建议清晰易懂,便于调试) | name: "Configure Web Servers" |
hosts | 目标主机或主机组(必填),支持清单中的组名、正则表达式或动态主机 | hosts: webservers hosts: 'node[1:3]' hosts: all:!db |
gather_facts | 是否收集目标主机的系统信息(如 IP、内核版本等),值为 yes 或 no | gather_facts: no (适用于无需系统信息的轻量级任务) |
become | 是否提权(如切换为 root 用户),值为 yes 或 no | become: yes become_user: root (指定提权用户) |
vars | 定义 Play 内的变量(优先级高于清单变量) | vars: <br> - port: 8080 <br> - user: admin |
remote_user | 指定连接远程主机的用户(默认取清单中的 ansible_user ) | remote_user: ubuntu |
2. tasks 任务列表
任务是 Playbook 的核心,每个任务调用一个 Ansible 模块完成具体操作。
- 模块类型:
- 核心模块:如
ping
(测试连通性)、yum
/apt
(包管理)、service
(服务管理)、copy
(文件复制)等。 - 扩展模块:如
git
(代码拉取)、mysql_user
(数据库用户管理)等。
- 核心模块:如
- 关键参数:
参数 说明 示例 name
任务的描述性名称(必填,建议明确操作内容,如 "Create directory") name: "Create data directory"
module
模块名称(必填,如 file
、shell
、template
等)file: path=/data state=directory mode=0755
when
条件判断(可选,支持 Jinja2 表达式) when: ansible_os_family == 'Debian'
tags
标记任务(可选,用于通过 --tags
或--skip-tags
选择性执行)tags: [install, web]
register
注册任务结果到变量(可选,用于后续任务引用) register: result <br> debug: var=result.stdout
3. handlers 处理程序
处理程序是被动触发的任务,通常用于重启服务、重载配置等操作,需配合 notify
触发。
tasks:- name: Update config filecopy: src=nginx.conf dest=/etc/nginx/nginx.confnotify: Restart Nginx # 触发名为 "Restart Nginx" 的处理程序handlers:- name: Restart Nginx # 处理程序名称需与 notify 一致service: name=nginx state=restarted
4. roles 角色
角色用于将 Playbook 拆分为模块化组件,提升复用性。
roles:- role: common # 引用 roles/common 目录下的角色var1: value1 # 传递参数给角色- role: webserverport: 8080
三、Playbook 示例
以下是一个完整的 Playbook 示例,用于在 Debian 系统上安装 Nginx 并启动服务:
---
- name: Install and configure Nginxhosts: webserversgather_facts: yesbecome: yesvars:nginx_pkg: nginxnginx_port: 80tasks:- name: Ensure Nginx is installedapt:name: "{{ nginx_pkg }}"state: presentwhen: ansible_os_family == 'Debian'- name: Copy Nginx configcopy:src: nginx.conf.j2dest: /etc/nginx/nginx.confnotify: Reload Nginx- name: Ensure Nginx is runningservice:name: nginxstate: startedenabled: yeshandlers:- name: Reload Nginxservice:name: nginxstate: reloaded
四、最佳实践
- 命名规范:
- Play 和任务名称应清晰描述操作(如
Install Docker Engine
而非Task 1
)。
- Play 和任务名称应清晰描述操作(如
- 变量管理:
- 复杂变量可通过
vars_files
引入外部 YAML 文件,避免 Playbook 臃肿。
- 复杂变量可通过
- 条件判断:
- 使用
when
区分不同系统或环境(如ansible_distribution == 'CentOS'
)。
- 使用
- 错误处理:
- 添加
ignore_errors: yes
忽略非关键错误,或failed_when: condition
自定义失败条件。
- 添加
- 测试与调试:
- 使用
--syntax-check
验证语法,-C
(--check)模式试运行,-vvv
查看详细日志。
- 使用
五、执行 Playbook
ansible-playbook -i inventory/hosts site.yml # 标准执行
ansible-playbook -i inventory/hosts site.yml --tags="install" # 仅执行标记为 install 的任务
ansible-playbook -i inventory/hosts site.yml --limit=webservers # 仅对 webservers 组执行
通过以上结构和规范,可高效编写可维护、易扩展的自动化任务脚本。
安装
安装方法
1.通过包管理器安装
[root@ansible-controller ~]# apt install ansible -y
[root@ansible-controller ~]# dnf install ansible -y
[root@ansible-controller ~]# dnf install ansible-core -y
[root@ansible-controller ~]# ansible --version
2.通过pip安装
[root@ansible-controller ~]# apt install python3 python3-pip -y
[root@ansible-controller ~]# sudo yum install python3 python3-pip -y
[root@free ~]# python
Python 3.9.18 (main, Sep 7 2023, 00:00:00)
[GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> >>> exit
Use exit() or Ctrl-D (i.e. EOF) to exitquit()也行
使用pip安装:
[root@ansible-controller ~]# pip3 install ansible
3.阿里云镜像下载eple辅助安装
阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区阿里巴巴开源镜像站,免费提供Linux镜像下载服务,拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源,此外还提供域名解析DNS、网络授时NTP等服务,致力于为互联网用户提供全面,高效和稳定的基础服务。https://developer.aliyun.com/mirror/eple中选择对应版本。
https://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpmhttps://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpm
1. 什么是 EPEL?
全称:Extra Packages for Enterprise Linux(企业 Linux 额外软件包)
作用:由 Fedora 社区维护的第三方开源软件仓库,为 RHEL、CentOS、Rocky Linux 等系统提供大量 非官方默认源 的软件包(如开发工具、系统工具、库文件等)。
优势:补充官方源中缺失的软件,版本更新相对及时,方便用户快速安装常用工具。
2. epel-release 软件包的作用
功能:这个软件包是 EPEL 源的 安装器和配置文件,用于自动配置系统的软件源信息(如 /etc/yum.repos.d/epel.repo 或 /etc/dnf.repos.d/epel.repo)。
安装后效果:
启用 EPEL 源,允许使用 yum 或 dnf 命令直接安装 EPEL 中的软件包。
包含 GPG 密钥,确保软件包的完整性和安全性。验证 EPEL 源是否启用
# 列出所有已启用的源
dnf repolist enabled# 输出应包含类似内容:
# epel Extra Packages for Enterprise Linux 9 - x86_64
三、使用 EPEL 源安装软件包
安装方式与官方源完全相同,直接使用 dnf 或 yum 命令:
# 示例:安装 htop(系统监控工具,官方源可能没有)
dnf install htop -y# 示例:安装 ansible(自动化运维工具)
dnf install ansible -y# 搜索 EPEL 源中的软件包
dnf search <关键词>
四、EPEL 源的配置与管理
1. 临时禁用 / 启用 EPEL 源
# 禁用 EPEL 源(本次命令生效)
dnf --disablerepo=epel install <软件包># 仅从 EPEL 源安装(忽略其他源)
dnf --enablerepo=epel install <软件包>
2. 永久禁用 EPEL 源
编辑配置文件,将 enabled=1 改为 enabled=0:
vi /etc/yum.repos.d/epel.repo# 修改为:
[epel]
name=Extra Packages for Enterprise Linux 9 - $basearch
#baseurl=https://download.fedoraproject.org/pub/epel/9/$basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-9&arch=$basearch
enabled=0 # 禁用 EPEL 源
gpgcheck=1
...
免密配置
这个是之前的内容(ssh服务)
准备主机
生成密钥对
[root@ansible-controller ~]# ssh-keygen -t rsa (三次回车,不输入其他信息)
# 执行命令后,输入正确密码即可
ssh-copy-id root@192.168.72.64
ssh-copy-id root@192.168.72.65
# 如果免密做成功则无需密码即可登录
ssh root@192.168.72.64
ssh root@192.168.72.65
注意
主机清单
官方文档
https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.
html
基本语法
清单内容可写位置
1. 默认全局清单文件
可以直接写在 Ansible 默认的全局清单文件 /etc/ansible/hosts
里 ,使用时直接执行 Ansible 命令,无需额外指定清单文件路径。不过要注意,直接修改该文件可能影响全局配置,操作前最好备份。
2. 自定义清单文件
后缀名:ini,yaml,yml
创建一个新的文本文件,比如 my_inventory.ini
,将清单内容写入其中。后续使用 Ansible 命令时,通过 -i
参数指定这个文件路径,例如 ansible -i my_inventory.ini server -m ping
。这种方式适合不同项目或环境分开管理清单,方便维护。
3. 清单目录(高级用法)
如果有多个环境(开发、测试、生产等)或更复杂的清单管理需求,可以创建一个清单目录,比如 my_inventory_dir
,在目录内创建不同环境的子目录(如 dev
、prod
) ,把清单文件放在对应的子目录中,使用时指定目录路径,如 ansible -i my_inventory_dir/dev server -m ping
。
配置示例
基本清单
[server]
192.168.72.64
192.168.72.65
[db]
db1.example.com
db2.example.com如果ip是连续的,还可以简写
[server]
192.168.72.[64:65]
[db]
db1.example.com
db2.example.com1. 分组定义
[server] 和 [db] 是两个主机组(Group),用于将功能相似的主机归类。
组名可以自定义,通常根据主机角色(如 web、db)或环境(如 dev、prod)命名。
2. 主机列表
[server] 组:包含两个 IP 地址的主机:
192.168.72.64
192.168.72.65[db] 组:包含两个域名的主机:
db1.example.com
db2.example.com二、Ansible 如何使用这个清单?
当执行 Ansible 命令时,可以通过组名选择目标主机:
# 对 [server] 组中的所有主机执行 ping 模块
ansible server -m ping# 对 [db] 组中的所有主机执行 shell 命令
ansible db -a "df -h"
测试:
[root@ansiblecontroller ~]# ansible -i my_inventory.yml server -m ping
192.168.153.137 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"
}
192.168.153.136 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"
}
这里使用的是135,136,137的主机-i 指定路径server 根据清单指定主机组 也可以是具体ip,域名
特殊标识符:
all 或 *:表示清单中的所有主机。
多组组合:如 server:db(同时选择 server 和 db 组)。-m 指定模块其他常用参数(可选)
1. -u username
指定 SSH 连接的用户名。
bash
-u root # 以 root 用户连接2. -k
提示输入 SSH 密码(适用于密码认证,非密钥认证)。
bash
-k # 执行后会提示输入密码3. -K
提示输入 sudo 密码(用于需要管理员权限的操作)。
bash
-K # 执行后会提示输入 sudo 密码4. -vvv
开启详细模式(-v 越多,输出越详细),用于调试。
bash
-vvv # 显示 SSH 连接过程、模块执行细节等5. -a "参数"
传递模块的参数(仅对部分模块需要)。
bash
-m command -a "ls -l" # 执行 ls -l 命令
-m copy -a "src=file.txt dest=/tmp/" # 复制文件
主机级变量
[server]
192.168.72.64 ansible_user=root ansible_port=22
192.168.72.65 ansible_user=root
[db]
db1.example.com ansible_host=192.168.72.100
db2.example.com ansible_host=192.168.72.101 ansible_user=postgres
配置好后测试同上
优先级:
如果同一参数在多个地方定义,优先级从高到低为:
命令行参数(如 -u root)。
清单文件中的主机变量(如 192.168.1.1 ansible_user=root)。
清单文件中的组变量(如 [web_servers:vars] ansible_user=deploy)。
ansible.cfg 中的全局配置。
为什么需要这些参数?
场景 1:多用户环境
假设你有:
- 生产服务器:只能用
root
用户 SSH 登录。 - 开发服务器:使用
devops
用户 + 密钥认证。
清单可配置为:
[prod_servers]
192.168.1.1 ansible_user=root[dev_servers]
192.168.1.10 ansible_user=devops
场景 2:非标准 SSH 端口
某服务器为安全起见,将 SSH 端口改为 5000:
[secure_servers]
192.168.1.20 ansible_port=5000
场景 3:内网域名与 IP 映射
公司内网有域名 db-prod
,但未配置 DNS,实际 IP 为 10.0.0.5
:
[databases]
db-prod ansible_host=10.0.0.5
主机变量示例:
inventory/ # 清单目录
├── hosts # 主清单文件(INI 或 YAML 格式)
├── group_vars/ # 组变量目录
│ └── web.yml # 名为 web 的组的变量文件
└── host_vars/ # 主机变量目录├── test1.yml # 主机 test1 的变量文件└── test2.yml # 主机 test2 的变量文件变量文件内容示例
1. inventory/hosts(主清单文件)
[web] # 定义名为 web 的主机组
test1 ansible_host=192.168.1.10
test2 ansible_host=192.168.1.112. inventory/host_vars/test1.yml(主机 test1 的变量)
http_port: 8080 # test1 的 HTTP 端口为 8080
app_env: development # test1 的应用环境为开发环境3. inventory/group_vars/web.yml(web 组的公共变量)
http_port: 443 # web 组默认使用 443 端口
ssl_enabled: true # 启用 SSL变量优先级与覆盖规则
Ansible 变量的优先级(从高到低):
命令行参数(如 -e "http_port=80")
主机变量(host_vars/test1.yml)
组变量(group_vars/web.yml)
角色默认变量(roles/<role>/defaults/main.yml)示例覆盖逻辑:
test1 的 http_port 为 8080(主机变量覆盖组变量)。
test2 的 http_port 为 443(继承组变量)。你可以验证什么?
当你执行命令 ansible web -m ping 时:
验证主机连通性:检查 test1 和 test2 是否可通过 SSH 访问。
验证变量加载:通过 debug 模块查看变量是否正确加载:
ansible web -m debug -a "var=http_port"输出应为:
yaml
test1 | SUCCESS => {"http_port": 8080
}
test2 | SUCCESS => {"http_port": 443
}
组级别变量
官方文档
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_varia
bles.html
[server]
192.168.72.64
192.168.72.65
[db]
db1.example.com
db2.example.com
[server:vars]
ansible_user=root
ansible_port=22
[db:vars]
ansible_user=postgres
配置好后可尝试用ping模块测试同上
示例:
invertory
├─ hosts
├─ main.yml
├─ group_vars
│ └─ server.ymlmain.yml:
---
- name: test variablehosts: server # 目标主机组(需与清单文件中的组名匹配)gather_facts: no # 不收集主机信息(加快执行速度)tasks:- name: test varsdebug:msg: "ansible_port = {{ ansible_port }}, ansible_user = {{ ansible_user }}"hosts:
[server]
192.168.72.[136:137]server.yml:
ansible_port: 22
ansible_user: root
ansile_password: '123456'测试:
1.测试playbook
[root@ansiblecontroller ~]# ansible-playbook -i invetory/hosts.yml invetory/main.yml PLAY [test variable] *******************************************************************************************************************************TASK [test vars] ***********************************************************************************************************************************
ok: [192.168.153.136] => {"msg": "ansible_port = 22, ansible_user = root"
}
ok: [192.168.153.137] => {"msg": "ansible_port = 22, ansible_user = root"
}PLAY RECAP *****************************************************************************************************************************************
192.168.153.136 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.153.137 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.测试连通性
[root@ansiblecontroller ~]# ansible -i invetory/hosts.yml all -m ping
192.168.153.136 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"
}
192.168.153.137 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"
}main.yml
Playbook 分析
yaml
---
- name: test variablehosts: server # 目标主机组(需与清单文件中的组名匹配)gather_facts: no # 不收集主机信息(加快执行速度)tasks:- name: test varsdebug:msg: "ansible_port = {{ ansible_port }}, ansible_user = {{ ansible_user }}"这个 Playbook 的作用是:
针对 server 组的所有主机。
打印每个主机的 ansible_port 和 ansible_user 变量值。