将应用程序部署到 Kubernetes 上并不容易,我们需要部署 Deployment 的 Pod,并在 Service 中定义可访问性。所有的这些资源都需要 YAML 文件才能正确定义和配置。
其中有一点很重要,应用程序可能需要与数据库进行通信、管理 Web 内容以及设置日志记录。此外,这些参数会由于部署环境的不同而有所不同。以上这些都可能导致 YAML 定义的代码库泛滥,每个代码都有一两行更改,以至于很难查明。
Kustomize 就是用于帮助解决这些问题的开源配置管理工具。从 Kubernetes v1.14 开始,kubectl 就完全支持 Kustomize 和 kustomization 文件。
本文将构建一个小型 Web 应用程序,然后使用 Kustomize 管理配置扩展,并使用不同的配置将应用程序部署到开发和生产环境。另外,本文还介绍了使用 Kustomize 的 Base 和 Overlay 对这些变量配置进行分层,使代码易于阅读,从而更易于维护。
K8sMeetup
先决条件
首先,我们需要:
- 连接 Kubernetes v1.14 以上的集群,设置 kubectl 默认值。
- 将 kubectl 安装在本地计算机上。
K8sMeetup
第 1 步 不用 Kustomize 部署应用程序
在使用 Kustomize 部署应用程序之前,我们首先使用传统方式进行部署。在这种情况下,我们先部署 sammy-app 开发版本,这是一个 Nginx 上 托管的静态 Web 应用程序,再将 Web 内容作为数据存储在 ConfigMap 中,并安装在 Deployment 中的 Pod 上。这里每一个都需要单独的 YAML 文件,我们接着创建该文件。
首先为应用程序及其所有配置文件创建一个文件夹。后续我们在此处运行本文的所有命令。在主目录中创建一个新文件夹:
- $ mkdir ~/sammy-app && cd ~/sammy-app
现在,使用文本编辑器来创建并打开一个名为 configmap.yml 的文件:
- $ nano configmap.yml
添加以下内容:
~/sammy-app/configmap.yml
这将创建一个新的 ConfigMap 对象,将其命名为 sammy-app,然后在 data: 中存储一些 HTML Web 内容。
保存并关闭文件。
创建并打开另一个 deployment.yml 文件:
- $ nano deployment.yml
添加以下内容:
~/sammy-app/deployment.yml
这将创建一个新的 Deployment 对象,添加的名称和标签为 sammy-app,副本数设置为 1,指定要使用的对象是 Nginx v1.17 容器镜像。另外,容器端口设置为 80,CPU 和内存请求和限制也定义,日志记录级别设置为 DEBUG。
保存并关闭文件。
现在这两个文件都有部署到 Kubernetes 集群中。下面要创建多个对象,将 cat 命令通过管道传递给 kubectl:
- $ cat configmap.yml deployment.yml | kubectl apply -f -
稍等一下,然后使用 kubectl 来检查应用程序的状态:
- $ kubectl get pods -l app=sammy-app
最终,我们将在 READY 列中看到一个 Pod 和应用程序正在运行,以及 1/1 容器:
Pod 正在运行并由 Deployment 支持,但是我们仍然无法访问应用程序。首先,我们需要添加 Service。
创建并打开第三个 YAML 文件,它是 service.yml:
- $ nano service.yml
添加以下内容:
~/sammy-app/service.yml
这创建了一个名为 sammy-app 的新 Service 对象。对于大多数云提供商,设置 spec.type 为 LoadBalancer 会预配负载均衡器。spec.ports 会把将以带有标签的任何Pod为目标TCP端口。
spec.ports 将把 TCP 80 端口作为任何带有 sammy-app 标签的 Pod 目标。
保存并关闭文件。
现在将 Service 部署到 Kubernetes 集群中:
- $ kubectl apply -f service.yml
稍等片刻,再使用 kubectl 检查应用程序状态:
- $ kubectl get services -w
最终,EXTERNAL-IP 列下将为 Service 显示一个公共 IP,唯一 IP 在 your_external_ip 这里:
复制显示的 IP 地址,并将其输入到 Web 浏览器中,我们可以看到 DEVELOPMENT 应用程序的版本。
在终端上,使用 CTRL + C 可以停止观看 Service。
在该步骤中,我们将 sammy-app 开发版本部署到 Kubernetes。在步骤 2 和 3 中,本文将使用 Kustomize 来重新部署 sammy-app 开发版本,然后部署配置略有不同的生产版本。使用这个新的工作流程,我们可以看到 Kustomize 是如何更好地管理配置更改并简化开发工作流程的。
K8sMeetup
第 2 步 使用 Kustomize 部署应用程序
在该步骤中,我们将部署完全相同的应用程序,但以 Kustomize 而不是默认的 Kubernetes 方式进行的。
现在文件系统当前如下所示:
要使此应用程序可通过 Kustomize 进行部署,我们需要添加一个 kustomization.yml 文件:
- $ nano kustomization.yml
该文件要指定使用 kubectl -k 时管理的资源,这用于 kubectl 处理 kustomation 文件。
添加以下内容:
~/sammy-app/kustomization.yml
保存并关闭文件。
在再次部署之前,要删除步骤 1 中现有的 Kubernetes 资源:
- $ kubectl delete deployment/sammy-app service/sammy-app configmap/sammy-app
然后再次部署它们,但是这次使用 Kustomize:
- $ kubectl apply -k .
这里不使用 kubectl -f 来指导 Kubernetes 从文件创建资源,而是使用 -k 和一个目录(在本例中,. 表示当前目录),这将通过 kubectl 使用 Kustomize 并检查该目录的 kustomization.yml。
这里会创建所有三个资源:ConfigMap、Deployment 和 Service。使用 get pods 命令检查 Deployment:
- $ kubectl get pods -l app=sammy-app
我们将在 READY 列中再次看到一个 Pod,其中包含正在运行的应用程序和 1/1 容器。
重新运行 get services 命令,我们还将通过公开访问的 EXTERNAL-IP 看到 Service:
- $ kubectl get services -l app=sammy-app
现在,我们已成功使用 Kustomize 管理 Kubernetes 配置。在下一步中,本文使用略有不同的配置部署 sammy-app 到生产环境,并通过 Kustomize 管理这些差异。
K8sMeetup
第 3 步 使用 Kustomize 管理应用程序
一旦开始处理多种资源类型,Kubernetes 资源的配置文件就会真正开始泛滥,尤其是当环境之间的差异很小时,例如开发与生产环境。我们可能有个 deployment-development.yml 和 deployment-production.yml 文件,但不是 deployment.yml。
想象一下,当发布新版本的 Nginx Docker 镜像时,我们开始使用时会发生什么?也许我们在 deployment-development.yml 中测试了新版本,并想继续,但后面忘记了使用 deployment-production.yml 进行新版本更新。因此,我们可能在开发环境中运行的 Nginx 版本与在生产中运行的版本不同。诸如此类的配置错误可能会破坏我们的应用程序。
Kustomize 可以大大简化这些管理问题。现在我们有一个包含 Kubernetes 配置文件和一个 kustomization.yml 文件的文件系统:
我们现在准备部署 sammy-app 到生产环境中,另外还想让应用程序的生产版本与开发版本在以下方面有所不同:
- replicas 从 1 增加至 3。
- 容器资源 requests 从 100m CPU 和 128M 内存增加到 250m CPU 和 256M 内存。
- 容器资源 limits 将从 100m CPU 和 256M 内存增加到 1 CPU 和 1G 内存。
- LOG_LEVEL 环境变量从 DEBUG 更改为 INFO。
- ConfigMap 数据更改为显示不同的 Web 内容。
首先,创建新目录以用于 Kustomize 方式组织事物:
- $ mkdir base
这将保留“默认”配置 Base。在示例中,这是 sammy-app 开发版本。
现在将当前的 sammy-app/ 配置移到该目录中:
- $ mv configmap.yml deployment.yml service.yml kustomization.yml base/
然后为生产环境配置创建一个新目录。Kustomize 将此称为 Overlay。Overlay 可以视为 Base 之上的图层,它们需要 Base 才能发挥作用:
- $ mkdir -p overlays/production
创建另一个 kustomization.yml 文件以定义生产环境 Overlay:
- $ nano overlays/production/kustomization.yml
添加以下内容:
~/sammy-app/overlays/production/kustomization.yml
该文件将为 Overlay 指定一个 Base,以及 Kubernetes 将使用哪些策略修补资源。此示例指定了一个 strategic-merge-style patch(SMP)以更新 ConfigMap 和 Deployment 资源。
保存并关闭文件。
最后,将 new deployment.yml 和 configmap.ymlfiles 添加到 overlays/production/ 目录中。
首先创建新 deployment.yml 文件:
- $ nano overlays/production/deployment.yml
将以下内容添加到文件中:
~/sammy-app/overlays/production/deployment.yml
注意该新 deployment.yml 的内容。它仅包含 TypeMeta 标识已更改资源的字段(在本例中是应用程序的 Deployment ),剩余的字段将进入嵌套结构以指定新的字段值,例如容器资源请求和限制(request 和 limit)。
保存并关闭文件。
现在为生产环境 overlay 创建一个新的 configmap.yml:
- nano /overlays/production/configmap.yml
添加以下内容:
~/sammy-app/overlays/production/configmap.yml
这里将文本更改为显示 PRODUCTION 而不是 DEVELOPMENT,另外还将文本颜色从红色调 #f22 改为蓝色 #22f。如果不使用 Kustomize 这样的配置管理工具,查找和跟踪这样的细微变化会非常麻烦。
目录结构现在如下所示:
下面准备使用基本配置进行部署,首先,删除现有资源:
- $ kubectl delete deployment/sammy-app service/sammy-app configmap/sammy-app
将基本配置部署到 Kubernetes:
- $ kubectl apply -k base/
检查 Deployment:
- $ kubectl get pods,services -l app=sammy-app
现在可以看到预期的基本配置,开发版本可以在 Service EXTERNAL-IP 上看到:
现在部署生产配置:
- $ kubectl apply -k overlays/production/
再次检查 Deployment:
- $ kubectl get pods,services -l app=sammy-app
我们将看到预期的 production 配置,并且 Service EXTERNAL-IP 上将显示生产版本:
请注意,在生产配置中,总共有 3 个 Pod,而不是 1 个。我们可以查看 Deployment 资源以确认小的更改也已生效:
- $ kubectl get deployments -l app=sammy-app -o yaml
在浏览器中访问 your_external_ip 以查看网站的生产版本。
现在我们正在使用 Kustomize 管理应用程序差异。回想一下原始问题之一,如果现在想更改 Nginx 镜像版本,则只需在 Base 中的 deployment.yml 进行修改,并且使用该 Base 的 Overlay 也将通过 Kustomize 接收该更改。这大大简化了开发工作流程,提高了可读性,并减少了出错的可能性。
K8sMeetup
结论
本文构建了一个小型 Web 应用程序并将其部署到 Kubernetes 中,然后使用 Kustomize 简化了针对不同环境的应用程序配置的管理。我们将一组几乎重复的 YAML 文件重组为一个分层模型,这将减少错误,减少手动配置,并使代码更易于识别和维护。