[Ansible] 制作并在Galaxy上发布自定义的集合
本文是「Ansible Advent Calendar 2020」第16天的介绍。
这篇文章将讲述我在之前的另一个圣诞日历上发布的「使用vim-cmd在ESXi上操作虚拟机的Ansible集合(可免费使用许可证)」是如何创建和发布的。
序文 (Qianzhuì)
在本文中,我们不会解释”如何制作模块”本身,基本上内容主要关注的是”如何将已创建的自制模块收集起来”的视角。
另外,适用范围仅限于模块插件。(不包括回调函数和查找功能等)
创建一个 Ansible Galaxy 帐户 (准备)
只要不公开创建的收藏品,就不需要Galaxy账户。
Ansible Galaxy
安瑟布尔银河
需要一个GitHub账号。
从画面右上方的「Login」开始。
点击后会要求与GitHub进行连接,因此要点击图标进行连接。
如果不打算公开的话就没有必要创建账户,但如果有可能会公开的话,创建账户可以立即了解如何决定命名空间,所以最好还是创建。
简单来说,个人创建时,GitHub账户名和集合名会组成一个整体。
(集合名可以根据功能等自由选择)
命名空间的选择方法
Ansible 2.10起,引入了命名空间的概念作为标准功能,其中模块等都经过了分类。
所以,在设计自定义集合的命名空间时,可以自由决定,但如果要在Ansible Galaxy上发布,则必须与Galaxy的命名空间相同。
因此,您需要使用GitHub帐户创建一个Galaxy帐户(个人情况很少),基本上使用GitHub帐户名.集合名称来创建会更方便。
如果GitHub(或其他地方)上的组织和代码库名称与Ansible Galaxy上的命名空间和收藏名称相匹配,那将非常方便,但不是必需的。然而,您在代码库和Galaxy收藏品中选择的插件名称始终是相同的。
https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_in_groups.html#naming-conventions
顺便提一下,我在GitHub的账户名是zaki-lknr,其中包含了一个连字符。但是,在集合的命名空间中,只能使用m/[a-zA-Z0-9_]中的字符,所以我会将连字符转换为下划线。
而且如果我使用这个GitHub账户名在Ansible Galaxy上创建账户,那么在Ansible Galaxy上,我的用户名将变为zaki_lknr。
如果您想创建一个专用的命名空间(例如共同开发的产品名称),而不是使用GitHub帐户名,则似乎需要在Galaxy的问题(Issue)中提出请求。
创建收藏夹
创建工作目录
首先,在拥有Playbook的位置上创建一个名为collections/ansible_collections的目录。
虽然创建的集合的路径是任意的,但将此目录结构用于使手头的Playbook能够轻松使用所创建的集合。(以便在执行时能够识别位于”集合路径”下的ansible_collections/<命名空间>/<集合>路径)
(2.10) [zaki@cloud-dev esxi-ansible]$ mkdir -p collections/ansible_collections
※由于“collections”目录不是默认的,所以可以随意命名。
创建收藏品模板
可以通过ansible-galaxy collection init命令自动生成。
使用格式为指定参数.。
使用选项–init-path collections,并在前面的collections/ansible_collections目录下创建。
(2.10) [zaki@cloud-dev esxi-ansible]$ ansible-galaxy collection init zaki_lknr.esxissh --init-path collections/ansible_collections
- Collection zaki_lknr.esxissh was created successfully
如果没有指定`collections`,则在运行时的当前目录下创建。
生成的文件组大致如下。
(2.10) [zaki@cloud-dev esxi-ansible]$ find collections/
collections/
collections/ansible_collections
collections/ansible_collections/zaki_lknr
collections/ansible_collections/zaki_lknr/esxissh
collections/ansible_collections/zaki_lknr/esxissh/README.md
collections/ansible_collections/zaki_lknr/esxissh/galaxy.yml
collections/ansible_collections/zaki_lknr/esxissh/docs
collections/ansible_collections/zaki_lknr/esxissh/plugins
collections/ansible_collections/zaki_lknr/esxissh/plugins/README.md
collections/ansible_collections/zaki_lknr/esxissh/roles
现在我们已经创建了一个名为zaki_lknr.esxissh.hogehoge和zaki_lknr.esxissh.foobar的模块的模板。
创建 Ansible 模块
这次我们将在集合下创建模块。
集合不仅仅是模块,还包括回调插件、查找插件等各种插件的集合。
如果从当前的Ansible文档网站的“Collection Index”中选择一项,你会发现它变成了“Plugin Index”,这样你就容易地理解到层次结构的概念。
举个例子,如果查看标准的“ansible.builtin collection”,它被分类如下:
-
- Become Plugins
-
- Cache Plugins
-
- Callback Plugins
-
- Connection Plugins
-
- Inventory Plugins
-
- Lookup Plugins
-
- Modules
今回これを作ります☆彡
Shell Plugins
Strategy Plugins
Vars Plugins
请查阅详细信息,可参考已创建的plugins/README.md文件和《与插件一起使用 — Ansible文档》。
所以,让我们回到话题,我们将创建一个名为zaki_lknr.esxissh的集合,在ESXi上创建esxissh_guest_power Ansible模块,用于打开/关闭虚拟机的电源。
Ansible模块的源代码位于templates文件夹下的plugins文件夹中的子文件夹modules中,并通过在该文件夹下创建模块插件来实现功能。
在这个例子中,创建了collections/zaki_lknr/esxissh/plugins/modules文件夹并在其中创建了esxissh_guest_power.py作为模块插件。
/home/zaki/src/esxi-ansible/collections/
└── ansible_collections
└── zaki_lknr
└── esxissh
├── README.md
├── docs
├── galaxy.yml
├── plugins
│ ├── README.md
│ ├── module_utils
│ │ └── esxissh.py
│ └── modules
│ ├── esxissh_guest.py
│ └── esxissh_guest_power.py <- これ
└── roles
在这里,我们将把预先创建的模块library/esxissh_guest_power.py放置在非收集环境中。
(2.10) [zaki@cloud-dev esxi-ansible]$ mkdir collections/ansible_collections/zaki_lknr/esxissh/plugins/modules
(2.10) [zaki@cloud-dev esxi-ansible]$ cp sample-playbook/library/esxissh_guest_power.py collections/ansible_collections/zaki_lknr/esxissh/plugins/modules/
放置在这里的源文件将成为模块的文件名。
被模块导入的Python包
如果要在从Ansible模块中引入的外部文件中实现处理(例如创建多个Ansible模块并将公共处理实现在外部源代码文件中等),可以像传统的Ansible模块一样,在modules的同一层级下创建一个名为module_utils的目录,并将源文件放置在那里以进行导入。
/home/zaki/src/esxi-ansible/collections/
└── ansible_collections
└── zaki_lknr
└── esxissh
├── README.md
├── docs
├── galaxy.yml
├── plugins
│ ├── README.md
│ ├── module_utils
│ │ └── esxissh.py <- これ
│ └── modules
│ ├── esxissh_guest.py
│ └── esxissh_guest_power.py
└── roles
(2.10) [zaki@cloud-dev esxi-ansible]$ mkdir collections/ansible_collections/zaki_lknr/esxissh/plugins/module_utils
(2.10) [zaki@cloud-dev esxi-ansible]$ cp sample-playbook/module_utils/esxissh.py collections/ansible_collections/zaki_lknr/esxissh/plugins/module_utils/
然后,导入的路径和格式应为from ansible_collections…plugins.module_utils import 。
(将从ansible.module_utils导入的部分改为→ 修改示例)
from ansible_collections.zaki_lknr.esxissh.plugins.module_utils import esxissh
这样一来,代码部分无需更改。
通过模块源代码中的注释生成文档文件。
有一个名为docs的目录作为模板正在创建,我们在这里为每个插件的文档“除了在模块源代码中指定的注释之外”提供了另外的准备。虽然应该自动化生成,但我暂时不知道该怎么做,不过在Ansible Advent Calendar第12天,sky_joker先生已经创建了一篇很棒的文章。
自动生成Ansible Collections模块文档 | 日常技术工程师的技术博客
您可以使用一个名为collection_prep的工具以rst格式生成文档。
顺便说一下,在我手上的环境中。
docker run -itd --name py38 -v $PWD:/usr/src/work --rm python:3.8
作为解决方法,我们配置了一个容器内的卷,可以访问本地的完整源代码,并进行了相关文档记录。但需要注意的是,由于以root权限运行的影响,生成的文件所有者将变为root,因此在这方面要小心。(在使用git切换分支时导致无法更改文件w)
这里是生成的文件。
请参考以下内容来进行对模块源代码的注释。
模块格式和文档 — Ansible文档
在执行Ansible时,本地引用集合。
现在在collections目录下放置了一个名为zaki_lknr.esxissh的集合,并创建了名为esxissh_guest_power的模块。
接下来将进行使用该模块的Playbook修正和配置。
以FQCN方式指定模块。
首先,将使用现有模块的playbook中的模块指定部分更改为FQCN。
通过完成这个修改,playbook的编辑就完成了。
index 43b96ba..d76cb17 100644
--- a/sample-playbook/create_vm.yml
+++ b/sample-playbook/create_vm.yml
@@ -3,7 +3,7 @@
tasks:
- name: create vm
- esxissh_guest:
+ zaki_lknr.esxissh.esxissh_guest:
esxiaddress: '{{ esxiaddr }}'
esxiusername: '{{ esxiuser }}'
esxipassword: '{{ esxipass }}'
指定集合的路径
在这里,我们已经创建了一个选择集和其下的模块的指定剧本。
至于关键的“在运行时使用此路径中的集合”部分,则很容易在ansible.cfg中进行指定。
顺便提一下,集合默认情况下会查看Ansible执行时用户的$HOME/.ansible/collections之下的设置。
这一点在使用venv时需要格外注意,因为它会引用venv环境之外的内容,所以在默认情况下,可能会发生“虽然打算在venv环境中切割环境,却在多个venv环境中查看到相同部分”的情况,如果在没有特别指定路径设置的情况下使用ansible-galaxy collection install进行安装,可能会混合环境。
说到该怎么办,我建议在ansible.cfg中
collections_path = /home/zaki/src/esxi-ansible/collections/
如果按照这样的描述进行,将会引用指定路径的集合而不是$HOME/.ansible。
在这里指定的路径下面,将会有ansible_collections///,其下面有plugins/modules/.py的配置。
/home/zaki/src/esxi-ansible/collections/
└── ansible_collections
└── zaki_lknr
└── esxissh
├── README.md
├── docs
├── galaxy.yml
├── plugins
│ ├── README.md
│ ├── module_utils
│ │ └── esxissh.py
│ └── modules
│ ├── esxissh_guest.py
│ └── esxissh_guest_power.py
└── roles
运行使用自己创建的模块的Ansible Playbook。
-
- playbookからFQCNでモジュール指定
- コレクションのパスをansible.cfgのcollections_pathで指定
在这两个方面,你可以从playbook中引用任何路径中的集合模块,因此可以使用自定义的集合模块来执行ansible-playbook。
对现在为止的总结
总结到这里如下所示。
ansible-galaxy collection init . –init-path /path/toでひな形作成
ansible.cfgでcollections_pathを指定
collections_pathのパス以下にコレクションを配置
PlaybookではFQCNでモジュール名を指定
如果在个人环境中,同时进行Playbook的创建和收集,并且不进行收集的分发等操作,我认为这样是可行的。
发放
将收藏品进行包装
要创建分发用的包,可以使用ansible-galaxy collection build命令。需要指定集合的路径(到<命名空间>.<集合>目录为止,该路径下应该有galaxy.yml文件)作为参数。(如果省略,则假定在当前目录中存在galaxy.yml文件)
最多只需要一个选项:收藏的星系元数据结构 — Ansible文档
另外,还需要创建一个被称为galaxy.yml的包装文件,即所谓的清单文件(根据模板创建并填写相应部分)。
我认为,查看内容是最快的方法,但在Galaxy的页面上,需要记录库和问题的链接,以及收集名称、版本等定义。您还可以在包装时指定要排除的文件,因此最好排除特定环境文件、中间文件和venv目录等。
以下是galaxy.yml文件的主要描述部分。
x.y.z
形式)readmeGalaxy用readmeファイルのパスauthorコレクション作成者(リスト形式)repositoryソースのリポジトリURLissuesIssueのURLbuild_ignorecollectoin build
時に除くファイルパターン当准备好后,请执行ansible-galaxy collection build <路径>。
(2.10) [zaki@cloud-dev esxi-ansible (features/collections)]$ ansible-galaxy collection build collections/ansible_collections/zaki_lknr/esxissh/
Created collection for zaki_lknr.esxissh at /home/zaki/src/esxi-ansible/zaki_lknr-esxissh-1.0.0.tar.gz
当成功时,将在执行目录中创建一个名为–.tar.gz的集合。(–output-path /path/to可更改输出路径)
顺便提一下,其内容大致如下。
(2.10) [zaki@cloud-dev esxi-ansible (features/collections)]$ tar tf zaki_lknr-esxissh-1.0.0.tar.gz
MANIFEST.json
FILES.json
docs/
roles/
README.md
plugins/
plugins/README.md
plugins/module_utils/
plugins/module_utils/esxissh.py
plugins/modules/
plugins/modules/esxissh_guest.py
plugins/modules/esxissh_guest_power.py
从文件中安装打包集合。
您可以通过指定本地文件进行安装,而无需使用Ansible Galaxy来安装集合。
(venv) [zaki@cloud-dev esxissh]$ ansible-galaxy collection -h
usage: ansible-galaxy collection [-h] COLLECTION_ACTION ...
positional arguments:
COLLECTION_ACTION
...
install Install collection(s) from file(s), URL(s) or Ansible
Galaxy
为了试用,新建一个不同的路径来创建环境并放置文件。
(venv) [zaki@cloud-dev esxissh]$ ls -F
venv/ zaki_lknr-esxissh-1.0.0.tar.gz
(venv) [zaki@cloud-dev esxissh]$ which ansible-galaxy
~/src/tmp/esxissh/venv/bin/ansible-galaxy
如果不指定安装目录,那么如前所述,默认安装在$HOME/.ansible/下面,因此在这里我们使用-p选项指定当前的collections。
(venv) [zaki@cloud-dev esxissh]$ ansible-galaxy collection install zaki_lknr-esxissh-1.0.0.tar.gz -p collections
Starting galaxy collection install process
[WARNING]: The specified collections path '/home/zaki/src/tmp/esxissh/collections' is not part of the configured Ansible
collections paths '/home/zaki/.ansible/collections:/usr/share/ansible/collections'. The installed collection won't be picked up
in an Ansible run.
Process install dependency map
Starting collection install process
Installing 'zaki_lknr.esxissh:1.0.0' to '/home/zaki/src/tmp/esxissh/collections/ansible_collections/zaki_lknr/esxissh'
zaki_lknr.esxissh (1.0.0) was installed successfully
(venv) [zaki@cloud-dev esxissh]$ ls -F
collections/ venv/ zaki_lknr-esxissh-1.0.0.tar.gz
已按照要求进行了安装。
(venv) [zaki@cloud-dev esxissh]$ tree collections/
collections/
└── ansible_collections
└── zaki_lknr
└── esxissh
├── FILES.json
├── MANIFEST.json
├── README.md
├── docs
├── plugins
│ ├── README.md
│ ├── module_utils
│ │ └── esxissh.py
│ └── modules
│ ├── esxissh_guest.py
│ └── esxissh_guest_power.py
└── roles
8 directories, 7 files
从任意的HTTP服务器进行安装
如果将集合文件放置在本地网络内的Web服务器上的类似于http://192.168.0.19/ansible/zaki_lknr-esxissh-1.0.0.tar.gz的位置,就可以通过URL指定进行安装。
(venv) [zaki@cloud-dev esxissh]$ ansible-galaxy collection install http://192.168.0.19/ansible/zaki_lknr-esxissh-1.0.0.tar.gz -p collections
Starting galaxy collection install process
[WARNING]: The specified collections path '/home/zaki/src/tmp/esxissh/collections' is not part of the configured Ansible
collections paths '/home/zaki/.ansible/collections:/usr/share/ansible/collections'. The installed collection won't be picked up
in an Ansible run.
Process install dependency map
Downloading http://192.168.0.19/ansible/zaki_lknr-esxissh-1.0.0.tar.gz to /home/zaki/.ansible/tmp/ansible-local-3625522b6vz_fk/tmpng661w25
Starting collection install process
Installing 'zaki_lknr.esxissh:1.0.0' to '/home/zaki/src/tmp/esxissh/collections/ansible_collections/zaki_lknr/esxissh'
zaki_lknr.esxissh (1.0.0) was installed successfully
(venv) [zaki@cloud-dev esxissh]$ ls
collections venv
(venv) [zaki@cloud-dev esxissh]$ tree collections/
collections/
└── ansible_collections
└── zaki_lknr
└── esxissh
├── FILES.json
├── MANIFEST.json
├── README.md
├── docs
├── plugins
│ ├── README.md
│ ├── module_utils
│ │ └── esxissh.py
│ └── modules
│ ├── esxissh_guest.py
│ └── esxissh_guest_power.py
└── roles
8 directories, 7 files
(venv) [zaki@cloud-dev esxissh]$
我认为在私人网络上使用业务中创建的集合,如多个主机等,非常方便。
在Ansible Galaxy上发布
通过将其上传到Ansible Galaxy中的个人命名空间,您也可以将其公开给全世界。
点击「添加内容」
「从GitHub导入角色」
遗留角色导入。不支持集合格式。
看起来不能设置存储库的收藏夹配置。
所以请按下“上传新收藏夹”按钮,并上传已创建的收藏夹的包文件…
无论做什么,都会显示“文件格式无效”,就无法正常进行了。。。
所以我会尝试通过CLI上传。
在使用ansible-galaxy命令进行上传操作时,需要指定上传用的令牌。
这个令牌可以从登录页面右上角的“Preferences”中获取。
当打开Preferences页面时,通过点击屏幕上的”Show API Key”按钮,可以显示API密钥。
只需提供这个API密钥作为–token=选项,并将打包为tar.gz文件的ansible-galaxy collection publish作为参数执行。
(2.10) [zaki@cloud-dev tmp (fix/collection-structure-dirs)]$ ansible-galaxy collection publish --token=${GALAXY_API_TOKEN} zaki_lknr-esxissh-1.0.0.tar.gz
Publishing collection artifact '/home/zaki/src/esxi-ansible/tmp/zaki_lknr-esxissh-1.0.0.tar.gz' to default https://galaxy.ansible.com/api/
Collection has been published to the Galaxy server default https://galaxy.ansible.com/api/
Waiting until Galaxy import task https://galaxy.ansible.com/api/v2/collection-imports/6382/ has completed
Collection has been successfully published and imported to the Galaxy server default https://galaxy.ansible.com/api/
(2.10) [zaki@cloud-dev tmp (fix/collection-structure-dirs)]$ echo $?
0
上传成功。
这里是实际收藏页面。
请参考“使用ESXi上的vim-cmd命令进行VM操作的Ansible集合(可供免费许可证使用)”来了解如何使用这个集合。
上传后你会发现,屏幕右上角的”Repo”或”Issue Tracker”按钮链接到的目标,以及”Read Me”中显示的内容和”Content”中列出的项目,都显示了galaxy.yml文件和包含在集合中的插件类别。
搞砸了 zā le)
用户无法删除在Galaxy上上传的收藏品。(可能的话)
至少目前没有任何删除按钮或类似选项,但搜索问题可以找到一些删除请求。
因此,在构建时,需要充分确认是否包含了不应该包含的文件。。。(翻译: 虽然已经设置了.gitignore,但与galaxy的构建无关,所以疏忽大意了,就是这个意思←)
另外,可以通过galaxy.yml的build_ignore:指定要从构建中排除的文件。
我们可以指定venv、*.tmp、*.bak等文件。
(※ 由于可上传的软件包大小最大为2MB,因此如果包含venv,上传几乎肯定会失败)
有时候,有关删除Issue的请求可能会在一天内得到处理,但也有可能会被管理员忽略一周左右呢。所以,请大家小心不要上传涉及机密信息的内容。这是个承诺哦!
后面可能会删除整个集合,而不仅仅是指定版本,所以务必要非常小心。(未经确认的信息)
参考所用之事物
虽然想说这是公式文档,但从头开始顺序阅读并不容易,所以我参考了实际发布的集合文档。就像GitHub上的这个源代码对应了Galaxy上的那个部分一样。
当我查看官方文档后,很容易理解了。
-
- コレクションやドキュメントの実装例
F5
Ansible Galaxy
F5Networks/f5-beacon
netbox
Ansible Galaxy
netbox-community/ansible_modules: Netbox modules for Ansible using Ansible Collections
VMware
Ansible Galaxy
ansible-collections/community.vmware: Ansible Collection for VMWare
Ansibleドキュメント
Developer Guide — Ansible Documentation
Ansible module development: getting started — Ansible Documentation
モジュール作成例
Module format and documentation — Ansible Documentation
モジュール作成時の書式やコメントの書き方
Collection Galaxy metadata structure — Ansible Documentation
galaxy.ymlの書き方
Creating a new collection — Ansible Documentation
命名規則など。。。ここはもしかするとコントリビュートするための情報かも
Developing collections — Ansible Documentation
コレクションのディレクトリ構造やファイル、ansible-galaxyの使い方など、コレクション開発全般
Galaxy Documentation — Ansible Documentation
Ansible Galaxyのドキュメント
Sample Ansible setup — Ansible Documentation
現verのAnsibleディレクトリ構造など
这次的成果
-
- Ansible Galaxy / esxissh – VM operation on ESXi with enabled SSH
- zaki-lknr/esxissh-ansible: sshを有効にしたESXiでVM操作するAnsibleモジュール