我们想听听你的意见!帮助我们深入了解 Ansible 生态系统的现状。
参加 Ansible 项目调查 2024

Ansible 内容集合入门

Ansible 内容集合入门

随着 Red Hat Ansible 自动化平台的发布,Ansible 内容集合现在已得到完全支持。Ansible 内容集合(或简称为集合)代表了自动化分发、维护和使用的新标准。通过将多种类型的 Ansible 内容(剧本、角色、模块和插件)结合在一起,极大地提高了灵活性及可扩展性。

谁将受益?

所有人!

传统上,模块创建者必须等待他们的模块被标记为包含在即将发布的 Ansible 版本中,或者将它们添加到角色中,这使得使用和管理更加困难。通过将模块与相关的角色和文档一起打包在 Ansible 内容集合中,并消除进入门槛,创建者现在可以根据其创作的需求快速行动。对于公有云提供商而言,这意味着可以与自动化新功能的能力一起推出现有服务的最新功能或全新服务。

对于自动化使用者而言,这意味着不断提供新鲜内容供使用。使用这种方式管理内容也变得更加容易,因为模块、插件、角色和文档将被打包并标记有集合版本。模块可以更新、重命名、改进;角色可以更新以反映模块交互的变化;文档可以重新生成以反映编辑内容,所有这些都将打包并标记在一起。

最重要的是,在引入集合之前,模块出现故障或缺乏及时更新以与它们所交互的服务进行交互的情况并不罕见。这通常要求 Ansible 用户或 Ansible Tower 管理员在 虚拟环境 中运行多个版本的 Ansible,以便使用解决模块问题的补丁。Ansible 内容集合通过将模块从核心发行版中分离出来,带来了稳定性和可预测性。

对于自动化组织而言,这意味着经过认证的内容可以从第一天开始就用于自动化用例。

在哪里可以找到集合?

随着 Red Hat Ansible 自动化平台的发布,Automation Hub 将成为经过认证的集合的来源。此外,集合创建者还可以将内容打包并分发到 Ansible Galaxy 上。最终,创建者决定其内容的交付机制,Automation Hub 是 Red Hat 认证集合的唯一来源。

深入了解集合

Ansible 内容集合可以描述为 Ansible 内容的打包格式。

example collection filesystem

此格式具有简单、可预测的数据结构,并具有明确的定义。

  • docs/:集合的本地文档
  • galaxy.yml:将作为集合包一部分的 MANIFEST.json 的源数据
  • playbooks/:剧本位于此处
    • tasks/:此处包含用于 include_tasks/import_tasks 用法的“任务列表文件”
  • plugins/:所有 Ansible 插件和模块都位于此处,每个模块位于其自己的子目录中
  • roles/:Ansible 角色的目录
  • tests/:集合内容的测试

有关集合元数据的更多信息

与集合交互

除了通过浏览器下载集合之外,ansible-galaxy 命令行实用程序已更新以管理集合,并提供与始终用于管理、创建和使用角色相同的许多功能。例如,ansible-galaxy collection init 可用于创建用户创建的新的集合的起点。

galaxy collection init example

除了创建集合的正确目录结构外,此命令还会生成一个元数据文件,该文件将在使用命名空间和集合名称预先填充的集合构建期间使用。

example galaxy metadata

下一步去哪里?

Ansible 内容集合最初作为技术预览版在 Ansible Engine 2.8 中推出,现在在 Ansible Engine 2.9 中得到完全支持,并且是 Red Hat Ansible 自动化平台的组成部分。集合使 Red Hat Ansible 自动化平台能够提供经过认证的稳定内容,以便继续扩展自动化的用例。以后的文章将更深入地探讨开发新的集合和将现有角色转换为集合。




Ansible 和 ServiceNow 第 3 部分,向 Red Hat Ansible Tower 发出传出 RESTful API 调用

Ansible 和 ServiceNow 第 3 部分,向 Red Hat Ansible Tower 发出传出 RESTful API 调用

Red Hat Ansible Tower 通过允许以受控的方式扩展自动化来提供价值 - 用户只能为他们需要访问的流程和目标运行剧本,而不会超过这个范围。

Ansible Tower 不仅提供大规模的自动化,而且还与多个外部平台集成。在许多情况下,这意味着用户可以使用他们习惯的界面,同时在后台启动 Ansible Tower 模板。

ServiceNow 是当今使用最广泛的自助服务平台之一,与 Ansible Tower 客户进行的许多企业级对话都集中在 ServiceNow 集成上。考虑到这一点,这篇博文将逐步介绍如何设置 ServiceNow 实例以使用 OAuth2 身份验证向 Ansible Tower 发出传出 RESTful API 调用。

使用以下软件版本

  • Ansible Tower:3.4、3.5
  • ServiceNow:伦敦、马德里

如果你注册了一个 ServiceNow 开发者帐户,ServiceNow 提供了一个免费的实例,可用于复制和测试此功能。你的 ServiceNow 实例需要能够访问你的 Ansible Tower 实例。此外,你可以访问 https://www.ansible.org.cn/license 获取 Ansible Tower 的试用许可证。有关安装 Ansible Tower 的说明,请参见 此处

