Mount local folder to a container as a volume in Helm

Some time ago I switched to another project, that is working completely in Kubernetes on Azure AKS. Honestly, I tried to use Azure Monitor for monitoring of infrastructure and application, but I didn't succeed.
So I've decided to return to my deeply loved Zabbix, run it in Kubernetes, send e-mails and notifications to Microsoft Teams and show graphs and panels in Grafana.
Of course, a question appeared, how to deploy it to Kubernetes, how to configure, how to upload my custom scripts?
- Deploy - obviously - Helm.
- Configure - manually or Terraform, depends on the situation and personal preferences.
Task
The third question I want to clarify in this article, because the task is the following:
How to mount all custom scripts and config files to the container with Zabbix Agent? At the same time, I don't want to change anything in helm-chart, so that everything will mount automatically.
Simplifying: I have a folder with files (files and their numbers can change during time). I want to mount that folder to container and read those files.
Solution
In general, the process will be the following: get folder, read the list of files, read each file, encode as Base64 and put to configmap. Then only mount configmap to container.
The most difficult here - is to generate configmap:
apiVersion: v1
kind: ConfigMap
metadata:
name: zabbixagent-customscripts
labels:
{{- include "zabbix.labels" . | nindent 4 }}
binaryData:
{{ range $path, $_ := .Files.Glob "customScripts/**" }}
{{- $name := base $path }}
{{- sha256sum (printf "%s/%s" (index (regexSplit "customScripts" (dir $path) -1) 1 ) $name ) | indent 2 }}{{ print ": "}}{{ $.Files.Get $path | replace "\r\n" "\n" | b64enc }}
{{ end }}
Then the matter is small: mount configmap (here the template is partial, but you will figure everything out!).
Code to put on the pod level: /spec/template/spec/volumes
volumes:
- name: zabbixagent-customscripts-volume
configMap:
name: zabbixagent-customscripts
Code to put on the container level: /spec/template/spec/containers/zabbix-agent/volumeMounts
volumeMounts:
{{ range $path, $bytes := .Files.Glob ( printf "customScripts/**") }}
{{ $name := base $path }}
- name: zabbixagent-customscripts-volume
mountPath: {{ printf "/etc/zabbix/zabbix_agentd.d/customScripts/%s/%s" (index (regexSplit "customScripts" (dir $path) -1) 1) $name | indent 2 }}
subPath: {{- sha256sum (printf "%s/%s" (index (regexSplit "customScripts" (dir $path) -1) 1 ) $name ) | indent 2 }}
{{ end }}
Necessarily to calculate hash for configmap to restart the pod if any file had changed: /spec/template/metadata/annotations
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap-zabbix-agent.yaml") . | sha256sum }}
Finally, you will get deployment similar to something like this (copied the export, so part of technical data there):
apiVersion: apps/v1
kind: Deployment
metadata:
name: zabbix-zabbix-server
namespace: zabbix
uid: f022b8d1-a505-4f17-9a9c-ce146415f5e4
resourceVersion: '141741819'
generation: 34
creationTimestamp: '2022-09-06T09:39:29Z'
labels:
app: zabbix-zabbix-server
app.kubernetes.io/instance: zabbix-zabbix-server
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: zabbix-server
helm.sh/chart: zabbix-3.1.1
annotations:
deployment.kubernetes.io/revision: '30'
meta.helm.sh/release-name: zabbix
meta.helm.sh/release-namespace: zabbix
spec:
replicas: 1
selector:
matchLabels:
app: zabbix-zabbix-server
template:
metadata:
creationTimestamp: null
labels:
aadpodidbinding: zabbix-identity
app: zabbix-zabbix-server
app.kubernetes.io/instance: zabbix-zabbix-server
app.kubernetes.io/managed-by: Helm-zabbix-server
app.kubernetes.io/name: zabbix-server
helm.sh/chart: zabbix-3.1.1
annotations:
checksum/config: 7493b02952c1ee885d8ec3cdddf1503185d9c23f7a24994802485f87047f1e07
kubectl.kubernetes.io/restartedAt: '2022-11-08T17:03:37Z'
spec:
volumes:
- name: zabbixserver-tmp
emptyDir: {}
- name: zabbixserver-etc-zabbix
emptyDir: {}
- name: zabbixagent-tmp
emptyDir: {}
- name: zabbixagent-etc-zabbix
emptyDir: {}
- name: zabbixagent-customscripts-volume
configMap:
name: zabbixagent-customscripts
defaultMode: 420
- name: zabbixagent-customconfigs-volume
configMap:
name: zabbixagent-customconfigs
defaultMode: 420
containers:
- name: zabbix-server
image: acr.azurecr.io/sre-zabbix-server:zabbix-12.12.2022-02.08
ports:
- name: zabbix-server
containerPort: 10051
protocol: TCP
- name: zabbix-jmx
containerPort: 10052
protocol: TCP
env:
- name: DB_SERVER_HOST
value: zabbix-postgresql
- name: DB_SERVER_PORT
value: '5432'
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: zabbixdb-pguser-zabbix
key: user
optional: true
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: zabbixdb-pguser-zabbix
key: password
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: zabbixdb-pguser-zabbix
key: dbname
optional: true
- name: ZBX_CACHESIZE
value: 1G
- name: ZBX_HISTORYCACHESIZE
value: 128M
- name: ZBX_VALUECACHESIZE
value: 256M
- name: ZBX_STARTLLDPROCESSORS
value: '20'
- name: ZBX_STARTHISTORYPOLLERS
value: '25'
- name: ZBX_STARTPREPROCESSORS
value: '30'
- name: ZBX_STARTHTTPPOLLERS
value: '25'
- name: ZBX_STARTPOLLERS
value: '70'
- name: ZBX_STARTPOLLERSUNREACHABLE
value: '25'
- name: ZBX_TIMEOUT
value: '30'
- name: ZBX_AUTOHANODENAME
value: hostname
- name: ZBX_NODEADDRESS
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
resources: {}
volumeMounts:
- name: zabbixserver-tmp
mountPath: /tmp/
- name: zabbixserver-etc-zabbix
mountPath: /etc/zabbix/
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1997
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
- name: zabbix-agent
image: acr.azurecr.io/sre-zabbix-agent2:zabbix-12.12.2022-02.08
ports:
- name: zabbix-agent
containerPort: 10050
protocol: TCP
env:
- name: ZBX_HOSTNAME
value: Zabbix server
- name: ZBX_SERVER_HOST
value: 127.0.0.1
- name: ZBX_SERVER_PORT
value: '10051'
- name: ZBX_PASSIVE_ALLOW
value: 'true'
- name: ZBX_PASSIVESERVERS
value: 127.0.0.1
- name: ZBX_ACTIVE_ALLOW
value: 'true'
- name: ZBX_ACTIVESERVERS
- name: ZBX_DEBUGLEVEL
- name: ZBX_TIMEOUT
value: '30'
- name: ZBX_LOADMODULE
- name: ZBX_UNSAFEUSERPARAMETERS
value: '1'
resources: {}
volumeMounts:
- name: zabbixagent-tmp
mountPath: /tmp/
- name: zabbixagent-etc-zabbix
mountPath: /etc/zabbix/
- name: zabbixagent-customscripts-volume
mountPath: >-
/etc/zabbix/zabbix_agentd.d/customScripts//discovery-azure-resource-names.sh
subPath: 2cb955a37388a8b19625881af61b649fbd80bb79445c68ba5e9d6ea408e5d0b2
- name: zabbixagent-customscripts-volume
mountPath: >-
/etc/zabbix/zabbix_agentd.d/customScripts//get-azmon-metric-dimension-value.sh
subPath: 6ebdd1ee42938288ef7feb846e4565a25a64d84789b5d3b09a13e8db50deeed7
- name: zabbixagent-customscripts-volume
mountPath: >-
/etc/zabbix/zabbix_agentd.d/customScripts//get-azmon-metric-value.sh
subPath: 4d4b274589ed92b0b7bd2c1ced85e016b293bc72cb130b475d4ee2c3aeb5e715
- name: zabbixagent-customscripts-volume
mountPath: >-
/etc/zabbix/zabbix_agentd.d/customScripts//get-azure-servicebus-topics-metrics.sh
subPath: 5f478d191e20496bb0717f4c75e4ba0ef65cd08dd25c94091dd2abc2152d217a
- name: zabbixagent-customscripts-volume
mountPath: >-
/etc/zabbix/zabbix_agentd.d/customScripts//get-etlsync-error-count.sh
subPath: 4396ef39da4e52a036dfdc075e3726a4487e49959e4037d61d60ebc66d8adfdf
- name: zabbixagent-customscripts-volume
mountPath: >-
/etc/zabbix/zabbix_agentd.d/customScripts//kusto/etlsync-errors-count.kusto
subPath: 5ee630c0c537e6e7c63ee5f1d97845e47e7878bbf93ae3acb1cedc8a8f7b86f8
- name: zabbixagent-customscripts-volume
mountPath: /etc/zabbix/zabbix_agentd.d/customScripts//test-script.ps1
subPath: fed07e23de807313771fa94de7ae16b8b8032a08c269ace5b9c0eae0b07720e9
- name: zabbixagent-customconfigs-volume
mountPath: /etc/zabbix/zabbix_agentd.d//userParameters.conf
subPath: cb99c00393da314983b2b2d2857189ea150cfb91ce50dd5836da6420f4c8b43e
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: Always
securityContext:
runAsUser: 1997
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
securityContext: {}
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/instance: zabbix-zabbix-server
topologyKey: kubernetes.io/hostname
schedulerName: default-scheduler
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
- Hits: 1025