深入浅出Ansible语法——Ansible安全基线配置(一)

举报
Prism 发表于 2025/11/13 11:10:42 2025/11/13
【摘要】 引言大家好,我是 Prism,本篇带你快速掌握 Ansible 常用语法与实践技巧。文中保留了大量示例,便于照抄并在真实环境中测试。本篇适合刚接触 Ansible 的运维或开发人员,也可作为查阅参考。 一、变量(Variables)变量是 Ansible 的基础,掌握变量定义与查找顺序能够极大提高剧本的灵活性与可维护性。 常见变量来源(优先级从低到高简述)Role defaults: ro...

引言

大家好,我是 Prism,本篇带你快速掌握 Ansible 常用语法与实践技巧。文中保留了大量示例,便于照抄并在真实环境中测试。本篇适合刚接触 Ansible 的运维或开发人员,也可作为查阅参考。


一、变量(Variables)

变量是 Ansible 的基础,掌握变量定义与查找顺序能够极大提高剧本的灵活性与可维护性。

常见变量来源(优先级从低到高简述)

  • Role defaults: roles/<role>/defaults/main.yml(最低优先)
  • inventory(hosts 文件、group_vars、host_vars)
    • group_vars/all.yml:全局变量
    • group_vars/<group>.yml:组变量
    • host_vars/<host>.yml:主机变量(优先级较高)
  • Playbook 的 vars / vars_files(局部或导入)
  • Role vars: roles/<role>/vars/main.yml
  • 命令行 -e 参数(最高优先)
  • facts(自动收集,ansible_* 前缀)
  • register(运行时注册的结果)

提示:

  • 敏感信息请用 Ansible Vault 管理,不要直接写到源码库。

变量实战演练(示例:vars / register / facts)

---
- name: 演示变量的用法
  hosts: localhost # 只在本地运行
  gather_facts: true # 明确开启事实变量
  
  vars: # 1.'vars:' 块中静态定义变量
    user_name: "你"
    target_dir: "/tmp/test-{{ user_name }}" # 变量可以嵌套引用
    packages_to_install:
      - htop
      - curl
      - vim
      
  tasks:
    - name: 1. 使用 'vars' 块中的变量
      ansible.builtin.debug:
        msg: "我将为用户 {{ user_name }} 在 {{ target_dir }} 创建目录。"

    - name: 2. 使用 'facts' 变量 (自动收集)
      ansible.builtin.debug:
        msg: "你正在运行的系统是 {{ ansible_distribution }} {{ ansible_distribution_version }},你的 IP 是 {{ ansible_default_ipv4.address }}。"
        
    - name: 3. 运行命令并 'register' 它的输出
      ansible.builtin.command: "uptime -p"
      register: uptime_result # 把命令的标准输出/错误/返回码存到这个变量
      changed_when: false # 这个命令只是查询,不会改变状态

    - name: 4. 使用 'register' 的变量
      ansible.builtin.debug:
        # 'uptime_result' 是个字典,我们用 .stdout 访问它的标准输出
        msg: "服务器已运行时间: {{ uptime_result.stdout }}"

补充说明:

  • 使用 default / omit 等过滤器可增强变量的健壮性:
    • {{ myvar | default(‘fallback’) }}
    • 在模块参数中使用 “{{ somevar | default(omit) }}” 可避免传入空值。

二、流程控制(When / Loop / Blocks)

流程控制决定剧本在不同环境下的分支执行逻辑与重复操作。

When(条件)

  • when: 表达式支持 Jinja2 语法与常见比较(==, !=, in, is defined 等)
  • 常用于按照操作系统分支执行不同模块、按标签跳过任务等

Loop(循环)

  • loop: 用于遍历列表;配合 loop_control 可自定义循环变量名与索引

Block / Rescue / Always(错误处理与事务)

  • block: 将多个任务作为一个逻辑单元;配合 rescue 和 always 实现 try/catch/finally 行为

流程控制示例(when + loop)

