Helm chart thì đã rất là quen thuộc với anh em sử dụng kubernetes
Chắc chắn là anh em từng sử dụng helm chart offical để deploy spinnaker, jenkins, ….
Nói chung là rất nhiều.
Và mình đã gặp 1 số case này. Không phải là tất cả các helm chart để được chi tiết và mọi ngóc ngách của các manifest yaml. Vẫn khó hiểu đúng không?
Mình ví dụ như sau:
Bạn deploy spinnaker và bạn sử dụng chart của hãng!
Và giờ bạn muốn workload halyard hay redis phải có config thêm nodeSelector
Nhưng mà bạn đã mò nát trong values.yaml thì thấy không thấy có config nào liên quan đến nodeSelector
How must we do it?
1) pull chart hãng về và sửa helm chart (Cái này ok thôi, nhưng khi bạn update chart mới của hãng cũng khá là cực hình)
2) Cứ deploy lên đi, rồi edit mamifest bằng argocd hay kubectl.
2 cách trên thì ok sẽ chạy thôi, nhưng cách nữa sửa dụng Kustomize và chúng ta sẽ tìm hiểu thử sem sao?
1) Research the way to design “Kustomize”
Tài liệu mình tham khảo là:
https://foxutech.com/managing-kubernetes-resources-with-kustomize/
1.1) Instruct “base” in Kustomize.
Kustomize thì có 2 thứ quan trọng là:
– A base is a directory containing a file called kustomization.yaml, which can enumerate some set of resources with some customizations that will be applied to them. A base should be declared in the resources field of a kustomization file.
Nghĩa là trong thư mục base chúng ta có 1 file tên là kustomization.yaml

kustomization.yaml ################### apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - service.yaml - deployment.yaml
Bạn thấy ở mục resource thì nó liên kê 1 số manifest. Đây là các manifest tiêu chuẩn và chúng ta không liên tục thay đổi trực tiếp nội dung trong các file này!
Khi mà deploy lên k8s thì chúng ta sẽ deploy các manifest này lên k8s (service.yaml, deployment.yaml)
service.yaml
#####################
apiVersion: v1
kind: Service
metadata:
name: kustom-demo-app
spec:
ports:
- name: http
port: 8080
selector:
app: kustom-demo-app
deployment.yaml
#######################
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustom-demo-app
spec:
selector:
matchLabels:
app: kustom-demo-app
template:
metadata:
labels:
app: kustom-demo-app
spec:
containers:
- name: app
image: nginx:latest
ports:
- name: http
containerPort: 8080
protocol: TCP
1.2) Instruct “overlay” in Kustomize
Tiếp đến là An overlay is a directory that refers to another kustomization directory as its, or one of its, bases.

1.2.1) Overlay connect Base

Cũng giống như helm bạn cũng có thể view trước template như thế nào trong mỗi chỉnh sửa?
Install kustomize:
# curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
# mv kustomize /usr/local/bin
và sau đó chạy lệnh này:
kustomize build kustomize/overlays/prod/
1.2.2) Add the configuration to Manifest
Deployment Environment Variable
Đây là tính năng chỉnh của kustomize, để change config của của deployment chẳng hạn thì chúng ta không change các file trong thư mục base.
Bạn chỉnh cần tạo 1 file yaml ở thư mục overlays

custom-env.yaml
#######################
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustom-demo-app
spec:
template:
spec:
containers:
- name: app # (1)
env:
- name: CUSTOM_ENV_VARIABLE
value: My First Value defined by Kustomize ❤️
và bạn cũng cần khai bào file trên vào mục patchesStrategicMerge:
# Warning: ‘patchesStrategicMerge’ is deprecated. Please use ‘patches’ instead

Đây là khi chúng ta sử dụng Patches.

Và ta cũng có nôi dụng của các file khác.
db-secret.yaml
####################
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustom-demo-app
spec:
template:
spec:
containers:
- name: app
env:
- name: "DB_PASSWORD"
valueFrom:
secretKeyRef:
name: kustom-demo-app
key: db.password
##################
custom-env.yaml
#####################
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustom-demo-app
spec:
template:
spec:
containers:
- name: app # (1)
env:
- name: CUSTOM_ENV_VARIABLE
value: My First Value defined by Kustomize ❤️
1.2.3) Create a manifest throught Kustomize Configuration!
1.2.3.1) Create a secret via kustomize code.

