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

简介: 本文由Prism撰写,系统讲解Ansible核心语法与实战技巧,涵盖变量、流程控制、错误处理、Roles、模板、Vault加密及常用模块,附丰富示例,助力运维与开发人员快速上手并应用于真实环境。

引言

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


一、变量(Variables)

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

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

  • Role defaults: roles//defaults/main.yml(最低优先)
  • inventory(hosts 文件、group_vars、host_vars)
    • group_vars/all.yml:全局变量
    • group_vars/.yml:组变量
    • host_vars/.yml:主机变量(优先级较高)
  • Playbook 的 vars / vars_files(局部或导入)
  • Role vars: roles//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 表示 '有漏洞'
      # 我们希望 0 和 1 都算成功,只有 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
  2. 编辑 roles//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 环境运行,再推广到生产。
目录
相关文章
|
1月前
|
监控 安全 Linux
Linux如何部署服务并设置为开机自启
系统ctl命令用于管理Linux服务,包括启动、停止、重启和重载配置等操作。journalctl命令可查看特定服务日志。编写服务文件时需定义[Unit]、[Service]和[Install]部分,通过systemctl管理新服务并设置开机自启。
213 14
|
1月前
|
安全 Ubuntu 应用服务中间件
基于code-server的云端编程环境部署
本文档描述如何在 Ubuntu 主机上部署 code-server(即“网页版 VS Code”),并通过 autossh 将服务反向隧道到跳板机、使用 Nginx 反向代理域名访问、以及使用 certbot 配置 HTTPS。适合在多设备间共享同一开发环境、并解决个人主机动态公网 IP 的访问问题。
486 5
|
1月前
|
存储 调度 KVM
深入浅出KVM虚拟化技术原理——Ansible安全基线配置(一)
本文深入解析KVM虚拟化核心机制,涵盖内核如何调度QEMU进程与KVM模块协同工作、CPU虚拟化扩展(VT-x/AMD-V)的硬件加速原理,以及存储池的管理与优势,助你全面掌握KVM底层运行逻辑。
248 11
|
1月前
|
JSON 网络安全 数据格式
深入浅出Ansible技术原理——Ansible安全基线配置(一)
本系列深入解析Ansible安全自动化,涵盖其无代理、幂等性、声明式三大设计哲学,剖析基于Python的内核原理与SSH通信机制,并详解Inventory、Roles、Handlers、Vault等核心组件与最佳实践,助你从入门到精通,构建高效、安全、可复用的自动化运维体系。
146 7
|
1月前
|
存储 算法 关系型数据库
【Java架构师体系课 | MySQL篇】② 深入理解MySQL索引底层数据结构与算法
InnoDB索引为何采用B+树?本文由浅入深解析二叉树、红黑树、B树的缺陷,详解B+树的结构优势:非叶子节点不存数据、叶子节点有序且双向链接,支持高效范围查询与磁盘预读,三层即可存储两千多万数据,极大提升查询性能。
132 7
|
10天前
|
弹性计算 搜索推荐 应用服务中间件
今非昔比:看完阿里云服务器租赁价格,沉默了~
阿里云服务器优惠汇总:轻量应用服务器200M带宽38元起/年,ECS云服务器2核2G仅99元/年,4核16G 89元/月,8核32G 160元/月,香港轻量服务器25元/月起,爆款低至1折,新老用户同享,续费同价,限时抢购!
140 14
|
25天前
|
弹性计算 安全 网络协议
阿里云云服务器ECS:安全、稳定、购买灵活、低成本
阿里云ECS是安全稳定、弹性灵活的明星级云服务器,支持多种实例规格与付费模式,可快速创建并部署。本文详解ECS介绍、购买流程(含地域、网络、实例、镜像、存储、安全组等设置)及使用教程,助您轻松上手云端应用搭建。
268 10
|
23天前
|
存储 数据采集 人工智能
最佳实践丨让苏东坡“复活”!我用Qwen3-8B实现了与千古文豪的跨时空对话
随着人工智能技术的不断发展,虚拟角色不再只是冰冷的对话机器,而是能够承载历史人物的气质、知识体系乃至精神风貌的“数字化身”。今天,我们将完整揭秘如何基于Qwen3-8B大模型,借助LLaMA-Factory Online平台,打造一个沉浸式的“苏东坡数字分身”,让前沿技术为文化传承注入新的活力。
345 9
最佳实践丨让苏东坡“复活”!我用Qwen3-8B实现了与千古文豪的跨时空对话