Ansible collection

Ansible Collections 是一种用于组织和分发 Ansible 内容的新方法,它使得内容管理更加灵活和模块化。Collections 允许你将 Ansible 角色、模块、插件等组合在一起,并以一种统一的方式进行发布和管理。这种新的内容组织方式提供了更好的版本控制和依赖管理能力。

Collections 的特点包括:

  1. 模块化:Collections 可以包含各种类型的 Ansible 内容,如模块、插件、角色等,并且可以单独发布和管理。
  2. 版本控制:每个 Collection 都有自己的版本号,这使得用户可以精确控制他们所使用的版本。
  3. 依赖管理:Collections 可以声明依赖关系,这样用户在安装一个 Collection 时,可以自动安装其依赖项。
  4. 灵活的安装位置:Collections 可以安装在任意位置,而不仅仅是固定的 Ansible 搜索路径中。
  5. 易于分发:Collections 可以被打包成一个 .tar.gz 文件,便于分发和安装。

Collections 的结构

一个典型的 Collection 目录结构如下所示:

ansible_collections/
└── namespace/
    └── collection/
        ├── plugins/
        │   ├── modules/
        │   └── module_utils/
        ├── roles/
        ├── files/
        ├── docs/
        ├── tests/
        └── meta/
            └── runtime.yml
  • plugins/: 存放各种插件,如模块(modules)、过滤器(filters)、lookup 插件等。
  • roles/: 存放 Ansible 角色。
  • files/: 存放文件资源。
  • docs/: 存放文档和手册。
  • tests/: 存放测试用例。
  • meta/runtime.yml: 存放 Collection 的元数据,包括依赖关系。

安装 Collections

你可以使用 ansible-galaxy 命令来安装 Collections。例如,要安装 community.general 这个 Collection,可以使用下面的命令:

bash深色版本1ansible-galaxy collection install community.general

更新 Collections

要更新已安装的 Collections,可以使用 ansible-galaxy collection update 命令:

bash深色版本1ansible-galaxy collection update

卸载 Collections

要卸载一个 Collection,可以使用 ansible-galaxy collection remove 命令:

bash深色版本1ansible-galaxy collection remove namespace.collection

创建 Collections

如果想创建一个新的 Collection,可以使用 ansible-galaxy collection init 命令来初始化一个新的 Collection:

bash深色版本1ansible-galaxy collection init namespace.collection

这将在当前目录下创建一个符合 Collection 结构的新目录。

发布 Collections

一旦你创建了 Collection 并准备好发布它,你可以使用 ansible-galaxy collection build 命令来构建 Collection 包:

bash深色版本1ansible-galaxy collection build

然后你可以使用 ansible-galaxy collection publish 命令来上传你的 Collection 到 Ansible Galaxy:

ansible-galaxy collection publish <path_to_collection_tarball>

Ansible galaxy

Ansible Galaxy 是一个用于 Ansible 内容的开放平台,它允许用户分享、发现和重用 Ansible 自动化内容,比如角色、集合(collections)和其他自动化资源。Ansible Galaxy 提供了一个集中式的仓库,帮助 Ansible 用户和开发者找到适合其需求的内容,并且可以轻松地集成到自己的 Ansible playbooks 中。

Ansible Galaxy 的主要特点包括:

  1. 角色和集合的存储库:Ansible Galaxy 作为角色和集合的主要存储库,用户可以在此上传和分享自己的内容,也可以下载和使用其他用户提供的内容。
  2. 可搜索性:Galaxy 提供了一个易于使用的界面,用户可以根据关键词、标签或其他属性搜索所需的内容。
  3. 版本控制:Galaxy 支持版本控制,因此用户可以跟踪角色和集合的变化历史,并且可以选择安装特定版本的内容。
  4. 社区支持:Galaxy 社区活跃,用户可以提交问题、评论和改进意见,促进内容的质量提升。
  5. 认证和安全:Galaxy 提供了对内容的安全验证,确保下载的内容是可信的。
  6. Ansible Galaxy CLI:Ansible 提供了一个命令行工具 ansible-galaxy,用于安装、更新和管理从 Galaxy 下载的角色和集合。

