运行分布式测试
已经确定 k6 可以从单个实例运行大型负载测试,但运行单个测试的多个实例呢?
您可能希望运行分布式测试的几个原因包括
- 您的被测系统 (SUT) 应从多个 IP 地址访问。
- 一个完全优化的节点无法产生您的超大型测试所需的负载。
- Kubernetes 已经是您首选的运维环境。
对于这些场景,我们创建了k6-operator。
k6-operator 介绍
k6-operator 是 Kubernetes 中操作符模式的实现,它在 Kubernetes 中定义了自定义资源。目的是自动化人类操作员通常会执行的任务;例如配置新的应用程序组件、更改配置或解决运行时问题。
k6-operator 定义了自定义的 TestRun
资源类型,并监听 TestRun
对象的更改或创建。每个 TestRun
对象都引用一个 k6 测试脚本,配置环境,并指定测试运行的实例数量,即 parallelism
。一旦检测到更改,操作符将通过修改集群状态来做出反应,根据需要启动 k6 测试作业。
开始使用 k6-operator
让我们来看看如何开始使用 k6-operator。唯一的要求是能够访问 Kubernetes 集群并拥有适当的权限和工具。
1. 安装操作符
在 Kubernetes 中运行分布式测试的第一步是安装操作符(如果集群尚未安装)。此时,安装确实需要将项目源代码下载到您的系统上。安装命令必须从源代码目录运行。
在命令行中,执行以下命令
git clone https://github.com/grafana/k6-operator && cd k6-operator
确保您的 kubectl
工具已设置为正确的 Kubernetes 集群。然后,在 k6-operator
目录中,您现在可以执行安装
make deploy
默认情况下,操作符将安装到一个新的命名空间 k6-operator-system
中。您可以通过列出该命名空间内的可用资源来验证安装是否成功
kubectl get pod -n k6-operator-system
稍等片刻后,您的结果状态应变为 Running
,如下所示
NAME READY STATUS RESTARTS AGE
k6-operator-controller-manager-7664957cf7-llw54 2/2 Running 0 160m
您现在可以开始创建和执行测试脚本了!
2. 创建测试脚本
为 Kubernetes 创建 k6 测试脚本与为命令行创建脚本没有区别。如果您尚未为您的系统创建测试用例,我们建议您阅读我们为网站和 API/微服务创建测试的指南之一
一般来说,建议从小处着手,并在迭代过程中扩展脚本。所以让我们从简单开始,创建一个包含以下内容的 test.js
文件
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 10,
duration: '10s',
};
export default function () {
http.get('https://test.k6.io/');
sleep(1);
}
注意
在创建脚本时,请先在本地运行它们,然后再发布到集群。这可以立即为您提供脚本中是否存在错误的反馈。
让我们执行一个简单的测试来验证我们的脚本是否有效
k6 run test.js
我们应该看到成功的执行和结果输出摘要。
3. 添加测试脚本
为了运行您的测试脚本,必须将它们发布到您的集群中。主要有两种方法:使用ConfigMap 或PersistentVolume 资源。
作为 ConfigMap 添加
使用 ConfigMap
是一种快速直接的方式,用于将您的测试脚本添加到 Kubernetes。kubectl
工具提供了一种方便的方法,可以从本地脚本创建新的 ConfigMap
。
让我们使用上一步中创建的 test.js
脚本内容,创建一个名为 my-test
的 ConfigMap
kubectl create configmap my-test --from-file test.js
注意
将测试脚本部署到
ConfigMap
中时,脚本的大小存在限制。Kubernetes 对数据大小施加了 1,048,576 字节 (1 MiB) 的限制,因此如果您的测试脚本超出此限制,您需要挂载一个PersistentVolume
。查看关于何时应使用
ConfigMap
与PersistentVolume
的动机。
您应该看到 configmap/my-test created
的确认信息。
添加到 PersistentVolume 内
设置 PersistentVolume
超出了本指南的范围,但它可以通过 PersistentVolumeClaim
实现从 Kubernetes 集群访问共享文件系统。
使用此选项时,请在适用的文件系统中组织您的测试脚本,就像在本地一样。当将庞大的脚本分解为可重用模块时,此机制是理想的选择。
注意
在 k6 Office Hours 第 76 期讨论中,组织测试脚本是讨论的一部分。
注意
使用
PersistentVolume
时,操作符会期望所有测试脚本都包含在名为/test/
的目录中。
要了解有关创建 PersistentVolume
和 PersistentVolumeClaim
资源的更多信息,请查阅Kubernetes 文档。
4. 创建自定义资源
在安装期间,TestRun
自定义资源定义已添加到 Kubernetes API。我们在自定义资源 TestRun
对象中提供的数据应包含 k6-operator 启动分布式负载测试所需的所有信息。
具体来说,TestRun
对象中定义的主要元素与要运行的测试脚本的名称和位置以及要使用的并行度有关。
以下示例将展示自定义资源的一些常见变体
ConfigMap 中的脚本
当要执行的测试脚本包含在 ConfigMap
资源中时,我们在YAML 的 configMap
块中指定脚本详细信息。name
是 ConfigMap 的名称,file
是该条目的键值。
让我们创建文件 run-k6-from-configmap.yaml
,内容如下
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
name: run-k6-from-configmap
spec:
parallelism: 4
script:
configMap:
name: my-test
file: test.js
回想一下,当我们作为配置值将脚本添加为 ConfigMap 时。我们创建了一个名为 my-test
的 ConfigMap。测试脚本内容是使用文件名作为键值添加到映射中的,因此 file
的值是 test.js
。
parallelism
的数量取决于您;您希望将测试分摊到多少个 Pod 上?操作符将使用execution segments 在 Pod 之间分配工作负载。
注意
ConfigMap 和 CustomResource 必须在同一个Namespace 中创建,这一点很重要。
PersistentVolume 中的脚本
如果待执行的测试脚本包含在 PersistentVolume
中,则需要创建PersistentVolumeClaim。我们不会详细介绍 PersistentVolumes 和 PersistentVolumeClaims,但要了解更多信息,您应查阅Kubernetes 文档。
假设我们已经针对包含测试脚本 /test/test.js
的 PersistentVolume 创建了一个名为 my-volume-claim
的 PersistentVolumeClaim,我们可以创建文件 run-k6-from-volume.yaml
,内容如下
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
name: run-k6-from-volume
spec:
parallelism: 4
script:
volumeClaim:
name: my-volume-claim
# File is relative to /test/ directory within volume
file: test.js
注意
PersistentVolumeClaim 和 CustomResource 必须在同一个Namespace 中创建,这一点很重要。
配置环境
并非所有内容都应该直接包含在您的脚本中。编写良好的脚本将允许变量来支持多种场景,并避免硬编码倾向于更改的值。这些可以是任何内容,从密码到目标 URL,以及系统选项。
我们可以将这些数据作为环境变量传递,供执行您脚本的每个 Pod 使用。这可以在 TestRun 资源中明确定义,或通过引用 ConfigMap 或 Secret 来定义。
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
name: run-k6-with-vars
spec:
parallelism: 4
script:
configMap:
name: my-test
file: test.js
runner:
env:
- name: MY_CUSTOM_VARIABLE
value: 'this is my variable value'
envFrom:
- configMapRef:
name: my-config-vars
- secretRef:
name: my-secrets-vars
注意
上面的 YAML 引入了
runner
部分。这部分适用于每个将运行您测试一部分的 Pod,具体取决于所需的parallelism
。
现在,有了引用的资源,我们的测试脚本就可以使用环境变量了,如下所示
export function setup() {
console.log(`Variable is set as: ${__ENV.MY_CUSTOM_VARIABLE}`);
}
更改命令行参数
k6 选项可以通过多种方式指定,其中一种是命令行。使用操作符时仍然可以通过命令行指定选项,如下面的示例所示
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
name: run-k6-with-args
spec:
parallelism: 4
script:
configMap:
name: my-test
file: test.js
arguments: --tag testid=run-k6-with-args --log-format json
通过上面的参数,我们正在为指标添加一个测试范围内的自定义标签,并将日志的输出格式更改为JSON。
注意
务必访问选项参考以获取可用选项的列表。
5. 运行测试
通过将自定义资源 TestRun
应用到运行操作符的集群来执行测试。测试配置应用如下
kubectl apply -f /path/to/your/k6-resource.yaml
测试运行完成后,您需要清理创建的测试作业。这可以通过运行以下命令来完成
kubectl delete -f /path/to/your/k6-resource.yaml
注意
如果您使用实时结果输出,例如 Prometheus Remote Write,请使用
cleanup
选项在测试完成后自动移除资源,如下例所示apiVersion: k6.io/v1alpha1 kind: TestRun metadata: name: run-k6-with-realtime spec: parallelism: 4 # Removes all resources upon completion cleanup: post script: configMap: name: my-test file: test.js arguments: -o experimental-prometheus-rw
6. 出现问题时
遗憾的是,并非所有事情都总是完美运行,因此知道可以在何处寻求帮助非常重要。
请务必在社区论坛的 k6-operator 类别中搜索。k6 拥有一个不断壮大且乐于助人的与 k6-operator 合作的工程师社区,因此您的问题很可能已经被讨论和解决。在这些论坛中,您还可以获得 k6 开发团队成员的帮助。
另请参阅
以下是一些额外的资源,可帮助您学习