从0到1掌握Ansible:让自动化运维不再是梦想

最近在公司推进自动化运维的时候,发现很多同事对Ansible还是一知半解,要么就是简单用用,要么就是直接放弃。其实Ansible真的没那么复杂,我用了这么多年,今天就把我的实战经验分享给大家。

说实话,刚开始接触Ansible的时候我也是懵的。那时候公司有几十台服务器需要管理,每次部署应用或者更新配置都要一台一台去操作,累死累活不说,还容易出错。后来接触到Ansible,真的是解放了双手。

Ansible到底是个什么东西?

简单来说,Ansible就是一个自动化工具。你可以把它理解成一个"遥控器",能够同时控制多台服务器干活。比如你要在100台服务器上安装nginx,传统方式得一台台登录去装,用Ansible的话,写个脚本,一键搞定。

我记得第一次用Ansible批量部署应用的时候,看着终端里刷刷刷地执行命令,那种感觉就像开了挂一样。原本需要一整天的工作,10分钟就搞定了。

控制节点和受控节点的关系

这个概念其实很好理解。控制节点就是你安装Ansible的那台机器,受控节点就是你要管理的那些服务器。

我一般会把Ansible装在跳板机上,这样管理起来比较方便。控制节点需要能SSH到所有受控节点,这是最基本的要求。

bash 复制代码
# 在控制节点安装Ansible
yum install ansible -y

# 或者用pip安装
pip install ansible

受控节点其实什么都不用装,只要能SSH连接就行。这也是Ansible的一个优势,不像其他工具还要在目标机器上装agent。

清单文件(Inventory):管理服务器的花名册

Inventory文件就像是你的服务器通讯录,记录着所有需要管理的机器信息。

最简单的inventory文件长这样:

ini 复制代码
[webservers]
192.168.1.10
192.168.1.11
192.168.1.12

[databases]
192.168.1.20
192.168.1.21

但实际生产环境中,我会写得更详细一些:

ini 复制代码
[webservers]
web01 ansible_host=192.168.1.10 ansible_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa
web02 ansible_host=192.168.1.11 ansible_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa

[databases]
db01 ansible_host=192.168.1.20 ansible_user=mysql ansible_become=yes
db02 ansible_host=192.168.1.21 ansible_user=mysql ansible_become=yes

[production:children]
webservers
databases

这样写的好处是可以给不同的机器设置不同的连接参数。比如有些机器用密钥登录,有些用密码,有些需要sudo权限等等。

模块(Modules):Ansible的工具箱

Ansible有几千个模块,每个模块负责不同的功能。刚开始的时候不用全部掌握,先学会常用的几个就够了。

文件操作模块

copy模块用来复制文件:

yaml 复制代码
- name: 复制配置文件
  copy:
    src: /local/path/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'

file模块用来管理文件和目录:

yaml 复制代码
- name: 创建目录
  file:
    path: /opt/myapp
    state: directory
    owner: www
    group: www
    mode: '0755'

软件包管理

yum模块在CentOS/RHEL上安装软件:

yaml 复制代码
- name: 安装nginx
  yum:
    name: nginx
    state: present

apt模块在Ubuntu/Debian上用:

yaml 复制代码
- name: 安装nginx
  apt:
    name: nginx
    state: present
    update_cache: yes

服务管理

systemd模块管理系统服务:

yaml 复制代码
- name: 启动nginx服务
  systemd:
    name: nginx
    state: started
    enabled: yes

我在实际使用中发现,掌握这几个模块就能解决80%的日常运维工作了。

任务(Tasks)和剧本(Playbooks):自动化的剧本

Task就是一个具体的操作,比如安装软件、复制文件等。Playbook就是把多个Task组织起来,形成一个完整的自动化流程。

我来分享一个实际的例子,部署一个简单的web应用:

