Ansible之Playbook(三):变量应用

Ansible Playbook 变量应用详解

一、为什么需要变量?

想象一下你要给10台OpenEuler服务器安装nginx软件包。如果每台机器的安装路径、配置文件位置都不同,难道要写10个Playbook吗?变量就是来解决这个问题的!它让你:

  • 一份Playbook,多处使用:通过改变变量的值,适应不同的服务器环境。
  • 配置更灵活:轻松管理不同主机组的差异(如开发环境、测试环境、生产环境)。
  • 减少重复,避免错误:重要信息(如密码、路径)只定义一次。

二、变量在哪里定义?(OpenEuler常见场景)

变量可以存放在很多地方,Ansible会按优先级合并:

  1. 命令行传递 (最高优先级)

    bash 复制代码
    ansible-playbook site.yml -e "package_name=nginx openEuler_version=22.03"
    • 临时覆盖其他变量,适合测试或一次性操作。
    • -e--extra-vars 后面跟变量。多个变量用空格隔开。
  2. Playbook 中定义 (vars 块)

    yaml 复制代码
    - hosts: webservers # 假设这是你的OpenEuler服务器组
      vars:
        http_port: 80
        config_path: "/etc/nginx/nginx.conf"
        openEuler_pkg_manager: "dnf" # OpenEuler 主要使用 dnf
      tasks:
        - name: Install {{ package_name }} using {{ openEuler_pkg_manager }}
          ansible.builtin.package:
            name: "{{ package_name }}"
            state: present
    • 直接在Playbook里写,作用范围是这个Play。
    • 适合这个Playbook专用的变量。
  3. 主机清单文件 (inventory) 中定义

    • 针对主机组 (group_vars)

      • 创建目录 group_vars/
      • 在里面创建文件,文件名对应主机组名,如 webservers.yml
      yaml 复制代码
      # group_vars/webservers.yml
      nginx_worker_processes: 4
      openEuler_timezone: "Asia/Shanghai"
    • 针对特定主机 (host_vars)

      • 创建目录 host_vars/
      • 在里面创建文件,文件名对应主机名,如 openeuler-server01.yml
      yaml 复制代码
      # host_vars/openeuler-server01.yml
      server_ip: "192.168.1.101"
      special_config: true
    • 这是最推荐的方式!将变量与主机/组管理分离,Playbook更通用清晰。

  4. vars_files 引入外部文件

    yaml 复制代码
    - hosts: all
      vars_files:
        - secrets.yml # 存放密码等敏感信息(注意用ansible-vault加密!)
        - common_vars.yml # 存放通用变量
      tasks:
        ...
    • 将变量定义在独立的YAML文件中,然后在Playbook中引用。
    • 方便管理大量变量或敏感信息。
  5. 任务执行结果注册为变量 (register)

    yaml 复制代码
    - name: Check if nginx is installed
      ansible.builtin.command: rpm -q nginx
      register: nginx_installed # 将命令执行结果存入变量 nginx_installed
      ignore_errors: yes # 即使命令失败(未安装)也继续
    
    - name: Start nginx if installed
      ansible.builtin.service:
        name: nginx
        state: started
      when: nginx_installed.rc == 0 # 使用注册变量的返回码(rc)做判断
    • 将某个task的执行结果(标准输出、返回码等)保存下来,供后续task使用。
    • 非常强大的功能!
  6. Facts (系统信息变量) : Ansible在执行Playbook前会自动收集目标主机的信息(称为Gathering Facts)。这些信息本身就是变量!

    yaml 复制代码
    - name: Print OpenEuler OS version
      ansible.builtin.debug:
        msg: "This host is running {{ ansible_distribution }} {{ ansible_distribution_version }}"
    • ansible_distribution: 系统发行版 (如 "openEuler")
    • ansible_distribution_version: 发行版版本 (如 "22.03 LTS")
    • ansible_hostname: 主机名
    • ansible_default_ipv4.address: 默认IPv4地址
    • 使用 ansible -m setup hostname 命令可以查看所有Facts。

三、如何在Playbook中使用变量?(语法)

在Playbook的任何地方 ,只要用双花括号 {``{ variable_name }} 包裹变量名即可:

yaml 复制代码
- name: Create configuration file for {{ app_name }} on OpenEuler
  ansible.builtin.template:
    src: templates/myapp.conf.j2 # 模板文件
    dest: "{{ config_path }}/myapp.conf" # 使用变量指定目标路径
    owner: root
    group: root
    mode: '0644'
  • ansible.builtin.template 模块 :这是使用变量的超级常用场景!它结合了模板文件(.j2)
  • 模板文件(.j2) :一个文本文件(如nginx.conf.j2),里面可以包含变量和Jinja2控制结构。Ansible会将变量替换成实际值后,把文件复制到目标主机。
    • 示例模板片段 (nginx.conf.j2):

      复制代码
      worker_processes {{ nginx_worker_processes }};
      listen {{ http_port }};
      server_name {{ ansible_hostname }};