准备 Ansible Tower

  1. 在 Ansible Tower 中,导航到屏幕左侧的“应用程序”。单击右侧的“绿色加号按钮”,这将显示一个创建应用程序对话框屏幕。填写以下字段

  2. 名称:将与 Ansible Tower 联系的应用程序的描述性名称

  3. 组织:你希望此应用程序所属的组织
  4. 授权授予类型:授权码
  5. 重定向 URI:https://<snow_instance_id>.service-now.com/oauth_redirect.do
  6. 客户端类型:机密

    image3-4

  7. 单击右侧的绿色“保存”按钮,此时将弹出一个窗口,其中显示 ServiceNow 用于向 Ansible Tower 发出 API 调用的客户端 ID 和客户端密钥。这将只显示 **一次**,因此请捕获这些值以备后用。

    image18

  8. 接下来,导航到屏幕左侧的“设置 - > 系统”。你需要将“允许外部用户创建 Oauth2 令牌”选项切换到“开启”。单击绿色“保存”按钮以提交更改。

    image4-4

准备 ServiceNow

  1. 在 ServiceNow 中,导航到“系统定义 -> 证书”。这将带你到 Service Now 使用的所有证书的屏幕。单击“蓝色新建按钮”,并填写以下详细信息

  2. 名称:证书的描述性名称

  3. 格式:PEM
  4. 类型:信任库证书
  5. PEM 证书:用于向 Ansible Tower 进行身份验证的证书。你可以使用 Tower 服务器上的内置证书,该证书位于 /etc/tower/tower.cert 中。将此文件的内容复制到 ServiceNow 中的字段中。

    单击底部的“提交”按钮。

    image9-1

  6. 在 ServiceNow 中,导航到“系统 OAuth -> 应用程序注册表”。这将带你到 ServiceNow 与之通信的所有应用程序的屏幕。单击“蓝色新建按钮”,系统将询问你想要设置哪种 OAuth 应用程序。选择“连接到第三方 OAuth 提供商”。

    image20

  7. 在新应用程序屏幕上,填写以下详细信息

  8. 名称:描述性应用程序名称

  9. 客户端 ID:你从 Ansible Tower 获得的客户端 ID
  10. 客户端密钥:你从 Ansible Tower 获得的客户端密钥
  11. 默认授予类型:授权码
  12. 授权 URL:https://<tower_url>/api/o/authorize/
  13. 令牌 URL:https://<tower_url>/api/o/token/
  14. 重定向 URL:https://<snow_instance_id>.service-now.com/oauth_redirect.do

    单击底部的“提交”按钮。

    image19

  15. 你应该会被带到所有应用程序注册表的列表。单击你刚刚创建的应用程序。在底部,应该有两个选项卡:单击“OAuth 实体范围”选项卡。在此选项卡下,有一个名为“插入新行...”的部分。双击此处,并在字段中输入“写入范围”。单击“绿色勾号”以确认此更改。然后,右键单击顶部显示“应用程序注册表”的灰色区域,并在弹出的菜单中单击“保存”。

    image11-1

  16. 写入范围现在应该可以单击。单击它,在弹出的对话框窗口中,在 OAuth 范围框中输入“write”。单击底部的“更新”按钮。

    image7-1

  17. 返回应用程序设置页面,滚动到底部,点击**Oauth 实体配置文件**选项卡。应该会显示一个实体配置文件 - 点击进入。

    image21

  18. 您将进入 Oauth 实体配置文件窗口。在底部,在 Oauth 实体范围字段中输入**写入范围**。点击绿色复选标记并更新。

    image23

  19. 导航到**系统 Web 服务 -> REST 消息**。点击蓝色**新建**按钮。在弹出的对话框中,填写以下字段

  20. 名称:描述性的 REST 消息名称

  21. 端点:您想要执行的 Ansible Tower 操作的 URL 端点。这可以从可浏览的 API 中获取,地址为 https://<tower_url>/api
  22. 身份验证类型:Oauth 2.0
  23. Oauth 配置文件:选择您创建的 Oauth 配置文件

    在顶部灰色区域内右键单击;点击**保存**。

    image10-1

  24. 点击 REST 消息屏幕上的**获取 Oauth 令牌**按钮。这将生成一个弹出窗口,要求您授权 ServiceNow 访问您的 Ansible Tower 实例/集群。点击授权。ServiceNow 现在将拥有一个 OAuth2 令牌,用于对您的 Ansible Tower 服务器进行身份验证。

    image22

  25. 在底部的 HTTP 方法部分,点击蓝色新建按钮。在弹出的新对话框中,填写以下字段

  26. HTTP 方法:POST

  27. 名称:描述性的 HTTP 方法名称
  28. 端点:您想要执行的 Ansible Tower 操作的 URL 端点。这可以从可浏览的 API 中获取,地址为 https://<tower_url>/api
  29. HTTP 标头(在 HTTP 请求选项卡下)
    • 唯一需要的 HTTP 标头是 Content-Type: application/json

您可以使用这些参数和**测试**链接启动对 Ansible Tower 的 RESTful 调用。

image6-3

测试 ServiceNow 和 Ansible Tower 之间的连接

点击**测试**链接将带您进入结果屏幕,该屏幕将显示 RESTful 调用已成功发送到 Ansible Tower。在本示例中,ServiceNow 启动了一个 Ansible Tower 作业模板,响应中包含 Ansible Tower 中的作业 ID:276。

image eight

您可以通过返回 Ansible Tower 并点击屏幕左侧的**作业**部分来确认此作业模板确实已启动;列表中应该存在一个具有相同 ID 的作业(并且,根据剧本的大小,可能仍在处理中)。

image15

创建 ServiceNow 目录项以启动 Ansible Tower 作业模板

现在您已经可以从 ServiceNow 向 Ansible Tower 发出出站 RESTful 调用了,是时候创建一个目录项,以便用户在 ServiceNow 中以生产自服务的方式进行选择。在 HTTP 方法选项中,点击**预览脚本使用**链接

image nine