---
- name: 演示流程控制 (when 和 loop)
  hosts: all
  gather_facts: true
  become: true # 安装和管理文件需要提权
  
  vars:
    # 准备一个字典列表,用于循环
    users_info:
      - name: "你"
        uid: 1001
        shell: /bin/bash
      - name: alice
        uid: 1002
        shell: /bin/bash
      - name: temp_guest
        state: absent # 我们希望删除这个用户

  tasks:
    # --- WHEN 示例 ---
    
    - name: 1. [WHEN] 仅在 Debian/Ubuntu 上安装 UFW 防火墙
      ansible.builtin.apt:
        name: ufw
        state: present
      when: ansible_os_family == "Debian" # 关键!

    - name: 2. [WHEN] 仅在 RedHat/CentOS 上安装 firewalld
      ansible.builtin.yum:
        name: firewalld
        state: present
      when: ansible_os_family == "RedHat" # 关键!
        
    # --- LOOP 示例 ---

    - name: 3. [LOOP] 批量创建目录
      ansible.builtin.file:
        path: "/opt/data-{{ item }}"
        state: directory
        mode: '0755'
      loop:
        - web
        - db
        - logs
        
    - name: 4. [LOOP + WHEN] 批量管理用户 (高级)
      ansible.builtin.user:
        name: "{{ item.name }}"
        uid: "{{ item.uid | default(omit) }}"   # 如果没提供uid,则忽略(omit)此参数
        shell: "{{ item.shell | default(omit) }}" # 如果没提供shell,则忽略
        state: "{{ item.state | default('present') }}" # 默认是 present (创建)
      loop: "{{ users_info }}"
      when: item.name is defined # 只有当 item.name 存在时才执行

提示:

  • 对于复杂循环可使用 subelements、with_items、dict2items 等高级技巧。

三、错误处理(Error Handling)

默认情况下任务失败会使当前主机的 play 停止执行。常用策略如下:

  1. ignore_errors: 跳过错误继续下一步(适用于可选步骤)
  2. failed_when / changed_when: 自定义失败或变更判断
  3. block / rescue / always: 推荐用于重要操作的回滚与补救

错误处理示例

---
- name: 演示错误处理
  hosts: localhost
  gather_facts: false
  
  tasks:
    - name: 1. [ignore_errors] 尝试删除一个可能不存在的文件
      ansible.builtin.command: "rm /tmp/a_file_that_may_not_exist.txt"
      ignore_errors: true # 就算 'rm' 报错 (文件不存在),也继续
      changed_when: false # 'rm' 改变了系统状态,但我们不关心

    - name: 2. [failed_when] 自定义失败条件
      # 某个安全脚本,如果返回码是 0 表示 '安全'1 表示 '有警告'2 表示 '有漏洞'
      # 我们希望 01 都算成功,只有 2 才算失败
      ansible.builtin.command: "/usr/bin/run_security_check.sh"
      register: security_check
      ignore_errors: true # 先忽略默认的失败 (返回码 > 0)
      
    - name: 2b. 真正检查 security_check 的结果
      ansible.builtin.fail:
        msg: "安全检查失败!返回码: {{ security_check.rc }},输出: {{ security_check.stdout }}"
      when: security_check.rc == 2 # *只有*当返回码是 2 时,才执行 'fail' 模块
        
    - name: 3. [block/rescue/always] 演示 'try...catch...finally'
      block:
        # --- (TRY) 尝试执行 ---
        - name: 3a. (BLOCK) 尝试下载主要配置文件
          ansible.builtin.uri:
            url: "http://config-server.internal/primary_config.conf"
            dest: "/etc/myapp/config.conf"
            timeout: 5

      rescue:
        # --- (CATCH) 如果 BLOCK 中有任务失败 ---
        - name: 3b. (RESCUE) 下载失败,使用备用配置
          ansible.builtin.copy:
            src: "files/fallback_config.conf"
            dest: "/etc/myapp/config.conf"
          
      always:
        # --- (FINALLY) 无论成功还是失败 ---
        - name: 3c. (ALWAYS) 确保服务被重启以加载配置
          ansible.builtin.service:
            name: myapp
            state: restarted

建议:

  • 仅对“可容忍失败”的非关键任务使用 ignore_errors;关键失败应使用 fail 报错并显式提示操作人员。

四、Roles(可复用的剧本结构)

Role 提供了约定的目录结构(tasks、vars、templates、files、handlers、defaults、meta),便于复用与发布到 Ansible Galaxy。