使用 Ansible Galaxy 的步骤:

安装角色

要从 Ansible Galaxy 安装一个角色,你可以使用 ansible-galaxy install 命令:

bash深色版本1ansible-galaxy install username.role_name

这里 username 是 Galaxy 上的用户名,role_name 是角色的名字。例如:

bash深色版本1ansible-galaxy install geerlingguy.apache

这将安装 geerlingguy 用户创建的 apache 角色。

更新角色

如果你已经安装了某个角色并且想要更新到最新版本,可以使用 ansible-galaxy update 命令:

bash深色版本1ansible-galaxy update

列出已安装的角色

要查看你已经安装了哪些角色,可以使用:

bash深色版本1ansible-galaxy list

创建新角色

如果你想创建一个新的角色,可以使用 ansible-galaxy role init 命令来初始化一个角色的目录结构:

bash深色版本1ansible-galaxy role init myusername.myrole

上传角色

如果你想要上传一个角色到 Ansible Galaxy,首先需要在 Galaxy 网站上注册一个账号,然后使用 ansible-galaxy collection publish 命令来上传你的角色。

默认情况下,ansible-galaxy install安装Role的位置顺序是:

  • (1).~/.ansible/roles
  • (2)./usr/share/ansible/roles
  • (3)./etc/ansible/roles

可以使用-p--roles-path选项指定安装路径。

$ ansible-galaxy install -p roles/ chusiang.helloworld

安装完成后,就可以直接使用这个Role。例如,创建一个enter.yml文件,并在此文件中引入该Role,其内容如下:

--- 
- name: role from galaxy
  hosts: localhost
  gather_facts: false
  roles: 
    - role: chusiang.helloworld

Ansible role

定义

Ansible 角色 (Roles) 是一种用于组织和复用 Ansible Playbooks 的方式。它们提供了一种标准化的方法来打包和管理配置任务、文件、模板、变量等。

基本结构

一个典型的 Ansible 角色目录结构如下所示:

myrole/
├── tasks/
│   └── main.yml
├── files/
│   └── example.conf
├── templates/
│   └── example.conf.j2
├── vars/
│   └── main.yml
├── defaults/
│   └── main.yml
├── handlers/
│   └── main.yml
└── meta/
    └── galaxy.yml
  • tasks/: 包含任务定义的 YAML 文件,通常是 main.yml
  • files/: 存储要复制到远程主机的文件。
  • templates/: 存储 Jinja2 模板文件,这些模板可以用来生成配置文件。
  • vars/: 存储角色相关的变量定义。
  • defaults/: 存储角色的默认变量值。
  • handlers/: 定义 handler 任务,这些任务在被通知时才会执行。
  • meta/: 存储元数据文件,如依赖关系和 Galaxy 元数据。

可以使用ansible-galaxy init --help查看更多选项。比如,使用--init-path选项指定创建的Role路径:

$ ansible-galaxy init --init-path /etc/ansible/roles first_role

角色的使用场合

  • 当你需要在多个环境中重复使用相同的配置时。
  • 当你需要将复杂的配置分解成更小的、可管理的部分时。
  • 当你需要与其他团队成员共享配置时。

Ansible role 入口文件

ansible-playbook执行的入口playbook文件(就像main()函数一样),在这个入口文件中引入一个或多个roles目录下的Role。入口文件的名称可以随意,比如www.yml、site.yml、main.yml等,但注意它们和roles目录在同一个目录下。

例如:

├── enter.yml
└── roles
    ├── first_role/
    └── second_role/

上面和roles同目录的enter.yml文件内容如下,此文件中使用roles指令引入了roles目录内的两个Role。

---
- name: play with role
  hosts: nginx
  gather_facts: false
  roles: 
    - first_role
    - second_role