复制出现的脚本,并将其粘贴到文本编辑器中以备后用。

  1. 在 ServiceNow 中,导航到**工作流 -> 工作流编辑器**。这将打开一个新的选项卡,其中包含所有现有的 ServiceNow 工作流列表。点击蓝色**新建工作流**按钮

    image16

  2. 在出现的**新建工作流**对话框中,填写以下选项

  3. 名称:工作流的描述性名称

  4. 表:请求项 sc_req_item

    其他所有内容都可以保持原样。点击**提交**按钮。

    image1-10

  5. 结果的工作流编辑器将只包含一个开始框和一个结束框。点击该行(它将变为蓝色以指示它已被选中),然后按删除键将其删除。

    image14-1

  6. 在工作流编辑器屏幕的右侧,选择核心选项卡,在核心活动 -> 实用程序下,将运行脚本选项拖到工作流编辑器中。在出现的新的对话框中,输入一个描述性名称,并粘贴之前捕获的脚本。点击提交以保存脚本。

    image12-1

  7. 从**开始**绘制一条连接到新创建的运行脚本框的线,再从**运行脚本**框绘制一条连接到**结束**的线。之后,点击工作流名称左侧的三个水平线,选择**发布**选项。您现在可以将此工作流与目录项关联起来。

    image8-1

  8. 导航到**服务目录 -> 目录定义 -> 维持项目**。点击结果项目列表中的蓝色**新建**按钮。在弹出的对话框中,填写以下字段

  9. 名称:目录项的描述性名称

  10. 目录:此项目应该属于哪个目录
  11. 类别:如果您希望用户能够搜索此项目,则该类别是必需的

    在过程引擎选项卡中,用您刚刚创建的工作流填充**工作流**字段。点击提交按钮。您已创建了一个新的目录项!

    image5-4

  12. 最后,要运行此目录项,请导航到**自助服务 -> 主页**,并搜索您刚刚创建的目录项。找到后,点击**立即订购**按钮。您将看到结果页面在 ServiceNow 中弹出,并且您可以确认该作业正在 Ansible Tower 中运行。

恭喜!完成这些步骤后,您现在可以使用 ServiceNow 目录项在 Ansible Tower 中启动作业和工作流模板。这非常适合让最终用户使用他们熟悉的界面来执行各种复杂程度的自动化任务。这种熟悉程度对于整个企业的价值实现时间至关重要,而不仅仅是负责编写正在使用的剧本的团队。




使用 Ansible 深入研究 Kubernetes 运算符,第 2 部分

使用 Ansible 深入研究 Kubernetes 运算符,第 2 部分

在本系列的第 1 部分中,我们介绍了运算符的整体概念,以及它们在 OpenShift/Kubernetes 中的作用。我们简要了解了运算符 SDK,以及为什么您可能希望使用 Ansible 运算符,而不是 SDK 提供的其他类型的运算符。我们还探讨了 Ansible 运算符的结构,以及在使用 Ansible 构建 Kubernetes 运算符时,运算符 SDK 创建的相关文件。

在本深入研究系列的第二部分中,我们将

  1. 看一下创建 OpenShift 项目和部署 Galera 运算符。
  2. 接下来,我们将检查 MySQL 集群,然后设置和测试 Galera 集群。
  3. 然后我们将测试缩减规模、灾难恢复,并演示清理工作。

创建项目并部署运算符

我们首先在 OpenShift 中创建一个新项目,我们将其简单地命名为 test

$ oc new-project test --display-name="Testing Ansible Operator"
Now using project "test" on server "https://ec2-xx-yy-zz-1.us-east-2.compute.amazonaws.com:8443"

我们不会深入研究这个角色,但是基本操作是

  1. 使用 set_fact 使用 k8s 查找插件或 defaults/main.yml 中定义的其他变量来生成变量。
  2. 根据以上变量确定是否需要采取任何纠正措施。例如,一个变量确定当前运行了多少个 Galera 节点 pod。将其与 CustomResource 中定义的变量进行比较。如果它们不同,该角色将根据需要添加或删除 pod。

要开始部署,我们有一个简单的脚本,它构建运算符镜像并将其推送到 test 项目的 OpenShift 仓库中

$ cat ./create_operator.sh
#!/bin/bash

docker build -t docker-registry-default.router.default.svc.cluster.local/test/galera-ansible-operator:latest .
docker push docker-registry-default.router.default.svc.cluster.local/test/galera-ansible-operator:latest
kubectl create -f deploy/operator.yaml
kubectl create -f deploy/cr.yaml

在我们运行此脚本之前,我们需要先部署 RBAC 规则和 Galera 示例的自定义资源定义

$ oc create -f deploy/rbac.yaml
clusterrole "galera-ansible-operator" created
clusterrolebinding "default-account-app-operator" created
$ oc create -f deploy/crd.yaml
customresourcedefinition "galeraservices.galera.database.coreos.com" created

现在,我们运行脚本(在使用登录命令允许 docker 连接到我们创建的 OpenShift 仓库后)

$ docker login -p $(oc whoami -t) -u unused docker-registry-default.router.default.svc.cluster.local
Login Succeeded

$ ./create_operator.sh
Sending build context to Docker daemon 490 kB
...
deployment.apps/galera-ansible-operator created
galeraservice "galera-example" created

很快,我们将看到 galera-ansible-operator pod 启动,随后是一个名为 galera-node-0001 的 pod 和一个 LoadBalancer 服务,该服务为我们的 Galera 集群提供入口。

