Ansible作为无代理、易上手的自动化运维工具,能通过简单的YAML配置实现服务器批量管理、软件部署、配置同步、任务执行等操作,大幅降低人工运维成本。
一、Ansible核心认知:为什么选择Ansible?
1.1 Ansible核心优势
- 无代理架构:目标主机无需安装Agent,仅需SSH和Python(大部分Linux系统默认自带),部署零侵入;
- 声明式配置:通过YAML编写Playbook,只需定义"最终状态",无需关注执行过程;
- 模块化设计:内置上千个模块(如yum、service、file),覆盖运维90%以上场景,无需重复造轮子;
- 幂等性:多次执行同一配置,结果一致(不会重复安装已存在的软件、不会重复启动已运行的服务);
- 易扩展:支持自定义模块、插件,适配企业个性化运维需求。
1.2 适用场景
- 批量服务器初始化(系统配置、用户创建、依赖安装);
- 软件包批量安装/升级/卸载(Nginx、MySQL、Redis等);
- 配置文件统一分发(跨服务器同步配置,保证一致性);
- 服务批量启停/重启(如集群服务重启、应用发布);
- 定时任务自动化(结合Crond实现周期性运维操作);
- 跨机房/跨云平台服务器管理(兼容阿里云、腾讯云、物理机等)。
1.3 核心架构
控制节点(Control Node) → SSH连接 → 目标节点(Managed Nodes)
- 控制节点:安装Ansible的主机(仅需1台,推荐Linux系统,Windows需WSL);
- 目标节点:需要被管理的服务器(Linux/Windows,本文以Linux为主);
- 核心组件:Inventory(主机清单)、Module(模块)、Playbook(剧本)、Role(角色)。
二、第一步:Ansible环境搭建
2.1 控制节点安装Ansible
2.1.1 CentOS/RHEL系统
bash
# 安装EPEL源(CentOS默认无Ansible)
yum install -y epel-release
# 安装Ansible(推荐2.10+版本)
yum install -y ansible
# 验证安装
ansible --version
2.1.2 Ubuntu/Debian系统
bash
# 更新源
apt update
# 安装软件依赖
apt install -y software-properties-common
# 添加Ansible源
add-apt-repository --yes --update ppa:ansible/ansible
# 安装Ansible
apt install -y ansible
2.1.3 验证安装
执行以下命令,输出Ansible版本即安装成功:
bash
ansible --version
# 预期输出示例:
# ansible [core 2.15.0]
# config file = /etc/ansible/ansible.cfg
# configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
# ansible python module location = /usr/lib/python3.9/site-packages/ansible
# ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
# executable location = /usr/bin/ansible
# python version = 3.9.16 (main, May 15 2023, 23:46:34) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)]
# jinja version = 3.1.2
# libyaml = True
2.2 目标节点前置配置
Ansible通过SSH管理目标节点,需保证控制节点能免密登录目标节点:
2.2.1 控制节点生成SSH密钥
bash
# 生成RSA密钥(一路回车,无需设置密码)
ssh-keygen -t rsa -b 2048
# 查看公钥
cat ~/.ssh/id_rsa.pub
2.2.2 推送公钥到目标节点
bash
# 方式1:手动复制(单节点)
ssh-copy-id root@192.168.1.10 # 替换为目标节点IP/用户名
# 方式2:批量推送(多节点,需提前安装sshpass)
# 安装sshpass
yum install -y sshpass
# 批量推送(示例:推送至192.168.1.10-12)
for ip in 192.168.1.10 192.168.1.11 192.168.1.12; do
sshpass -p "目标节点root密码" ssh-copy-id -o StrictHostKeyChecking=no root@$ip
done
2.2.3 验证免密登录
bash
ssh root@192.168.1.10 # 无需输入密码即登录成功
2.3 基础配置(可选)
修改Ansible主配置文件/etc/ansible/ansible.cfg,优化默认配置:
ini
[defaults]
# 禁用主机密钥检查(避免首次连接提示)
host_key_checking = False
# 默认Inventory文件路径
inventory = /etc/ansible/hosts
# 超时时间(避免SSH连接超时)
timeout = 30
# 模块并行执行数
forks = 50
[privilege_escalation]
# 默认提权(目标节点执行sudo无需密码)
become = True
become_method = sudo
become_user = root
become_ask_pass = False
三、第二步:核心组件解析与基础使用
3.1 Inventory(主机清单):定义被管理节点
Inventory是Ansible的"主机列表",用于分组管理目标节点,支持静态文件和动态脚本(如对接云平台API)。
3.1.1 静态Inventory示例(/etc/ansible/hosts)
ini
# 单主机配置
192.168.1.10 ansible_ssh_port=22 ansible_ssh_user=root
# 分组配置(推荐)
[web_servers] # 组名:Web服务器
192.168.1.10
192.168.1.11
[db_servers] # 组名:数据库服务器
192.168.1.20
192.168.1.21
# 组变量(该组所有主机共用)
[web_servers:vars]
nginx_port=80
app_path=/var/www/html
# 嵌套组(包含其他组)
[all_servers:children]
web_servers
db_servers
3.1.2 验证Inventory
bash
# 列出所有主机
ansible all --list-hosts
# 列出指定组主机
ansible web_servers --list-hosts
3.2 Ad-Hoc命令:临时执行单条运维操作
Ad-Hoc是Ansible的"临时命令",适合快速执行简单操作(无需编写Playbook),语法:
bash
ansible <目标主机/组> -m <模块名> -a <模块参数>
3.2.1 常用Ad-Hoc命令示例
bash
# 1. 测试所有主机连通性(ping模块)
ansible all -m ping
# 2. 批量执行shell命令(查看目标主机内存)
ansible web_servers -m shell -a "free -h"
# 3. 批量安装Nginx(yum模块)
ansible web_servers -m yum -a "name=nginx state=present"
# 4. 批量启动Nginx服务(service模块)
ansible web_servers -m service -a "name=nginx state=started enabled=yes"
# 5. 批量分发文件(copy模块)
ansible web_servers -m copy -a "src=/root/nginx.conf dest=/etc/nginx/nginx.conf mode=0644"
# 6. 批量创建目录(file模块)
ansible web_servers -m file -a "path=/var/www/html state=directory mode=0755"
# 7. 批量重启服务(service模块)
ansible all_servers -m service -a "name=network state=restarted"
3.3 Module(模块):Ansible的"功能单元"
Ansible内置上千个模块,覆盖运维全场景,核心模块分类:
| 模块类型 | 常用模块 | 用途 |
|---|---|---|
| 系统模块 | yum/apt、service、user | 软件安装、服务管理、用户创建 |
| 文件模块 | copy、file、template | 文件拷贝、目录创建、模板渲染 |
| 命令模块 | shell、command、script | 执行命令/脚本 |
| 网络模块 | uri、iptables、firewalld | HTTP请求、防火墙配置 |
| 数据库模块 | mysql_db、redis | 数据库管理、Redis操作 |
3.3.2 模块帮助查询
bash
# 查看模块列表
ansible-doc -l
# 查看指定模块详细用法(如yum模块)
ansible-doc yum
3.4 Playbook:自动化配置的核心(声明式配置)
Playbook是Ansible的"剧本",通过YAML格式定义一系列运维任务,支持变量、条件、循环、角色等高级特性,是企业级自动化配置的核心。
3.4.1 Playbook基础结构
一个Playbook包含一个或多个"Play",每个Play对应一组目标主机和任务:
yaml
# 示例:install_nginx.yml
- name: 批量安装并配置Nginx # Play名称(可选,便于日志查看)
hosts: web_servers # 目标主机/组
remote_user: root # 执行用户
become: yes # 是否提权到root(默认no)
tasks: # 任务列表(按顺序执行)
- name: 安装Nginx软件包 # 任务名称(必填,便于调试)
yum: # 模块名
name: nginx # 模块参数
state: present
- name: 部署Nginx配置文件
copy:
src: ./nginx.conf
dest: /etc/nginx/nginx.conf
mode: 0644
notify: restart nginx # 触发Handlers(配置变更后重启)
- name: 启动Nginx服务
service:
name: nginx
state: started
enabled: yes
handlers: # 触发器(仅被notify触发时执行)
- name: restart nginx
service:
name: nginx
state: restarted
3.4.2 执行Playbook
bash
# 基本执行
ansible-playbook install_nginx.yml
# 常用参数
ansible-playbook install_nginx.yml \
-i inventory.ini # 指定自定义Inventory文件(默认/etc/ansible/hosts)
--check # 干跑模式(验证语法,不实际执行)
-v # 详细输出(-vvv为最详细,用于调试)
--limit web_servers # 仅执行指定组
--tags install # 仅执行带指定标签的任务
四、第三步:Playbook核心特性实战
4.1 变量(Variables):减少重复配置
变量用于存储可复用的值,支持多种定义方式,优先级:命令行变量 > Play变量 > Inventory变量 > 事实变量。
4.1.1 定义变量的4种方式
yaml
# 方式1:Play内部定义(vars字段)
- name: 使用Play变量
hosts: web_servers
vars:
nginx_port: 80
nginx_conf_path: /etc/nginx/nginx.conf
tasks:
- name: 打印变量
debug:
msg: "Nginx端口:{{ nginx_port }}" # 引用变量:{{ 变量名 }}
# 方式2:外部变量文件(vars_files字段)
# 新建vars/nginx_vars.yml
# nginx_port: 8080
# nginx_conf_path: /etc/nginx/nginx.conf
- name: 使用外部变量文件
hosts: web_servers
vars_files:
- ./vars/nginx_vars.yml
tasks:
- name: 打印变量
debug:
msg: "Nginx端口:{{ nginx_port }}"
# 方式3:Inventory变量(在hosts文件中定义)
# [web_servers:vars]
# nginx_port=80
# 方式4:命令行传递(-e参数)
# ansible-playbook playbook.yml -e "nginx_port=8080"
4.1.2 事实变量(Facts):自动采集目标主机信息
Ansible自动采集目标主机的系统信息(如IP、CPU、系统版本),可直接引用:
yaml
- name: 使用事实变量
hosts: all
tasks:
- name: 打印目标主机信息
debug:
msg: |
主机名:{{ ansible_hostname }}
IP地址:{{ ansible_default_ipv4.address }}
系统版本:{{ ansible_distribution_version }}
CPU核心数:{{ ansible_processor_vcpus }}
4.2 模板(Templates):动态生成配置文件
通过Jinja2模板引擎动态生成配置文件,支持变量、条件、循环,模板文件后缀为.j2。
4.2.1 模板示例(templates/nginx.conf.j2)
nginx
worker_processes {{ ansible_processor_vcpus }}; # 引用事实变量(CPU核心数)
listen {{ nginx_port }}; # 引用自定义变量
server_name {{ ansible_default_ipv4.address }};
{% if nginx_port == 443 %} # 条件判断
ssl on;
ssl_certificate /etc/nginx/cert.pem;
{% endif %}
4.2.2 使用模板模块
yaml
- name: 部署动态Nginx配置
hosts: web_servers
vars:
nginx_port: 80
tasks:
- name: 渲染模板并部署
template:
src: ./templates/nginx.conf.j2 # 本地模板文件
dest: /etc/nginx/nginx.conf # 目标路径
mode: 0644
4.3 条件判断(Conditionals):按需执行任务
通过when关键字实现条件执行,适合跨系统、差异化配置场景:
yaml
- name: 跨系统安装Nginx
hosts: all
tasks:
# CentOS系统用yum安装
- name: CentOS安装Nginx
yum:
name: nginx
state: present
when: ansible_distribution == "CentOS"
# Ubuntu系统用apt安装
- name: Ubuntu安装Nginx
apt:
name: nginx
state: present
update_cache: yes
when: ansible_distribution == "Ubuntu"
4.4 循环(Loops):批量执行重复任务
通过loop关键字实现循环执行,减少代码冗余:
yaml
- name: 批量操作示例
hosts: web_servers
tasks:
# 批量安装多个软件
- name: 安装Nginx、Redis、Git
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- redis
- git
# 批量创建用户(循环字典)
- name: 创建运维用户
user:
name: "{{ item.name }}"
group: "{{ item.group }}"
create_home: yes
loop:
- { name: "devops", group: "admin" }
- { name: "test", group: "guest" }
4.5 角色(Roles):Playbook模块化(企业级必备)
当Playbook复杂时,通过Roles将任务、变量、模板按功能拆分,实现模块化复用,适合大型项目。
4.5.1 Roles目录结构
web_deploy/
├── inventory.ini
├── site.yml # 主Playbook
├── roles/
│ ├── nginx/ # Nginx角色
│ │ ├── tasks/ # 任务(main.yml为入口)
│ │ ├── vars/ # 变量
│ │ ├── templates/ # 模板
│ │ ├── handlers/ # 触发器
│ │ └── defaults/ # 默认变量(优先级最低)
│ └── redis/ # Redis角色
│ ├── tasks/
│ └── ...
4.5.2 编写Roles(以nginx角色为例)
- 编写任务:
roles/nginx/tasks/main.yml
yaml
- name: 安装Nginx
yum:
name: nginx
state: present
- name: 部署配置文件
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: 启动Nginx
service:
name: nginx
state: started
enabled: yes
- 编写触发器:
roles/nginx/handlers/main.yml
yaml
- name: restart nginx
service:
name: nginx
state: restarted
- 主Playbook引用Roles:
site.yml
yaml
- name: 部署Web服务
hosts: web_servers
roles:
- nginx # 引用nginx角色
- redis # 引用redis角色
- 执行Roles
bash
ansible-playbook -i inventory.ini site.yml
五、第四步:企业级实战案例------服务器初始化自动化
5.1 需求场景
批量初始化10台新服务器,完成以下操作:
- 系统初始化(关闭SELinux、配置时区、同步时间);
- 安装基础依赖(wget、curl、gcc、firewalld);
- 创建运维用户(devops),配置sudo权限;
- 关闭无用服务(postfix、bluetooth);
- 配置防火墙(开放22、80、443端口)。
5.2 目录结构
server_init/
├── inventory.ini
├── site.yml
└── roles/
└── init/
├── tasks/
│ └── main.yml
├── vars/
│ └── main.yml
└── handlers/
└── main.yml
5.3 核心文件编写
5.3.1 Inventory(inventory.ini)
ini
[new_servers]
192.168.1.100
192.168.1.101
192.168.1.102
192.168.1.103
192.168.1.104
[new_servers:vars]
ansible_ssh_user=root
ansible_ssh_port=22
5.3.2 变量文件(roles/init/vars/main.yml)
yaml
# 基础依赖包
base_packages:
- wget
- curl
- gcc
- make
- firewalld
- chrony
# 运维用户配置
ops_user: devops
ops_group: admin
# 开放的防火墙端口
firewall_ports:
- 22/tcp
- 80/tcp
- 443/tcp
# 要关闭的无用服务
unwanted_services:
- postfix
- bluetooth
5.3.3 任务文件(roles/init/tasks/main.yml)
yaml
# 1. 安装基础依赖包
- name: 安装基础依赖包
yum:
name: "{{ base_packages }}"
state: present
update_cache: yes
# 2. 关闭SELinux
- name: 临时关闭SELinux
command: setenforce 0
ignore_errors: yes
- name: 永久关闭SELinux
lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: 'SELINUX=disabled'
# 3. 配置系统时区
- name: 设置时区为Asia/Shanghai
timezone:
name: Asia/Shanghai
# 4. 同步系统时间
- name: 启动chrony服务
service:
name: chrony
state: started
enabled: yes
- name: 同步网络时间
command: chronyc sync
changed_when: false
# 5. 创建运维用户组和用户
- name: 创建运维用户组
group:
name: "{{ ops_group }}"
state: present
- name: 创建运维用户
user:
name: "{{ ops_user }}"
group: "{{ ops_group }}"
shell: /bin/bash
create_home: yes
home: /home/{{ ops_user }}
password: "$6$salt$xxxxxxxxxxxx" # 加密后的密码(可用openssl passwd -6生成)
# 6. 配置sudo权限(无需密码)
- name: 配置devops用户sudo权限
lineinfile:
path: /etc/sudoers
line: "{{ ops_user }} ALL=(ALL) NOPASSWD: ALL"
validate: "visudo -cf %s" # 验证sudoers语法
# 7. 关闭无用服务
- name: 关闭无用服务
service:
name: "{{ item }}"
state: stopped
enabled: no
loop: "{{ unwanted_services }}"
ignore_errors: yes # 服务不存在时忽略错误
# 8. 配置防火墙
- name: 启动firewalld服务
service:
name: firewalld
state: started
enabled: yes
- name: 开放防火墙端口
firewalld:
port: "{{ item }}"
zone: public
permanent: yes
state: enabled
loop: "{{ firewall_ports }}"
notify: restart firewalld
5.3.4 触发器(roles/init/handlers/main.yml)
yaml
- name: restart firewalld
service:
name: firewalld
state: restarted
5.3.5 主Playbook(site.yml)
yaml
- name: 批量初始化新服务器
hosts: new_servers
remote_user: root
roles:
- init
- name: 验证初始化结果
hosts: new_servers
tasks:
- name: 验证SELinux状态
command: getenforce
register: selinux_status
changed_when: false
failed_when: selinux_status.stdout != "Disabled"
- name: 验证运维用户存在
command: id {{ ops_user }}
register: user_status
changed_when: false
- name: 输出初始化状态
debug:
msg: |
SELinux状态:{{ selinux_status.stdout }}
运维用户状态:{{ "存在" if user_status.rc == 0 else "不存在" }}
防火墙端口:{{ firewall_ports }}
vars:
ops_user: devops
firewall_ports: [22/tcp, 80/tcp, 443/tcp]
5.4 执行初始化
bash
# 干跑验证
ansible-playbook -i inventory.ini site.yml --check -v
# 实际执行
ansible-playbook -i inventory.ini site.yml -v
六、Ansible自动化配置最佳实践
6.1 目录规范化
project/
├── inventory/ # Inventory文件(按环境拆分:dev/test/prod)
│ ├── dev.ini
│ ├── test.ini
│ └── prod.ini
├── playbooks/ # Playbook文件
│ ├── server_init.yml
│ ├── deploy_nginx.yml
│ └── deploy_mysql.yml
├── roles/ # 角色目录
│ ├── init/
│ ├── nginx/
│ └── mysql/
├── vars/ # 全局变量
├── templates/ # 全局模板
└── scripts/ # 自定义脚本
6.2 安全最佳实践
-
敏感信息加密 :用Ansible Vault加密密码、密钥等敏感变量:
bash# 加密变量文件 ansible-vault encrypt vars/secret_vars.yml # 执行Playbook时解密 ansible-playbook playbook.yml --ask-vault-pass -
最小权限原则:避免用root执行Playbook,配置普通用户sudo权限;
-
禁用危险模块 :生产环境限制使用
shell/command模块,优先用专用模块(如yum、service)。
6.3 性能优化
- 提高并行数 :修改
ansible.cfg的forks参数(默认5,可改为50~100); - 关闭事实采集 :无需主机信息时,添加
gather_facts: no减少执行时间; - 使用管道模式 :
ansible.cfg中开启pipelining = True,减少SSH连接次数。
6.4 调试技巧
-
干跑模式 :
--check参数验证Playbook语法和执行计划; -
详细输出 :
-v/-vvv参数查看执行细节,定位错误; -
任务调试 :用
debug模块打印变量,验证逻辑:yaml- name: 调试变量 debug: var: ansible_default_ipv4.address