如果遵循了Role规范,入口文件中可以直接使用Role名称来引入roles目录下的Role(正如上面的示例),也可以指定Role的路径来引入。

定义Role的task

Role的任务定义在roles/xxx/tasks/main.yml文件中,main.yml是该Role任务的入口,在执行Role的时候会自动执行main.yml中的任务。可以直接将所有任务定义在此文件中,也可以定义在其它文件中,然后在main.yml文件中去引入。

定义Role的handler

handler和task类似,它定义在roles/xxx/handlers/main.yml中,当Role的task触发了对应的handler,会自动来此文件中寻找。

仍然要说的是,可以将handler定义在其它文件中,然后在roles/xxx/handlers/main.yml使用include_tasksimport_tasks指令来引入,而且前面也提到过这两者在handler上的区别和注意事项。

例如,roles/first_role/handlers/main.yml中定义了如下简单的handler:

例如,roles/first_role/handlers/main.yml中定义了如下简单的handler:

---
- name: handler for test
  debug: 
    msg: "a simple handler for test"

roles/first_role/tasks/main.yml中通过notify触发该Handler:

---
- name: task in main.yml
  debug:
    msg: "task in main.yml"
  changed_when: true
  notify: handler for test

定义Role的变量

Role中有两个地方可以定义变量:

  • (1).roles/xxx/vars/main.yml
  • (2).roles/xxx/defaults/main.yml

从目录名称中可以看出,defaults/main.yml中用于定义Role的默认变量,那么显然,vars/main.yml用于定义其它变量。

这两个文件之间的区别在于,defaults/main.yml中定义的变量优先级低于vars/main.yml中定义的变量。事实上,defaults/main.yml中的变量优先级几乎是最低的,基本上其它任何地方定义的变量都可以覆盖它。

Role中定义的模块和插件

对于绝大多数需求,使用Ansible已经提供的模块和插件就能解决问题,但有时候确实有些需求需要自己去写模块或插件,Ansible也支持用户自定义的模块和插件。

对于Role来说,如果这个Role需要额外使用自己编写的模块或插件,则模块放在roles/xxx/librarys/目录下,而插件放在各自对应类型的目录下:

定义Role的依赖关系

很多时候,一个系统化配置管理的需求中并不仅仅只有一个Role。一个典型的案例是部署LAMP,这里面涉及到了部署Apache、MySQL、PHP,但通常不会将它们全部定义到单个Role中,而是按照一些分类逻辑进行Role的划分,比如MySQL作为DB,单独定义成一个Role,apache和php作为一个webserver整体定义成一个Role。如何对功能进行划分由我们自己决定,正如上面的apache和php完全可以定义成两个Role。

有了多个Role,这些Role可能会存在依赖关系。例如,在新结点上部署集群服务的时候,通常都要对这些新结点进行一些初始化配置,比如设置时间同步,只有满足了这个条件,才会去启动集群服务。

换句话说,有些任务必须先行,这些先行任务就是被依赖的任务。

按照Role规范,被依赖的先行任务都定义在roles/xxx/meta/main.yml文件中。

例如:

---
dependencies: 
  - second_role
  - third_role

使用Role:roles、include_role和import_role

写好Role之后就是使用Role,即在一个入口playbook文件中去加载Role。

加载Role的方式有多种:

  • (1).roles指令:play级别的指令,在playbook解析阶段加载对应文件,这是传统的引入Role的方式
  • (2).import_role指令:task级别的指令,在playbook解析阶段加载对应文件
  • (3).include_role指令:task级别的指令,在遇到该指令的时候才加载Role对应文件

例如前面使用的是roles,如下:

---
- name: play1
  hosts: localhost
  gather_facts: false
  roles: 
    - first_role

上面通过roles指令来定义要解析和执行的Role,可以同时指定多个Role,且也可以加上role:参数,例如:

roles: 
  - first_role
  - role: seconde_role
  - role: third_role