secretGenerator: nó sẽ tạo manifest secret
1.2.3.2) Create a secret via kustomize Command.
thì có 2 cách:
Run command và kustomize sẽ thêm config trên
Chúng ta có thể tạo secret bằng kustomize mà ko push bất cứ file nào lên github
# cd kustomize/overlays/prod
# kustomize edit add secret kustom-demo-app --from-literal=nimtechnology=ohmypassword
kustomize edit add secret my-secret --from-literal=my-literal=12345
Cách còn lại bạn tự biết thêm vào kustomize.yaml
Bạn thử check lại các file manifest bạn sẽ thấy có thêm buil secret
# kustomize build kustomize/overlays/prod/
apiVersion: v1
data:
db-password: b2hteXBhc3N3b3Jk
kind: Secret
metadata:
name: kustom-demo-app-62dhmggmh9
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
name: kustom-demo-app
spec:
ports:
- name: http
port: 8080
selector:
app: kustom-demo-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustom-demo-app
spec:
replicas: 3
selector:
1.2.4) Change the image of a deployment
Để thay đổi 1 config nào đó trong deploy ví dụ như là image
cd kustomize/overlays/prod
TAG=1.21.6
kustomize edit set image nginx=nginx:$TAG
khi bạn chạy lệnh edit ở trên thì trong file Kustomization sẽ được thêm

Khi bạn chạy
kustomize build kustomize/overlays/prod/
thì bạn sẽ thấy được là image đã được thay đổi


Tất cả config ở trên bạn có thể tham khảo git repo sau:
https://github.com/foxutech/kubernetes
1.2.5) Using Kustomize to delete resources and fields in the manifest.
Mình chắc hẳn bạn sẽ muốn delete một số thử trong base manifest hoặc trong Helm chart (nếu values không làm đươc điều này)
Reference Links:
https://www.modb.pro/db/127982
https://tech.aabouzaid.com/2021/05/delete-a-manifest-from-kustomize-base.html
1.2.5.1) Delete Object or Kind.
Ở đây chúng ta sẽ delete 1 Kind luôn. Ví dụ bạn muốn delete service ra khỏi tòa bộ base resource hay helm chart,

Ở đây chúng ta có 2 cách
Cách 1:
Tạo 1 file delete-service.yaml
apiVersion: v1 kind: Service metadata: name: spinnaker-spinnaker-halyard $patch: delete #look at
sau đó bạn sẽ có 1 file kustomization.yaml như sau
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base/dev
helmChartInflationGenerator:
- chartName: spinnaker
chartRepoUrl: https://helmcharts.opsmx.com/
chartVersion: 2.2.7
releaseName: spinnaker
releaseNamespace: spinnaker
values: values_helm.yaml
# You need to add below content
patches:
- delete-service.yaml
1.2.5.2) Delete field.
Mình ví dụ như bạn muốn delete 1 env trong 1 deployment
Bạn tạo 1 file delete-env-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: flaskapp
spec:
replicas: 1
template:
metadata:
labels:
app: flaskapp
version: v1
spec:
containers:
- name: flaskapp
image: dustise/flaskapp
env:
- name: CONFIG
$patch: delete #look at
và bạn có file kustomization.yaml như sau:
bases: - ../add # Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead patchesStrategicMerge: - delete-env-deployment.yam
từ các ví dụ bên trên thì bạn thấy là vị trí của $patch: delete rất là quan trọng
1.2.5.3) Delete a few lines inside the data of configmap.