yaml 复制代码
---
- name: 部署web应用
  hosts: webservers
  become: yes
  vars:
    app_name: myapp
    app_version: 1.2.3
  
  tasks:
    - name: 安装必要的软件包
      yum:
        name:
          - nginx
          - python3
          - git
        state: present
      
    - name: 创建应用目录
      file:
        path: "/opt/{{ app_name }}"
        state: directory
        owner: nginx
        group: nginx
        mode: '0755'
      
    - name: 下载应用代码
      git:
        repo: https://github.com/company/myapp.git
        dest: "/opt/{{ app_name }}"
        version: "{{ app_version }}"
      notify: restart nginx
    
    - name: 复制nginx配置
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/conf.d/myapp.conf
      notify: restart nginx
    
    - name: 启动nginx服务
      systemd:
        name: nginx
        state: started
        enabled: yes
      
  handlers:
    - name: restart nginx
      systemd:
        name: nginx
        state: restarted

这个playbook做了几件事:安装软件、创建目录、下载代码、配置nginx、启动服务。如果配置文件有变化,还会自动重启nginx。

变量和模板:让配置更灵活

在实际项目中,不同环境的配置肯定是不一样的。这时候就需要用到变量和模板了。

我通常会创建不同环境的变量文件:

group_vars/production.yml:

yaml 复制代码
db_host: prod-db.company.com
db_port: 3306
app_env: production
log_level: warn

group_vars/staging.yml:

yaml 复制代码
db_host: staging-db.company.com
db_port: 3306
app_env: staging
log_level: debug

然后在模板文件中使用这些变量:

templates/app.conf.j2:

复制代码
[database]
host = {{ db_host }}
port = {{ db_port }}

[app]
environment = {{ app_env }}
log_level = {{ log_level }}

这样同一个playbook就能适用于不同的环境了。

角色(Roles):模块化管理的艺术

当项目变得复杂的时候,把所有东西都写在一个playbook里就不合适了。这时候就需要用到Role。

Role的目录结构是这样的:

复制代码
roles/
  nginx/
    tasks/main.yml
    handlers/main.yml
    templates/
    files/
    vars/main.yml
    defaults/main.yml

我来展示一个nginx role的例子:

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: 复制站点配置
  template:
    src: "{{ item }}"
    dest: "/etc/nginx/conf.d/{{ item | basename | regex_replace('.j2$', '') }}"
  with_fileglob:
    - "../templates/sites/*.j2"
  notify: restart nginx

- name: 启动nginx服务
  systemd:
    name: nginx
    state: started
    enabled: yes

roles/nginx/handlers/main.yml:

yaml 复制代码
---
- name: restart nginx
  systemd:
    name: nginx
    state: restarted

使用role的playbook就很简洁了:

yaml 复制代码
---
- name: 配置web服务器
  hosts: webservers
  roles:
    - nginx
    - php
    - mysql

处理器(Handlers):响应式的自动化

Handler是Ansible里一个很有用的特性。它只有在被notify的时候才会执行,而且每次playbook运行时,同一个handler最多只会执行一次。

比如说,你修改了nginx配置文件,肯定要重启nginx服务。但如果你在playbook里修改了多个配置文件,你不希望每修改一个就重启一次,而是希望所有修改完成后再重启一次。这时候handler就派上用场了。

yaml 复制代码
tasks:
  - name: 修改nginx主配置
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: restart nginx
  
  - name: 修改站点配置
    template:
      src: site.conf.j2
      dest: /etc/nginx/conf.d/site.conf
    notify: restart nginx
  
  - name: 修改ssl配置
    template:
      src: ssl.conf.j2
      dest: /etc/nginx/conf.d/ssl.conf
    notify: restart nginx

handlers:
  - name: restart nginx
    systemd:
      name: nginx
      state: restarted

即使三个task都触发了notify,nginx也只会重启一次。

实战技巧和踩坑经验

SSH密钥管理

刚开始用Ansible的时候,我总是为SSH连接的问题头疼。后来发现最好的方式是用密钥认证,而且要做好密钥的分发。

bash 复制代码
# 生成密钥对
ssh-keygen -t rsa -b 4096 -f ~/.ssh/ansible_rsa

# 分发公钥到所有受控节点
ssh-copy-id -i ~/.ssh/ansible_rsa.pub user@target_host

在inventory文件中指定私钥:

