Ansible自动化运维入门实战:从安装配置到批量管理服务器
【摘要】 Ansible 自动化运维入门实战:从安装配置到批量管理服务器 一、Ansible 是什么Ansible 是一款无代理(Agentless)的自动化运维工具。所谓无代理,指的是被管理的节点上不需要安装任何客户端程序,Ansible 通过 SSH 连接目标机器并执行命令、推送文件、运行模块。它和 Puppet、Chef 这类需要 Agent 的工具相比,部署成本低得多,适合中小规模集群和云上...
Ansible 自动化运维入门实战:从安装配置到批量管理服务器
一、Ansible 是什么
Ansible 是一款无代理(Agentless)的自动化运维工具。所谓无代理,指的是被管理的节点上不需要安装任何客户端程序,Ansible 通过 SSH 连接目标机器并执行命令、推送文件、运行模块。
它和 Puppet、Chef 这类需要 Agent 的工具相比,部署成本低得多,适合中小规模集群和云上弹性伸缩场景。
Ansible 的核心概念只有四个:
| 概念 | 说明 | 类比 |
|---|---|---|
| Inventory | 主机清单,定义要管哪些机器 | 通讯录 |
| Playbook | YAML 写的剧本,描述要做什么 | 剧本 |
| Task | 剧本里的一个步骤 | 动作 |
| Module | 执行具体工作的插件 | 工具箱 |
二、安装 Ansible
2.1 Ubuntu / Debian
sudo apt update
sudo apt install -y ansible
ansible --version
2.2 CentOS / RHEL
sudo yum install -y epel-release
sudo yum install -y ansible
2.3 pip 安装(推荐版本更可控)
python3 -m pip install --user ansible==2.16.14
export PATH="$HOME/.local/bin:$PATH"
ansible --version
2.4 Windows 宿主机管理 Linux
pip install pywinrm
ansible all -m winrm_ping -e ansible_connection=winrm
三、主机清单(Inventory)
3.1 静态清单
在 inventory.ini 中定义主机组:
[web]
web01.example.com
web02.example.com
[db]
db01.example.com ansible_user=root
[all:children]
web
db
[prod:vars]
ansible_user=root
ansible_port=22
ansible_ssh_private_key_file=~/.ssh/id_rsa
3.2 分组变量与组变量
# group_vars/all.yml
ansible_python_interpreter: /usr/bin/python3
timezone: Asia/Shanghai
# group_vars/web.yml
http_port: 80
nginx_worker_processes: 4
3.3 动态清单(云上必备)
在华为云上可以用动态清单自动拉取 ECS 列表,避免每次手动维护:
#!/usr/bin/env python
import json
import subprocess
def main():
cmd = [
'hcloud', 'ecs', 'list', '-o', 'json',
'-f', 'table', '--columns', 'name,ip,status'
]
out = subprocess.check_output(cmd).decode()
print(json.dumps({"_meta": {"hostvars": {}}}))
# 实际生产中把解析结果写入 hostvars
if __name__ == '__main__':
main()
四、第一个 Playbook
4.1 目录结构
ansible-project/
├── inventory.ini
├── group_vars/
│ └── all.yml
├── playbooks/
│ └── site.yml
└── roles/
└── nginx/
├── tasks/main.yml
├── handlers/main.yml
└── templates/nginx.conf.j2
4.2 site.yml
- name: 配置 web 服务器
hosts: web
become: yes
vars:
package_name: nginx
tasks:
- name: 安装 nginx
ansible.builtin.package:
name: "{{ package_name }}"
state: present
notify: restart nginx
- name: 确保服务开机自启
ansible.builtin.service:
name: "{{ package_name }}"
state: started
enabled: yes
- name: 写入站点首页
ansible.builtin.copy:
content: "Hello from Ansible at {{ ansible_date_time.iso8601 }}\n"
dest: /usr/share/nginx/html/index.html
mode: "0644"
notify: restart nginx
handlers:
- name: restart nginx
ansible.builtin.service:
name: "{{ package_name }}"
state: restarted
4.3 执行 playbook
ansible-playbook -i inventory.ini playbooks/site.yml
常用参数:
# 检查语法,不实际执行
ansible-playbook --syntax-check playbooks/site.yml
# 详细输出
ansible-playbook -v playbooks/site.yml
# 只跑部分主机
ansible-playbook playbooks/site.yml --limit web01
# 差异对比(改之前先看会变什么)
ansible-playbook playbooks/site.yml --check --diff
五、常用模块速查
| 场景 | 模块 | 关键参数 |
|---|---|---|
| 执行命令 | ansible.builtin.command / shell |
chdir, creates |
| 安装软件 | ansible.builtin.package |
name, state |
| 管理服务 | ansible.builtin.service |
state, enabled |
| 写文件 | ansible.builtin.copy / template |
dest, content, src |
| 模板渲染 | ansible.builtin.template |
src, dest, backup |
| 文件属性 | ansible.builtin.file |
path, state, mode |
| 用户管理 | ansible.builtin.user |
name, groups, shell |
| 拉取文件 | ansible.builtin.fetch |
src, dest, flat |
5.1 copy 与 template 的区别
copy:内容是静态文本,适合配置文件不随环境变化时template:使用 Jinja2 渲染,适合多环境共用一套模板
- name: 渲染 nginx 配置
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
backup: yes
notify: restart nginx
对应的 nginx.conf.j2:
worker_processes {{ nginx_worker_processes }};
events {
worker_connections 1024;
}
http {
server {
listen {{ http_port }};
server_name _;
root /usr/share/nginx/html;
}
}
5.2 让命令幂等
command 模块默认不幂等,重复执行就会报错。加 creates 条件:
- name: 解压安装包
ansible.builtin.command: tar -xzf /tmp/app.tar.gz -C /opt/
args:
creates: /opt/app
或者改用 unarchive 模块,它本身就是幂等的。
六、变量与优先级
Ansible 变量优先级(从高到低,数字越小越优先):
- 命令行
-e key=value host_vars/group_vars/- Playbook 内
vars: set_fact产生的事实变量- 采集到的 facts(
ansible_*开头)
6.1 常用内置变量
ansible_default_ipv4.address: 192.168.1.10
ansible_distribution: Ubuntu
ansible_os_family: Debian
ansible_processor_vcpus: 4
ansible_memtotal_mb: 8192
ansible_date_time.iso8601: "2026-11-09T08:30:00.000000+08:00"
6.2 set_fact 跨任务传值
- name: 探测服务端口
ansible.builtin.shell: ss -tlnp | grep {{ port }} || true
register: port_probe
changed_when: false
- name: 记录结果
ansible.builtin.set_fact:
service_running: "{{ port_probe.rc == 0 }}"
set_fact 产生的变量在同一 play 内可被后续任务引用,优先级高于 vars。
七、角色(Role)组织结构
Role 把一组可复用的任务、变量、模板、文件打包在一起:
roles/
└── deploy-app/
├── defaults/main.yml # 默认变量(优先级最低,但最该写默认值)
├── vars/main.yml # 强制变量
├── tasks/main.yml # 任务列表
├── handlers/main.yml # 处理器
├── templates/ # Jinja2 模板
├── files/ # 静态文件
└── meta/main.yml # 依赖声明
7.1 defaults/main.yml
app_name: demo
app_port: 8080
app_dir: /opt/{{ app_name }}
7.2 tasks/main.yml
- name: 创建应用目录
ansible.builtin.file:
path: "{{ app_dir }}"
state: directory
mode: "0755"
- name: 复制应用包
ansible.builtin.copy:
src: "{{ app_name }}.tar.gz"
dest: "{{ app_dir }}/"
mode: "0644"
notify: restart app
- name: 编写启动脚本
ansible.builtin.template:
src: start.sh.j2
dest: "{{ app_dir }}/start.sh"
mode: "0755"
notify: restart app
7.3 使用角色
- name: 部署应用
hosts: all
become: yes
roles:
- role: deploy-app
app_port: 9090
tags: [deploy]
八、标签与跳过
- name: 配置数据库
hosts: db
tasks:
- name: 初始化数据
ansible.builtin.command: /opt/db/init.sh
tags: [init, db]
执行时只跑指定标签:
ansible-playbook site.yml --tags init
ansible-playbook site.yml --skip-tags db
九、错误处理
9.1 忽略错误
- name: 探测服务(失败不中断)
ansible.builtin.command: systemctl status nginx
failed_when: false
changed_when: false
9.2 block 与 rescue
- name: 带兜底的部署流程
hosts: web
block:
- name: 执行部署
ansible.builtin.script: /opt/deploy.sh
rescue:
- name: 回滚
ansible.builtin.command: /opt/rollback.sh
always:
- name: 清理临时文件
ansible.builtin.file:
path: /tmp/deploy.lock
state: absent
9.3 any_errors_fatal
- name: 关键节点
hosts: all
any_errors_fatal: true
tasks:
- name: 不可失败的操作
ansible.builtin.command: /opt/check.sh
十、最佳实践
- 用
--check --diff预演:正式执行前先看差异,确认没写错路径 - 所有任务保持幂等:用
state: present而不是无脑执行命令 - 敏感数据用 Vault:
ansible-vault encrypt group_vars/all/vault.yml - 统一用
become: yes提权,不要在命令里拼sudo - 日志输出到文件:
ANSIBLE_LOG_PATH=/var/log/ansible.log ansible-playbook site.yml - 版本管理:playbook 和 inventory 一起进 Git,改动走 code review
- 超时保护:长任务加
async+poll: 0
- name: 耗时的编译任务
ansible.builtin.command: make -j4
async: 3600
poll: 0
register: compile_job
十一、常用命令速查
# 查看所有主机
ansible all -i inventory.ini --list-hosts
# Ping 测试连通性
ansible all -m ping
# 采集 facts(可缓存加速)
ansible all -m setup
ansible all -m setup --facts-cache
# 执行临时命令
ansible web -m command -a "uptime"
# 同步文件到远程
ansible web -m copy -a "src=./nginx.conf dest=/tmp/nginx.conf"
# 列出可用模块
ansible-doc -l
# 查看模块文档
ansible-doc ansible.builtin.template
十二、小结
Ansible 的学习曲线主要在三个地方:
- YAML 写法:注意缩进统一用空格,不要用 Tab
- 变量优先级:搞清楚了才知道该改哪一层
- 幂等性:让 playbook 可以反复执行而不产生副作用
一旦这三个点吃透,Ansible 就能替代掉绝大部分重复的批量运维操作。建议的上手路径是:先在 localhost 上用 connection: local 练手,写通一个安装 Nginx 的 playbook,再扩展到多机,最后才引入 Role 拆分。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)