对比
在维护 Kubernetes 过程中,一开始是直接使用 kubectl
编辑集群资源,但毕竟需要归档编排,那么就需要一个配置管理工具。一开始尝试使用 Helm,但尝试过后发现我的使用场景并不适合 Helm。后来发现 Kustomize,那么先对比一下两款工具:
- Helm 依赖服务端(tiller),Kustomize 专注于本地渲染
- Helm 的配置可读性差(go-template),但大部分用户不需要关心 template,只需要更改 values 即可
- Helm 通过 tiller 有完整声明周期管理,Kustomize 只能通过 Git 追踪变更
- Helm 可以进行依赖管理
- Kustomize 本质是 Kubernetes 的 Yaml 语法,并且增加 Patch、Generator、Transformer 等功能
- Helm 打包的 Chart 易于分发,可做私有 Repository
- Helm的其他问题:参考
如果是需要对外发布应用,Helm Chart 可以帮助用户远离复杂性,只需要关心能够配置的参数即可,这种模式非常利于分发。
而如果是业务应用,特别是自运维场景下,更为轻量级的 Kustomize 可能更为实用,与 Kubernetes Yaml 一致的语法能够让研发人员快速编排,与 Git 结合可以快速变更应用或者 Fork 出一个新版本,overlay 则能够有效地管理不同环境。
使用
在 Kubernetes v1.14 之后,kustomize 成为 kubectl 的子命令,但这里还是推荐安装完整 kustomize,比 kubectl 提供更完善的特性支持。
# 如 brew
brew install kustomize
环境管理
Domain 划分
首先初始化 Git 仓库:git init
,第一层根据 Namesapce 以及通用资源划分目录(比如业务服务、基础服务、K8S集群资源),第二层根据资源以文件夹区分。
.
├── app
│ ├── app1
│ └── app2
├── base
│ ├── postgres
│ ├── rabbitmq
│ └── redis
├── ingress
├── monitering
│ ├── fluent-bit
│ └── prometheus
├── secrets
│ ├── docker-registry
└── storage
└── rook-ceph
应用编排
比如现在有一个以 Deployment 形式部署的服务,按照 Kustomize 建议划分 base 和 overlays 层。
- base 层定义基础配置
- overlays 层根据不同环境 override 基础配置
.
├── README.md
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── production
│ ├── deployment.yaml
│ └── kustomization.yaml
└── staging
├── deployment.yaml
└── kustomization.yaml
定义一个基础 Deployment:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: app1
spec:
replicas: 1 # production 中 override 到合适副本
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: api
image: registry.com/app1:latest
ports:
- containerPort: 80
env:
- name: DEBUG
value: "false"
在 overlay 中定义一个对应的 patch,并根据迭代在不同环境配置对应 image 版本号:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
patchesStrategicMerge:
- deployment.yaml
images:
- name: registry.com/app1
newTag: v1.0.0 # v1.2.3 不同环境配置不同版本号
多次继承
这里用一个定时任务来举例说明:现在我们有一个 CLI 应用,我们需要利用 Kubernetes 的 CronJob 去定时驱动,并且这个应用可根据参数执行不同的任务。如果只是按照上面的简单分两层,那我们需要定义多个独立的 CronJob。那如何解决这个问题,这里利用到了 kustomization 配置是不限层级继承的特性。
.
├── base
│ ├── cronjobs
│ │ ├── job1
│ │ │ ├── kustomization.yaml
│ │ │ └── patch.yaml
│ │ ├── job2
│ │ │ ├── kustomization.yaml
│ │ │ └── patch.yaml
│ │ └── kustomization.yaml
│ └── kustomization.yaml
├── cronjobs
│ ├── base.yaml
│ └── kustomization.yaml
└── overlays
├── production
│ ├── configmap.yaml
│ └── kustomization.yaml
└── staging
首先定义这类定时任务的基本定义(cronjobs/base.yaml
):
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: schedule # 任务名称
spec:
concurrencyPolicy: Forbid
schedule: "0 0 * * *"
successfulJobsHistoryLimit: 0
failedJobsHistoryLimit: 2
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: registry.com/cli:latest
args:
- run
- echo
volumeMounts:
- mountPath: /app/job.yaml
subPath: job.yaml
name: config
volumes:
- name: config
configMap:
name: job-config
然后在 base/cronjobs/
下定义多个独立任务。如果不 patch 资源的名称,则注意需要使用 nameSuffix
或 namePrefix
为每个独立任务配置独立的 name
。
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
nameSuffix: -my-job1 # 最终生成的名称为 schedule-my-job1
bases:
- ../../../cronjobs
patchesJson6902:
- target:
group: batch
version: v1beta1
kind: CronJob
name: schedule
path: patch.yaml
# patch.yaml
- op: replace # patch cron
path: /spec/schedule
value: "0 1 */1 * *"
- op: replace # patch args
path: /spec/jobTemplate/spec/template/spec/containers/0/args
value:
- run
- job1
由于每个独立任务还需要更改容器启动 Args 与定时时间,与上一个应用编排的例子不一样,由于本例需要 Patch 的内容更少,且层级更深,如果使用 patchesStrategicMerge 描述资源 override 则非常冗长,所以使用 JSON Patch(可以用 Yaml 格式)。
到此就可以生成多个独立 CronJob,然后再加上 overlay 根据不同环境定义 ConfigMap。
Generator
以 Secret Generator 从明文生成密码为例:
generatorOptions:
disableNameSuffixHash: true
secretGenerator:
- name: mysecret
namespace: ns1
literals: &secret
- user=the-user-name
- name: rabbitmq
namespace: ns2
literals:
*secret
如果需要固定生成资源的名称则需要将 disableNameSuffixHash
设置为 true
,否则生成资源的名称会如下带有 hash 后缀。目前 Generator 仍有一个问题,就是同时需要生成同样的资源在不同 Namespace 的场景,语法上并没有给出解决方案,目前只能通过 Yaml 锚点解决。
secret/mysecret-dddghtt9b5 created
你甚至可以定义 Generator 来对 Helm Chart 进行修改。
配置继承
由于 Kustomize 这种配置分层结构,是可以继承外部配置,然后作出自己的定制修改。思路就是使用 Git Submodule 作为 base 层,overlays 做自己的定制层,随时跟踪上游的变更。
git submodule add https://example.com/repo.git base
mkdir -p overlays/customization-one
mkdir -p overlays/customization-two
检查配置 && 应用
# 检查
kustomize build app1/overlays/staging | less
# 应用
kustomize build app1/overlays/staging | kubectl apply -f -
另外一个选择
如果项目是需要部署到多种云上,并且可能需要交付的,那么还有另外一种选择:Terraform,可以对接多种云提供商(Provider),将云端资源代码化(Infrastructure as Code)。而且 Terraform 有自己的 DSL(HCL),用户编写时甚至不需要关心了解 Kubernetes 许多概念(configmap、secret)。