半小时快速入门Ansible(自动化运维)

821 阅读8分钟

功能特性介绍

Ansible主要有以下特点:

  1. 无代理架构,通过避免在 IT 基础设施上安装额外软件来降低维护开销。
  2. 简单性,自动化剧本使用简单的 YAML 语法,代码就像文档一样易于阅读。Ansible 也是分散式的,使用 SSH 和现有的操作系统凭据来访问远程机器。
  3. 可扩展性和灵活性,通过模块化设计轻松快速地扩展您自动化的系统,该设计支持各种操作系统、云平台和网络设备。
  4. 幂等性和可预测性,当系统处于您的剧本描述的状态时,即使多次运行剧本,Ansible 也不会更改任何内容。

Ansible大致框架如图:

原理:控制节点生成可执行的python文件发送给受控节点,之后受控节点执行python脚本

安装

在客户机上安装ansible(注意需提前安装python环境版本3.7+)

 `yum 安装:`
 yum install epel-release.noarch  -y
 yum install ansible -y

 pip install ansible
 pip3 install ansible
 
 `查看版本:`
 [root@7-3 ~]#  ansible --version
 ansible 2.9.27
 
 `查看配置文件:`
 [root@7-3 ~]#  rpm -qc ansible
 /etc/ansible/ansible.cfg    //这个基本上不需要改
 /etc/ansible/hosts          //主机清单,很重要⭐

配置主机清单

下面为ini格式的主机清单设置

 [host]             //组名
 111.111.111.111   //主机号
 
 [host2]              //第二个组名
 112.112.112.112
 [all]       //组名也可以嵌套
 host1
 host1

对于复杂的应用场景,可以使用结构更加清晰合理的yaml格式,如:

myhosts:
  hosts:
    my_host_01:
      ansible_host: 192.0.2.50
    my_host_02:
      ansible_host: 192.0.2.51
    my_host_03:
      ansible_host: 192.0.2.52
      

下面是一个数据中心的基础结构设置:

leafs:
  hosts:
    leaf01:
      ansible_host: 192.0.2.100
    leaf02:
      ansible_host: 192.0.2.110

spines:
  hosts:
    spine01:
      ansible_host: 192.0.2.120
    spine02:
      ansible_host: 192.0.2.130

network:
  children:
    leafs:
    spines:

webservers:
  hosts:
    webserver01:
      ansible_host: 192.0.2.140
    webserver02:
      ansible_host: 192.0.2.150

datacenter:
  children:
    network:
    webservers:

配置完成后验证清单

ansible-inventory -i inventory.ini --list

Ping清单中的某组进行测试

ansible myhosts -m ping -i inventory.ini

容易报错的地方:

  1. 目标主机未安装python会报错
  2. 目标主机的python版本不能低于3.7
  3. 如果目标主机有多个python版本,需指定
  4. 需提前进行ssh密钥认证,ssh-keygen -t rsa -b 4096生成密钥 ssh-copy-id root@xxx,将密钥复制到目标主机

成功后如图:

创建剧本

剧本是 Ansible 用于部署和配置受管节点的自动化蓝图,采用 YAML 格式。

  1. 剧本一系列定义 Ansible 执行操作顺序的剧目,自上而下,以实现总体目标。
  2. 剧目一个有序的任务列表,映射到清单中的受管节点。
  3. 任务对单个模块的引用,定义 Ansible 执行的操作。
  4. 模块,Ansible 在受管节点上运行的代码或二进制单元。Ansible 模块按集合分组,每个模块都有一个完全限定的集合名称 (FQCN)。

在项目文件夹中创建playbook.yaml文件,输入:

- name: My first play
  hosts: myhosts
  tasks:
   - name: Ping my hosts
     ansible.builtin.ping:

   - name: Print message
     ansible.builtin.debug:
       msg: Hello world

运行剧本:ansible-playbook -i inventory.ini playbook.yaml

运行效果如图:

