将应用部署到 Kubernetes 中的方式有很多,目前主流是就是使用 kubectl
和 Helm
,不过其先决条件都需要 YAML 清单文件。
不同由于部署环境的多样化,比如有开发环境、测试环境、预生产环境、生产环境,我们就会针对不同的环境定制各种 YAML 文件,但是在很多情况下同一个应用在不同的环境可能只做了简单的更改,这样就会导致 YAML 泛滥。
而 **Kustomize 就是用于帮助解决这些问题的开源配置管理工具。** 从 Kubernetes v1.14 开始,kubectl 就完全支持 Kustomize 和 kustomization 文件。
kustomize 是什么?
kustomize
lets you customize raw, template-free YAML files for multiple purposes, leaving the original YAML untouched and usable as is.
上面是官方对于 kustomize 的定义。大致是说:kustomize 允许您自定义无模板的原始 YAML 文件来用于多种目的,而原始的 YAML 则保持不变并可以使用。
kustomize 的作用
当我们在 K8S 中有多套环境的时候,就会面临如下问题:
- 多环境多团队多个 YAML 资源清单
- 不同环境差异微小,但是不得不 copy and change
- helm 稍显复杂,需要额外的学习投入
而 kustomize 可以很好的解决这些问题:
- kustomize 通过 Base & Overlays 方式方式维护不同环境的应用配置
- kustomize 使用 patch 方式复用 Base 配置,并在 Overlay 描述与 Base 应用配置的差异部分来实现资源复用
- kustomize 管理的都是 Kubernetes 原生 YAML 文件,不需要学习额外的 DSL 语法
安装
在 kubernetes 1.14 版本以上,已经集成到 kubectl 中了,你可以通过 kubectl --help
来进行查看命令。
如果需要额外安装,直接到 https://github.com/kubernetes-sigs/kustomize/releases 里进行下载对应的版本。
比如:
wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.8.7/kustomize_v3.8.7_linux_amd64.tar.gz
tar xf kustomize_v3.8.7_linux_amd64.tar.gz
cp kustomize/kustomize /usr/local/bin
这样就完成了简单的安装了。
实践测试
背景
- 版本信息
- kubernetes:1.17.9
- 集群信息,由于在一个环境中进行测试,所以采用不同的 namespace 进行分开
- 开发环境:dev
- 预发环境:stag
- 生产环境:prod
- 测试用例:一个简单的 hello world 示例
创建基础模板
首先创建一个 helloworld 目录,表示应用,然后在里面创建一个 base 目录,如下:
mkdir helloworld/base -p
然后在 base 目录下创建以下配置清单:
base/
├── configMap.yaml
├── deployment.yaml
├── ingress.yaml
├── kustomization.yaml
└── service.yaml
他们的清单内容分别如下:
configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
namespace: default
data:
altGreeting: "Hello World!"
enableRisky: "false"
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
namespace: default
spec:
replicas: 3
selector:
matchLabels:
deployment: hello
template:
metadata:
labels:
deployment: hello
spec:
containers:
- name: the-container
image: monopole/hello:1
command: ["/hello",
"--port=8080",
"--enableRiskyFeature=$(ENABLE_RISKY)"]
ports:
- containerPort: 8080
env:
- name: ALT_GREETING
valueFrom:
configMapKeyRef:
name: the-map
key: altGreeting
- name: ENABLE_RISKY
valueFrom:
configMapKeyRef:
name: the-map
key: enableRisky
service.yaml
kind: Service
apiVersion: v1
metadata:
name: the-service
namespace: default
spec:
selector:
deployment: hello
type: NodePort
ports:
- protocol: TCP
port: 8080
targetPort: 8080
ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: the-ingress
namespace: default
spec:
rules:
- host: test.coolops.cn
http:
paths:
- backend:
serviceName: the-service
servicePort: 8080
path: /
kustomization.yaml
# Example configuration for the webserver
# at https://github.com/monopole/hello
commonLabels:
app: hello
resources:
- deployment.yaml
- service.yaml
- configMap.yaml
- ingress.yaml
这样基础模板就创建好了,我们可以使用如下命令将所有文件连在一起。
kustomize build ../base
然后如果想创建应用可以用以下方式。
# 直接使用kubectl apply -k (集群版本要高于1.14)
kubectl apply -k ../base/
# 还可以通过kustomize命令
kustomize build ../base | kubectl apply -f -
删除应用命令类似,可以自行尝试。
根据不同环境创建 overlays
上面的是基础模板,所有的配置都是基于它,现在我们根据不同的环境进行定制。
首先创建如下目录结构
.
├── base
│ ├── configMap.yaml
│ ├── deployment.yaml
│ ├── ingress.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── dev
├── prod
└── stag
其中:
- dev 目录下存放开发环境定制清单
- stag 目录下存放预发环境定制清单
- prod 目录下存放生产环境定制清单
配置开发环境
在 dev 目录下创建以下文件:
../dev/
├── ingress.yaml
├── kustomization.yaml
└── map.yaml
其中 ingress.yaml 如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: the-ingress
namespace: default
spec:
rules:
- host: hello-dev.coolops.cn
http:
paths:
- backend:
serviceName: the-service
servicePort: 8080
path: /
map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Hello,This is Dev!"
enableRisky: "true"
kustomization.yaml
namePrefix: dev-
commonLabels:
org: acmeCorporation
variant: dev
commonAnnotations:
note: Hello, This is dev!
patchesStrategicMerge:
- map.yaml
- ingress.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: dev
开发环境更改了 configmap 的内容、ingress 的 host,还有 namespace。
然后可以通过 kustomize build .
测试配置是否正确。
配置预发环境
在 stag 目录下创建以下文件:
../stag/
├── kustomization.yaml
└── map.yaml
其中 map.yaml 内容如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Hello,This is Stag!"
enableRisky: "true"
kustomization.yaml
namePrefix: stag-
commonLabels:
org: acmeCorporation
variant: stag
commonAnnotations:
note: Hello, This is stag!
patchesStrategicMerge:
- map.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: stag
预发环境更改了 configmap 和 namespace。
配置生产环境
在 prod 目录下创建以下文件:
../prod/
├── deployment.yaml
├── kustomization.yaml
└── map.yaml
其中 deployment.yaml 配置如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 3
map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Hello,This is prod!"
enableRisky: "true"
kustomization.yaml
namePrefix: prod-
commonLabels:
org: acmeCorporation
variant: prod
commonAnnotations:
note: Hello, This is prod!
patchesStrategicMerge:
- deployment.yaml
- map.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: prod
生产环境更改了 configmap、deploy 副本数、namspace。
发布使用
上面我们已经将整个需要的配置定制好了。现在就可以进行发布了。
如果要发布开发环境,则使用:
cd helloworld/
kustomize build overlays/dev/ | kubectl apply -f -
然后我们可以看到发布完成,如下:
# kubectl get all -n dev
NAME READY STATUS RESTARTS AGE
pod/dev-the-deployment-6cdcbbc878-27n5g 1/1 Running 0 50s
pod/dev-the-deployment-6cdcbbc878-fgx89 1/1 Running 0 50s
pod/dev-the-deployment-6cdcbbc878-xz5q2 1/1 Running 0 50s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/dev-the-service NodePort 10.103.77.190 <none> 8080:32414/TCP 50s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/dev-the-deployment 3/3 3 3 50s
NAME DESIRED CURRENT READY AGE
replicaset.apps/dev-the-deployment-6cdcbbc878 3 3 3 50s
然后通过域名访问如下:
其他环境是类似的操作,这里不再赘述。
结合 CD 使用
在进行持续部署的时候每次都需要修改镜像地址为最新的版本,使用 kustomize 也可以简单的实现。
加入我们要修改 dev 环境下的镜像地址为 nginx,命令如下
cd overlays/dev
kustomize edit set image monopole/hello=nginx:latest
说明:
- monopole/hello 是原来的镜像名字
- nginx:latest 是新的镜像 + 标签
然后可以看到 kustomization.yaml 下的镜像地址已经变成了 nginx,如下:
namePrefix: dev-
commonLabels:
org: acmeCorporation
variant: dev
commonAnnotations:
note: Hello, This is dev!
patchesStrategicMerge:
- map.yaml
- ingress.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: dev
images:
- name: monopole/hello
newName: nginx
newTag: latest
我们这时候再发布,就是 nginx 的镜像了。
# kustomize build . | kubectl apply -f -
configmap/dev-the-map unchanged
service/dev-the-service unchanged
deployment.apps/dev-the-deployment configured
ingress.extensions/dev-the-ingress unchanged
同样,修改 namespace 可以使用如下命令。
kustomize edit set namespace test
更多操作可以查看官方文档:https://kubernetes-sigs.github.io/kustomize/zh/guides/
写在最后
使用 Kustomize 简化了针对不同环境的应用程序配置的管理。我们将一组几乎重复的 YAML 文件重组为一个分层模型,这将减少错误,减少手动配置,并使代码更易于识别和维护。