前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在CI流水线中测试Kubernetes部署

在CI流水线中测试Kubernetes部署

作者头像
CNCF
发布2020-06-24 16:11:12
1.5K0
发布2020-06-24 16:11:12
举报
文章被收录于专栏:CNCFCNCF

客座文章最初由Eficode Praqma云基础设施和DevOps顾问Michael Vittrup Larsen在Eficode Praqma上发表。

https://www.praqma.com/stories/testing-kubernetes-deployments-within-ci-pipelines/

低开销,按需在CI工作节点上使用KIND部署Kubernetes集群

如何使用KIND(Kubernetes in Docker)部署低开销、按需Kubernetes集群在CI流水线中测试诸如Helm chart和YAML清单之类的Kubernetes工件。

容器在打包应用程序方面非常流行,因为它们解决了依赖关系管理问题。打包在容器中的应用程序包括所有必要的运行时依赖项,因此可以跨执行平台移植。换句话说,如果它能在我的机器上工作,它很可能也能在你的机器上工作。

自动化测试在DevOps中是普遍存在的,我们应该将我们的测试打包,就像我们打包我们的应用程序一样:如果某个测试在我的机器上可靠地验证,那么它在你的机器上也应该同样有效,不管你本地安装了哪些库和工具。

测试用的容器

下图演示了一个流水线(或者可能是两个,取决于你组织流水线的方式),上面的部分在容器中构建并打包应用程序,下面的部分对将用于验证应用程序的测试进行相同的操作。只有在基于容器的测试通过时,应用程序才会得到提升。

如果我们假设应用程序是一个网络附加服务,黑盒测试可以通过网络连接执行,像上面这样的设置很容易通过以下方式实现:

  1. 构建应用程序和测试容器,例如使用“docker Build…”
  2. 启动连接到网络的应用程序容器的实例,例如“docker run…”
  3. 启动与应用程序连接到同一网络的测试容器实例,例如“docker run…”
  4. 测试容器的退出代码决定了应用程序测试结果

如下图所示。

上面列出的步骤2到4也可以用docker-compose定义描述,其中包含两个服务,例如(测试容器通过环境变量配置应用程序网络位置):

代码语言:javascript
复制
version: '3.7'
    services:
    test:
      image: test-container:latest
      environment:
        APPLICATION_URL: http://application:8080
    depends_on:
      - application
    application:
      image: application:latest
      ports:
        - 8080:8080

使用两个容器的测试现在可以执行:

代码语言:javascript
复制
docker-compose up --exit-code-from test

在CI流水线中测试Kubernetes工件

上面描述的过程对于“容器级别”的测试非常有效。但是,如果CI流水线的输出工件包括Kubernetes工件,例如YAML清单或Helm chart,或者需要部署到Kubernetes集群中进行验证,该怎么办呢?我们如何在这些情况下进行测试?

一种选择是部署一个Kubernetes集群,CI流水线可以部署到这个集群上。然而,这给了我们一些问题需要考虑:

  • 所有CI流水线都可以部署的共享集群基本上成为一个多租户集群,可能需要仔细考虑隔离、安全性和健壮性。
  • 我们如何确定CI Kubernetes集群的大小?最有可能的情况是,集群容量将与CI worker容量断开连接,即它们不能共享计算资源。这将导致低利用率。另外,我们不能将CI集群设置得太小,因为我们不希望由于其他流水线临时消耗资源而导致测试失败。
  • 我们可能想要测试我们的Kubernetes工件在不同版本和配置的Kubernetes,也就是说,我们基本上需要N个CI集群可用。

我们还可以根据需要为每个CI作业创建Kubernetes集群。这就要求:

  • 访问类似云的平台,可以在其中动态提供Kubernetes集群。
  • 我们的CI流水线拥有创建基础设施所需的特权,从安全性的角度来看,这可能是不希望的。