通过上面输出可以看到:

  1. 剧本中的命名name会在输出中显示,因此name尽量使用易于理解的描述
  2. Gathering Facts任务没在剧本中描述但出现在运行结果中,该任务是隐式运行的,它主要是收集主机信息
  3. 任务下面的ok代码任务已成功运行
  4. play recap为总结摘要,总结每个主机上所有任务的执行结果,本示例中的有三个任务,所以ok=3代表任务全部执行成功

其他功能

在掌握清单和剧本后我们便可以进行基础的自动化管理了,不过Ansible的一些其他功能可以帮助我们实现更复杂的需求。碍于篇幅,这里只是简单介绍下,想了解更多可以查询官方文档:Ansible文档

模块和扩展

模块(也称为“任务插件”或“库插件”)是可以从命令行或在 playbook 任务中使用的离散代码单元。Ansible 通常在远程托管节点上执行每个模块,并收集返回值。

下面是yaml文件中使用模块的一个示例:

- name: restart webserver
  service:
    name: httpd
    state: restarted

集合

集合是 Ansible 内容的一种分发格式,其中可以包含剧本、角色、模块和插件。可以理解为编程中的函数,将众多模块等打包为一个函数方法,提供输入参数

- name: Run a play using the collections keyword
  hosts: all
  collections:
    - my_namespace.my_collection

  tasks:

    - name: Import a role
      ansible.builtin.import_role:
        name: role1

    - name: Run a module not specifying FQCN
      my_module:
        option1: value

    - name: Run a debug task
      ansible.builtin.debug:
        msg: '{{ lookup("my_namespace.my_collection.lookup1", "param1")| my_namespace.my_collection.filter1 }}'

数据保护Ansible vault

Ansible Vault能够为变量和文件进行加密保护,帮助您安全地存储密码、密钥等敏感信息,避免这些内容以明文形式暴露在Playbook或角色文件中。要使用该功能,您需要预先设置一个或多个加密密码用于数据的加解密操作。如果您选择将密码存放在第三方密钥管理工具中,则需编写脚本实现密码的自动调用。
通过ansible-vault命令行工具,您可以便捷地管理加密内容:无论是创建加密变量、生成加密文件,还是对现有文件进行加密、编辑、重新加密或解密等操作,都能轻松完成。加密后的文件可直接纳入版本控制系统进行妥善托管,团队成员也能更安全地协作共享。
在实际使用场景中,您只需在执行临时命令或运行Playbook时提供对应的加密密码,即可正常调用这些受保护的内容。此外,通过修改ansible.cfg配置文件预设密码文件路径,或是选择在执行时手动输入密码,都能灵活适配不同的安全策略需求。

实际应用场景

下面提出一个实际应用场景并使用ansible进行自动化运行。

场景一:假设现在开发人员在测试库提交了代码,代码编译后程序打包在客户机某目录下,现在需要将文件传输到受控主机指定项目文件夹中,在传输前将项目打包备份到备份目录,传输完成后解压缩并重启服务