创建与使用 Role 的快速流程:

  1. ansible-galaxy init <role_name>
  2. 编辑 roles/<role>/tasks/main.yml、vars/main.yml 等
  3. 在 playbook 中通过 roles: 调用

示例 Role 任务片段:

---
# tasks/main.yml(示例)
- name: 确保 UFW 防火墙已安装
  ansible.builtin.apt:
    name: ufw
    state: present
  when: ansible_os_family == "Debian"

- name: 禁用 root SSH 登录 (安全加固)
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: "^PermitRootLogin"
    line: "PermitRootLogin no"
    state: present
  notify: Restart SSHD

对应 handler 示例:

---
# handlers/main.yml
- name: Restart SSHD
  ansible.builtin.service:
    name: sshd
    state: restarted

提示:

  • Role 的 defaults 比 vars 优先级低,适合放可被覆盖的默认值。

五、Templates(Jinja2 模板)

模板能根据主机变量渲染不同配置文件,适合 sshd_config、nginx.conf、systemd 单元等场景。

模板示例(sshd_config.j2):

# /etc/ssh/sshd_config
Port {{ ssh_port | default(22) }}
PermitRootLogin {{ allow_root_login | default("no") }}

# 使用 for 循环
{% for user in ssh_allow_users %}
AllowUsers {{ user }}
{% endfor %}

# 使用 if 判断
{% if ansible_os_family == "Debian" %}
UsePAM yes
{% else %}
UsePAM no
{% endif %}

在 playbook 中渲染:

- name: 部署 SSHD 配置文件 (安全加固)
  hosts: ssh_servers
  become: true
  
  vars:
    ssh_port: 2222 
    allow_root_login: "no"
    ssh_allow_users:
      - "你"
      - admin
      
  tasks:
    - name: 部署模板化的 SSHD 配置文件
      ansible.builtin.template:
        src: templates/sshd_config.j2
        dest: /etc/ssh/sshd_config
        mode: '0600'
        owner: root
        group: root
        backup: yes
      notify: Restart SSHD

  handlers:
    - name: Restart SSHD
      ansible.builtin.service:
        name: sshd
        state: restarted

建议:

  • 模板内避免复杂逻辑;复杂计算可在 playbook 里预处理并传入模板。

六、Ansible Vault(敏感信息加密)

Ansible Vault 用于加密变量文件或剧本中的敏感数据,推荐在 CI/CD 或多人协作时强制使用。

常用命令:

# 新建并加密文件
ansible-vault create host_vars/db_server_01.yml

# 编辑加密文件
ansible-vault edit host_vars/db_server_01.yml

# 运行 playbook 时提供 vault 密码
ansible-playbook deploy_db.yml --ask-vault-pass

示例加密文件内容(编辑时输入):

db_password: "MySuperSecretPassword123"
api_key: "sk_live_123456789"

建议:

  • 在 CI 中用 --vault-password-file 或使用 CI 平台的 Secret 管理器,避免交互式输入。

七、常用模块与工具

  • 文件/目录:file、copy、template
  • 包管理:apt、yum、dnf、package
  • 服务管理:service、systemd
  • 命令执行:command、shell(尽量避免 shell)
  • libvirt/KVM:community.libvirt.*(需要安装相应 Collection)
  • 查看模块文档:ansible-doc

示例命令:

# 列出本地模块
ansible-doc -l

# 查看模块详细文档
ansible-doc file

# 查看模块简短说明
ansible-doc -s file

八、最佳实践小贴士(速览)

  • 将敏感凭据放入 Vault 或外部秘钥管理系统。
  • 对复杂逻辑使用 roles 与模块化。
  • 避免使用 shell 模块替代专用模块(idempotent)。
  • 使用 handlers 来减少不必要的服务重启。
  • 在 CI 中执行 lint(ansible-lint)与语法检查(ansible-playbook --syntax-check)。
  • 小步迭代、频繁验证:先在 test 环境运行,再推广到生产。

结语

本文保留了丰富示例并在关键段落加入了说明,旨在帮助你快速上手并编写更稳健的 Ansible 剧本。实践中遇到具体问题可以把剧本与错误输出贴出来,我会帮你分析建议。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。