Ca nay là mình delete 1 line cloud trong data của config map.
Hiện tại mình dùng cách sau, copy lại toàn bộ Configmap và bỏ các line liên quan đến cloud.
file jenkins-jcasc-config.yaml
#Delete config cloud in jenkins controller
apiVersion: v1
data:
jcasc-default-config.yaml: |-
jenkins:
authorizationStrategy:
loggedInUsersCanDoAnything:
allowAnonymousRead: false
securityRealm:
local:
allowsSignup: false
enableCaptcha: false
users:
- id: "${chart-admin-username}"
name: "Jenkins Admin"
password: "${chart-admin-password}"
disableRememberMe: false
mode: NORMAL
numExecutors: 0
labelString: ""
projectNamingStrategy: "standard"
markupFormatter:
plainText
#Delete Cloud at here
crumbIssuer:
standard:
excludeClientIPFromCrumb: true
security:
apiToken:
creationOfLegacyTokenEnabled: false
tokenGenerationOnCreationEnabled: false
usageStatisticsEnabled: true
unclassified:
location:
adminAddress:
url: https://build-android.tiki.services
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: jenkins-controller
app.kubernetes.io/instance: jenkins-controller-android
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: jenkins
helm.sh/chart: jenkins-4.1.1
jenkins-controller-android-jenkins-config: 'true'
name: jenkins-controller-android-jenkins-jcasc-config
namespace: default
và file kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
#look at
patches:
- jenkins-jcasc-config.yaml
helmChartInflationGenerator:
- chartName: jenkins
chartRepoUrl: https://charts.jenkins.io
chartVersion: 4.1.1
releaseName: jenkins-controller-android
releaseNamespace: default
values: values_helm.yaml
2) Integrate between Kustomize and Helm-chart
2.1) structure introduction
Phần này mình sẽ demo thực tế và cách sắp xếp các file sẽ tùy cá nhân môi người nhé!
root@work-space-u20:~/mylab-helm-chart/spinnaker# tree
.
├── base
│ └── dev
│ ├── configmap-spinnaker-script.yaml
│ └── kustomization.yaml
├── manifest
│ └── dev
│ ├── kustomize.yaml
│ └── spinnaker_dev.yaml
└── overlays
└── dev
├── add_label_sa.yaml
├── charts
├── kustomization.yaml
└── values_helm.yaml
2.2) Design “base configuration”
base sẽ là nơi mình chứa các file yaml và nội dụng dụng của nó đã hoàn chỉnh và đây đủ
Mình sẽ show config
configmap-spinnaker-script.yaml
#####################
apiVersion: v1
data:
config.sh: |-
$HAL_COMMAND config features edit --artifacts true
$HAL_COMMAND config artifact github enable
export GITHUB_ACCOUNT_NAME=mrnim94
$HAL_COMMAND config artifact github account add ${GITHUB_ACCOUNT_NAME} \
--token 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
$HAL_COMMAND config features edit --pipeline-templates true
kind: ConfigMap
metadata:
name: spinnaker-scripts
kustomization.yaml ################ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - configmap-spinnaker-script.yaml
2.3) Design Overlays
Overlays mình sử dụng:
– chứa các Generator: helmChartInflationGenerator, secretGenerator, …
– chứa các config để thêm vào manifest: patches
Có 1 điểm cần chú ý với patches mình đã giới thiệu bên trên.
Mình config 1 file yaml như sau:
apiVersion: v1 kind: ServiceAccount metadata: labels: organization: nimtechnology
Và mình gặp lỗi:
kustomize build --enable-helm > ../../manifest/dev/spinnaker_dev.yaml
Error: trouble configuring builtin PatchStrategicMergeTransformer with config: `
paths:
- add_label_sa.yaml
`: missing metadata.name in object {{v1 ConfigMap} {{ } map[organization:nimtechnology] map[]}}
Mục đích của mình là thêm label cho Service Account. Nó yêu cầu bạn khai bào thêm name của service acount đó. Vì có nhiều service account thì biết sửa cái nào
2.3.1) helmChartInflationGenerator (can ignored)
helmChartInflationGenerator (can ignored)Sau 1 ngày trải nghiệm thì mình thấy là nếu bạn sử dụng helmChartInflationGenerator trên argocd thì chúng ta không thể change chartVersion.
Lý do khi argocd run kustomize build –enable-helm thì nó sinh ra 1 folder chart trong argocd. Cho dừ bạn có change chartVersion thì nó cũng không tại lại chart với version mới
Bạn phải xóa folder chart thì mới generate ra chart mới nhưng trong argocd thì mình ko biết xóa chỗ nào?
kustomization.yaml
#######################
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base/dev
helmChartInflationGenerator:
- chartName: spinnaker
chartRepoUrl: https://helmcharts.opsmx.com/
chartVersion: 2.2.7
releaseName: test
releaseNamespace: spinnaker
values: values_helm.yaml
# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead
patchesStrategicMerge:
- add_label_sa.yaml
2.3.2) helmCharts
helmGlobals: chartHome: jenkins-controller-android_4.1.8/ #look at helmCharts: - name: jenkins includeCRDs: false releaseName: jenkins-controller-android version: 4.1.8 #look at repo: https://charts.jenkins.io valuesFile: values_helm.yaml namespace: default
cách hiện tại của mình là sử dụng helmCharts
mỗi khi bạn muốn change version thì bạn cần change 2 thử là:
– version trong helmCharts
– chartHome trong helmGlobals
Việc change này thì nó tạo ra 1 folder mới để bạn có thể generate chart mới!
values cho helm chart
values_helm.yaml
#########################
halyard:
# Set to false to disable persistence data volume for halyard
persistence:
enabled: false
additionalScripts:
enabled: true
configMapName: spinnaker-scripts
configMapKey: config.sh
additionalProfileConfigMaps:
data:
gate-local.yml: |-
server:
tomcat:
protocolHeader: X-Forwarded-Proto
remoteIpHeader: X-Forwarded-For
internalProxies: .*
httpsServerPort: X-Forwarded-Port
redis:
# Uncomment if you don't want to create a PVC for redis
master:
persistence:
enabled: false
minio:
resources:
requests:
memory: "2Gi"
persistence:
enabled: true
và mình cũng có test add thêm label Service Acount
add_label_sa.yaml
######################
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-spinnaker-halyard
labels:
organization: nimtechnology
Define application of argocd
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: kubecost-nimtechnology-dev
namespace: argocd
spec:
destination:
namespace: kubecost
name: 'arn:aws:eks:us-west-2:04370XXXXXX:cluster/dev-mdcl-nimtechnology-engines'
project: meta-structure
source:
path: meta-structure/kubecost
repoURL: git@nimtechnology.org:metascan/mdce-nimtechnology-argo
targetRevision: meta-structure
plugin:
name: kustomize-build-with-helm
2.4) Gen manifest and deploy
các file config của mình đã được chuẩn bị khá là chu đáo.
Mình gen ra file manifest
mkdir manifest/dev/
cd overlays/dev/
kustomize build --enable-helm > ../../manifest/dev/spinnaker_dev.yaml
Khi run xong chúng ta sẽ có file manifest và bạn có thể dụng để kubectl apply -f manifest/dev/spinnaker_dev.yaml
Bạn sẽ hỏi là vậy có thể dùng với Argocd hem?
Mình mới test thì dụng được nhé!

