# 4.2-Ansible基础与进阶

2024年5月15日40分钟阅读

- FormalSciences/ComputerScience
- DevSecOps/ConfigMgmt

## Ansible

Ansible 是一个开源的自动化工具，主要用于配置管理、应用部署、编排（Orchestration）等。由 Michael DeHaan 于 2012 年创建，Ansible 的设计理念是简单易用、无代理（Agentless）和基于推送的模型。通过简单的 YAML 文件（称为剧本，Playbooks）定义自动化任务，Ansible 能帮助系统管理员和开发人员在大量服务器上快速、可靠地执行各种操作。

### Ansible 历史与发展

Ansible 由 Michael DeHaan 创建，并在 2012 年发布首个版本。它迅速在 DevOps 社区中获得了广泛的关注和使用，因其易用性和强大的功能。2015 年，Ansible 被 Red Hat 收购，这使其发展得更为迅速和稳定。如今，Ansible 已成为业界领先的自动化工具之一，被广泛应用于各类企业和组织中。

#### 为什么选择 Ansible

1. 简单易用：Ansible 采用 YAML 作为配置语言，简单明了，易于理解和编写。
2. 无代理架构：Ansible 不需要在被管理的节点上安装任何代理软件，减少了维护成本和复杂性。
3. 强大的模块支持：Ansible 提供了数百个模块，支持多种操作系统、云平台、网络设备等。
4. 声明式配置：Ansible 允许用户通过声明式配置文件定义所需状态，确保系统的一致性。
5. 社区活跃：Ansible 拥有一个活跃的开源社区，丰富的文档和资源，支持广泛。

### Ansible 架构概述

Ansible 的架构设计非常简洁，主要包括以下几个组件：

- 控制节点（Control Node）：运行 Ansible 的机器，通常是管理员的工作站或管理服务器。所有的 Ansible 命令和 Playbook 都从控制节点执行。
- 被管理节点（Managed Nodes）：通过 SSH 或 WinRM 连接并由 Ansible 控制的机器，这些节点可以是物理服务器、虚拟机、容器，或网络设备等。
- 剧本（Playbooks）：使用 YAML 编写的配置文件，定义了一系列的任务和操作，用于配置、部署和编排多个被管理节点上的资源。
- 模块（Modules）：Ansible 的基本执行单元，每个模块都实现了特定的功能，如安装软件包、管理文件、执行命令等。Ansible 提供了数百个内置模块，并允许用户编写自定义模块。
- 插件（Plugins）：扩展 Ansible 功能的小程序，包括连接插件（connection plugins）、回调插件（callback plugins）、过滤插件（filter plugins）等，增强 Ansible 的灵活性和功能。
- 清单（Inventory）：定义被管理节点及其分组信息的文件，可以是静态文件（如 INI 或 YAML 格式）或动态生成的脚本，支持定义主机变量和组变量。
- 角色（Roles）：将剧本、任务、处理程序、变量、模板和文件等组织在一起的目录结构，用于复用和共享配置，实现配置管理的模块化和标准化。

### Ansible 主要特性

#### 无代理架构

Ansible 采用无代理架构，这意味着它不需要在被管理的节点上安装任何软件或代理。Ansible 通过 SSH 进行通信，简化了管理和维护工作，并提高了系统的安全性和可靠性。

#### 基于 YAML 的配置

Ansible 使用 YAML 作为其配置语言。YAML 简洁直观，易于阅读和编写，特别适合用来编写配置文件。通过 YAML 文件，用户可以定义各种自动化任务，轻松实现复杂的操作。

#### 以声明式为中心

Ansible 采用声明式配置模型，用户只需定义期望的系统状态，Ansible 会自动计算并执行所需的操作，确保系统达到期望状态。这种方式减少了配置错误，提高了系统的一致性和可维护性。

#### 广泛的模块支持

Ansible 提供了丰富的内置模块，涵盖了几乎所有常见的系统管理和应用部署任务。此外，Ansible 还支持用户编写自定义模块，满足特殊需求。模块可以通过官方 Ansible Galaxy 平台共享和下载，进一步扩展了 Ansible 的功能和应用范围。

### Ansible 应用场景

#### 配置管理

Ansible 可以用于配置管理，自动化配置服务器和网络设备。通过剧本定义配置细节，Ansible 能够确保大规模环境中所有设备的一致性，简化了系统维护和升级工作。

#### 应用部署

Ansible 支持自动化应用部署，从代码拉取、编译、安装到配置，均可以通过剧本实现。无论是简单的单机应用，还是复杂的多节点分布式系统，Ansible 都能有效管理和部署。

#### 编排（Orchestration）

Ansible 不仅可以执行单个任务，还可以编排复杂的工作流程。通过定义依赖关系和执行顺序，Ansible 能够协调多个服务和系统的协同工作，确保在多步骤操作中各个环节的正确执行。

## Ansible 安装与配置

### 系统要求

Ansible 设计为跨平台运行，支持多种操作系统，包括但不限于以下几种：

- Linux：支持绝大多数发行版，如 Ubuntu、CentOS、Debian、Red Hat Enterprise Linux (RHEL) 等。
- macOS：可以在 macOS 上安装并运行 Ansible，用于开发和测试环境。
- Windows：通过 WSL（Windows Subsystem for Linux）或在 Windows 上安装 Cygwin，可以在 Windows 上运行 Ansible。

Ansible 运行时需要以下基本依赖项：