ini 复制代码
[servers]
server1 ansible_host=192.168.1.10 ansible_ssh_private_key_file=~/.ssh/ansible_rsa

幂等性的重要性

Ansible的一个重要特性就是幂等性,也就是说多次执行同一个操作,结果应该是一样的。

比如这样写就不是幂等的:

yaml 复制代码
- name: 添加用户到sudoers
  shell: echo "myuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

每次执行都会添加一行,这显然不对。应该这样写:

yaml 复制代码
- name: 添加用户到sudoers
  lineinfile:
    path: /etc/sudoers
    line: "myuser ALL=(ALL) NOPASSWD:ALL"
    state: present

错误处理和调试

在实际使用中,playbook不可能一次就写对。我总结了几个调试技巧:

  1. 使用-v参数增加输出详细程度:
bash 复制代码
ansible-playbook -vvv playbook.yml
  1. 使用debug模块输出变量值:
yaml 复制代码
- name: 显示变量值
  debug:
    var: ansible_facts['os_family']
  1. 使用ignore_errors忽略某些错误:
yaml 复制代码
- name: 可能会失败的任务
  command: some_command_that_might_fail
  ignore_errors: yes
  1. 使用failed_when自定义失败条件:
yaml 复制代码
- name: 检查服务状态
  command: systemctl is-active nginx
  register: nginx_status
  failed_when: nginx_status.rc != 0 and nginx_status.rc != 3

性能优化

当管理的机器多了之后,性能就成了问题。我用过的几个优化技巧:

  1. 调整并发数:
ini 复制代码
# ansible.cfg
[defaults]
forks = 50
  1. 开启SSH pipelining:
ini 复制代码
[ssh_connection]
pipelining = True
  1. 使用strategy插件:
yaml 复制代码
- name: 快速执行的playbook
  hosts: all
  strategy: free
  tasks:
    - name: 简单任务
      ping:

配置文件管理

Ansible的配置文件ansible.cfg可以放在几个地方,优先级从高到低是:

  1. ANSIBLE_CONFIG环境变量指定的文件
  2. 当前目录下的ansible.cfg
  3. 家目录下的.ansible.cfg
  4. /etc/ansible/ansible.cfg

我一般会在项目目录下放一个ansible.cfg:

ini 复制代码
[defaults]
inventory = inventory/hosts
host_key_checking = False
timeout = 30
forks = 20
remote_user = root

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True

实际应用场景

我在工作中用Ansible解决了很多实际问题,分享几个典型场景:

批量系统初始化

新机器上架后需要做一堆初始化工作:创建用户、配置SSH、安装基础软件、设置时区等等。用Ansible写个playbook,新机器几分钟就能初始化完成。

应用部署

以前部署应用要登录每台服务器,停服务、备份、更新代码、重启服务。现在一个playbook搞定,还能做到零停机部署。

配置管理

系统配置变更是运维的家常便饭,用Ansible可以确保所有机器的配置一致性,还能追踪变更历史。

定期维护

比如日志清理、证书更新、安全补丁等定期任务,写成playbook配合cron执行,省心省力。

说到这里,我想起前段时间公司要给所有服务器更新SSL证书。如果手动操作,几百台机器得忙好几天。用Ansible写了个playbook,半小时就全部搞定了,而且零出错。

当然,Ansible也不是万能的。对于一些复杂的编排场景,可能还需要结合其他工具。但对于大部分运维工作来说,Ansible已经足够强大了。

学习Ansible最好的方式就是多动手实践。从简单的任务开始,比如批量执行命令、复制文件等,然后慢慢学习更复杂的特性。记住,任何工具都是为了解决实际问题的,不要为了用而用。

希望这篇文章能帮助大家更好地理解和使用Ansible。自动化运维的路还很长,但有了Ansible这个利器,我们的工作会轻松很多。如果你觉得这篇文章有用,记得点赞转发,让更多的同行受益!

关注@运维躬行录,一起在自动化运维的道路上越走越远!

个人博客:躬行笔记

相关推荐
SelectDB18 小时前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode2 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220703 天前
如何搭建本地yum源(上)
运维
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质6 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工6 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智6 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_6 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉6 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造