---
- name: Deploy application update
  hosts: myhosts  # 指定目标主机组,按实际情况修改
  gather_facts: yes  # 设置为no,不收集主机信息,以提升运行速度,这里因为需要时间数据所以打开
  #become: yes  # 使用特权权限执行任务
  vars:
    # 控制节点上的软件包路径
    local_package_path: "your_dir/publish.zip"
    # 目标主机上的项目部署路径
    remote_project_dir: "/your_dir"
    # 目标主机上的备份根目录
    backup_root: "/your_dir"
    # 服务名称
    service_name: "your_service_name"

  tasks:
    # 获取时间戳用于创建唯一备份目录
    - name: Create timestamp
      ansible.builtin.set_fact:
        timestamp: "{{ ansible_date_time.date }}_{{ ansible_date_time.time }}"

    # 设置备份路径变量
    - name: Set backup path
      ansible.builtin.set_fact:
        backup_path: "{{ backup_root }}/{{ timestamp }}"

    # 创建备份目录
    - name: Create backup directory
      ansible.builtin.file:
        path: "{{ backup_path }}"
        state: directory
        mode: 0755

    # 检查项目目录是否存在
    - name: Check project directory existence
      ansible.builtin.stat:
        path: "{{ remote_project_dir }}"
      register: dir_stat

    # 此处可增加一步,先停止服务再备份
    # 备份现有项目(仅当项目目录存在时执行)
    - name: Backup existing project
      ansible.builtin.archive:
        path: "{{ remote_project_dir }}"
        dest: "{{ backup_path }}/backup.tar.gz"
        format: zip
      when: dir_stat.stat.exists

    # 传输新软件包到目标主机临时目录
    - name: Transfer new package
      ansible.builtin.copy:
        src: "{{ local_package_path }}"
        dest: "{{ remote_project_dir }}/publish.zip"
        mode: 0644

    # 解压新软件包到项目目录
    - name: Deploy new package
      ansible.builtin.unarchive:
        src: "{{ remote_project_dir }}/publish.zip"
        dest: "{{ remote_project_dir }}"
        remote_src: yes  # 表示源文件在目标主机上
        owner: "root"  # 按实际情况修改用户
        group: "root"  # 按实际情况修改用户组
        mode: 0755

    # 重启应用服务
    - name: Restart application service
      ansible.builtin.systemd:
        name: "{{ service_name }}"
        state: restarted
        enabled: yes
        daemon_reload: yes

    # 清理临时文件
    - name: Cleanup temporary package
      ansible.builtin.file:
        path: "{{ remote_project_dir }}/publish.zip"
        state: absent

执行命令ansible-playbook -i inventory.ini playbook.yaml运行

场景二:需要对受控服务集群统一更新某项目中的配置文件Appsetting.json

---
- name: Update Appsetting.json
  hosts: all  # 目标主机组,按实际情况修改
  become: yes  # 使用特权权限执行任务
  vars:
    # 本地 Appsetting.json 文件路径
    local_config_path: "/path/on/controller/Appsetting.json"
    # 目标主机上的项目配置文件路径
    remote_config_path: "/opt/your_project/Appsetting.json"
    # 备份目录
    backup_root: "/backup/your_project"
    # 服务名称
    service_name: "your_service"

  tasks:
    # 获取时间戳用于创建唯一备份目录
    - name: Create timestamp
      ansible.builtin.set_fact:
        timestamp: "{{ ansible_date_time.date }}_{{ ansible_date_time.time }}"

    # 设置备份路径变量
    - name: Set backup path
      ansible.builtin.set_fact:
        backup_path: "{{ backup_root }}/{{ timestamp }}"

    # 创建备份目录
    - name: Create backup directory
      ansible.builtin.file:
        path: "{{ backup_path }}"
        state: directory
        mode: 0755

    # 检查配置文件是否存在
    - name: Check if Appsetting.json exists
      ansible.builtin.stat:
        path: "{{ remote_config_path }}"
      register: config_stat

    # 备份现有配置文件(仅当文件存在时执行)
    - name: Backup existing Appsetting.json
      ansible.builtin.copy:
        src: "{{ remote_config_path }}"
        dest: "{{ backup_path }}/Appsetting.json"
        remote_src: yes  # 表示源文件在目标主机上
      when: config_stat.stat.exists

    # 传输新的 Appsetting.json 文件到目标主机
    - name: Transfer new Appsetting.json
      ansible.builtin.copy:
        src: "{{ local_config_path }}"
        dest: "{{ remote_config_path }}"
        owner: "www-data"  # 按实际情况修改用户
        group: "www-data"  # 按实际情况修改用户组
        mode: 0644

    # 重启服务(视情况增加这步,有些服务配置文件更改不需要重启)
    - name: Restart application service
      ansible.builtin.systemd:
        name: "{{ service_name }}"
        state: restarted
        enabled: yes
        daemon_reload: yes

参考

blog.csdn.net/pushiqiang/…

www.cnblogs.com/yinzhengjie…

docs.ansible.org.cn/ansible/lat…