3) Why my argocd does not work helmChartInflationGenerator.
Nếu bạn run helmChartInflationGenerator với argocd thì sẽ gặp lỗi
Unable to create application: application spec for spinnaker is invalid: InvalidSpecError: Unable to generate manifests in spinnaker/overlays/dev: rpc error: code = Unknown desc = `kustomize build .spinnaker/overlays/dev` failed exit status 1: Error: trouble configuring builtin HelmChartInflationGenerator with config: ` name: spinnaker releaseName: spinnaker repo: https://helmcharts.opsmx.com/ valuesFile: values_helm.yaml version: 2.2.7 `: must specify –enable-helm
Để Argocd worked với helmChart thì bạn cần phải thêm config sau vào configmap của argocd
Link reference:
https://github.com/argoproj/argo-cd/issues/7835#issuecomment-1027971749
apiVersion: v1
data:
configManagementPlugins: |
- name: kustomize-build-with-helm
generate:
command: [ "sh", "-c" ]
args: [ "kustomize build --enable-helm" ]
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/instance: argocd
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
name: argocd-cm
namespace: argocd

trong argocd thì bạn chọn plugin để sử dụng được config trên

4) Use the “patches” to merge or add the contents that you want to adjust the main configuration.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# helmGlobals:
# chartHome: kubecost_1.101.0-rc.4_nim/
# configHome: TMP_DIR/helm/
helmCharts:
- name: cost-analyzer
includeCRDs: false
releaseName: kubecost
version: 1.101.0-rc.4
repo: https://kubecost.github.io/cost-analyzer
valuesFile: values_helm.yaml
namespace: kubecost
#https://github.com/kubernetes-sigs/kustomize/blob/master/examples/inlinePatch.md
patches:
- target:
kind: Service
name: kubecost-cost-analyzer
patch: |-
apiVersion: v1
kind: Service
metadata:
name: kubecost-cost-analyzer
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: 'true'
labels:
app: cost-analyzer
spec:
type: LoadBalancer

Cách 2: Mình sử dụng path in patches
https://github.com/kubernetes-sigs/kustomize/issues/3481#issuecomment-1434407293
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization # resources: # - ../../base # helmGlobals: # chartHome: chartmuseum_3.9.1/ helmCharts: - name: opentelemetry-coralogix includeCRDs: false releaseName: otel-agent version: 0.0.25 repo: https://cgx.jfrog.io/artifactory/coralogix-charts-virtual valuesFile: values_helm.yaml namespace: coralogix # generators: # - ./kops.yaml patches: - path: mergeNodeSelector.yaml
Tiếp đến là file mergeNodeSelector.yaml
mình muốn add nodeSelector vào DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-coralogix-agent
spec:
template:
spec:
nodeSelector:
kubernetes.io/os: linux
Còn 1 cách nữa thì minh sưu tầm ở đây:
https://medium.com/@giorgiodevops/kustomize-use-patches-to-add-or-override-resources-48ef65cb634c