资讯动态

Ansible Playbook 实战秘籍:轻松实现服务器配置与管理的自动化

发布时间:2026/8/24 0:22:48 来源:尧图企业网站定制
第一部分开篇与基础入门1.1 为什么需要自动化运维在传统的运维模式中我们通常通过SSH登录到服务器逐条执行命令来部署应用或修改配置。这种“人肉运维”模式存在以下痛点效率低下重复性劳动尤其是在管理成百上千台服务器时。人为失误多打一个空格、漏掉一个参数都可能导致服务故障。配置漂移不同服务器之间的配置随着时间的推移变得不一致。缺乏记录无法追溯谁在什么时候改了什么配置。Ansible的出现解决了这些问题。它是一种基于Python的开源自动化工具具有以下显著特点无代理架构不需要在目标服务器上安装任何Agent基于SSH协议通信。声明式语言你只需要定义“系统最终应该是什么状态”Ansible负责实现它。YAML语法剧本Playbook使用YAML编写易于阅读和编写。1.2 Ansible 核心组件解析在开始编写Playbook之前必须理解Ansible的四大核心组件控制节点安装了Ansible的机器。可以是你的笔记本也可以是专门的堡垒机。管理节点通过SSH连接被管理的节点。被管理节点 (Managed Nodes)由Ansible管理的服务器物理机、虚拟机、容器。不需要安装Ansible但需要Python环境和SSH服务。清单 (Inventory)定义被管理节点的文件。通常是/etc/ansible/hosts或自定义的INI/YAML文件。可以将主机分组如[webservers][dbservers]。模块 (Modules)Ansible执行的具体动作单元。例如copy模块用于复制文件yum模块用于安装软件包。Ansible有上千个内置模块。剧本 (Playbooks)核心所在。一个YAML文件包含了一个或多个“Play”。每个Play定义了在哪些主机上执行用什么用户执行以及执行哪些任务Tasks。1.3 环境搭建与配置1. 安装 Ansible (控制节点)Ubuntu/Debian:bashsudo apt update sudo apt install ansible -yCentOS/RHEL 8:bashsudo dnf install epel-release sudo dnf install ansible -y验证安装:bashansible --version # 输出示例: ansible [core 2.14.x]2. 配置 SSH 免密登录Ansible依赖SSH。为了方便建议配置密钥认证。在控制节点生成密钥:bashssh-keygen -t rsa -b 4096 -C ansible将公钥复制到被管理节点:bashssh-copy-id useryour_server_ip3. 创建 Inventory 文件我们创建一个项目目录和简单的库存文件。bashmkdir ansible-automation cd ansible-automation vim inventory.iniinventory.ini 内容:ini[webservers] web1.example.com ansible_userroot web2.example.com ansible_userroot [databases] db1.example.com ansible_userubuntu [all:vars] ansible_python_interpreter/usr/bin/python34. 测试连通性 (Ad-Hoc 命令)在正式写Playbook之前先测试是否能成功管理节点。bash# -i 指定库存文件 -m 指定模块 ping 模块用于测试连通性 ansible all -i inventory.ini -m ping成功返回:textweb1.example.com | SUCCESS { changed: false, ping: pong }第二部分Playbook 核心语法与结构2.1 第一个 Playbook: Hello World让我们创建一个最简单的Playbook在所有Web服务器上创建一个文件。文件名:first_playbook.ymlyaml--- # --- 这是YAML文件的开始标记 - name: 我的第一个Playbook hosts: webservers # 目标主机组对应inventory中的[webservers] become: yes # 是否提权相当于sudo vars: # 定义变量 file_content: Hello from Ansible! dest_path: /tmp/hello.txt tasks: - name: 创建一个包含文本的文件 ansible.builtin.copy: # 使用copy模块 (全限定名) content: {{ file_content }} # 使用变量 dest: {{ dest_path }} mode: 0644 - name: 显示文件内容 (仅调试用) ansible.builtin.shell: cat /tmp/hello.txt register: result # 将命令输出注册到变量result - name: 打印输出信息 ansible.builtin.debug: var: result.stdout # 打印result变量的stdout属性执行Playbookbashansible-playbook -i inventory.ini first_playbook.yml输出解读:PLAY [我的第一个Playbook]: 显示正在执行的Play名称。TASK [Gathering Facts]: 自动执行的事实收集任务获取主机信息。TASK [创建一个包含文本的文件]: 我们的任务。PLAY RECAP: 总结显示成功、失败、变更的数量。2.2 YAML 语法要点YAML是Playbook的基础必须严格遵守缩进规则。缩进: 使用空格不要使用Tab。通常缩进2个或4个空格。列表: 使用短横线-表示。yamltasks: - name: task1 - name: task2字典: 使用key: value格式冒号后必须有空格。yamlvars: http_port: 80 max_clients: 200多行字符串:保留换行: 使用|折叠换行: 使用2.3 常用模块详解模块是Ansible的瑞士军刀。以下是生产环境最常用的几个模块。1.copy模块将控制节点的文件复制到远程节点。yaml- name: 复制配置文件 ansible.builtin.copy: src: /local/path/app.conf dest: /etc/app/app.conf owner: root group: root mode: 0644 backup: yes # 如果文件存在冲突备份原文件2.file模块管理文件、目录、链接的属性。yaml- name: 创建目录 ansible.builtin.file: path: /var/www/html state: directory mode: 0755 - name: 创建软链接 ansible.builtin.file: src: /usr/bin/python3 dest: /usr/bin/python state: link3.yum/apt模块包管理。yaml- name: 安装 Nginx (CentOS) ansible.builtin.yum: name: nginx state: present # present: 安装, latest: 更新, absent: 卸载 when: ansible_os_family RedHat - name: 安装 Nginx (Ubuntu) ansible.builtin.apt: name: nginx state: present update_cache: yes # 相当于 apt update when: ansible_os_family Debian4.service/systemd模块管理服务状态。yaml- name: 启动并开机自启 Nginx ansible.builtin.service: name: nginx state: started # started, stopped, restarted, reloaded enabled: yes5.template模块基于Jinja2模板生成文件支持变量、循环、条件判断。后续会详细讲。6.command与shellcommand: 默认模块不支持$HOME|等shell特性。shell: 通过/bin/sh执行支持管道和重定向。yaml- name: 执行简单命令 ansible.builtin.command: uptime - name: 执行复杂Shell命令 ansible.builtin.shell: echo Memory usage: free -h第三部分变量、事实与循环3.1 变量的定义与使用变量让Playbook变得灵活。变量可以在多个层级定义。1. 在 Playbook 中定义 (vars)yaml- hosts: all vars: package_name: nginx service_port: 8080 tasks: - name: 安装 {{ package_name }} ansible.builtin.yum: name: {{ package_name }} state: present2. 在 Inventory 中定义ini[webservers] web1 ansible_host192.168.1.10 http_port80 web2 ansible_host192.168.1.11 http_port443 [webservers:vars] ntp_serverntp.ubuntu.com3. 在文件中定义 (vars_files)yaml- hosts: all vars_files: - vars/common.yml - vars/{{ ansible_os_family }}.yml4. 变量优先级 (由低到高)inventory group_varsinventory host_varsplaybook vars_filesplaybook varsinclude_vars命令行-e参数 (最高优先级)3.2 Facts (收集系统信息)Facts是Ansible在运行Playbook时通过setup模块自动收集的关于被管理节点的信息。bash# 手动查看所有 facts ansible web1 -i inventory.ini -m setup常用 Facts 变量:ansible_distribution: 操作系统发行版 (Ubuntu, CentOS)ansible_os_family: 家族 (Debian, RedHat)ansible_default_ipv4.address: 默认IPv4地址ansible_memtotal_mb: 总内存(MB)ansible_processor_cores: CPU核心数实战基于系统类型执行不同任务yaml- name: 根据操作系统安装不同的Web服务器 hosts: all tasks: - name: 安装 Apache for Debian ansible.builtin.apt: name: apache2 state: present when: ansible_os_family Debian - name: 安装 httpd for RedHat ansible.builtin.yum: name: httpd state: present when: ansible_os_family RedHat - name: 确保服务启动 ansible.builtin.service: name: {{ apache2 if ansible_os_family Debian else httpd }} state: started性能提示: 如果不需要Facts可以在Playbook中设置gather_facts: no来加速执行。3.3 循环 (Loops)Ansible提供了多种循环方式。1.loop标准循环yaml- name: 安装多个软件包 ansible.builtin.yum: name: {{ item }} state: present loop: - git - wget - vim - curl2. 循环字典yaml- name: 创建多个用户并配置不同的UID ansible.builtin.user: name: {{ item.name }} uid: {{ item.uid }} state: present loop: - { name: alice, uid: 1001 } - { name: bob, uid: 1002 }3.with_items(旧语法但常见)yaml- name: 旧式循环 ansible.builtin.copy: src: {{ item }} dest: /tmp/ with_items: - file1.txt - file2.txt第四部分高级特性与最佳实践4.1 条件判断 (When)条件判断控制任务是否执行。yaml- name: 只有当配置文件改变时才重启服务 ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx # register 注册变量用于判断是否有变更 - name: 如果操作系统版本是 20.04 则执行特定任务 ansible.builtin.shell: echo Ubuntu 20.04 detected when: ansible_distribution_version 20.04 - name: 多条件组合 ansible.builtin.debug: msg: Condition met when: (ansible_distribution CentOS and ansible_distribution_major_version 7) or force_upgrade is defined4.2 处理程序 (Handlers)Handlers是特殊的Tasks只有在被notify通知时才会执行且只在Play结束时执行一次无论被通知多少次。yaml- name: 部署 Nginx 配置 hosts: webservers tasks: - name: 更新 Nginx 配置文件 ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: - restart nginx # 通知handler - reload firewall # 可以通知多个 - name: 更新 SSL 证书 ansible.builtin.copy: src: cert.pem dest: /etc/ssl/cert.pem notify: restart nginx handlers: - name: restart nginx ansible.builtin.service: name: nginx state: restarted - name: reload firewall ansible.builtin.systemd: name: firewalld state: reloaded4.3 Jinja2 模板引擎模板文件通常以.j2结尾。它允许你将动态变量注入到静态配置文件中。场景: 生成 Nginx 配置其中 server_name 和 root 目录根据主机名变化。模板文件:nginx.conf.j2jinja2server { listen 80; server_name {{ ansible_fqdn }}; root {{ web_root }}; index index.html; # 使用 if 语句 {% if enable_ssl %} listen 443 ssl; ssl_certificate /etc/ssl/certs/{{ ansible_hostname }}.crt; ssl_certificate_key /etc/ssl/private/{{ ansible_hostname }}.key; {% endif %} # 使用循环生成 location 块 location / { try_files $uri $uri/ 404; } {% for proxy in proxies %} location {{ proxy.path }} { proxy_pass {{ proxy.url }}; } {% endfor %} }Playbook 引用:yaml- name: 使用模板部署配置 hosts: webservers vars: web_root: /var/www/mysite enable_ssl: true proxies: - path: /api url: http://backend-api:8080 - path: /admin url: http://admin-service:3000 tasks: - name: 部署 nginx 配置 ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/sites-available/default notify: restart nginx4.4 角色 (Roles)Roles 是 Ansible 中用于代码复用的最佳实践。它将变量、任务、文件、模板、处理器等组织成标准化的目录结构。目录结构textplaybook.yml roles/ └── common/ # 角色名称 ├── tasks/ # 主要任务列表 │ └── main.yml ├── handlers/ # 处理器 │ └── main.yml ├── defaults/ # 默认变量 (优先级最低) │ └── main.yml ├── vars/ # 角色变量 (优先级高) │ └── main.yml ├── files/ # 静态文件 (copy 模块使用) │ └── foo.conf ├── templates/ # Jinja2 模板 (template 模块使用) │ └── nginx.conf.j2 └── meta/ # 角色依赖关系 └── main.yml创建角色bash# 使用 ansible-galaxy 初始化角色骨架 ansible-galaxy init roles/webserver编写角色示例 (roles/webserver/tasks/main.yml)yaml--- - name: 安装 Nginx ansible.builtin.package: name: nginx state: present - name: 复制虚拟主机配置 ansible.builtin.template: src: default.conf.j2 dest: /etc/nginx/conf.d/default.conf notify: restart nginx - name: 启动 Nginx ansible.builtin.service: name: nginx state: started enabled: yes在 Playbook 中使用角色yaml--- - name: 配置 Web 服务器 hosts: webservers roles: - common # 角色名称 - webserver # 按顺序执行 - { role: monitoring, when: enable_monitoring } # 带条件4.5 Ansible Vault (加密)当Playbook中包含敏感信息如密码、API密钥时必须使用Vault进行加密。加密文件bash# 创建加密文件 ansible-vault create secrets.yml # 加密现有文件 ansible-vault encrypt vars/secret.yml使用加密文件Playbook 引用:yaml- hosts: all vars_files: - vars/common.yml - vars/secret.yml # 加密文件 tasks: - name: 输出密码 (仅用于演示) debug: msg: DB Password is {{ db_password }}执行时提供密码bash# 交互式输入密码 ansible-playbook site.yml --ask-vault-pass # 从文件读取密码 (注意文件权限) ansible-playbook site.yml --vault-password-file .vault_pass第五部分实战案例 - 搭建 LNMP 环境通过一个完整的案例将以上知识点串联起来。我们将自动化部署一套LNMP环境 (Linux, Nginx, MySQL, PHP) 并部署一个简单的应用。5.1 项目结构textlnmp-project/ ├── ansible.cfg # Ansible 配置文件 ├── inventory.ini # 主机清单 ├── site.yml # 主入口Playbook ├── group_vars/ # 组变量 │ └── all.yml ├── roles/ # 角色 │ ├── common/ # 基础优化 │ ├── nginx/ │ ├── mysql/ │ └── php-fpm/ └── vars/ # 全局变量 └── vault.yml # 加密的敏感变量5.2 配置 ansible.cfg为了优化体验创建ansible.cfg。ini[defaults] inventory inventory.ini host_key_checking False retry_files_enabled False gathering smart stdout_callback yaml # 更美观的输出格式 [ssh_connection] pipelining True # 大幅提升SSH执行效率5.3 编写角色角色: nginxroles/nginx/tasks/main.ymlyaml--- - name: 安装 Nginx ansible.builtin.package: name: nginx state: present - name: 创建网站目录 ansible.builtin.file: path: {{ web_root }} state: directory owner: nginx group: nginx mode: 0755 - name: 复制虚拟主机配置 ansible.builtin.template: src: site.conf.j2 dest: /etc/nginx/conf.d/site.conf notify: restart nginx - name: 启动并启用 Nginx ansible.builtin.service: name: nginx state: started enabled: yesroles/nginx/templates/site.conf.j2jinja2server { listen 80; server_name {{ server_name }}; root {{ web_root }}; index index.php index.html; location / { try_files $uri $uri/ 404; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }roles/nginx/handlers/main.ymlyaml--- - name: restart nginx ansible.builtin.service: name: nginx state: restarted角色: php-fpmroles/php-fpm/tasks/main.ymlyaml--- - name: 安装 PHP 及相关扩展 ansible.builtin.package: name: - php-fpm - php-mysqlnd - php-gd - php-mbstring - php-xml state: present - name: 确保 PHP-FPM 服务运行 ansible.builtin.service: name: php-fpm state: started enabled: yes角色: mysqlroles/mysql/tasks/main.ymlyaml--- - name: 安装 MySQL 服务器 ansible.builtin.package: name: mysql-server state: present - name: 启动 MySQL 服务 ansible.builtin.service: name: mysqld state: started enabled: yes - name: 设置 root 密码 (使用变量) community.mysql.mysql_user: name: root password: {{ mysql_root_password }} host: localhost login_unix_socket: /var/lib/mysql/mysql.sock no_log: true # 防止密码打印到日志 - name: 删除匿名用户 community.mysql.mysql_user: name: host_all: yes state: absent login_user: root login_password: {{ mysql_root_password }} no_log: true - name: 创建应用数据库 community.mysql.mysql_db: name: {{ app_db_name }} state: present login_user: root login_password: {{ mysql_root_password }}5.4 主 Playbook (site.yml)yaml--- - name: 部署 LNMP 环境 hosts: all become: yes vars_files: - vars/vault.yml # 包含 mysql_root_password 等敏感信息 roles: - common - nginx - mysql - php-fpm tasks: - name: 部署测试 PHP 文件 ansible.builtin.copy: content: | ?php phpinfo(); ? dest: {{ web_root }}/info.php owner: nginx group: nginx mode: 0644 - name: 检查 Nginx 语法 ansible.builtin.shell: nginx -t register: nginx_test changed_when: false - name: 显示测试结果 ansible.builtin.debug: var: nginx_test.stdout5.5 变量文件group_vars/all.ymlyamlweb_root: /var/www/lnmp-demo server_name: demo.example.com app_db_name: myappvars/vault.yml (加密)yamlmysql_root_password: SuperSecret123!5.6 执行部署bash# 加密敏感变量文件 ansible-vault encrypt vars/vault.yml # 执行完整部署 ansible-playbook -i inventory.ini site.yml --ask-vault-pass第六部分性能优化与生产环境技巧6.1 加速执行 (Mitogen)Mitogen 是一个 Python 库可以极大提升 Ansible 的执行速度提升 1.5x - 7x。安装 Mitogen:bashpip install mitogen ansible配置 ansible.cfg:ini[defaults] strategy_plugins /usr/local/lib/python3.9/site-packages/ansible_mitogen/plugins/strategy strategy mitogen_linear6.2 Facts 缓存对于大规模的集群每次运行都收集 Facts 非常耗时。配置 Facts 缓存到 Redis 或 JSON 文件。ansible.cfg:ini[defaults] gathering smart fact_caching jsonfile fact_caching_connection /tmp/ansible_facts_cache fact_caching_timeout 86400 # 缓存24小时6.3 并发与 Forkforks参数控制 Ansible 同时与多少台主机通信的并发数。默认是5如果网络好且机器多可以调大。ini[defaults] forks 506.4 标签 (Tags)Tags 允许你只运行 Playbook 中的特定部分而不是全部。yamltasks: - name: 安装软件 ansible.builtin.yum: name: nginx tags: - packages - nginx - name: 配置 Nginx ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf tags: - config - nginx执行特定标签:bash# 只运行 packages 相关的任务 ansible-playbook site.yml --tags packages # 跳过 nginx 相关的任务 ansible-playbook site.yml --skip-tags nginx6.5 调试技巧Syntax Check: 先检查语法。bashansible-playbook site.yml --syntax-checkCheck Mode (Dry Run): 模拟运行查看会发生什么变化但不实际修改。bashansible-playbook site.yml --checkDiff Mode: 显示文件修改的详细差异。bashansible-playbook site.yml --check --diffVerbose: 增加日志输出级别。bashansible-playbook site.yml -vvvv第七部分Ansible 与 CI/CD 集成7.1 集成 Jenkins / GitLab CI在 CI/CD 流水线中集成 Ansible可以实现“配置即代码”和持续部署。GitLab CI 示例 (.gitlab-ci.yml):yamlstages: - deploy deploy_production: stage: deploy before_script: - apt-get update apt-get install -y ansible sshpass - echo $SSH_PRIVATE_KEY key.pem - chmod 600 key.pem script: - ansible-playbook -i inventory/production site.yml --vault-password-file .vault_pass only: - main environment: name: production7.2 Ansible Tower / AWX对于企业级环境推荐使用AWX(开源版) 或Ansible Tower(商业版)。它们提供了Web UI 管理界面RBAC 权限控制作业调度与定时任务日志记录与审计REST API第八部分常见问题与排错SSH 连接失败检查ansible_user是否正确。检查 SSH 端口是否默认22如果不是在 inventory 中设置ansible_port2222。检查防火墙和 SELinux。模块缺失错误:No module named yum或No module named apt。解决: 在被管理节点上安装对应包:python3-yum或python3-apt。模板语法错误template error while templating string: expected token end of print statement。原因: 在 Jinja2 中变量引用忘记加双引号或者在{% if %}中使用了错误的逻辑。幂等性不足同一个Playbook运行多次应该只有第一次会“改变”后面都是“OK”。避免使用shell模块执行非幂等的命令尽量使用专门的模块。循环引用或变量未定义使用ansible-playbook --syntax-check捕获明显的错误。使用debug模块打印变量值进行排查。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价