四、OpenEuler系统下变量应用实战案例

场景: 配置多台OpenEuler服务器上的Nginx,不同服务器监听端口可能不同,且需要设置时区。

  1. 主机清单 (inventory.ini):

    复制代码
    [webservers]
    openeuler01 ansible_host=192.168.1.101
    openeuler02 ansible_host=192.168.1.102 http_port=8080 # 给02单独指定端口
  2. 组变量 (group_vars/webservers.yml):

    yaml 复制代码
    openEuler_pkg_manager: "dnf"
    package_name: "nginx"
    config_path: "/etc/nginx"
    openEuler_timezone: "Asia/Shanghai"
    nginx_worker_processes: 4 # 默认值
  3. 主机变量 (host_vars/openeuler02.yml):

    yaml 复制代码
    http_port: 8080 # 覆盖组变量或Playbook中的默认值
  4. Playbook (deploy_nginx.yml):

    yaml 复制代码
    - hosts: webservers
      become: yes # 提权
      tasks:
        - name: Set OpenEuler timezone to {{ openEuler_timezone }}
          ansible.builtin.timezone:
            name: "{{ openEuler_timezone }}"
    
        - name: Ensure {{ package_name }} is installed (via {{ openEuler_pkg_manager }})
          ansible.builtin.package:
            name: "{{ package_name }}"
            state: present
    
        - name: Configure Nginx
          ansible.builtin.template:
            src: "templates/nginx.conf.j2"
            dest: "{{ config_path }}/nginx.conf"
            owner: root
            group: root
            mode: '0640'
          notify: Restart Nginx # 触发handler
    
        - name: Ensure Nginx is enabled and running
          ansible.builtin.service:
            name: nginx
            state: started
            enabled: yes
    
      handlers:
        - name: Restart Nginx
          ansible.builtin.service:
            name: nginx
            state: restarted
  5. Nginx 模板 (templates/nginx.conf.j2):

    复制代码
    user nginx;
    worker_processes {{ nginx_worker_processes }};
    ...
    server {
        listen {{ http_port }} default_server; # 这里会使用主机或组定义的端口
        server_name {{ ansible_hostname }};
        ...
    }

执行:

bash 复制代码
ansible-playbook -i inventory.ini deploy_nginx.yml
  • 对于 openeuler01http_port 使用组变量 webservers.yml 中的值(如果没定义则可能报错,说明组变量里也应该给个默认值)。
  • 对于 openeuler02http_port 使用 host_vars/openeuler02.yml 中定义的 8080
  • openEuler_timezone, package_name, config_path 等都来自组变量。

五、变量优先级小贴士

当同一个变量在多个地方定义时,优先级高的覆盖优先级低的: 命令行 > Playbook中vars > 主机变量(host_vars) > 组变量(group_vars) > Playbook中vars_files > Facts

六、给OpenEuler新手的建议

  1. 从简单开始 :先在Playbook里用vars定义,测试成功后再移到group_varshost_vars

  2. 命名清晰 :变量名要有意义,如openEuler_dns_serverdns_ip好。

  3. 善用debug :不确定变量值?用debug模块打印出来看看!

    yaml 复制代码
    - name: Show variable value
      ansible.builtin.debug:
        var: my_variable_name # 直接打印变量值
  4. 模板是神器template模块加.j2文件是配置管理的核心手段,一定要掌握。

  5. 注意空格{``{ variable }} 花括号里不要有多余空格,容易出错。

  6. 安全第一 :密码等敏感变量务必ansible-vault 加密!

相关推荐
invicinble2 小时前
前端技术栈整理
前端
码路飞2 小时前
昨天还在发 Qwen3.5,今天技术负责人就被阿里云赶走了
java·javascript
倾颜2 小时前
pnpm monorepo 下,如何把 Next.js 应用里的稳定内核拆成内部 workspace 包
前端·react.js·next.js
程序员老邢2 小时前
【技术底稿 15】SpringBoot 异步文件上传实战:多线程池隔离 + 失败重试 + 实时状态推送
java·经验分享·spring boot·后端·程序人生·spring
念格2 小时前
Flutter 仿微信输入框最佳实践:自适应高度 + 超行数智能切换全屏
前端·flutter
GISer_Jing2 小时前
前端图片、动图与动画全解析(含PNG/APNG/Lottie/GIF/Canvas/WebGL/WebGPU)
前端·3d·动画·webgl
OpenTiny社区2 小时前
多端开发头疼?TinyVue 3.30 一招搞定,AI还帮你写代码!
前端·vue.js·github
ZHENGZJM2 小时前
前端认证状态管理与路由守卫
前端·状态模式
凌览2 小时前
Claude半个月崩7次!算力不够自己造,强制实名制封
前端·后端