- Python：Ansible 需要 Python 2.7 或 Python 3.5 及以上版本。
- SSH：Ansible 通过 SSH 与被管理节点通信，需要在控制节点和被管理节点上配置 SSH。
- 其他依赖：根据具体模块需求，可能需要额外安装一些依赖包，例如用于云平台管理的 SDK。

### Ansible 安装步骤

#### 在不同操作系统上的安装

##### Ubuntu

在 Ubuntu 上安装 Ansible 非常简单，可以通过官方的包管理器 APT 进行安装：

    sudo apt update
    sudo apt install ansible

##### CentOS

在 CentOS 上，可以通过 EPEL（Extra Packages for Enterprise Linux）库安装 Ansible：

    sudo yum install epel-release
    sudo yum install ansible

##### macOS

在 macOS 上，可以使用 Homebrew 来安装 Ansible：

    brew install ansible

#### 通过 Python Pip 安装

可以使用 Python 的包管理器 pip 来安装 Ansible，这种方法适用于任何支持 Python 的操作系统：

    pip install ansible

#### 从源代码安装

从源代码安装适用于需要最新功能或定制 Ansible 的场景：

    git clone https://github.com/ansible/ansible.git
    cd ansible
    source ./hacking/env-setup

这种方法需要额外的依赖包，具体可以参考 Ansible 官方文档。

### Ansible 配置方法

#### Ansible 配置文件结构（ansible.cfg）

Ansible 的配置文件 `ansible.cfg` 允许用户自定义 Ansible 的运行参数。该文件通常位于以下位置之一：

1. 当前目录下的 `ansible.cfg`
2. 用户主目录下的 `.ansible.cfg`
3. 全局配置文件 `/etc/ansible/ansible.cfg`