对于某些测试场景,我们需要一个类似于生产的集群,我们将不得不考虑上述解决方案之一,例如特征测试或可伸缩性测试。然而,在许多情况下,我们希望CI流水线执行的测试可以在单个CI工作节点的能力范围内进行管理。下面的部分描述如何在具有容器功能的CI工作节点上创建按需集群。

使用KIND的按需私有Kubernetes集群

Kubernetes-in-Docker(KIND)是使用Docker-in-Docker(DIND)技术实现的Kubernetes集群。Docker-in-docker意味着我们可以在容器内运行容器,而那些内部容器只在外部容器内可见。KIND使用它通过使用外部容器实现Kubernetes集群节点来实现集群。当在节点上启动Kubernetes POD时,它是通过外部节点容器中的容器实现的。

通过KIND,我们可以在CI工作节点的容器功能之上创建按需和多节点的Kubernetes集群。

一个KIND Kubernetes集群

集群容量显然将受到CI工作节点容量的限制,但除此之外,Kubernetes集群将具有生产集群的许多功能,包括HA功能。

让我们演示如何测试用Helm部署到一类集群的应用程序。这个应用程序是k8s-sentence-age应用程序,可以在Github上找到,包括一个Github action,它实现了本博客中描述的CI流水线。该应用程序是一个简单的服务,可以返回0到100之间的随机数(年龄),并提供适当的Prometheus兼容指标。

安装KIND

KIND是一个单独的可执行文件,名为kind,它基本上与CI工作节点上的容器运行时通信。它将使用包含Kubernetes控制平面的容器镜像为集群中的每个节点创建一个(外部)容器。作为Github action的一部分安装kind的例子可以在这里找到。

https://github.com/praqma-training/k8s-sentences-age/blob/master/test/setup-kind.sh

创建一个集群

使用kind工具,我们的CI流水线可以创建一个单一节点Kubernetes集群,使用以下命令:

代码语言:javascript
复制
kind create cluster --wait 5m

如果我们的测试需要多节点集群,我们也可以创建它们。多节点集群需要一个列出节点角色的配置文件:

代码语言:javascript
复制
# config.yaml
  kind: Cluster
  apiVersion: kind.x-k8s.io/v1alpha4
  nodes:
  - role: control-plane
  - role: worker
  - role: worker

通过上面的配置文件,我们可以用下面的命令创建一个三节点集群:

代码语言:javascript
复制
kind create cluster --config config.yaml

我们可以指定Kubernetes节点应该使用的类型容器镜像,从而控制Kubernetes的版本:

代码语言:javascript
复制
kind create cluster --image "kindest/node:v1.16.4"

有了它,作为CI流水线的一部分,我们可以轻松地测试Kubernetes的多个版本的兼容性。

构建应用程序镜像并使它们供KIND使用

示例k8s-sentences-age应用程序打包在一个名为“age”的容器中,应用程序的测试打包在一个名为“age-test”的容器中。这些容器按照通常的方式建造如下:

代码语言:javascript
复制
docker build -t age:latest ../app
docker build -t age-test:latest .

我们可以通过以下命令将这些镜像的新版本提供给我们的KIND Kubernetes节点:

代码语言:javascript
复制
kind load docker-image age:latest
kind load docker-image age-test:latest

将镜像加载到KIND集群节点将镜像复制到集群中的每个节点。

运行一个测试

我们的流水线将使用它的Helm chart部署应用程序,并针对这个部署的应用程序实例运行测试。

使用应用程序Helm chart部署应用程序意味着,在部署到Kubernetes时,我们不仅要测试应用程序容器,而且还要验证Helm chart本身。Helm chart包含定义应用程序Kubernetes蓝图的YAML清单,这对于验证尤其重要——不仅针对不同版本的Kubernetes,而且在各种配置中,例如Helm chart的值的排列。

我们使用以下Helm命令安装应用程序。请注意,我们覆盖了镜像存储库、标签和pullPolicy的Helm chart默认设置,以便使用本地镜像。

