本人是helm的重度用户,但是吧越用越不爽。。。 helm v2版本三大弊病:

  • 多租户支持不了
  • 搞个tiller服务端,鸡肋
  • 扯出自己很多概念

未来一定是 kustomize + operator生态

v3版本抛弃tiller算是个进步,但是听说要上撸啊(lua)我就瞬间崩溃了,我只是想渲染个yaml文件而已。好在好多chart包貌似生态很繁荣。。。

今天给大家介绍kustomize是如何让helm寝食难安,做梦都在颤抖的.

<!--more-->

安装

kustomize已经集成在高版本(1.14+)的kubectl里了,可以使用 kubectl apply -k [目录] 来执行

安装太低级不说了,装不上的智商估计就不用往下继续看了。。。

快速开始

mkdir ~/helloDEMO_HOME=~/helloBASE=$DEMO_HOME/basemkdir -p $BASEcurl -s -o "$BASE/#1.yaml" "https://raw.githubusercontent.com\/kubernetes-sigs/kustomize\/master/examples/helloWorld\/{configMap,deployment,kustomization,service}.yaml"

看下目录结构:

base    ├── configMap.yaml    ├── deployment.yaml    ├── kustomization.yaml    └── service.yaml

configmap deployment service里就是我们普通的yaml文件,再加个kustomizeation文件:

文件中指定了一些配置,指定我们把哪些个文件进行合并

➜  hello cat base/kustomization.yaml # Example configuration for the webserver# at https://github.com/monopole/hellocommonLabels:  app: helloresources:- deployment.yaml- service.yaml- configMap.yaml

build一下就会输出整个yaml了:

# kustomize build baseapiVersion: v1data:  altGreeting: Good Morning!  enableRisky: "false"kind: ConfigMapmetadata:  labels:    app: hello  name: the-map---apiVersion: v1kind: Servicemetadata:  labels:    app: hello  name: the-service...

很简单吧,是不是发现没什么卵用,咱再继续

预上线配置与生产配置

我们经常会遇到如开发环境与生产环境的配置文件不一样的情况,典型的配额与副本数不一样。 我们现在就来处理这种场景,staging环境与production环境。

OVERLAYS=$DEMO_HOME/overlaysmkdir -p $OVERLAYS/stagingmkdir -p $OVERLAYS/production

如两个环境的configmap不一样的场景

cat <<'EOF' >$OVERLAYS/staging/kustomization.yamlnamePrefix: staging-commonLabels:  variant: staging  org: acmeCorporationcommonAnnotations:  note: Hello, I am staging!resources:- ../../basepatchesStrategicMerge: # 这里意思是我们要把base里的configmap用下面的configmap overlay一下- map.yamlEOF

这样我们用下面的configmap去更新base中的,这里相当于增加了俩字段。

cat <<EOF >$OVERLAYS/staging/map.yamlapiVersion: v1kind: ConfigMapmetadata:  name: the-mapdata:  altGreeting: "Have a pineapple!"  enableRisky: "true"EOF

再build一下观察configmap变化:

➜  hello kustomize build overlays/staging apiVersion: v1data:  altGreeting: Have a pineapple!  # 覆盖了base中的data  enableRisky: "true"kind: ConfigMapmetadata:  annotations:    note: Hello, I am staging!  # 新增了配置文件中的commonAnnotations  labels:    app: hello                  # 继承了base中的label    org: acmeCorporation        # 新增了配置文件中的label    variant: staging  name: staging-the-map

production同理不再赘述了, 然后就可以部署到k8s集群中:

kustomize build $OVERLAYS/staging |\    kubectl apply -f -

或者

kubectl apply -k $OVERLAYS/staging

设置字段,如镜像tag

我们yaml文件中镜像有tag,每次版本更新都去修改文件比较麻烦。特别是在CI/CD时有可能取的是类似 DRONE_TAG的环境变量用作镜像tag。

cd basekustomize edit set image monopole/hello=alpine:3.6

kustomization.yaml中就可以看到:

images:- name: monopole/hello  newName: alpine  newTag: "3.6"

再build时deployment中镜像就变了:

apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: hello  name: the-deploymentspec:...        image: alpine:3.6

这样在CI/CD时以DRONE为例就可以直接这样:

deploy:   image: kustomize:latest   commands:     - kustomize edit set image monopole/hello=alpine:{DRONE_TAG=latest}     - kubectl apply -k .

这样你代码的tag与构建镜像的tag以及yaml文件中的tag就完美保持一致了,再也不用担心上错版本了。

注入k8s运行时数据

kustomize有个很强大的特性就是允许注入k8s运行时的一些数据,举个栗子:

假设部署个php要去连mysql,但是只知道mysql的Servicename 并不知道端口号是啥,那么kubemize就可以帮你解决这个问题:

这里给个获取metadata.name的例子,其它运行时数据一个理

php的yaml文件可以这样写:

apiVersion: apps/v1beta2kind: Deploymentmetadata:  name: wordpressspec:  template:    spec:      initContainers:      - name: init-command        image: debian        command:        - "echo $(WORDPRESS_SERVICE)"        - "echo $(MYSQL_SERVICE)"      containers:      - name: wordpress        env:        - name: WORDPRESS_DB_HOST          value: $(MYSQL_SERVICE)        - name: WORDPRESS_DB_PASSWORD          valueFrom:            secretKeyRef:              name: mysql-pass              key: password

然后配置下kusztomize:

cat <<EOF >>$DEMO_HOME/kustomization.yamlvars:  - name: WORDPRESS_SERVICE  # 最终被渲染进yaml    objref:      kind: Service      name: wordpress        # 获取叫wordpress的Service      apiVersion: v1    fieldref:      fieldpath: metadata.name # 最终获取service中的metadata.name作为WORDPRESS_SERVICE   - name: MYSQL_SERVICE    objref:      kind: Service      name: mysql      apiVersion: v1EOF

这是个十分强大的特性,比如有时我们觉得DNS不够稳定或者短链接多不想走DNS服务发现,A访问B时想直接用B的clusterip,但是B部署之前又不知道IP是啥,就可以

通过这种方式获取到clusterip,理解了这个原理就可以随意发挥了.

json patch

同样可以通过指定json patch对yaml进行修改, yaml和json格式都支持:

cat <<EOF >$DEMO_HOME/ingress_patch.yaml- op: replace  path: /spec/rules/0/host  # 修改ingress中的host  value: foo.bar.io- op: add  path: /spec/rules/0/http/paths/-  # 增加path  value:    path: '/test'    backend:      serviceName: my-test      servicePort: 8081EOF
cat <<EOF >>$DEMO_HOME/kustomization.yamlpatchesJson6902:- target:    group: extensions    version: v1beta1    kind: Ingress    name: my-ingress  path: ingress_patch.yamlEOF

还可以把一个patch打到多个对象上,比如我们给所有Deployment加探针啥的

cat <<EOF >>$DEMO_HOME/kustomization.yamlpatches:- path: patch.yaml  target:    kind: DeploymentEOF

总结

个人是不太喜欢重的东西的,只是管理个yaml文件而已真的不用搞那么复杂。当初helm v2时想通过程序去调用时发现非常麻烦,还得找个swift项目中转,结果swift有些返回值非常之不友好,还需要自己去解析一波,还是挺痛苦的回忆。

我觉得简单yaml kustomize很够用,需要复杂精细的控制时helm也无可奈何还得靠operator发挥,这上下一挤压让helm处境就比较尴尬了。。。 kustomize还被集成到kubectl里了这样确实更方便了。

探讨可加QQ群:98488045
kubernetes一键HA