$ oc get all
NAME DOCKER REPO TAGS UPDATED
is/galera-ansible-operator docker-registry-default.router...:5000/test/galera-ansible-operator latest 3 hours ago

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/galera-ansible-operator 1 1 1 1 4m

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/galera-external-loadbalancer 172.30.251.195 172.29.17.210,172.29.17.210 33066:30072/TCP 1m
svc/glusterfs-dynamic-galera-node-0001-mysql-data 172.30.49.250 <none> 1/TCP 1m

NAME DESIRED CURRENT READY AGE
rs/galera-ansible-operator-bc6cd548 1 1 1 4m

NAME READY STATUS RESTARTS AGE
po/galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 4m
po/galera-node-0001 1/1 Running 0 1m

验证 MySQL 集群,初始设置和测试

我们可以使用 describe 函数查看自定义资源的状态,特别是我们指定的规模

$ kubectl describe -f deploy/cr.yaml |grep -i size
Galera _ Cluster _ Size: 1

现在我们有了 MySQL 集群,让我们使用 sysbench 对其进行测试。如上所述,我们有一个系统可以进行测试,因此我们可以避免互联网往返。但首先,我们需要一些信息。我们需要知道我们可以通过作为运算符部署的一部分创建的负载均衡服务连接到的转发端口

$ oc get services

接下来,我们需要知道主机的 IP 地址。我们可以使用 oc describe 获取它

$ oc describe node ec2-xx-yy-zz-1.us-east-2.compute.amazonaws.com| grep ^Addresses
Addresses: 10.0.0.46,ec2-xx-yy-zz-1.us-east-2.compute.amazonaws.com

因此,对于此测试,我们将连接到 IP 地址 10.0.0.46 上的端口 XXXXX。端口值 33066 在上面的规范中指定,它将接收转发流量。我们将导出它们,以便更轻松地重复使用我们的测试命令。

从测试服务器

$ export MYSQL_IP=10.0.0.46
$ export MYSQL_PORT=XXXXX

在运行 sysbench 之前,我们需要创建它期望的数据库(将来版本的 Galera 运算符将能够自动执行此操作)

$ mysql -h $MYSQL_IP --port=$MYSQL_PORT -u root -e 'create database sbtest;'

接下来,我们将通过使用包含 100 万行的 OLTP 只读测试运行 sysbench 来准备测试

$ sysbench --db-driver=mysql --threads=150 --mysql-host=${MYSQL_IP} --mysql-port=${MYSQL_PORT} --mysql-user=root --mysql-password= --mysql-ignore-errors=all --table-size=1000000 /usr/share/sysbench/oltp_read_only.lua prepare
sysbench 1.0.9 (using system LuaJIT 2.0.4)
Initializing worker threads...
Creating table 'sbtest1'...
Inserting 1000000 records into 'sbtest1'
Creating a secondary index on 'sbtest1'

...

请注意,我们在此处使用 150 个线程,因为单个 MySQL/MariaDB 实例将其最大连接数默认设置为该值。

所以现在一切都准备就绪,让我们使用 sysbench 运行我们的第一个测试

$ sysbench --db-driver=mysql --threads=150 --mysql-host=${MYSQL_IP} --mysql-port=${MYSQL_PORT} --mysql-user=root --mysql-password= --mysql-ignore-errors=all /usr/share/sysbench/oltp_read_only.lua run
sysbench 1.0.9 (using system LuaJIT 2.0.4)
Running the test with following options:
Number of threads: 150
Initializing random number generator from current time
Initializing worker threads...
Threads started!
SQL statistics:
    queries performed:
        read:                            174776
        write:                           0
        other:                           24968
        total:                           199744
    transactions:                        12484  (1239.55 per sec.)
    queries:                             199744 (19832.77 per sec.)
    ignored errors:                      0      (0.00 per sec.)
    reconnects:                          0      (0.00 per sec.)
General statistics:
    total time:                          10.0700s
    total number of events:              12484
Latency (ms):
         min:                                  3.82
         avg:                                120.66
         max:                               1028.51
         95th percentile:                    292.60
         sum:                            1506263.71
Threads fairness:
    events (avg/stddev):           83.2267/42.84
    execution time (avg/stddev):   10.0418/0.02

这只是一次运行,但重新运行几次会产生类似的结果。因此,我们的单节点集群每秒可以处理约 20K 个查询。但是只有单个成员的集群不是很有用 - 因此让我们将其扩展。我们通过编辑之前定义的自定义资源并更改 galera_cluster_size 变量来实现这一点。现在,我们将扩展到一个三节点集群

$ oc edit -f deploy/cr.yaml
galeraservice.galera.database.coreos.com/galera-example edited

接下来,我们可以验证 OpenShift 是否看到了这个新值

$ kubectl describe -f deploy/cr.yaml | grep -i size
Galera _ Cluster _ Size: 3

很快,我们将看到 Ansible 运算符接收一个信号更改的事件,并开始更新集群

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 30m
galera-node-0001 1/1 Running 0 26m
galera-node-0002 0/1 Running 0 1m
galera-node-0003 0/1 Running 0 56s

在大约一分钟后(每个 Galera 节点必须启动并从另一个成员同步数据),我们将看到新的 pod 变得可用

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 31m
galera-node-0001 1/1 Running 0 27m
galera-node-0002 1/1 Running 0 2m
galera-node-0003 1/1 Running 0 2m

现在我们有了三节点集群,我们可以重新运行与之前相同的测试