也可以使用include_roleimport_role来引入Role,但需注意,这两个指令是tasks级别的,也正因为它们是task级别,使得它们可以和其它task共存。

---
- hosts: localhost
  gather_facts: false
  tasks:
  - debug:
      msg: "before first role"
  - import_role:
      name: first_role
  - include_role:
      name: second_role
  - debug:
      msg: "after second role"

这三种引入Role的方式都可以为对应的Role传递参数,例如:

---
- hosts: localhost
  gather_facts: false
  roles: 
    - role: first_role
      varvar: "valuevalue"
      vars: 
        var1: value1

  tasks:
  - import_role:
      name: second_role
    vars: 
      var1: value1
  - include_role:
      name: third_role
    vars: 
      var1: value1

查看任务和打标签tags

每个Role的任务有可能分布在多个文件中,还有可能会在入口文件中加载多个Role,这时想要知道执行playbook时具体会执行哪些任务,可以使用ansible-playbook命令的--list-tasks选项,它会列出某个playbook中的所有任务。

$ ansible-playbook --list-tasks enter.yml

playbook: enter.yml

  play #1 (localhost): play1      TAGS: []
    tasks:
      first_role : task1          TAGS: []
      first_role : task in t.yml  TAGS: []

上面的结果表示,enter.yml这个playbook文件中只有一个play,这个play中包含了两个任务。

从结果中还看到play和task的后面都带有TAGS: [],它是标签。当在play或task级别使用tags指令后就表示为此play或task打了标签。

1.可以在task级别为单个任务打一个或多个标签,多个任务可以打同一个标签名

例如:

- name: yum install ntp
  yum: 
    name: ntp
    state: present
  tags: 
    - initialize
    - pkginstall
    - ntp

- name: started ntpd
  service:
    name: ntpd
    state: started
  tags: 
    - ntp
    - initialize

当任务具有了标签之后,就可以在ansible-playbook命令行中使用--tags来指定只有带有某标记的任务才执行,也可以使用--skip-tags选项明确指定不要执行某个任务。

# 只执行第一个任务
$ ansible-playbook test.yml --tags "pkginstall"

# 两个任务都执行
$ ansible-playbook test.yml --tags "ntp,initialize"

# 第一个任务不执行
$ ansible-playbook test.yml --skip-tags "pkginstall"

如果想要确定tag筛选之后会执行哪些任务,加上--list-tasks即可:

2.可以在play级别打标签,这等价于对play中的所有任务都打上标签

例如:

- name: play1
  hosts: localhost
  gather_facts: false
  tags: 
    - tag1
    - tag2
  pre_tasks:
    - debug: "msg='pre_task1'"
    - debug: "msg='pre_task2'"
  tasks: 
    - debug: "msg='task1'"
    - debug: "msg='task2'"

Ansible 组织变量

在Ansible中有很多种定义变量的方式,想要搞清楚所有这些散布各个角落的知识,是一个很大的难点。好在,我们没必要去过多关注,只需要掌握几个常用的变量定义和应用的方式即可。此处我要介绍的是将变量定义在外部文件中,然后去引入这些外部文件中的变量。

引入保存了变量的文件有两种方式:include_varsvars_files。此外,还可以在命令行中使用-e--extra-vars选项来引入。

var_files 文件引入变量

例如,pb.yml文件如下:

---
- name: play1
  hosts: localhost
  gather_facts: false
  vars_files: 
    - varfile1.yml
    - varfile2.yml
  tasks: 
    - debug:
        msg: "var in varfile1: {{var1}}"
    - debug:
        msg: "var in varfile2: {{var2}}"

pb.yml文件通过vars_files引入了两个变量文件,变量文件的写法要求遵守YAML或JSON格式。下面是这两个文件的内容:

# 下面是varfile1.yml文件的内容
---
var1: "value1"
var11: "value11"

# 下面是varfile2.yml文件的内容
---
var2: "value2"
var22: "value22"

