Kustomize 入门:用 Base 和 Overlay 管理 Kubernetes 多环境配置
来源与版本边界
本文由《Kustomize 入门:用 Base 和 Overlay 管理 Kubernetes 多环境配置》一文清洗整理。字段支持情况取决于独立 Kustomize 与 kubectl 内置版本;新项目优先使用 resources、labels 和统一的 patches 字段,遇到兼容问题先执行 kubectl version --client 并核对对应版本文档。
在学习 Kubernetes 时,我们通常会先编写 deployment.yaml 、 service.yaml 等资源清单。
当只有一个环境时,这种方式没有什么问题。但随着测试环境、预发布环境和生产环境逐渐增加,一个新的问题就出现了:不同环境的大部分配置相同,只有少量内容不一样。
例如,测试环境和生产环境可能只有以下差异:
- Namespace 不同;
- 镜像仓库或镜像版本不同;
- Deployment 副本数不同;
- 环境标签不同;
- CPU、内存等资源限制不同。
最直接的做法,是为每个环境复制一套完整的 YAML。但是随着项目迭代,这种方式很容易出现配置不一致的问题。
例如,Deployment 新增了健康检查,如果只修改了测试环境的 YAML,却忘记同步修改生产环境,那么两套配置就会逐渐产生偏差。
Kustomize 要解决的,正是这个问题:
保留一份公共 Kubernetes 配置,只单独描述不同环境之间的差异。
一、Kustomize 是什么
Kustomize 是一个用于定制 Kubernetes 配置的工具。
它可以读取普通的 Kubernetes YAML,然后根据 kustomization.yaml 中声明的规则,对资源进行组合和修改,最终生成一份新的 Kubernetes YAML。
整个过程可以简单理解为:
原始 Kubernetes YAML
+
kustomization.yaml 中的定制规则
↓
最终 Kubernetes YAML
Kustomize 官方将这种方式称为“template-free”,也就是不依赖传统模板。
例如,使用模板工具时,可能会在 YAML 中写入变量占位符:
image: ${IMAGE_NAME}:${IMAGE_TAG}
而 Kustomize 通常保留正常的 Kubernetes YAML:
image: nginx:latest
然后在 kustomization.yaml 中使用 images 、 replicas 、 namespace 、 labels 、 patches 等字段对它进行修改。
这样做的一个好处是:Base 中的 YAML 仍然是普通的 Kubernetes YAML,不需要先替换变量才能阅读和分析。
Kustomize 可以作为独立命令使用,也已经集成进 kubectl 。根据 Kubernetes 官方文档, kubectl 从 1.14 版本开始支持通过 Kustomize 管理 Kubernetes 对象,因此已经安装 kubectl 的情况下,通常可以直接使用:
kubectl kustomize <目录>
kubectl apply -k <目录>
本文主要介绍 kubectl 内置的使用方式。
二、Kustomize 不是什么
在继续学习之前,需要先明确 Kustomize 的能力边界。
1. Kustomize 不是 Kubernetes 控制器
Kustomize 通常在客户端执行。
运行下面的命令时:
kubectl kustomize overlays/test
Kustomize 只会读取本地文件、执行定制规则,并把最终 YAML 输出到终端,不会在 Kubernetes 集群中创建资源。
只有继续执行 kubectl apply -k ,生成的资源才会被提交给 Kubernetes API Server。
2. Kustomize 不是传统模板引擎
Kustomize 的主要思路不是在 YAML 中预留变量,然后用参数替换字符串,而是对 Kubernetes 资源进行结构化修改。
例如:
- 使用
images修改镜像; - 使用
replicas修改副本数; - 使用
namespace设置命名空间; - 使用
patches修改资源限制。
3. Kustomize 不是 Release 管理器
Kustomize 负责生成最终 Kubernetes 配置,但它本身不会像 Helm 一样维护 Release、Release 历史和回滚记录。
因此,Kustomize 和 Helm 并不是完全相同的工具,本文不展开二者的详细比较。
三、Kustomize 的核心思路:Base 和 Overlay
学习 Kustomize,最重要的是理解 Base 和 Overlay。
1. Base:公共配置
Base 保存多个环境共同使用的 Kubernetes 配置。
例如,测试环境和生产环境都需要以下资源:
- Deployment;
- Service;
- 相同的容器端口;
- 相同的健康检查;
- 相同的 Volume 挂载;
- 相同的应用标签和 Selector。
这些真正公共、相对稳定的内容,可以统一放在 Base 中。
一个简单的 Base 目录如下:
base/
├── deployment.yaml
├── service.yaml
└── kustomization.yaml
其中:
deployment.yaml:定义应用工作负载;service.yaml:定义集群内部访问方式;kustomization.yaml:声明 Base 中包含哪些资源。
2. Overlay:环境差异
Overlay 在 Base 的基础上继续定制配置。
例如:
- Test Overlay 设置测试环境的 Namespace;
- Prod Overlay 设置生产环境的 Namespace;
- 测试环境使用 1 个副本;
- 生产环境使用 3 个副本;
- 测试和生产使用不同的镜像版本;
- 生产环境设置更高的 CPU 和内存限制。
一个常见的项目目录如下:
kustomize-demo/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── test/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml
它们之间的关系可以理解为:
Base 公共配置
+
Test Overlay 环境差异
↓
测试环境最终 YAML
以及:
Base 公共配置
+
Prod Overlay 环境差异
↓
生产环境最终 YAML
Base 不需要知道有哪些 Overlay。测试和生产 Overlay 可以分别引用同一个 Base,然后生成各自的最终配置。
需要注意的是,Base 和 Overlay 都不是特殊的 Kubernetes 资源类型。它们本质上都是包含 kustomization.yaml 的配置目录,只是承担的职责不同:
- Base:提供公共配置;
- Overlay:引用 Base,并描述环境差异。
还有一个容易混淆的地方:
Base 是 Kustomize 中的一个概念,但现在不建议在
kustomization.yaml中继续使用旧的bases字段。
当前推荐使用 resources 引用 Base:
resources:
- ../../base
Kustomize 官方代码已经将 bases 标记为弃用字段,并建议迁移到 resources 。
四、kustomization.yaml 是干什么的
kustomization.yaml 是 Kustomize 的核心配置文件。
它主要用来说明:
- 需要读取哪些 Kubernetes 资源;
- 需要引用哪些 Base;
- 需要生成哪些资源;
- 需要对资源进行哪些修改。
推荐使用下面的完整头部:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
这里的 apiVersion 和 kind 描述的是 Kustomize 配置格式,而不是要在 Kubernetes 集群中创建一个名为 Kustomization 的业务资源。
因此,不应该直接执行:
kubectl apply -f kustomization.yaml
因为 -f 会把这个文件当成普通 Kubernetes 资源提交给 API Server。
正确方式是使用 -k ,并让它指向包含 kustomization.yaml 的目录:
kubectl apply -k overlays/test
此时, kubectl 会先使用 Kustomize 构建该目录,再把构建结果提交给 Kubernetes API Server。
五、六个最常用的 Kustomize 字段
Kustomize 支持的字段很多,但初学阶段没有必要全部掌握。
对于常见的测试、生产多环境配置,建议先掌握以下六个字段:
| 字段 | 主要用途 |
|---|---|
resources |
引入 YAML 文件或其他 Kustomization 目录 |
namespace |
设置资源所属的 Namespace |
images |
修改镜像名称、Tag 或 Digest |
replicas |
修改工作负载副本数 |
labels |
为资源和 Pod 添加标签 |
patches |
修改其他复杂字段 |
下面分别介绍它们的作用。
1. resources:引入资源
假设 Base 目录中有两个资源文件:
base/
├── deployment.yaml
├── service.yaml
└── kustomization.yaml
那么 base/kustomization.yaml 可以写成:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
resources 表示当前 Kustomization 需要包含哪些资源。
它既可以引用普通 Kubernetes YAML:
resources:
- deployment.yaml
- service.yaml
也可以引用另一个包含 kustomization.yaml 的目录:
resources:
- ../../base
当 Overlay 引用 ../../base 时,Kustomize 会先构建 Base,再对 Base 生成的资源进行环境定制。
需要注意:
resources中的相对路径,以当前kustomization.yaml所在目录为基准,而不是以执行命令时所在的 Shell 目录为基准。
例如,当前文件位于:
overlays/test/kustomization.yaml
那么:
resources:
- ../../base
表示从 overlays/test 向上返回两级,然后进入项目根目录下的 base 。
2. namespace:设置资源所属的命名空间
测试和生产环境通常会使用不同的 Namespace:
namespace: kustomize-test
Kustomize 构建时,会给 Deployment、Service、ConfigMap 等命名空间作用域资源设置:
metadata:
namespace: kustomize-test
例如,Base 中的 Deployment 原来是:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-demo
构建后可能变成:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-demo
namespace: kustomize-test
但这里必须区分两个概念:
namespace: kustomize-test
表示把命名空间作用域资源放入 kustomize-test ,它不会自动创建这个 Namespace。
如果集群中还不存在该 Namespace,就需要额外提供一个 Namespace 资源:
apiVersion: v1
kind: Namespace
metadata:
name: kustomize-test
然后通过 resources 把它加入最终输出。
3. images:修改容器镜像
假设 Base 中的 Deployment 使用:
containers:
- name: web
image: nginx:latest
测试环境希望使用固定版本,可以在 Overlay 中写:
images:
- name: nginx
newTag: "1.27.4-alpine"
构建后,镜像会变成:
image: nginx:1.27.4-alpine
如果还需要修改镜像仓库地址,可以同时使用 newName :
images:
- name: nginx
newName: registry.example.com/library/nginx
newTag: "1.27.4-alpine"
构建结果为:
image: registry.example.com/library/nginx:1.27.4-alpine
这里最容易混淆的是 name 的匹配对象。
Base 中的配置是:
containers:
- name: web
image: nginx:latest
其中:
- 容器名称是
web; - 镜像名称是
nginx。
所以 images.name 应该写成:
name: nginx
它匹配的是 image: nginx:latest 中的镜像名称,而不是 containers[].name 。
还需要注意:
Kustomize 只负责修改 YAML 中的镜像字符串,不会连接镜像仓库检查这个 Tag 是否真实存在。
即使写了一个不存在的 Tag, kubectl kustomize 也可能正常生成 YAML。真正部署后,Kubelet 拉取不到镜像时,Pod 才会出现 ErrImagePull 或 ImagePullBackOff 。
4. replicas:修改副本数
假设 Base 中的 Deployment 为:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-demo
spec:
replicas: 1
生产环境需要 3 个副本,可以在 Overlay 中写:
replicas:
- name: kustomize-demo
count: 3
构建后:
spec:
replicas: 3
其中:
name:匹配资源的metadata.name;count:设置最终副本数。
这里的 name 不是容器名称,也不是镜像名称,而是 Deployment 等工作负载资源的名称。
replicas 适合处理简单的副本数差异。如果需要同时修改滚动更新策略、资源限制等复杂字段,则应该使用 patches 。
5. labels:添加环境标签
为了区分测试和生产环境,可以给资源添加环境标签:
labels:
- pairs:
environment: test
includeTemplates: true
includeSelectors: false
其中:
pairs:要添加的标签键值;includeTemplates: true:把标签加入 Deployment 等工作负载的 Pod Template;includeSelectors: false:不把标签加入 Deployment、Service 等资源的 Selector。
构建后,Deployment 自身可能得到:
metadata:
labels:
environment: test
Pod Template 也会得到:
spec:
template:
metadata:
labels:
environment: test
这样,Deployment 创建出来的 Pod 也会带有:
environment: test
可以通过下面的命令查询:
kubectl get pods -l environment=test
为什么示例中将 includeSelectors 设置为 false ?
因为 Selector 决定资源之间的匹配关系,例如:
- Deployment 通过 Selector 管理 Pod;
- Service 通过 Selector 选择后端 Pod。
环境、版本、发布批次等标签可能会发生变化,不适合随意加入已经存在资源的 Selector。尤其是 Deployment 的 Selector 创建后不能随意修改,否则可能导致资源更新失败。
因此,对于 environment: test 这类环境标识,通常可以加入资源和 Pod Template,但不必加入 Selector。
6. patches:修改其他复杂字段
namespace 、 images 、 replicas 等字段,适合处理常见且结构比较固定的修改。
如果需要修改以下内容:
- CPU 和内存 Requests、Limits;
- 环境变量;
- 探针;
- 节点选择器;
- 亲和性;
- 容忍度;
- 滚动更新策略;
通常可以使用 patches 。
例如,生产环境需要设置资源限制,可以创建:
overlays/prod/deployment-resources-patch.yaml
内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-demo
spec:
template:
spec:
containers:
- name: nginx
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
然后在生产环境的 kustomization.yaml 中引用:
patches:
- path: deployment-resources-patch.yaml
Kustomize 会找到名为 kustomize-demo 的 Deployment,并把补丁中的资源配置合并进去。
对于目标较多或者需要精确选择资源的场景,还可以显式指定 target :
patches:
- path: deployment-resources-patch.yaml
target:
group: apps
version: v1
kind: Deployment
name: kustomize-demo
初学阶段不需要一次掌握所有补丁格式,只需要先记住:
常见差异优先使用
images、replicas等专用字段,其他复杂差异再使用patches。
Kubernetes 官方文档还建议,一个补丁最好只完成一类修改。例如,副本数和内存限制可以分别使用两个小补丁,这样更容易阅读、审查和复用。
六、Kustomize 最终生成了什么
Kustomize 最终输出的不是特殊格式,而是一组普通 Kubernetes YAML。
假设测试环境配置位于:
overlays/test/
可以使用下面的命令构建:
kubectl kustomize overlays/test
这个命令会:
- 找到
overlays/test/kustomization.yaml; - 读取其中的
resources; - 构建引用的 Base;
- 应用
namespace、images、replicas、labels和patches; - 把最终 Kubernetes YAML 输出到终端。
它不会在集群中创建任何资源。
如果想查看构建结果与集群当前资源的差异,可以执行:
kubectl diff -k overlays/test
如果确认结果没有问题,再执行:
kubectl apply -k overlays/test
可以把这三个命令记成:
kubectl kustomize = 生成并查看
kubectl diff -k = 比较差异
kubectl apply -k = 构建并部署
还需要区分 -f 和 -k :
kubectl apply -f deployment.yaml
-f 表示直接读取 Kubernetes 资源文件。
kubectl apply -k overlays/test
-k 表示先构建包含 kustomization.yaml 的目录,再应用生成的资源。
根据 Kubernetes 官方命令参考, kubectl kustomize 的参数应该是包含 kustomization.yaml 的目录,或者符合要求的远程 Git 地址。
七、初学 Kustomize 应该记住的三个原则
1. Base 只保存真正公共的配置
Base 中适合保存:
- Deployment、Service 的基本结构;
- 稳定的资源名称;
- 稳定的应用标签和 Selector;
- 容器端口;
- 健康检查;
- 公共的 Volume 配置。
不要把明显属于某个环境的配置强行放进 Base。
2. Overlay 只描述环境差异
Overlay 中适合保存:
- Namespace;
- 镜像仓库和镜像版本;
- 副本数;
- 环境标签;
- CPU、内存资源限制;
- 环境变量;
- 节点调度规则。
如果 Test Overlay 和 Prod Overlay 中出现了大量完全相同的内容,通常说明这些内容可能应该上移到 Base。
3. 部署前先检查构建结果
推荐按照下面的顺序操作:
kubectl kustomize overlays/test
kubectl diff -k overlays/test
kubectl apply -k overlays/test
先确认 Kustomize 最终生成了什么,再把配置应用到集群。
八、版本和字段使用说明
本文使用的是当前推荐写法:
- 使用
resources,不使用已经弃用的bases; - 使用
labels,不使用已经弃用的commonLabels; - 使用
patches,不使用已经弃用的patchesStrategicMerge; - 使用
patches,不使用已经弃用的patchesJson6902。
这些旧字段可能仍然可以在部分版本中运行,但新项目应优先使用当前推荐字段。
另外, kubectl 内置的 Kustomize 与独立安装的 Kustomize 可能不是同一个版本。可以通过下面的命令查看当前客户端信息:
kubectl version --client
遇到某个字段无法识别时,应先确认当前 kubectl 内置的 Kustomize 版本是否支持该字段。
九、总结
Kustomize 的核心并不是简单地减少 YAML 行数,而是把 Kubernetes 配置拆分成两个部分:
Base = 多个环境共同使用的公共配置
Overlay = 不同环境之间的配置差异
然后通过 kustomization.yaml 告诉 Kustomize:
resources = 读取哪些资源
namespace = 资源属于哪个命名空间
images = 使用哪个镜像
replicas = 运行多少个副本
labels = 添加哪些标签
patches = 修改哪些复杂字段
最终再通过:
kubectl kustomize overlays/test
生成普通的 Kubernetes YAML。
一句话总结:
Kustomize 通过 Base 复用公共配置,通过 Overlay 描述环境差异,在不修改原始 YAML 的情况下生成测试、生产等环境的最终 Kubernetes 配置。
相关阅读
- K8s 配置定制工具 Kustomize:覆盖 Kustomize 基础用法、生成器与更多进阶特性;其中部分旧字段应结合本文的版本说明辨别。
- Kustomize 实体页