$ sysbench --db-driver=mysql --threads=150 --mysql-host=${MYSQL_IP} --mysql-port=${MYSQL_PORT} --mysql-user=root --mysql-password= --mysql-ignore-errors=all /usr/share/sysbench/oltp_read_only.lua run
sysbench 1.0.9 (using system LuaJIT 2.0.4)
Running the test with following options:
Number of threads: 150
Initializing random number generator from current time
Initializing worker threads...
Threads started!
SQL statistics:
    queries performed:
        read:                            527282
        write:                           0
        other:                           75326
        total:                           602608
    transactions:                        37663  (3756.49 per sec.)
    queries:                             602608 (60103.86 per sec.)
    ignored errors:                      0      (0.00 per sec.)
    reconnects:                          0      (0.00 per sec.)
General statistics:
    total time:                          10.0247s
    total number of events:              37663
Latency (ms):
         min:                                  4.30
         avg:                                 39.88
         max:                               8371.55
         95th percentile:                     82.96
         sum:                            1501845.63
Threads fairness:
    events (avg/stddev):           251.0867/87.82
    execution time (avg/stddev):   10.0123/0.01

结果很显著!我们的集群现在每秒可以处理 60K 个查询!我们能把它扩展到多远?好吧,如果您注意到我们启动时的节点数量,我们的 k8s 集群中有五个节点,因此让我们让我们的 Galera 集群与之匹配

$ oc edit -f deploy/cr.yaml
galeraservice.galera.database.coreos.com/galera-example edited
$ kubectl describe -f deploy/cr.yaml | grep -i size
Galera _ Cluster _ Size: 5

Ansible 运算符开始扩展 Galera 集群...

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 35m
galera-node-0001 1/1 Running 0 32m
galera-node-0002 1/1 Running 0 7m
galera-node-0003 1/1 Running 0 7m
galera-node-0004 0/1 Running 0 38s
galera-node-0005 0/1 Running 0 34s

在大约一分钟后,我们将再次看到一个包含五个 pod 的 Galera 集群,它们已准备好为查询提供服务

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 36m
galera-node-0001 1/1 Running 0 33m
galera-node-0002 1/1 Running 0 8m
galera-node-0003 1/1 Running 0 8m
galera-node-0004 1/1 Running 0 1m
galera-node-0005 1/1 Running 1 1m

奇怪的是,第五个节点出现问题,但 OpenShift 在其失败后重新尝试了它,它启动并加入了集群。太好了!

因此,让我们再次重新运行相同的测试

$ sysbench --db-driver=mysql --threads=150 --mysql-host=${MYSQL_IP} --mysql-port=${MYSQL_PORT} --mysql-user=root --mysql-password= --mysql-ignore-errors=all /usr/share/sysbench/oltp_read_only.lua run
sysbench 1.0.9 (using system LuaJIT 2.0.4)
Running the test with following options:
Number of threads: 150
Initializing random number generator from current time
Initializing worker threads...
Threads started!
SQL statistics:
queries performed:
        read:                            869260
        write:                           0
        other:                           124180
        total:                           993440
    transactions:                        62090  (6196.82 per sec.)
    queries:                             993440 (99149.17 per sec.)
    ignored errors:                      0      (0.00 per sec.)
    reconnects:                          0      (0.00 per sec.)
General statistics:
    total time:                          10.0183s
    total number of events:              62090
Latency (ms):
         min:                                  5.41
         avg:                                 24.18
         max:                                159.70
         95th percentile:                     46.63
         sum:                            1501042.93
Threads fairness:
    events (avg/stddev):           413.9333/78.17
    execution time (avg/stddev):   10.0070/0.00

我们正在达到每秒 100K 个查询。到目前为止,我们的集群已随着我们扩展的节点数量线性扩展。在这一点上,我们已经耗尽了 OpenShift 集群的资源,扩展更多 Galera 节点无济于事

$ oc edit -f deploy/cr.yaml
galeraservice.galera.database.coreos.com/galera-example edited
$ kubectl describe -f deploy/cr.yaml | grep -i size
Galera _ Cluster _ Size: 9

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 44m
galera-node-0001 1/1 Running 0 41m
galera-node-0002 1/1 Running 0 16m
galera-node-0003 1/1 Running 0 16m
galera-node-0004 1/1 Running 0 9m
galera-node-0005 1/1 Running 1 9m
galera-node-0006 1/1 Running 0 1m
galera-node-0007 1/1 Running 0 1m
galera-node-0008 1/1 Running 0 1m
galera-node-0009 1/1 Running 0 1m

$ sysbench --db-driver=mysql --threads=150 --mysql-host=${MYSQL_IP} --mysql-port=${MYSQL_PORT} --mysql-user=root --mysql-password= --mysql-ignore-errors=all /usr/share/sysbench/oltp_read_only.lua run
sysbench 1.0.9 (using system LuaJIT 2.0.4)
Running the test with following options:
Number of threads: 150
Initializing random number generator from current time
Initializing worker threads...
Threads started!
SQL statistics:
    queries performed:
        read:                            841260
        write:                           0
        other:                           120180
        total:                           961440
    transactions:                        60090  (5995.71 per sec.)
    queries:                             961440 (95931.35 per sec.)
    ignored errors:                      0      (0.00 per sec.)
    reconnects:                          0      (0.00 per sec.)
General statistics:
    total time:                          10.0208s
    total number of events:              60090
Latency (ms):
         min:                                  5.24
         avg:                                 24.98
         max:                                192.46
         95th percentile:                     57.87
         sum:                            1501266.08
Threads fairness:
    events (avg/stddev):           400.6000/134.04
    execution time (avg/stddev):   10.0084/0.01

性能实际上下降了一点!这表明 MySQL/MariaDB 非常资源密集,因此如果您想继续扩展性能,您可能需要添加更多 OpenShift 集群资源。但在这一点上,我们的集群提供的流量是最初启动时的近 5 倍。对 MySQL/MariaDB 和 Galera 的持续调整可以扩展这一点,并使我们能够进一步提高性能。但是,这里的目标是展示如何创建 Ansible 运算符来控制非常复杂、面向数据的应用程序。