需要说明的是,vars_files指令是play级别的指令,且是在解析playbook的时候加载并解析的,所以所引入变量的变量是play范围内可用的,其它play不可使用这些变量。

include_vars 引入变量

include_vars指令也可用于引入外部变量文件,它和vars_files不同。一方面,include_vars是模块提供的功能,它是一个实实在在的任务,所以在这个任务执行之后才会创建变量。另一方面,既然include_vars是一个任务,它就可以被一些task级别的指令控制,如when指令。

例如:

---
- name: play1
  hosts: localhost
  gather_facts: false
  tasks: 
    - name: include vars from files
      include_vars: varfile1.yml
      when: 3 > 2
    - debug:
        msg: "var in varfile1: {{var1}}"

ansible-playbook命令的-e选项或--extra-vars选项也可以用来定义变量或引入变量文件。

# 定义单个变量
$ ansible-playbook -e 'var1="value1"' xxx.yml

# 定义多个变量
$ ansible-playbook -e 'var1="value1" var2="value2"' xxx.yml

# 引入单个变量文件
$ ansible-playbook -e '@varfile1.yml' xxx.yml

# 引入多个变量文件
$ ansible-playbook -e '@varfile1.yml' -e '@varfile2.yml' xxx.yml

因为是通过选项的方式来定义变量的,所以它所定义的变量是全局的,对所有play都有效。

通常来说不建议使用-e选项,因为这对用户来说是不透明也不友好的,要求用户记住要定义哪些变量。

Ansible handler

Ansible 的 handler 是一种特殊的任务类型,它只在被其他任务通过 notify 关键字显式触发时才会执行。这种机制允许你将某些操作(如服务重启或配置文件重新加载)与配置更改解耦,确保这些操作仅在必要时执行。

Handler 的用途

Handlers 主要用于以下情况:

  • 避免不必要的重启或重新加载。
  • 执行配置更改后的清理操作。
  • 执行一些只有在特定条件下才需要的操作。

如何定义 Handler

Handlers 通常定义在一个单独的 YAML 文件中,通常位于 Ansible 角色的 handlers/ 目录下,文件名为 main.yml

示例

这里有一个简单的示例来说明如何定义和使用 handlers:

定义 Handler

在角色的 handlers/main.yml 文件中定义 handler 任务:

---
- name: Restart nginx
  service:
    name: nginx
    state: restarted

触发 Handler

在角色的 tasks/main.yml 文件中定义任务,并使用 notify 关键字来标记 handler:

– name: Copy Nginx configuration
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: ‘0644’
notify: Restart nginx

在这个例子中,当配置文件 /etc/nginx/nginx.conf 被更新后,Ansible 会标记 Restart nginx handler 任务。在所有标记了 notify 的任务完成后,Ansible 将会执行 Restart nginx 任务。

更多示例

如果你想看到一个更完整的示例,我们可以创建一个包含 handler 的简单 Ansible 角色。这里是一个基于前面提到的 Nginx 角色的例子:

1、创建角色目录

ansible-galaxy role init nginx

2、编辑任务配置文件(tasks/main.yml):

---
- name: Install Nginx
  package:
    name: nginx
    state: present

- name: Copy Nginx configuration
  copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
  notify: Restart nginx

3、定义 handler (handlers/main.yml):

---
- name: Restart nginx
  service:
    name: nginx
    state: restarted

4、定义元数据 (meta/galaxy.yml):

---
galaxy_info:
  author: Your Name
  description: A role to install and configure Nginx
  license: MIT
  min_ansible_version: "2.9"
  platforms:
    - name: Ubuntu
      versions:
        - all
  dependencies: []

5、在 Playbook 中使用角色

---
- name: Configure Nginx server
  hosts: webservers
  become: true
  roles:
    - nginx

这个示例展示了如何在角色中使用 handler 来重启 Nginx 服务,只有当配置文件发生变化时才会触发重启。

Index