一个典型的 `ansible.cfg` 文件结构如下：

    [defaults]
    inventory = ./hosts
    remote_user = ansible
    private_key_file = ~/.ssh/id_rsa
    host_key_checking = False

    [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

#### Ansible 配置文件优先级

Ansible 允许在多个位置定义配置文件，并根据以下优先级顺序应用配置：

1. 命令行参数：直接在命令行上指定的参数优先级最高。
2. 环境变量：通过环境变量设置的配置次高优先级。
3. ansible.cfg 文件：
   1. 当前目录下的 `ansible.cfg`
   2. 用户主目录下的 `.ansible.cfg`
   3. 全局配置文件 `/etc/ansible/ansible.cfg`
4. 模块参数：模块内部的参数配置。
5. 默认值：Ansible 内部的默认值。

#### 常用配置选项

配置选项 | 说明
--- | ---
inventory | 定义主机清单文件的位置。
remote_user | 指定远程主机的默认用户。
private_key_file | 定义用于 SSH 连接的私钥文件。
host_key_checking | 是否检查 SSH 主机密钥，默认启用。
retry_files_enabled | 是否生成重试文件，默认启用。
log_path | 指定 Ansible 运行日志的存储路径。
become | 是否启用权限提升（如 sudo）。
become_method | 权限提升的方法（如 sudo 或 su）。
become_user | 权限提升后的目标用户。
become_ask_pass | 是否提示输入密码用于权限提升。
ssh_args | 定制 SSH 连接参数。
pipelining | 启用管道以提高性能。

#### SSH 密钥和认证配置

Ansible 通过 SSH 与被管理节点通信，配置 SSH 密钥认证可以提高安全性和自动化程度。

1. 生成 SSH 密钥对：

    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

生成的密钥文件通常存储在 `~/.ssh/` 目录下。

1. 将公钥添加到被管理节点：

    ssh-copy-id user@remote_host

或者手动将公钥添加到被管理节点的 `~/.ssh/authorized_keys` 文件中。

1. 配置 SSH 代理（可选）： 使用 SSH 代理可以管理多个 SSH 密钥，提高连接效率：

    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_rsa

通过上述步骤，Ansible 可以无密码地通过 SSH 访问被管理节点，从而实现自动化操作。

## Ansible 自动化管理基础

### Ansible Playbooks

#### Playbook 的基本结构

Playbook 是 Ansible 的核心配置文件，用于定义一系列自动化任务。它使用 YAML 格式编写，主要由 Plays 和 Tasks 组成。一个典型的 Playbook 结构如下：

    - name: Describe the purpose of the playbook
      hosts: target_hosts_group
      become: yes
      vars:
        variable_name: value
      tasks:
        - name: Describe the task
          module_name:
            module_option: value

#### Playbook 的常用关键字

关键字 | 说明
--- | ---
`name` | 描述 Play 或 Task 的名称，便于阅读和调试。
`hosts` | 指定目标主机或主机组，可以是一个或多个主机组名。
`become` | 是否启用权限提升（如 sudo），默认值为 `no`。
`vars` | 定义在 Play 级别的变量，适用于整个 Play。
`tasks` | 任务列表，每个任务调用一个模块执行特定操作。
`roles` | 指定在 Play 中包含的角色，角色是一个组织良好的任务集合。
`handlers` | 定义事件触发的任务，当其他任务通知这些处理程序时执行。
`environment` | 指定任务或 Play 级别的环境变量。
`gather_facts` | 是否在 Play 开始时收集远程主机的信息，默认值为 `yes`。
`notify` | 通知一个或多个处理程序在任务完成时执行。
`when` | 条件语句，用于在特定条件下执行任务。
`with_items` | 循环语句，用于在任务中迭代一个列表。
`register` | 捕获任务的输出结果并存储在变量中。
`tags` | 为任务或 Play 打标签，便于选择性地运行特定任务或 Play。
`ignore_errors` | 是否忽略任务执行中的错误，继续执行后续任务。
`delegate_to` | 将任务委派给指定的主机执行，而不是在目标主机上执行。
`serial` | 控制任务并行执行的主机数量或批次大小。
`max_fail_percentage` | 允许的最大失败百分比，超过此比例时停止 Play。

#### 编写和运行第一个 Playbook

1. 编写 Playbook 文件（如 `first_playbook.yml`）：

    - name: Install and start Apache web server
      hosts: webservers
      become: yes
      tasks:
        - name: Install Apache
          apt:
            name: apache2
            state: present
        - name: Start Apache service
          service:
            name: apache2
            state: started

1. 运行 Playbook：

    ansible-playbook first_playbook.yml

在此示例中，Playbook 定义了一个 Play，包含两个任务：一个用于安装 Apache Web 服务器，另一个用于启动 Apache 服务。`hosts` 指定了目标主机组为 `webservers`，并通过 `become: yes` 启用权限提升（通常是 sudo）。

#### 多 Play 和任务的组织

一个 Playbook 可以包含多个 Play，每个 Play 针对不同的主机组或执行不同的任务。这种结构有助于在一个 Playbook 中管理复杂的部署场景。

    - name: Setup web servers
      hosts: webservers
      become: yes
      tasks:
        - name: Install Apache
          apt:
            name: apache2
            state: present

        - name: Start Apache service
          service:
            name: apache2
            state: started

    - name: Setup database servers
      hosts: dbservers
      become: yes
      tasks:
        - name: Install MySQL
          apt:
            name: mysql-server
            state: present

        - name: Start MySQL service
          service:
            name: mysql
            state: started

在此示例中，Playbook 包含两个 Play：第一个 Play 针对 `webservers` 主机组，安装并启动 Apache Web 服务器；第二个 Play 针对 `dbservers` 主机组，安装并启动 MySQL 数据库服务。

通过组织多个 Play 和任务，可以在一个 Playbook 中处理多种部署需求，提高配置管理的灵活性和可维护性。

### Ansible 模块

#### 常用模块

模块名称 | 用途 | 示例
--- | --- | ---
`file` | 管理文件和目录 | `yaml\n- name: Create a directory\n file:\n path: /path/to/directory\n state: directory\n`
`service` | 管理服务 | `yaml\n- name: Start a service\n service:\n name: nginx\n state: started\n`
`command` | 执行命令 | `yaml\n- name: Run a command\n command: /usr/bin/uptime\n`
`shell` | 执行 shell 命令 | `yaml\n- name: Run a shell command\n shell: echo "Hello, world!" > /tmp/hello.txt\n`
`copy` | 复制文件到远程主机 | `yaml\n- name: Copy a file\n copy:\n src: /local/path/to/file\n dest: /remote/path/to/file\n`
`template` | 使用 Jinja2 模板渲染并复制文件到远程主机 | `yaml\n- name: Deploy configuration file from template\n template:\n src: /path/to/template.j2\n dest: /path/to/destination\n`
`yum` | 使用 YUM 包管理器安装、卸载包（适用于 RHEL 系） | `yaml\n- name: Install a package using yum\n yum:\n name: httpd\n state: present\n`
`apt` | 使用 APT 包管理器安装、卸载包（适用于 Debian 系） | `yaml\n- name: Install a package using apt\n apt:\n name: apache2\n state: present\n`
`user` | 管理用户 | `yaml\n- name: Create a user\n user:\n name: username\n state: present\n password: password_hash\n`
`group` | 管理用户组 | `yaml\n- name: Create a group\n group:\n name: groupname\n state: present\n`
`cron` | 管理 cron 作业 | `yaml\n- name: Add a cron job\n cron:\n name: "backup script"\n minute: "0"\n hour: "2"\n job: "/path/to/backup.sh"\n`
`git` | 管理 Git 仓库 | `yaml\n- name: Clone a Git repository\n git:\n repo: "https://github.com/repo.git"\n dest: "/path/to/destination"\n`

每个模块都有特定的参数和选项，可以在 Ansible 官方文档中查找详细信息。例如，`file` 模块的常用参数包括 `path`、`state`、`owner`、`group` 等。

#### 自定义模块

如果内置模块不能满足需求，可以编写自定义模块。自定义模块可以使用 Python 编写，并放置在库路径中。

示例自定义模块（`my_module.py`）：

    #!/usr/bin/python

    from ansible.module_utils.basic import AnsibleModule

    def run_module():
        module_args = dict(
            name=dict(type='str', required=True)
        )

        module = AnsibleModule(
            argument_spec=module_args,
            supports_check_mode=True
        )

        result = dict(
            changed=False,
            message=''
        )

        name = module.params['name']
        result['message'] = f'Hello, {name}!'

        if module.check_mode:
            module.exit_json(**result)

        module.exit_json(**result)

    def main():
        run_module()

    if __name__ == '__main__':
        main()

运行自定义模块：

    - name: Use custom module
      hosts: localhost
      tasks:
        - name: Call custom module
          my_module:
            name: Ansible

### Ansible 变量和模板

#### 变量的定义与使用

变量可以在多个地方定义，如 Playbook、清单文件、角色等：

    - name: Example with variables
      hosts: localhost
      vars:
        http_port: 80
      tasks:
        - name: Display variable
          debug:
            msg: "HTTP port is {{ http_port }}"

#### 变量优先级

Ansible 变量的优先级从低到高依次为：

1. 角色默认变量（role defaults）
2. 组变量（group vars）
3. 主机变量（host vars）
4. 播放（Play）中的变量
5. 任务（Task）中的变量
6. 命令行定义的变量（使用 `-e` 参数）

这个优先级决定了当同一个变量在多个地方定义时，哪个值会被使用。

#### Jinja2 模板语法

Ansible 使用 Jinja2 作为模板引擎，支持复杂的模板生成。模板文件通常以 `.j2` 结尾，放置在 `templates` 目录下。

示例模板文件（`config.j2`）：

    ## 变量替换
    Hello, {{ name }}!

    ## 条件语句
    {% if http_port == 80 %}
      server {
          listen 80;
      }
    {% else %}
      server {
          listen {{ http_port }};
      }
    {% endif %}

    ## 循环语句
    {% for user in users %}
      user {{ user.name }} with id {{ user.id }}
    {% endfor %}

#### 使用模板生成配置文件

可以使用 `template` 模块将 Jinja2 模板渲染为实际配置文件，并部署到目标主机上。

示例 Playbook（`deploy_config.yml`）：

    - name: Deploy configuration file
      hosts: webservers
      become: yes
      vars:
        http_port: 80
        server_name: example.com
        proxy_url: 127.0.0.1:8080
      tasks:
        - name: Deploy nginx configuration
          template:
            src: templates/nginx.conf.j2
            dest: /etc/nginx/sites-available/default
          notify:
            - restart nginx

      handlers:
        - name: restart nginx
          service:
            name: nginx
            state: restarted

示例模板文件（`nginx.conf.j2`）：

    server {
        listen {{ http_port }};
        server_name {{ server_name }};

        location / {
            proxy_pass http://{{ proxy_url }};
        }
    }

在此 Playbook 中，`template` 模块会将 `templates/nginx.conf.j2` 文件渲染为实际的配置文件，并部署到 `/etc/nginx/sites-available/default`。如果模板内容发生变化，通知部分会触发 `restart nginx` 处理程序，重启 nginx 服务以应用新的配置。

通过这种方式，可以使用 Ansible 自动化生成和部署配置文件，大大简化了系统配置管理的工作，并确保配置的一致性和可重复性。

## Ansible 高级应用技巧

### Ansible 角色

#### 角色的结构与组成

角色（Roles）是 Ansible 中的一种组织方式，用于将 Playbooks 和相关文件（如任务、处理程序、变量、模板等）结构化和模块化。角色的目录结构通常如下：

    roles/
      └── role_name/
          ├── tasks/
          │   └── main.yml
          ├── handlers/
          │   └── main.yml
          ├── templates/
          │   └── template_file.j2
          ├── files/
          │   └── file_name
          ├── vars/
          │   └── main.yml
          ├── defaults/
          │   └── main.yml
          ├── meta/
          │   └── main.yml
          └── README.md

- tasks：存放主要任务列表（`main.yml` 是入口文件）。
- handlers：存放处理程序（`main.yml` 是入口文件）。
- templates：存放 Jinja2 模板文件。
- files：存放需要复制到远程主机的静态文件。
- vars：存放角色专用变量。
- defaults：存放默认变量。
- meta：存放角色的元数据，如依赖关系。
- README.md：角色的说明文档，描述角色的用途、用法等。

#### 创建和使用角色

1. 创建角色：

    ansible-galaxy init my_role

这条命令会生成上述结构的角色目录。

1. 定义任务（`roles/my_role/tasks/main.yml`）：

    - name: Install Apache
      apt:
        name: apache2
        state: present

    - name: Start Apache service
      service:
        name: apache2
        state: started

在这个例子中，定义了两个任务：一个用于安装 Apache，另一个用于启动 Apache 服务。

1. 在 Playbook 中使用角色：

    - name: Apply my role
      hosts: webservers
      roles:
        - my_role

在 Playbook 中，通过 `roles` 关键字引用角色。

#### 角色的共享与重用（Ansible Galaxy）

Ansible Galaxy 是 Ansible 官方的角色分享平台，用户可以在上面发布和下载角色，方便角色的共享与重用。

1. 安装角色：

    ansible-galaxy install username.role_name

可以从 Galaxy 下载并安装角色。安装的角色通常会存放在 Ansible 的角色路径中（默认是 `/etc/ansible/roles` 或 `~/.ansible/roles`）。

1. 使用已安装的角色：

    - name: Use a role from Ansible Galaxy
      hosts: webservers
      roles:
        - username.role_name

在 Playbook 中通过 `roles` 关键字引用已经安装的角色。

通过使用 Ansible 角色，可以将复杂的 Playbook 结构化、模块化，使得配置管理更为清晰、可维护。同时，通过 Ansible Galaxy 平台，可以方便地共享和重用角色，提升团队协作和生产效率。

### Ansible 动态 Inventory

#### 静态 Vs 动态 Inventory

静态 Inventory 是一个简单的文本文件，列出所有被管理节点及其分组。动态 Inventory 则是通过脚本或插件生成的，适用于云环境或动态变化的基础设施。

示例静态 Inventory（`hosts`）：

    [webservers]
    web1.example.com
    web2.example.com

    [dbservers]
    db1.example.com
    db2.example.com

#### 动态 Inventory 脚本编写

动态 Inventory 脚本可以用任何语言编写，只要它能输出 JSON 格式的主机和组信息。例如，使用 Python 编写一个简单的动态 Inventory 脚本（`my_inventory.py`）：

    #!/usr/bin/env python

    import json

    inventory = {
        "webservers": {
            "hosts": ["web1.example.com", "web2.example.com"],
        },
        "dbservers": {
            "hosts": ["db1.example.com", "db2.example.com"],
        }
    }

    print(json.dumps(inventory))

运行 Playbook 时使用该脚本：

    ansible-playbook -i my_inventory.py my_playbook.yml

#### 常用的动态 Inventory 插件（如 AWS、Azure）

Ansible 提供了多种动态 Inventory 插件，支持 AWS、Azure、GCP 等云平台。

1. AWS 动态 Inventory： 安装 `boto3`：

    pip install boto3

创建 `aws_ec2.yml` 配置文件，使用 `aws_ec2` 插件：

    plugin: aws_ec2
    regions:
      - us-east-1
    filters:
      instance-state-name: running
    keyed_groups:
      - key: tags.Name
        prefix: tag
      - key: tags.Environment
        prefix: env

使用该配置文件运行 Playbook：

    ansible-playbook -i aws_ec2.yml my_playbook.yml

1. Azure 动态 Inventory： 安装 `azure-cli` 和 `azure-mgmt`：

    pip install azure-cli azure-mgmt

使用 `azure_rm` 插件：

    plugin: azure_rm
    include_vm_resource_groups:
      - myResourceGroup
    auth_source: auto

使用该配置文件运行 Playbook：

    ansible-playbook -i azure_rm.yml my_playbook.yml

1. GCP 动态 Inventory

安装 `google-auth` 和 `google-api-python-client` 库：

    pip install google-auth google-api-python-client

创建 `gcp_compute.yml` 配置文件，使用 `gcp_compute` 插件：

    plugin: gcp_compute
    projects:
      - my-gcp-project
    filters:
      - status = RUNNING
    auth_kind: serviceaccount
    service_account_file: /path/to/service-account.json

使用该配置文件运行 Playbook：

    ansible-playbook -i gcp_compute.yml my_playbook.yml

通过动态 Inventory，可以自动发现和管理云环境中的资源，提高自动化程度和灵活性。这在动态变化的基础设施中尤其有用，确保 Ansible 的管理目标始终是最新的。

### Ansible Vault

#### 使用 Vault 加密敏感数据

Ansible Vault 用于加密敏感数据，如密码、密钥等，确保这些信息在存储和传输过程中不会被泄露。以下是 Ansible Vault 的基本使用方法：

    # 1.加密文件
    ansible-vault encrypt secret.yml

    # 2.解密文件
    ansible-vault decrypt secret.yml

    # 3.编辑加密文件
    ansible-vault edit secret.yml

    # 4.查看加密文件
    ansible-vault view secret.yml

    # 5.重新加密文件（更改加密密码）
    ansible-vault rekey secret.yml

#### Vault 的管理和使用

为了更方便地管理 Vault，可以在 `ansible.cfg` 中指定 Vault 密码文件，这样在运行 Playbook 时无需每次手动输入密码：

    [defaults]
    vault_password_file = /path/to/.vault_pass.txt

`/path/to/.vault_pass.txt` 文件中应只包含 Vault 密码，且该文件应设置为仅有文件所有者可读写：

    chmod 600 /path/to/.vault_pass.txt

如果不希望将密码写入文件，也可以使用命令行参数 `--ask-vault-pass`：

    ansible-playbook --ask-vault-pass my_playbook.yml

#### 在 Playbooks 中集成 Vault

在 Playbook 中使用 Vault 加密的变量文件时，可以通过 `vars_files` 引用这些文件：

    - name: Deploy with Vault
      hosts: webservers
      vars_files:
        - secret.yml
      tasks:
        - name: Use encrypted variable
          debug:
            msg: "The secret is {{ vault_secret }}"

在这个示例中，`secret.yml` 是一个加密的变量文件，其中包含敏感数据。Ansible 会在运行 Playbook 时解密并加载这些变量。

#### Vault ID 和多 Vault 支持

Ansible Vault 支持使用多个 Vault ID 来加密不同级别或类型的敏感数据。使用 `--vault-id` 选项可以指定不同的 Vault 密码文件或密码提示命令。

例如，加密文件时指定 Vault ID：

    ansible-vault encrypt --vault-id dev@prompt secret_dev.yml
    ansible-vault encrypt --vault-id prod@/path/to/prod_vault_pass.txt secret_prod.yml

在 Playbook 中引用不同 Vault ID 的变量文件：

    - name: Deploy with Vault IDs
      hosts: webservers
      vars_files:
        - vault_id: dev
          file: secret_dev.yml
        - vault_id: prod
          file: secret_prod.yml
      tasks:
        - name: Use dev encrypted variable
          debug:
            msg: "Dev secret is {{ dev_secret }}"
        - name: Use prod encrypted variable
          debug:
            msg: "Prod secret is {{ prod_secret }}"

运行 Playbook 时，指定 Vault ID 和密码文件：

    ansible-playbook --vault-id dev@prompt --vault-id prod@/path/to/prod_vault_pass.txt my_playbook.yml

通过 Ansible Vault，可以有效地保护敏感数据，确保自动化流程的安全性，同时保持操作的便捷性和高效性。

## Ansible 与其他自动化工具的比较

维度 | Ansible | Puppet | Chef
--- | --- | --- | ---
架构 | 无代理架构，通过 SSH 或 WinRM 与被管理节点通信 | 有代理架构，需要在被管理节点上安装 Puppet Agent | 有代理架构，需要在被管理节点上安装 Chef Client
通信模型 | 基于推送模型，由控制节点推送任务到被管理节点执行 | 基于拉取模型，被管理节点定期向 Puppet Master 拉取配置 | 基于拉取模型，被管理节点定期向 Chef Server 拉取配置
配置语言 | 使用 YAML 编写 Playbook，直观易读 | 使用 Puppet 自定义的声明式语言编写清单（Manifest） | 使用 Ruby 编写食谱（Cookbooks），脚本式语言，灵活性高
学习曲线 | 简单易用，适合快速上手 | 学习曲线较为陡峭 | 学习曲线较陡，需要掌握 Ruby
适用场景 | 临时和一次性任务、多平台支持、快速部署和小型团队 | 大规模配置管理、复杂依赖管理、企业级功能 | 复杂和大型环境管理、需要复杂逻辑和自定义的场景
模块支持 | 内置丰富的模块，适用于多种场景 | 提供丰富的模块和企业级工具 | 提供灵活的配置和扩展能力
依赖管理 | 依赖管理能力相对较弱 | 强大的资源依赖管理能力 | 灵活的依赖管理和配置能力
企业级功能 | 提供一些企业级功能，社区活跃，资源丰富 | 提供丰富的企业级功能和工具，如报告、审计、合规管理等 | 提供强大的企业级功能和支持
性能 | 由于采用 SSH 推送模型，在大规模环境中性能可能会受到限制 | 性能较好，适合大规模环境 | 性能较好，适合复杂和大型环境
维护成本 | 无代理架构，减少了管理和维护成本 | 需要管理和维护 Puppet Master 和 Agent | 需要管理和维护 Chef Server 和 Client
社区和支持 | 拥有庞大且活跃的社区，提供丰富的资源和支持 | 社区活跃，企业级支持完善 | 社区活跃，企业级支持完善

### Ansible 在云环境中的应用

#### AWS 集成

安装并配置 `boto3` 库，使用 `ec2` 模块管理 AWS 资源。

    pip install boto3

配置 Ansible Inventory 使用 AWS 动态库存插件 `aws_ec2`：

    plugin: aws_ec2
    regions:
      - us-east-1
    filters:
      instance-state-name: running

示例 Playbook：创建和管理 EC2 实例。

    - name: Launch EC2 instance
      hosts: localhost
      tasks:
        - name: Launch an instance
          ec2:
            key_name: my-key
            instance_type: t2.micro
            image: ami-0abcdef1234567890
            wait: yes
            region: us-east-1
            group: my-security-group

#### Azure 集成

安装并配置 `azure-cli` 和 `azure-mgmt` 库，使用 `azure_rm` 模块管理 Azure 资源。

    pip install azure-cli azure-mgmt

配置 Ansible Inventory 使用 Azure 动态库存插件 `azure_rm`：

    plugin: azure_rm
    include_vm_resource_groups:
      - myResourceGroup

示例 Playbook：创建和管理 Azure VM 实例。

    - name: Launch Azure VM
      hosts: localhost
      tasks:
        - name: Create a VM
          azure_rm_virtualmachine:
            resource_group: myResourceGroup
            name: myVM
            vm_size: Standard_DS1_v2
            admin_username: azureuser
            admin_password: Password123!
            image:
              offer: UbuntuServer
              publisher: Canonical
              sku: 18.04-LTS
              version: latest

#### 云资源管理和部署

##### 动态库存管理

使用动态库存插件自动发现和管理云资源，无需手动更新 Inventory 文件。

       - name: List EC2 instances
         hosts: localhost
         tasks:
           - name: List instances
             ec2_instance_facts:
               region: us-east-1

##### 自动化部署

使用 Ansible Playbook 实现云资源的自动化部署和配置，简化操作流程。

    - name: Deploy web application on AWS
      hosts: tag_Environment_web
      become: yes
      tasks:
        - name: Install Nginx
          yum:
            name: nginx
            state: present
        - name: Start Nginx
          service:
            name: nginx
            state: started

### Ansible 在容器化环境中的应用

#### Docker 集成

使用 `community.docker` 集成 Docker，管理 Docker 容器和镜像。

    - name: Manage Docker
      hosts: all
      become: yes
      tasks:
        - name: Install Docker
          apt:
            name: docker.io
            state: present
        - name: Run a Docker container
          community.docker.docker_container:
            name: mycontainer
            image: nginx
            state: started
            ports:
              - "80:80"

#### Kubernetes 集成

使用 `kubernetes.core` 集成 Kubernetes，管理 Kubernetes 资源和集群。

    - name: Manage Kubernetes
      hosts: localhost
      tasks:
        - name: Create a namespace
          kubernetes.core.k8s:
            state: present
            definition:
              apiVersion: v1
              kind: Namespace
              metadata:
                name: mynamespace
        - name: Deploy a pod
          kubernetes.core.k8s:
            state: present
            definition:
              apiVersion: v1
              kind: Pod
              metadata:
                name: mypod
                namespace: mynamespace
              spec:
                containers:
                - name: nginx
                  image: nginx

#### 容器部署

使用 Ansible 部署和管理容器化应用，实现自动化运维。

    - name: Deploy Dockerized application
      hosts: all
      become: yes
      tasks:
        - name: Pull Docker image
          community.docker.docker_image:
            name: myapp
            tag: latest
            source: pull
        - name: Run Docker container
          community.docker.docker_container:
            name: myapp
            image: myapp:latest
            state: started
            ports:
              - "8080:8080"

#### Kubernetes 应用编排

使用 Ansible 管理 Kubernetes 集群，实现应用编排和服务发现。

    - name: Deploy Kubernetes application
      hosts: localhost
      tasks:
        - name: Create deployment
          kubernetes.core.k8s:
            state: present
            definition:
              apiVersion: apps/v1
              kind: Deployment
              metadata:
                name: myapp
                namespace: default
              spec:
                replicas: 3
                selector:
                  matchLabels:
                    app: myapp
                template:
                  metadata:
                    labels:
                      app: myapp
                  spec:
                    containers:
                    - name: myapp
                      image: myapp:latest
                      ports:
                      - containerPort: 8080
        - name: Expose service
          kubernetes.core.k8s:
            state: present
            definition:
              apiVersion: v1
              kind: Service
              metadata:
                name: myapp-service
                namespace: default
              spec:
                selector:
                  app: myapp
                ports:
                - protocol: TCP
                  port: 80
                  targetPort: 8080

### Ansible 在传统 IT 环境中的应用

#### 数据中心管理

##### 服务器配置管理

使用 Ansible 管理数据中心服务器的配置，确保一致性和自动化。

    - name: Configure data center servers
      hosts: datacenter
      become: yes
      tasks:
        - name: Update all packages
          apt:
            upgrade: dist
        - name: Ensure NTP is installed
          apt:
            name: ntp
            state: present
        - name: Configure NTP
          copy:
            src: templates/ntp.conf.j2
            dest: /etc/ntp.conf
          notify:
            - restart ntp

      handlers:
        - name: restart ntp
          service:
            name: ntp
            state: restarted

##### 硬件管理

使用 Ansible 自动化硬件管理，如固件升级和 BIOS 配置。

    - name: Manage hardware
      hosts: datacenter
      become: yes
      tasks:
        - name: Upgrade firmware
          command: /usr/bin/upgrade_firmware.sh

#### 网络设备配置

##### 网络设备管理

使用 Ansible 管理网络设备配置，自动化网络设备的部署和更新。

    - name: Configure network devices
      hosts: switches
      become: yes
      tasks:
        - name: Update switch firmware
          ios_command:
            commands:
              - copy tftp://192.0.2.1/new_firmware.bin flash:
              - reload

##### 网络拓扑管理

使用 Ansible 自动化网络拓扑的配置和管理，确保网络配置的一致性。

    - name: Configure network topology
      hosts: routers
      become: yes
      tasks:
        - name: Configure OSPF
          ios_config:
            lines:
              - router ospf 1
              - network 10.0.0.0 0.255.255.255 area 0

#### 跨平台管理

##### 多操作系统管理

使用 Ansible 管理多种操作系统，包括 Linux、Windows 和 macOS。

    - name: Manage multiple OS
      hosts: all
      become: yes
      tasks:
        - name: Install packages on Linux
          apt:
            name: nginx
            state: present
          when: ansible_os_family == "Debian"

        - name: Install packages on Windows
          win_feature:
            name: Web-Server
            state: present
          when: ansible_os_family == "Windows"

        - name: Install packages on macOS
          homebrew:
            name: nginx
            state: present
          when: ansible_os_family == "Darwin"

##### 跨平台应用部署

使用 Ansible 实现跨平台应用的自动化部署，确保各平台的一致性。

    - name: Deploy application across platforms
      hosts: all
      become: yes
      tasks:
        - name: Deploy app on Linux
          command: /usr/local/bin/deploy_app.sh
          when: ansible_os_family == "Debian"

        - name: Deploy app on Windows
          win_command: C:\Deploy\deploy_app.bat
          when: ansible_os_family == "Windows"

        - name: Deploy app on macOS
          command: /usr/local/bin/deploy_app.sh
          when: ansible_os_family == "Darwin"

## Ansible 实践案例

### 常见使用案例

#### 系统用户和组管理

创建用户和组，设置权限和密码。

    - name: Create a new user
      hosts: all
      become: yes
      tasks:
        - name: Add a user
          user:
            name: john
            state: present
            password: "{{ 'password' | password_hash('sha512') }}"

#### 软件安装和更新

使用包管理器安装和更新软件包。

    - name: Install and update software packages
      hosts: all
      become: yes
      tasks:
        - name: Install nginx
          apt:
            name: nginx
            state: present
        - name: Update all packages
          apt:
            upgrade: dist

#### 服务管理

启动、停止和重启服务。

    - name: Manage services
      hosts: all
      become: yes
      tasks:
        - name: Ensure nginx is running
          service:
            name: nginx
            state: started

#### 文件和目录管理

创建、删除文件和目录，设置权限和所有者。

    - name: Manage files and directories
      hosts: all
      become: yes
      tasks:
        - name: Create a directory
          file:
            path: /etc/myapp
            state: directory
        - name: Copy a configuration file
          copy:
            src: files/myapp.conf
            dest: /etc/myapp/myapp.conf
            owner: root
            group: root
            mode: '0644'

#### 网络配置

配置网络接口和防火墙规则。

    - name: Configure network interfaces
      hosts: all
      become: yes
      tasks:
        - name: Configure eth0
          network:
            name: eth0
            state: up
            address: 192.168.1.100
            netmask: 255.255.255.0
            gateway: 192.168.1.1

### 真实场景的 Playbook 编写

#### LAMP 堆栈部署

安装 Apache、MySQL 和 PHP，配置虚拟主机和数据库。

    - name: Deploy LAMP stack
      hosts: webservers
      become: yes
      tasks:
        - name: Install Apache
          apt:
            name: apache2
            state: present

        - name: Install MySQL
          apt:
            name: mysql-server
            state: present

        - name: Install PHP
          apt:
            name: php
            state: present

        - name: Configure Apache virtual host
          template:
            src: templates/vhost.conf.j2
            dest: /etc/apache2/sites-available/000-default.conf
          notify:
            - restart apache

      handlers:
        - name: restart apache
          service:
            name: apache2
            state: restarted

#### Docker 容器管理

安装 Docker，启动容器，部署应用。

    - name: Manage Docker containers
      hosts: all
      become: yes
      tasks:
        - name: Install Docker
          apt:
            name: docker.io
            state: present

        - name: Ensure Docker is running
          service:
            name: docker
            state: started

        - name: Run a web application container
          docker_container:
            name: mywebapp
            image: nginx
            state: started
            ports:
              - "80:80"

### 故障排除与调试技巧

#### 使用 `-vvv` 选项

提供详细的输出信息，帮助定位问题。

    ansible-playbook -i inventory myplaybook.yml -vvv

#### 调试模块

使用 `debug` 模块输出变量信息。

    - name: Debug variables
      hosts: all
      tasks:
        - name: Show variable value
          debug:
            var: my_variable

#### 条件执行

使用 `when` 条件语句，避免在不满足条件时执行任务。

    - name: Conditional execution
      hosts: all
      tasks:
        - name: Only run when condition is met
          command: /usr/bin/somecommand
          when: ansible_os_family == "Debian"

#### 查看日志文件

查看 Ansible 生成的日志文件，分析错误信息。

    tail -f /var/log/ansible.log

## Ansible 性能优化

### 大规模部署的性能优化

#### 并行执行

增加并行任务的数量，默认值为 5，可以通过 `forks` 参数调整。

    ansible-playbook -i inventory myplaybook.yml -f 10

#### SSH 连接复用

启用 SSH 连接复用，提高效率。

    [ssh_connection]
    ssh_args = -o ControlMaster=auto -o ControlPersist=60s

#### 使用缓存

使用事实缓存减少收集远程主机信息的时间。

    [defaults]
    fact_caching = jsonfile
    fact_caching_connection = /tmp/ansible_cache

### 高效编写 Playbooks 的技巧

#### 避免重复

使用角色和 include 机制，避免重复代码。

    - name: Include common tasks
      import_tasks: common.yml

#### 变量和模板

使用变量和模板简化配置文件。

    - name: Use variables in tasks
      hosts: all
      vars:
        my_var: "value"
      tasks:
        - name: Print variable
          debug:
            msg: "The value is {{ my_var }}"

#### 条件和循环

使用条件和循环减少代码冗余。

    - name: Install multiple packages
      hosts: all
      become: yes
      tasks:
        - name: Install packages
          apt:
            name: "{{ item }}"
            state: present
          loop:
            - nginx
            - mysql-server
            - php

### 常见性能问题及解决方案

#### SSH 连接瓶颈

使用 `pipelining` 提升 SSH 连接速度。

    [ssh_connection]
    pipelining = True

#### 冗余任务执行

​ 使用 `check_mode` 检查任务是否需要执行，避免不必要的任务执行。

    - name: Check mode example
      hosts: all
      tasks:
        - name: Ensure nginx is installed
          apt:
            name: nginx
            state: present
          check_mode: yes

#### 过多事实收集

禁用不必要的事实收集，提高效率。

    - name: Disable fact gathering
      hosts: all
      gather_facts: no
      tasks:
        - name: Ensure nginx is installed
          apt:
            name: nginx
            state: present

## Ansible 集成

### Jenkins

1. 安装 Jenkins 插件

   安装 Ansible 插件和 SSH 插件，以便 Jenkins 可以运行 Ansible 任务。

2. 配置 Jenkins 作业

   创建一个 Jenkins 作业，配置源代码管理、构建触发器等。

3. 在 Jenkins 中运行 Playbook

   在 Jenkins 作业中添加构建步骤，运行 Ansible Playbook。

       ansible-playbook -i inventory myplaybook.yml

### Nagios

使用 Ansible 安装和配置 Nagios，部署监控插件。

       - name: Install Nagios
         hosts: all
         become: yes
         tasks:
           - name: Install Nagios packages
             apt:
               name: nagios3
               state: present
           - name: Configure Nagios
             template:
               src: templates/nagios.cfg.j2
               dest: /etc/nagios3/nagios.cfg
             notify:
               - restart nagios

         handlers:
           - name: restart nagios
             service:
               name: nagios3
               state: restarted

### Prometheus

使用 Ansible 部署 Prometheus 和 Node Exporter，收集和监控指标。

       - name: Install Prometheus
         hosts: all
         become: yes
         tasks:
           - name: Download Prometheus
             get_url:
               url: https://github.com/prometheus/prometheus/releases/download/v2.26.0/prometheus-2.26.0.linux-amd64.tar.gz
               dest: /tmp/prometheus.tar.gz

           - name: Extract Prometheus
             unarchive:
               src: /tmp/prometheus.tar.gz
               dest: /opt/
               remote_src: yes

           - name: Configure Prometheus
             template:
               src: templates/prometheus.yml.j2
               dest: /opt/prometheus-2.26.0.linux-amd64/prometheus.yml

           - name: Create systemd service
             template:
               src: templates/prometheus.service.j2
               dest: /etc/systemd/system/prometheus.service
             notify:
               - reload systemd
               - start prometheus

         handlers:
           - name: reload systemd
             command: systemctl daemon-reload
           - name: start prometheus
             service:
               name: prometheus
               state: started

通过以上系统全面的内容，您可以更好地理解和掌握 Ansible 的使用，从而实现自动化部署和管理，提高工作效率。