缩减集群规模

由于这些额外的节点没有帮助(除了在发生故障时提供更多冗余),让我们将集群规模缩减到五个节点

$ oc edit -f deploy/cr.yaml
galeraservice.galera.database.coreos.com/galera-example edited
$ kubectl describe -f deploy/cr.yaml | grep -i size
Galera _ Cluster _ Size: 5

过了一会儿,我们将看到运算符开始终止不再需要的 pod

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 46m
galera-node-0001 1/1 Running 0 43m
galera-node-0002 1/1 Running 0 18m
galera-node-0003 1/1 Running 0 18m
galera-node-0004 1/1 Running 0 11m
galera-node-0005 1/1 Running 1 11m
galera-node-0006 0/1 Terminating 0 3m
galera-node-0007 0/1 Terminating 0 3m
galera-node-0008 0/1 Terminating 0 3m
galera-node-0009 0/1 Terminating 0 3m

灾难恢复

现在,让我们添加一些混乱。查看我们的第一个 worker xx-yy-zz-2,我们可以看到哪些 pod 正在该节点上运行

$ oc describe node ec2-xx-yy-zz-2.us-east-2.compute.amazonaws.com
...
Non-terminated Pods: (5 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
openshift-monitoring node-exporter-bqnzv 10m (0%) 20m (1%) 20Mi (0%) 40Mi (0%)
openshift-node sync-hjtmj 0 (0%) 0 (0%) 0 (0%) 0 (0%)
openshift-sdn ovs-55hw4 100m (5%) 200m (10%) 300Mi (4%) 400Mi (5%)
openshift-sdn sdn-rd7kp 100m (5%) 0 (0%) 200Mi (2%) 0 (0%)
test galera-node-0004 0 (0%) 0 (0%) 0 (0%) 0 (0%)
...

因此 galera-node-0004 正在此处运行,以及一些其他基础设施部分。让我们从 AWS EC2 控制台重新启动它,看看会发生什么...

$ oc get nodes
NAME STATUS AGE
ec2-xx-yy-zz-1.us-east-2.compute.amazonaws.com Ready 1d
ec2-xx-yy-zz-2.us-east-2.compute.amazonaws.com NotReady 1d
ec2-xx-yy-zz-3.us-east-2.compute.amazonaws.com Ready 1d
ec2-xx-yy-zz-4.us-east-2.compute.amazonaws.com Ready 1d
ec2-xx-yy-zz-5.us-east-2.compute.amazonaws.com Ready 1d
ec2-xx-yy-zz-6.us-east-2.compute.amazonaws.com Ready 1d
ec2-xx-yy-zz-7.us-east-2.compute.amazonaws.com Ready 1d
ec2-xx-yy-zz-8.us-east-2.compute.amazonaws.com Ready 1d

最终,我们将看到 galera-node-0004 进入未知状态

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 50m
galera-node-0001 1/1 Running 0 47m
galera-node-0002 1/1 Running 0 22m
galera-node-0003 1/1 Running 0 22m
galera-node-0004 1/1 Unknown 0 16m
galera-node-0005 1/1 Running 1 16m

过了一会儿,该 pod 将被终止,之后 Ansible 运算符将重新启动它

$ oc get pods
NAME READY STATUS RESTARTS AGE
galera-ansible-operator-bc6cd548-46b2r 1/1 Running 5 55m
galera-node-0001 1/1 Running 0 52m
galera-node-0002 1/1 Running 0 27m
galera-node-0003 1/1 Running 0 27m
galera-node-0004 1/1 Running 1 1m
galera-node-0005 1/1 Running 1 21m

...我们的集群又恢复到其请求的容量!

清理

由于这是一个测试,我们需要清理我们的工作。完成后,我们将使用 delete_operator.sh 脚本删除自定义资源和操作符部署。

$ ./delete_operator.sh
galeraservice.galera.database.coreos.com "galera-example" deleted
deployment.apps "galera-ansible-operator" deleted

几分钟后,所有东西都将消失。

$ oc get all
NAME DOCKER REPO TAGS UPDATED
is/galera-ansible-operator docker-registry-default.router...:5000/test/galera-ansible-operator latest 4 hours ago

总结

Galera 操作符正在开发中,绝对不适合生产环境。如果您想查看剧本本身,可以在这里查看代码。

https://github.com/water-hole/galera-ansible-operator

我们将继续开发它,目标是使其成为其他数据存储应用程序的事实标准示例。感谢您的阅读!




Ansible 深入解析 Kubernetes 操作符,第一部分

Ansible 深入解析 Kubernetes 操作符,第一部分

本深入解析系列假设读者拥有 Kubernetes 测试环境。类似 minikube 的工具对于本文的目的来说是可接受的平台。如果您是现有的 Red Hat 客户,另一个选择是通过 cloud.redhat.com 启动 OpenShift 集群。这个 SaaS 门户使尝试 OpenShift 成为一项即插即用的操作。

在本深入解析系列的这一部分中,我们将

  1. 总体了解操作符及其在 OpenShift/Kubernetes 中的作用。
  2. 快速了解 Operator SDK,以及为什么您可能希望使用 Ansible 操作符而不是 SDK 提供的其他类型的操作符。
  3. 最后,Ansible 操作符的结构以及 Operator SDK 创建的相关文件。

什么是操作符?

对于那些可能不太熟悉 Kubernetes 的人来说,它最简单的描述就是一个资源管理器。用户指定他们想要多少特定资源,Kubernetes 管理这些资源以实现用户指定的狀態。这些资源可以是 Pod(包含一个或多个容器)、持久卷,甚至是由用户定义的自定义资源。

这使得 Kubernetes 非常适合管理不包含任何状态的资源(例如 Web 服务器 Pod 或负载均衡资源)。但是,Kubernetes 没有提供任何用于管理数据库或缓存等资源的内置逻辑,这些资源是有状态的,对重启很敏感。操作符的创建是为了弥合这一差距,为用户提供一种方法,可以指定与 Kubernetes 中的自定义资源定义 绑定的代码片段(传统上是用 Golang 编写的)。

操作符之所以得名,是因为它们允许您将应用程序的操作逻辑嵌入到 Kubernetes/OpenShift 上运行的自动化管理器中。

Operator SDK 以及 Ansible 操作符的快速概述

Red Hat 创建了 Operator Framework 使得在整个生命周期中创建和管理操作符变得更加容易。作为框架的一部分,Operator SDK 的任务是为用户以自动化方式创建和构建操作符。随着时间的推移,它已经发展壮大,增加了许多操作符类型。2018 年,我们开始着手将 Ansible 操作符类型添加到 SDK 中。我们希望让基于 Ansible 的 Kubernetes 环境中构建操作符变得更加容易。

为什么要在操作符中使用 Ansible?

最初,操作符是用 Golang 编写的。对于任何想要编写操作符的人来说,这立即将门槛提高了一些——有人必须知道一种相对低级的编程语言才能入门。最重要的是,您还必须熟悉 Kubernetes 内部机制,例如 API 以及为资源生成事件的方式。

Ansible 操作符的创建是为了解决这一缺陷。Ansible 操作符主要由两部分组成:

  1. 一小段 Golang 代码,它处理 Kubernetes/OpenShift 与操作符之间的接口。
  2. 一个容器,它接收来自上述代码的事件,并在需要时运行 Ansible 剧本。

就是这样!Ansible 和 Operator SDK 抽象了编写操作符的所有困难部分,让您专注于重要的部分——管理您的应用程序。如果您的组织已经拥有大量的 Ansible 知识库,您可以立即开始使用 Ansible 操作符管理应用程序。使用 Ansible 作为操作符的另一个额外好处是,您可以立即访问 Ansible 可以运行的任何模块。这使得人们能够将与应用程序相关的集群外管理任务整合起来。例如

  1. 为新部署的应用程序创建 DNS 条目
  2. 启动集群外部的资源,例如存储或网络
  3. 更轻松地将 off-site 备份到外部云服务
  4. 基于自定义指标管理外部负载均衡

使用 Ansible 编写的 Kubernetes 操作符可以为许多可能性提供潜在的解决方案。

从头开始创建 Ansible Kubernetes 操作符

首先,按照他们的说明 安装 Operator SDK。安装完成后,我们可以使用以下命令创建一个新的操作符

$ operator-sdk new test-operator \
    --api-version=test.ansible-operator.com/v1 \
    --kind=Test \
    --type=ansible

INFO[0000] Creating new Ansible operator 'test-operator'.
...
INFO[0000] Project creation complete.

$ cd test-operator/

Ansible Kubernetes 操作符结构和文件

[现在我们有了操作符骨架,让我们看看在一般情况下部署操作符时使用的一些主要文件,以及 Ansible 操作符类型专门生成的哪些文件。这些文件是

  1. watches.yaml 文件。
  2. build 目录。
  3. deploy 目录。
  4. roles 目录。

这里还存在另一个目录:molecule 目录,其中包含使用 Molecule 自动化测试您的角色/剧本的文件。我们不会在此处介绍 Molecule 的使用方法,只是为了完整性而提及它。

如果您在上面的 test-operator 目录中运行 ls -l,您将在创建新的操作符骨架后看到这些文件/目录。

watches.yaml 文件

该文件由 Ansible 操作符用来告诉 Kubernetes/OpenShift 操作符负责处理哪些自定义资源(基于 Group/Version/Kind 字段)。它是将我们的自定义代码与 Kubernetes API 联系起来的纽带。

---
- version: v1
  group: test.ansible-operator.com
  kind: Test
  role: /opt/ansible/roles/test

指定任何其他剧本样板。但是,如果您在操作符中运行多个角色,您可以将该行更改为

playbook: /opt/ansible/playbook.yaml

此外,您需要调整 build/Dockerfile(关于这一点将在下面详细介绍),将剧本复制到容器中,因此请添加以下行

COPY playbook.yaml ${HOME}/playbook.yaml

然后,您将在与 watches.yaml 文件相同的目录中创建指定的剧本。

build 目录

该目录包含一些与构建操作符工件相关的文件。因为操作符只是 OpenShift/Kubernetes 的另一个应用程序,所以该工件是一个使用 Dockerfile 构建的容器。此处的其他文件与通过 Molecule 进行测试有关,我们不会在本博客系列中介绍。

Dockerfile 非常简单,因此我们不会深入研究,只是说它基于来自 quay.io 的 ansible-operator 镜像,并将角色和 watches.yml 文件复制到容器镜像中。

deploy 目录

该目录包含使用 oc CLI 命令将操作符部署到 OpenShift/K8s 的 YAML 文件。

CustomResourceDefinition (CRD) 和 CustomResource (CR) 在 deploy/crds/ 目录中定义。CRD 是 watches.yaml 文件引用的内容,这意味着此定义的所有实例 (CR) 都将由我们的操作符控制。

CRD 在 deploy/crds/test_v1_test_crd.yaml 中定义,它主要用于 OpenShift/Kubernetes。

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: tests.test.ansible-operator.com
spec:
  ...

您可以看到上面的 operator-sdk 命令用我们指定的 value 填充了大多数字段。CRD 本身并不实用,您需要实际的实例来定义它们——这就是 CustomResource 的作用。我们的 CustomResource (CR) 在 deploy/crds/test_v1_test_cr.yaml 中定义,并且相对较短(与其他 YAML 文件相比,无论如何)

apiVersion: test.ansible-operator.com/v1
kind: Test
metadata:
  name: example-test
spec:
  size: 3

spec 条目下设置的每个值都将成为传递给 Ansible 的额外变量。使用这些变量,我们可以自定义操作符的行为。默认示例创建一个名为 size 的条目,我们可以用它在角色中动态地扩展操作符管理的应用程序。

deploy/role.yamldeploy/role_binding.yaml(未显示)定义了一些 RBAC 控制,这些控制允许您的登录访问权限来管理上面定义的自定义资源。Role Based Access Control (RBAC) 本文未涉及,因此再次提及它们是为了完整性起见。

最后,deploy/operator.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-operator
spec:
  ...

该文件相当长,但主要是在 OpenShift/Kubernetes 中创建一个新的 Deployment 资源,这有助于确保操作符保持运行状态。

roles 目录

这是您放置想要包含在操作符中的任何角色的目录,对于有经验的 Ansible 用户来说应该很熟悉。如上所述,此目录将完全复制到 Ansible 操作符容器中,此处的角色可以在 watches.yaml 文件或您包含的其他剧本中引用。

角色通常使用 k8s 模块(从 2.6 版开始包含在 Red Hat Ansible Automation 中)来管理集群中的资源。如果您熟悉 Kubernetes 资源文件,这个模块将非常直观(来自资源文件的 YAML 可以直接复制粘贴为该模块的输入)。要了解更多信息,您可以阅读此处有关 k8s 模块的文档

https://docs.ansible.org.cn/ansible/latest/modules/k8s_module.html

总结

至此,我们对操作符、Operator SDK 以及 Ansible 操作符的创建和结构进行了深入解析。使用 Ansible 编写的操作符为您提供了操作符的一般功能,同时允许您利用现有的 Ansible 专业知识,快速上手在 OpenShift 或 Kubernetes 上部署应用程序。




Ansible 内容交付的未来

Ansible 内容交付的未来

每天,我都会对 Ansible 发展成为的规模感到敬畏。社区的惊人增长和技术的病毒式传播导致了该项目的内容管理挑战。

我不想重复我们亲爱的朋友 Jan-Piet Mens 或我们出色的社区团队所说的大部分内容,但我需要花点时间来谈谈它。

我们面临的主要挑战源于可扩展性的问题。我们每天看到的 Pull Request 和 Issue 的数量远远超过了 Ansible 社区能够跟上的速度。

因此,我们正在踏上一个新的旅程。我们知道,无论是内容创建者还是内容消费者,社区都对这个旅程充满期待。

这个“新世界秩序”(半开玩笑的说法),正如我们一直所称,是一个能够赋能 Ansible 内容贡献者社区(即模块、插件和角色的贡献者)以他们自己的节奏提供内容的模型。

为了实现这一点,我们对 Ansible 如何利用非“内置”内容的方式进行了一些更改。简而言之,Ansible 内容将不再必须成为引擎本身的里程碑核心版本的一部分。我们将利用一个交付流程和内容结构/格式,这将有助于缓解由于将插件绑定到核心引擎而导致的许多模棱两可和痛苦。

这个旅程的基石是您可能在网络上听到过的一些传言。它被称为 Ansible 内容集合,简称集合。

为了创建 Ansible 内容集合,我们研究了许多已经实践的方案。我们参考了其他工具、其他打包格式、交付引擎、存储库,当然还有我们自己的经验。通过这些调查,我们认为我们已经制定了一个相当完善的规范。下面我们将介绍其中的一些细节。

集合是 Ansible 内容的严格项目/目录结构。与角色目录结构类似;我们现在强调对 Ansible Playbook 执行至关重要的内容。以下是我的队友 Tim Appnel 创建的该规范的图形。

Screenshot_future-of-content-1

正如您所见,这种结构与角色非常相似。不过也有一些细微的差别。请注意,roles 目录不再包含 library 文件夹?这里的想法是,集合本身是与之相关的每个内容片段(包括执行该内容的 Playbook)的真正封装。因此,我们将库从可能存在于集合中的各种角色中移除,并将它们放置在 plugins 目录的顶层。在那里,所有类型的插件(是的,模块也在那里,因为模块实际上是插件)将可以被角色使用,最终可以使用所有可能调用它们的 Playbook。因为这些内容将被“安装”在一个引擎意识到的位置,并知道在 Playbook 中被调用的内容在哪里。

此外,通过这些更改,我们还引入了一些命名空间的概念到 Playbook 中。这是 Tim 创建的另一个图形,它展示了 Playbook 中的命名空间片段。

Screenshot_future-of-content-2

所以我们这里有一个非常简单的 Playbook。在这个 Playbook 中,我们突出显示了我们感兴趣使用的集合列表。对于每个任务,我们使用模块的 FQCN(完全限定的集合命名空间)路径。当然,我们仍然希望使它变得简单。因此,Playbook 创建者不必始终完全限定他们的内容路径。正如您在第四个任务中所看到的,创建者仍然可以使用模块的简写名称。Ansible 将按照在 Ansible 配置或 Playbook 本身中定义的顺序,以先到先得的方式搜索集合的路径。

关于集合,我就介绍到这里了。

祝大家自动化愉快!