代码语言:javascript
复制
helm install --wait age ../helm/age \
--set image.repository=age      \
--set image.tag=latest          \
--set image.pullPolicy=Never

测试容器使用Kubernetes Job资源部署。Kubernetes Job资源定义运行到完成并报告完成状态的工作负载。作业将使用我们之前构建的本地“age-test”容器镜像,并使用环境变量中提供的URL连接到应用程序POD。URL引用由Helm chart创建的Kubernetes服务。

代码语言:javascript
复制
apiVersion: batch/v1
kind: Job
metadata:
  name: component-test
spec:
  template:
    metadata:
      labels:
        type: component-test
    spec:
      containers:
      - name: component-test
        image: age-test
        imagePullPolicy: Never
        env:
        - name: SERVICE_URL
          value: http://age:8080
        - name: METRICS_URL
          value: http://age:8080/metrics
      restartPolicy: Never

使用以下命令部署作业:

代码语言:javascript
复制
kubectl apply -f k8s-component-test-job.yaml

检查测试结果

在检查结果之前,我们需要等待组件测试工作完成。kubectl工具允许在不同资源上等待各种条件,包括作业完成。例如,我们的流水线将通过以下命令等待测试完成:

代码语言:javascript
复制
kubectl wait --for=condition=complete \
--timeout=1m job/component-test

组件测试作业将测试结果作为其日志的一部分。为了将这些结果作为流水线输出的一部分,我们使用kubectl打印作业的日志,并使用标签选择器选择作业pod。

代码语言:javascript
复制
kubectl logs -l type=component-test

组件测试的总体状态从作业POD字段.status.succeeded读取,并存储在一个SUCCESS变量中,如下所示。如果状态指示失败,流水线终止并提供一个错误:

代码语言:javascript
复制
SUCCESS=$(kubectl get job component-test \
-o jsonpath='{.status.succeeded}')
if [ $SUCCESS != '1' ]; then exit 1; fi
echo "Component test successful"

完整的流水线可以在Github上的k8s-sentences-age库中找到。

这里值得注意的是,helm test的作用是启动测试工作并验证结果。Helm test是将测试正式集成到Helm chart中的一种方式,这样chart的用户就可以在安装chart后运行这些测试。因此,在Helm chart中包含测试,并提供测试容器给Helm chart的用户是很有意义的。要将上面的测试作业包含到Helm chart中,我们只需要添加如下所示的注释,并将YAML文件作为chart的一部分。

代码语言:javascript
复制
...
metadata:
  name: component-test
  annotations:
    "helm.sh/hook": test

当一个KIND集群不够时

在某些情况下,CI工作节点上的本地Kubernetes集群可能不适合你的测试目的。这可能是:

  • 单元测试有调用函数,例如使用应用程序中的类。在这种情况下,应用程序和测试很可能是一个单独的容器,可以在没有Kubernetes的情况下执行。
  • 组件测试不涉及kubernetes相关的工件。如果上面显示的示例没有要测试的Helm chart,那么docker-compose解决方案就足够了。
  • 测试包括特性测试,例如测量应用程序的性能和可伸缩性。在这种情况下,就容量而言,你需要更稳定的基础设施。
  • 依赖于其他构件的集成测试不容易部署到本地类集群中,比如带有客户数据的大型数据库。
  • 功能、集成或验收测试需要部署整个“应用程序”。有些应用程序可能不适合这种有限的集群大小。
  • 有外部依赖的测试,例如云提供商特定入口/负载平衡、存储解决方案、密钥管理服务等。在某些情况下,可以通过在类集群上部署数据库来模拟这些情况,而在其他情况下则不能。

然而,在很多情况下,使用某种Kubernetes集群进行测试是理想的,例如,当你有Kubernetes相关的工件需要测试,如Helm chart或YAML清单,以及外部CI/staging Kubernetes集群涉及太多维护开销或资源效率低的情况下。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CNCF 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档