# Ansible 实战指南 ## 目录 1. [运维自动化发展历程及技术应用](#1-运维自动化发展历程及技术应用) 2. [Ansible 架构和相关命令使用](#2-ansible-架构和相关命令使用) 3. [Ansible 常用模块详解](#3-ansible-常用模块详解) 4. [Ansible Playbook 基础](#4-ansible-playbook-基础) 5. [Playbook 变量、Tags、Handlers 使用](#5-playbook-变量tagshandlers使用) 6. [Playbook 模板 Templates](#6-playbook-模板-templates) 7. [Playbook 条件判断 When](#7-playbook-条件判断-when) 8. [Playbook 字典 with_items](#8-playbook-字典-with_items) 9. [Ansible Roles](#9-ansible-roles) --- ## 1. 运维自动化发展历程及技术应用 ### 1.1 运维自动化发展历程 ``` ┌─────────────────────────────────────────────────────┐ │ 运维自动化发展历程 │ ├─────────────────────────────────────────────────────┤ │ │ │ 1. 手动时代 │ │ ├── 人工登录服务器 │ │ ├── 逐台执行命令 │ │ └── 效率低下,易出错 │ │ │ │ 2. 脚本时代 │ │ ├── Shell/Python 脚本 │ │ ├── 批量执行脚本 │ │ └── 脚本难以维护,无标准化 │ │ │ │ 3. 工具时代 │ │ ├── Puppet、SaltStack、Chef │ │ ├── 配置管理工具 │ │ └── 解决一致性,但复杂 │ │ │ │ 4. 自动化时代 │ │ ├── Ansible、Terraform │ │ ├── 简单易用,Agentless │ │ └── 编排 + 自动化 │ │ │ │ 5. DevOps 时代 │ │ ├── CI/CD + 自动化运维 │ │ ├── Kubernetes + 容器 │ │ └── GitOps 理念 │ │ │ └─────────────────────────────────────────────────────┘ ``` ### 1.2 常见运维自动化工具对比 | 工具 | 类型 | 架构 | 优点 | 缺点 | |------|------|------|------|------| | **Ansible** | 配置管理/编排 | Agentless | 简单易学、YAML 语法、无 Agent | 执行速度稍慢 | | **Puppet** | 配置管理 | C/S (Agent) | 功能强大、成熟 | 学习曲线陡峭 | | **SaltStack** | 配置管理/执行 | C/S (Agent) | 高性能、可远程执行 | 语法复杂 | | **Chef** | 配置管理 | C/S (Agent) | Ruby 语法、社区活跃 | 需要编写 Ruby 代码 | | **Terraform** | 基础设施代码 | Agentless | 基础设施即代码、云原生 | 专注于基础设施 | ### 1.3 Ansible 应用场景 | 场景 | 说明 | |------|------| | **配置管理** | 统一配置服务器、操作系统、应用软件 | | **应用部署** | 自动化部署应用程序、容器 | | **批量操作** | 批量执行命令、批量修改配置 | | ** orchestration** | 多节点编排、任务编排 | | **持续交付** | CI/CD 流水线集成 | | **基础设施** | 云资源管理、容器编排 | ### 1.4 Ansible 在企业中的应用 ``` ┌─────────────────────────────────────────────────────┐ │ Ansible 企业应用架构 │ ├─────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Ansible Control Node │ │ │ │ (Ansible Server) │ │ │ └────────────────────┬────────────────────────┘ │ │ │ │ │ ┌─────────────┼─────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Web │ │ App │ │ Database │ │ │ │ Servers │ │ Servers │ │ Servers │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ 场景: │ │ - 批量部署/配置服务器 │ │ - 应用发布和回滚 │ │ - 监控和日志收集 │ │ - 安全合规检查 │ │ │ └─────────────────────────────────────────────────────┘ ``` --- ## 2. Ansible 架构和相关命令使用 ### 2.1 Ansible 架构 ``` ┌─────────────────────────────────────────────────────┐ │ Ansible 架构 │ ├─────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Ansible Engine │ │ │ │ │ │ │ │ Inventory ──→ Playbooks │ │ │ │ │ │ │ │ │ │ ▼ ▼ │ │ │ │ Plugins ──→ Modules │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ │ └───────────┼────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Managed Nodes │ │ │ │ (无 Agent) │ │ │ │ │ │ │ │ SSH Connection ──→ Execute Modules │ │ │ │ │ │ │ └─────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────┘ ``` ### 2.2 Ansible 核心组件 | 组件 | 说明 | |------|------| | **Inventory** | 主机清单,定义管理的主机 | | **Playbook** | 任务剧本,YAML 格式的任务定义 | | **Module** | 模块,Ansible 执行的具体任务单元 | | **Plugin** | 插件,扩展 Ansible 功能 | | **API** | 编程接口,供二次开发使用 | ### 2.3 Ansible 安装 ```bash # 使用 pip 安装 pip install ansible # Ubuntu/Debian apt install ansible # CentOS/RHEL yum install epel-release yum install ansible # macOS brew install ansible # 验证安装 ansible --version ``` ### 2.4 Inventory 主机清单 #### 2.4.1 静态 Inventory ```ini # /etc/ansible/hosts 或 -i 指定文件 # 单主机 192.168.1.10 # 主机组 [web] 192.168.1.10 192.168.1.11 192.168.1.12 [db] 192.168.1.20 192.168.1.21 # 嵌套组 [production:children] web db # 主机变量 [web] 192.168.1.10 ansible_user=admin ansible_ssh_pass=pass123 192.168.1.11 ansible_user=admin ansible_ssh_pass=pass123 # 组变量 [web:vars] ansible_user=admin ansible_ssh_pass=pass123 http_port=80 ``` #### 2.4.2 动态 Inventory ```bash # 使用脚本获取主机列表 ansible-playbook -i inventory.py playbook.yml # AWS EC2 动态 Inventory ansible-playbook -i ec2.py playbook.yml ``` ### 2.5 Ansible 配置文件 ```ini # ansible.cfg [defaults] inventory = /etc/ansible/hosts host_key_checking = False retry_files_enabled = False gathering = explicit # 加速配置 pipelining = True # 并行数 forks = 50 [privilege_escalation] become = True become_method = sudo become_user = root become_ask_pass = False [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s pipelining = True ``` ### 2.6 常用命令 ```bash # 帮助 ansible-doc -h ansible-doc ansible-doc -l # 列出所有模块 # 测试连通性 ansible all -m ping # 执行临时命令 ansible all -m command -a "uptime" ansible all -m shell -a "df -h" ansible all -m setup # 获取主机信息 # 文件传输 ansible all -m copy -a "src=/tmp/file dest=/tmp/" # 用户管理 ansible all -m user -a "name=test state=present" # 包管理 ansible all -m yum -a "name=httpd state=present" # 服务管理 ansible all -m service -a "name=httpd state=started" # 查看配置 ansible-config dump # 查看清单 ansible-inventory --list ``` ### 2.7 Playbook 命令 ```bash # 执行 playbook ansible-playbook playbook.yml # 检查模式(不执行) ansible-playbook --check playbook.yml # 差异化执行(检查变更) ansible-playbook --diff playbook.yml # 指定主机 ansible-playbook -i inventory.ini playbook.yml # 指定标签 ansible-playbook --tags "web" playbook.yml # 跳过标签 ansible-playbook --skip-tags "debug" playbook.yml # 启动步骤 ansible-playbook --start-at-task "Install Apache" playbook.yml # 步骤执行 ansible-playbook --step playbook.yml # 详细输出 ansible-playbook -v playbook.yml ansible-playbook -vv playbook.yml ansible-playbook -vvv playbook.yml # 详细调试 # 清缓存 ansible-playbook --flush-cache playbook.yml ``` --- ## 3. Ansible 常用模块详解 ### 3.1 模块分类 | 分类 | 说明 | 常见模块 | |------|------|----------| | **命令执行** | 执行远程命令 | command, shell, script, raw | | **文件操作** | 文件管理 | copy, file, template, synchronize | | **包管理** | 软件包管理 | yum, apt, package | | **服务管理** | 服务管理 | service, systemd | | **用户管理** | 用户管理 | user, group | | **数据库** | 数据库操作 | mysql_db, postgresql_db | | **云资源** | 云资源管理 | ec2, azure_rm, gce | | **容器** | 容器管理 | docker, k8s | | **通知** | 通知模块 | email, slack | ### 3.2 命令执行模块 #### 3.2.1 command 模块 ```yaml - name: Execute command command: uptime - name: Execute with args command: systemctl start nginx - name: Check file exists command: test -f /etc/nginx/nginx.conf register: result - name: Create directory command: mkdir -p /tmp/test creates: /tmp/test # 存在则跳过 ``` #### 3.2.2 shell 模块 ```yaml - name: Execute shell shell: echo $PATH - name: Execute with pipe shell: cat /etc/passwd | grep root - name: Execute script shell: | #!/bin/bash echo "Hello" ``` #### 3.2.3 script 模块 ```yaml - name: Run local script script: /tmp/script.sh - name: Run with args script: /tmp/script.sh --arg1 value1 - name: Run on remote script: /tmp/script.sh args: creates: /tmp/result ``` ### 3.3 文件操作模块 #### 3.3.1 copy 模块 ```yaml - name: Copy file copy: src: /tmp/source.conf dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' - name: Copy with backup copy: src: /tmp/source.conf dest: /etc/nginx/nginx.conf backup: yes - name: Copy content copy: dest: /tmp/test.txt content: "Hello World" ``` #### 3.3.2 file 模块 ```yaml - name: Create directory file: path: /tmp/dir state: directory mode: '0755' - name: Create file file: path: /tmp/file state: touch - name: Create symlink file: src: /tmp/source dest: /tmp/link state: link - name: Delete file file: path: /tmp/file state: absent ``` #### 3.3.3 template 模块 ```yaml - name: Template file template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' validate: 'nginx -t -c %s' ``` #### 3.3.4 synchronize 模块 ```yaml - name: Sync directory synchronize: src: /tmp/local/ dest: /tmp/remote/ delete: yes rsync_opts: - "--exclude=.git" ``` ### 3.4 包管理模块 #### 3.4.1 yum 模块 ```yaml - name: Install package yum: name: nginx state: present - name: Install latest yum: name: '*' state: latest - name: Install multiple yum: name: - nginx - php-fpm state: present - name: Remove package yum: name: nginx state: absent - name: Install from repo yum: name: epel-release enablerepo: epel ``` #### 3.4.2 apt 模块 ```yaml - name: Install package apt: name: nginx state: present update_cache: yes - name: Install without update apt: name: nginx state: present update_cache: no - name: Install from deb apt: deb: /tmp/package.deb state: present ``` ### 3.5 服务管理模块 #### 3.5.1 service 模块 ```yaml - name: Start service service: name: nginx state: started enabled: yes - name: Stop service service: name: nginx state: stopped - name: Restart service service: name: nginx state: restarted - name: Reload service service: name: nginx state: reloaded ``` #### 3.5.2 systemd 模块 ```yaml - name: Enable and start service systemd: name: nginx state: started enabled: yes daemon_reload: yes ``` ### 3.6 用户管理模块 #### 3.6.1 user 模块 ```yaml - name: Create user user: name: appuser comment: "Application User" shell: /bin/bash home: /home/appuser create_home: yes - name: Create with password user: name: admin password: "{{ 'password' | password_hash('sha512') }}" - name: Add to group user: name: appuser groups: - wheel - docker append: yes - name: Remove user user: name: appuser state: absent remove: yes ``` #### 3.6.2 group 模块 ```yaml - name: Create group group: name: mygroup state: present gid: 1000 ``` ### 3.7 其他常用模块 #### 3.7.1 get_url 模块 ```yaml - name: Download file get_url: url: http://example.com/file.tar.gz dest: /tmp/file.tar.gz mode: '0644' ``` #### 3.7.2 unarchive 模块 ```yaml - name: Unarchive file unarchive: src: /tmp/file.tar.gz dest: /tmp/ remote_src: no ``` #### 3.7.3 lineinfile 模块 ```yaml - name: Add line lineinfile: path: /etc/selinux/config regexp: '^SELINUX=' line: SELINUX=enforcing - name: Remove line lineinfile: path: /etc/selinux/config regexp: '^SELINUX=' state: absent ``` #### 3.7.4 find 模块 ```yaml - name: Find files find: paths: /var/log patterns: "*.log" age: 7d register: log_files ``` --- ## 4. Ansible Playbook 基础 ### 4.1 Playbook 概述 Playbook 是 Ansible 的任务配置文件,使用 YAML 格式编写,定义了一组有序的任务。 ``` ┌─────────────────────────────────────────────────────┐ │ Playbook 结构 │ ├─────────────────────────────────────────────────────┤ │ │ │ Playbook (剧本) │ │ ├── Play 1 │ │ │ ├── Hosts (主机) │ │ │ ├── Vars (变量) │ │ │ └── Tasks (任务) │ │ │ ├── Task 1 (Module) │ │ │ └── Task 2 (Module) │ │ │ │ │ └── Play 2 │ │ ├── Hosts │ │ ├── Vars │ │ └── Tasks │ │ │ └─────────────────────────────────────────────────────┘ ``` ### 4.2 基础 Playbook 示例 ```yaml # playbook.yml --- - name: Configure Web Server hosts: web become: yes vars: http_port: 80 tasks: - name: Install Apache yum: name: httpd state: present - name: Ensure Apache is running service: name: httpd state: started enabled: yes - name: Copy configuration copy: src: files/httpd.conf dest: /etc/httpd/conf/httpd.conf notify: Restart Apache - name: Copy index page template: src: templates/index.html.j2 dest: /var/www/html/index.html handlers: - name: Restart Apache service: name: httpd state: restarted ``` ### 4.3 多个 Play ```yaml --- - name: Configure Web Servers hosts: web become: yes tasks: - name: Install Apache yum: name: httpd state: present - name: Start Apache service: name: httpd state: started - name: Configure Database Servers hosts: db become: yes tasks: - name: Install MySQL yum: name: mysql-server state: present - name: Start MySQL service: name: mysqld state: started ``` ### 4.4 Play 常用参数 | 参数 | 说明 | |------|------| | `name` | Play 名称 | | `hosts` | 目标主机 | | `become` | 是否提权 | | `become_method` | 提权方式(sudo/su) | | `become_user` | 提权用户 | | `gather_facts` | 是否收集主机信息 | | `vars` | 变量 | | `tasks` | 任务列表 | | `handlers` | 处理器 | | `roles` | 角色 | ### 4.5 Task 常用参数 | 参数 | 说明 | |------|------| | `name` | 任务名称 | | `module` | 使用的模块 | | `args` | 模块参数 | | `when` | 条件判断 | | `register` | 注册变量 | | `changed_when` | 改变判断条件 | | `failed_when` | 失败判断条件 | | `loop` | 循环 | | `until` | 循环直到 | | `retries` | 重试次数 | | `delay` | 重试延迟 | ### 4.6 任务控制 ```yaml # 顺序执行 - name: Task 1 yum: name: httpd state: present - name: Task 2 service: name: httpd state: started # 忽略错误 - name: Ignore error command: /some/command ignore_errors: yes # 强制失败 - name: Force fail command: /some/command failed_when: "'FAILED' in result.stderr" # 标签 - name: Install packages yum: name: "{{ item }}" tags: - packages - web ``` --- ## 5. Playbook 变量、Tags、Handlers 使用 ### 5.1 变量 #### 5.1.1 变量定义 ```yaml # 方式 1:Play 变量 - hosts: web vars: http_port: 80 server_name: example.com tasks: - name: Use variable debug: msg: "Port is {{ http_port }}" # 方式 2:Task 变量 - name: Task variable debug: msg: "{{ task_var }}" vars: task_var: "Hello" ``` #### 5.1.2 主机变量 ```ini # inventory [web] 192.168.1.10 http_port=8080 192.168.1.11 http_port=8090 ``` #### 5.1.3 组变量 ```yaml # group_vars/all.yml --- ansible_user: admin ansible_ssh_pass: password # group_vars/web.yml --- http_port: 80 ``` #### 5.1.4 变量引用 ```yaml - name: Reference variables debug: msg: "{{ variable_name }}" - name: Complex reference debug: msg: "{{ hostvars[groups['web'][0]]['ansible_host'] }}" ``` #### 5.1.5 Facts 变量 ```yaml # 获取 facts - name: Get facts setup: filter: ansible_* - name: Show facts debug: msg: "{{ ansible_hostname }}" # 常用 facts # ansible_hostname - 主机名 # ansible_default_ipv4.address - IP 地址 # ansible_distribution - 发行版 # ansible_distribution_version - 版本 # ansible_memory_mb.real.total - 内存 # ansible_processor_vcpus - CPU 核心数 ``` ### 5.2 Tags #### 5.2.1 Tag 定义 ```yaml - name: Install Apache yum: name: httpd state: present tags: - web - httpd - name: Configure Apache template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf tags: - config - httpd ``` #### 5.2.2 Tag 使用 ```bash # 只执行带 tag 的任务 ansible-playbook --tags "web" playbook.yml # 跳过 tag ansible-playbook --skip-tags "debug" playbook.yml # 多个 tag ansible-playbook --tags "web,mysql" playbook.yml ``` ### 5.3 Handlers #### 5.3.1 Handler 定义 ```yaml - name: Configure Apache template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf notify: - Restart Apache handlers: - name: Restart Apache service: name: httpd state: restarted ``` #### 5.3.2 多个 Handlers ```yaml - name: Configure Apache template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf notify: - Restart Apache - Reload Nginx handlers: - name: Restart Apache service: name: httpd state: restarted - name: Reload Nginx service: name: nginx state: reloaded ``` #### 5.3.3 Handler 监听 ```yaml - name: Config changed template: src: app.conf.j2 dest: /etc/app.conf notify: - Notify handler handlers: - name: Notify handler service: name: app state: restarted listen: "config changed" ``` --- ## 6. Playbook 模板 Templates ### 6.1 Jinja2 模板概述 Ansible 使用 Jinja2 作为模板引擎,支持变量、过滤器、循环等特性。 ### 6.2 基础模板 ```jinja {# config.conf.j2 #} # Server configuration ServerName {{ server_name }} Listen {{ http_port }} DocumentRoot "{{ document_root }}" {% if enable_ssl %} SSLEngine on SSLCertificateFile {{ ssl_cert }} SSLCertificateKeyFile {{ ssl_key }} {% endif %} ``` ### 6.3 变量和过滤器 ```jinja {# 使用变量 #} {{ variable }} {# 默认值 #} {{ variable | default('default_value') }} {# 过滤器 #} {{ name | upper }} {{ list | join(',') }} {{ number | int }} {# 条件判断 #} {% if var == 'value' %} ... {% endif %} {# 循环 #} {% for item in items %} {{ item }} {% endfor %} ``` ### 6.4 完整示例 ```yaml # playbook.yml --- - name: Configure Nginx hosts: web become: yes vars: server_name: example.com http_port: 80 document_root: /var/www/html enable_ssl: true ssl_cert: /etc/nginx/ssl/server.crt ssl_key: /etc/nginx/ssl/server.key tasks: - name: Ensure Nginx installed yum: name: nginx state: present - name: Configure Nginx template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf validate: 'nginx -t -c %s' notify: Restart Nginx handlers: - name: Restart Nginx service: name: nginx state: restarted ``` ```jinja {# nginx.conf.j2 #} user nginx; worker_processes {{ worker_processes | default('auto') }}; error_log /var/log/nginx/error.log; events { worker_connections {{ worker_connections | default(1024) }}; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout {{ keepalive_timeout | default(65) }}; upstream backend { {% for server in upstream_servers %} server {{ server.host }}:{{ server.port }}{% if server.weight %} weight={{ server.weight }}{% endif %}; {% endfor %} } server { listen {{ http_port }}; server_name {{ server_name }}; root {{ document_root }}; {% if enable_ssl %} listen 443 ssl http2; ssl_certificate {{ ssl_cert }}; ssl_certificate_key {{ ssl_key }}; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; {% endif %} location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } } ``` ### 6.5 模板变量文件 ```yaml # group_vars/web.yml --- server_name: example.com http_port: 80 document_root: /var/www/html enable_ssl: true ssl_cert: /etc/nginx/ssl/server.crt ssl_key: /etc/nginx/ssl/server.key upstream_servers: - host: 192.168.1.10 port: 8080 weight: 5 - host: 192.168.1.11 port: 8080 weight: 3 worker_processes: 4 worker_connections: 2048 keepalive_timeout: 60 ``` --- ## 7. Playbook 条件判断 When ### 7.1 when 基础 ```yaml - name: Install Apache on CentOS yum: name: httpd state: present when: ansible_os_family == "RedHat" - name: Install Apache on Debian apt: name: apache2 state: present when: ansible_os_family == "Debian" ``` ### 7.2 多个条件 ```yaml # AND 条件 - name: Install on specific OS yum: name: httpd state: present when: - ansible_os_family == "RedHat" - ansible_distribution_version | int >= 7 # OR 条件 - name: Install web server yum: name: nginx state: present when: ansible_os_family == "RedHat" or ansible_os_family == "Debian" ``` ### 7.3 变量判断 ```yaml - name: Register variable command: /usr/bin/test -f /etc/httpd/conf/httpd.conf register: httpd_conf - name: Check result debug: msg: "Config file exists" when: httpd_conf.rc == 0 - name: Check changed command: /usr/bin/some-command register: result changed_when: result.rc != 0 - name: Conditional execution debug: msg: "Command changed" when: result is changed ``` ### 7.4 内置条件测试 ```yaml - name: Test defined debug: msg: "Variable defined" when: my_var is defined - name: Test undefined debug: msg: "Variable not defined" when: my_var is not defined - name: Test true debug: msg: "Value is true" when: my_var | bool - name: Test false debug: msg: "Value is false" when: not my_var | bool - name: Test string debug: msg: "String test" when: my_string == "value" - name: Test number debug: msg: "Number test" when: my_number > 100 - name: Test in debug: msg: "In list" when: ansible_hostname in groups['web'] ``` ### 7.5 循环 + 条件 ```yaml - name: Install packages based on OS yum: name: "{{ item }}" state: present loop: - httpd - nginx when: ansible_os_family == "RedHat" - name: Install specific packages apt: name: "{{ item.name }}" state: present loop: - { name: 'apache2', os: 'Debian' } - { name: 'httpd', os: 'RedHat' } when: ansible_os_family == item.os ``` ### 7.6 完整示例 ```yaml --- - name: Configure servers based on OS hosts: all gather_facts: yes vars: install_web: true install_db: false tasks: - name: Install Apache yum: name: httpd state: present when: - install_web | bool - ansible_os_family == "RedHat" - name: Install Apache on Debian apt: name: apache2 state: present when: - install_web | bool - ansible_os_family == "Debian" - name: Install MySQL yum: name: mysql-server state: present when: - install_db | bool - ansible_distribution == "CentOS" - name: Configure firewall for CentOS 7+ firewalld: service: http permanent: yes state: enabled when: - ansible_os_family == "RedHat" - ansible_distribution_version | int >= 7 - name: Only on web servers debug: msg: "This is a web server" when: "'web' in group_names" ``` --- ## 8. Playbook 字典 with_items ### 8.1 with_items 基础 ```yaml - name: Install multiple packages yum: name: "{{ item }}" state: present loop: - httpd - nginx - php-fpm - name: Create users user: name: "{{ item }}" state: present loop: - alice - bob - charlie ``` ### 8.2 字典列表 ```yaml - name: Create multiple users with attributes user: name: "{{ item.name }}" comment: "{{ item.comment }}" shell: "{{ item.shell }}" create_home: yes loop: - { name: 'alice', comment: 'Alice User', shell: '/bin/bash' } - { name: 'bob', comment: 'Bob User', shell: '/bin/sh' } ``` ### 8.3 嵌套循环 ```yaml - name: Create directories file: path: "{{ item.0 }}/{{ item.1 }}" state: directory loop: - ['/tmp', 'dir1'] - ['/tmp', 'dir2'] - ['/var', 'log'] ``` ### 8.4 with_dict ```yaml - name: Define dictionary set_fact: users: alice: shell: /bin/bash home: /home/alice bob: shell: /bin/sh home: /home/bob - name: Create users from dict user: name: "{{ item.key }}" shell: "{{ item.value.shell }}" home: "{{ item.value.home }}" loop: "{{ dict(users) | dict2items }}" ``` ### 8.5 with_fileglob ```yaml - name: Copy all files copy: src: "{{ item }}" dest: /tmp/ mode: '0644' loop: - "{{ playbook_dir }}/files/*" ``` ### 8.6 with_sequence ```yaml - name: Create sequence files file: path: "/tmp/file{{ item }}" state: touch loop: "{{ range(1, 11) | list }}" ``` ### 8.7 with_together ```yaml - name: Combine lists debug: msg: "{{ item.0 }} - {{ item.1 }}" loop: "{{ list1 | zip(list2) | list }}" ``` ### 8.8 with_nested ```yaml - name: Nested loop debug: msg: "{{ item.0 }} - {{ item.1 }}" loop: "{{ ['a', 'b', 'c'] | product(['1', '2', '3']) | list }}" ``` ### 8.9 注册变量 + 循环 ```yaml - name: Get file contents command: cat {{ item }} register: file_contents loop: - /tmp/file1.txt - /tmp/file2.txt - name: Show contents debug: msg: "{{ item.stdout }}" loop: "{{ file_contents.results }}" ``` ### 8.10 完整示例 ```yaml --- - name: Configure multi-tier application hosts: app vars: app_users: - { name: 'appuser', uid: 1000, group: 'app', shell: '/bin/bash' } - { name: 'deploy', uid: 1001, group: 'app', shell: '/bin/sh' } app_dirs: - { path: '/opt/app', owner: 'appuser', mode: '0755' } - { path: '/var/log/app', owner: 'appuser', mode: '0755' } - { path: '/tmp/app', owner: 'appuser', mode: '1777' } packages: - java-11-openjdk - maven - git tasks: - name: Create groups group: name: "{{ item }}" state: present loop: - app - deploy - name: Create users user: name: "{{ item.name }}" uid: "{{ item.uid }}" group: "{{ item.group }}" shell: "{{ item.shell }}" create_home: yes loop: "{{ app_users }}" - name: Create directories file: path: "{{ item.path }}" owner: "{{ item.owner }}" mode: "{{ item.mode }}" state: directory loop: "{{ app_dirs }}" - name: Install packages yum: name: "{{ item }}" state: present loop: "{{ packages }}" when: ansible_os_family == "RedHat" - name: Install packages (Debian) apt: name: "{{ item }}" state: present update_cache: yes loop: "{{ packages }}" when: ansible_os_family == "Debian" ``` --- ## 9. Ansible Roles ### 9.1 Roles 概述 Roles 是 Ansible 的组织结构化机制,将 Playbook 分解为可重用的组件。 ``` ┌─────────────────────────────────────────────────────┐ │ Roles 目录结构 │ ├─────────────────────────────────────────────────────┤ │ │ │ roles/ │ │ └── role_name/ │ │ ├── defaults/ # 默认变量(最低优先级)│ │ │ └── main.yml │ │ ├── vars/ # 变量(最高优先级) │ │ │ └── main.yml │ │ ├── tasks/ # 任务 │ │ │ └── main.yml │ │ ├── handlers/ # 处理器 │ │ │ └── main.yml │ │ ├── templates/ # 模板 │ │ │ └── *.j2 │ │ ├── files/ # 静态文件 │ │ │ └── * │ │ ├── meta/ # 依赖关系 │ │ │ └── main.yml │ │ └── README.md # 文档 │ │ │ └─────────────────────────────────────────────────────┘ ``` ### 9.2 创建 Role ```bash # 使用 ansible-galaxy 创建 ansible-galaxy init role_name # 手动创建目录结构 mkdir -p roles/nginx/{defaults,vars,tasks,handlers,templates,files,meta} ``` ### 9.3 Role 示例:Nginx #### 9.3.1 defaults/main.yml ```yaml --- # defaults/main.yml nginx_version: "1.24" nginx_port: 80 nginx_worker_processes: auto nginx_worker_connections: 1024 nginx_server_name: localhost nginx_document_root: /var/www/html ``` #### 9.3.2 vars/main.yml ```yaml --- # vars/main.yml nginx_user: nginx nginx_group: nginx nginx_conf_dir: /etc/nginx nginx_log_dir: /var/log/nginx ``` #### 9.3.3 tasks/main.yml ```yaml --- # tasks/main.yml - name: Ensure nginx is installed yum: name: nginx state: present when: ansible_os_family == "RedHat" - name: Ensure nginx is installed apt: name: nginx state: present update_cache: yes when: ansible_os_family == "Debian" - name: Copy nginx configuration template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: Restart nginx - name: Ensure nginx is running service: name: nginx state: started enabled: yes ``` #### 9.3.4 handlers/main.yml ```yaml --- # handlers/main.yml - name: Restart nginx service: name: nginx state: restarted - name: Reload nginx service: name: nginx state: reloaded ``` #### 9.3.5 templates/nginx.conf.j2 ```jinja # nginx.conf.j2 user {{ nginx_user }}; worker_processes {{ nginx_worker_processes }}; error_log {{ nginx_log_dir }}/error.log; events { worker_connections {{ nginx_worker_connections }}; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log {{ nginx_log_dir }}/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; server { listen {{ nginx_port }}; server_name {{ nginx_server_name }}; root {{ nginx_document_root }}; location / { index index.html index.htm; } } } ``` ### 9.4 使用 Role ```yaml # site.yml --- - name: Configure web servers hosts: web roles: - role: nginx nginx_port: 8080 nginx_server_name: example.com - name: Configure database servers hosts: db roles: - role: mysql mysql_port: 3306 ``` ### 9.5 Role 依赖 ```yaml # roles/common/meta/main.yml --- dependencies: - role: common vars: common_version: 1.0 - role: monitoring ``` ### 9.6 完整 Playbook 示例 ```yaml # site.yml - 完整项目配置 --- - name: Infrastructure setup hosts: all gather_facts: yes roles: - common - ntp - name: Web servers setup hosts: web become: yes roles: - nginx - php-fpm - firewall - name: Database servers setup hosts: db become: yes roles: - mysql - backup - name: Application deployment hosts: app become: yes roles: - app_deploy - monitoring_agent ``` ### 9.7 导入 Role ```yaml # 静态导入 - name: Import role import_role: name: nginx vars: nginx_port: 8080 - name: Import handlers import_tasks: handlers.yml ``` ### 9.8 动态 Role ```yaml # 动态导入 - name: Include role include_role: name: nginx vars: nginx_port: 80 ``` ### 9.9 Galaxy 角色 ```bash # 搜索角色 ansible-galaxy search nginx # 安装角色 ansible-galaxy install geerlingguy.nginx # 查看已安装角色 ansible-galaxy list # 删除角色 ansible-galaxy remove geerlingguy.nginx ``` --- ## 附录 ### 常用命令速查 | 命令 | 说明 | |------|------| | `ansible all -m ping` | 测试连通性 | | `ansible-playbook site.yml` | 执行 Playbook | | `ansible-playbook --check site.yml` | 模拟执行 | | `ansible-playbook --tags "web" site.yml` | 指定标签 | | `ansible-doc -l` | 列出模块 | | `ansible-doc user` | 查看模块文档 | | `ansible-galaxy init role` | 创建角色 | | `ansible-config dump` | 查看配置 | ### 配置参数速查 | 参数 | 说明 | |------|------| | `inventory` | 主机清单 | | `forks` | 并行数 | | `become` | 提权 | | `host_key_checking` | 主机指纹检查 | | `retry_files_enabled` | 重试文件 | ### 变量优先级 | 优先级(低到高) | |----------| | role defaults | | inventory file/script group vars | | inventory group vars | | playbook group vars | | host facts | | register vars | | set_facts | | role/vars | | include vars | | include params | | extra vars | --- *文档创建时间:2024年*