[TOC]html
首先,放上此模板連接:java
https://github.com/ygqygq2/charts/tree/master/ygqygq2/mod-chartnode
此chart可看成POD單image的通用模板,只須要使用sed
替換下chart名,並修改下README.md
和NOTES.txt
就能夠了。下文,我經過複製此chart成example-chart
來做示範說明。nginx
[root@master1 mod-chart]# tree . ├── Chart.yaml # chart版本信息文件 ├── README.md # chart說明文件 ├── templates # kubernetes資源yaml模板 │ ├── configmap.yaml # configmap模板 │ ├── deployment-statefulset.yaml # deployment或statefulset模板 │ ├── _helpers.tpl # 輔助模板和 partials │ ├── ingress.yaml # ingress模板 │ ├── NOTES.txt # 部署chart後輸出的幫助文檔 │ ├── pvc.yaml # pvc模板 │ ├── secret.yaml # secret模板 │ ├── service-headless.yaml # service headless模板 │ └── service.yaml # service模板 └── values.yaml # 默認設置 1 directory, 12 files [root@master1 mod-chart]# helm3 lint --strict . 1 chart(s) linted, 0 chart(s) failed
注:
下文中文件內容我保留,只加註釋。
註釋中須要修改的地方[*]
標記爲必選,[-]
標識爲可選。git
將模板mod-chart
複製成example-chart
,並做內容替換。github
rsync -avz mod-chart/ example-chart/ cd example-chart/ sed -i 's@mod-chart@example-chart@g' *.* sed -i 's@mod-chart@example-chart@g' templates/*.*
Chart.yaml
vim Chart.yaml
web
apiVersion: v1 # 當前helm api版本,不須要修改 appVersion: 1.14.2 # 此處爲你應用程序的版本號 [*] description: Chart for the nginx server # 介紹此chart是幹嗎的,按需求修改 engine: gotpl # go模板引擎,不須要修改 [-] name: example-chart # 模板名,對應目錄名 [*] version: 1.0.0 # 此chart版本號 [*] home: http://www.nginx.org # 應用程序官網 [*] icon: https://bitnami.com/assets/stacks/nginx/img/nginx-stack-220x234.png # 應用程序logo地址 [*] keywords: # 關鍵字列表 [*] - nginx - http - web - www - reverse proxy maintainers: # 維護人員列表 [*] - email: 29ygq@sina.com name: Chinge Yang sources: # 應用程序來源 [-] - https://github.com/bitnami/bitnami-docker-nginx
values.yaml
由於values.yaml
設置涉及到yaml格式,yaml文件格式說明能夠看這篇文章:docker
http://www.ruanyifeng.com/blog/2016/07/yaml.htmlvim
這裏提幾個經常使用的地方:api
string: "" list: [] map: {}
沒什麼特殊要求,通常須要修改的地方有image
、service
、healthCheck
、persistentVolume.mountPaths
# Default values for mod-chart. # This is a YAML-formatted file. # Declare variables to be passed into your templates. ## Global Docker image parameters ## Please, note that this will override the image parameters, including dependencies, configured to use the global value ## Current available global Docker image parameters: imageRegistry and imagePullSecrets ## global: # 設置後覆蓋後面默認的鏡像倉庫 imageRegistry: "" imagePullSecrets: [] # - myRegistryKeySecretName statefulset: enabled: false ## String to partially override fullname template (will maintain the release name) ## nameOverride: "" ## String to fully override fullname template ## fullnameOverride: "" ## By default deploymentStrategy is set to rollingUpdate with maxSurge of 25% and maxUnavailable of 25% . ## You can change type to `Recreate` or can uncomment `rollingUpdate` specification and adjust them to your usage. deploymentStrategy: {} # rollingUpdate: # maxSurge: 25% # maxUnavailable: 25% # type: RollingUpdate # 副本個數 replicaCount: 1 # 容器image及tag image: registry: docker.io repository: bitnami/nginx tag: latest pullPolicy: IfNotPresent # IfNotPresent: 有則不拉(減小流量和操做步驟),Always: 無論tag總拉(適合tag不變時更新) pullSecrets: [] # - private-registry-key service: type: ClusterIP # 通常不用修改 ingressPort: 8080 ports: http: # 多端口暴露時,複製一段 port: 8080 # Service port number for client-a port. protocol: TCP # Service port protocol for client-a port. ## env set ## ref: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/ env: [] # - name: DEMO_GREETING # value: "Hello from the environment" # - name: DEMO_FAREWELL # value: "Such a sweet sorrow" ## command set startCommand: [] # - "java -Xdebug -Xnoagent -Djava.compiler=NONE" # - "-Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n" # - "-Djava.security.egd=file:/dev/urandom" # - "-jar /test.jar" # - "-Duser.timezone=GMT+08" ## Enable configmap and add data in configmap config: enabled: false subPath: "" mountPath: /conf data: {} ############################# 示例 #################################### ## 如下示例,掛載文件至 /conf/app.conf # enabled: true # mountPath: /conf/app.conf # subPath: app.conf # 使用subPath時,上面mountPath路徑寫文件完整絕對路徑 # data: # app.conf: |- # appname = example-chart ## 如下示例,掛載多個文件至 /conf/ 下 # enabled: true # mountPath: /conf # 不使用subPath # data: # app.conf: |- # appname = example-chart # bpp.conf: |- # bppname # ## 掛載多個文件至多個不一樣路徑,須要相應修改 templates/deployment-statefulset.yaml ############################# 示例 #################################### ## To use an additional secret, set enable to true and add data ## 用法同上,不另做說明 secret: enabled: false mountPath: /etc/secret-volume subPath: "" readOnly: true data: {} ## liveness and readiness ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ healthCheck: enabled: true type: tcp # http/tcp port: http # 健康檢查的端口名或端口 httpPath: '/' # http時必須設置 livenessInitialDelaySeconds: 10 # 初始延遲秒數 livenessPeriodSeconds: 10 # 檢測週期,默認值10,最小爲1 readinessInitialDelaySeconds: 10 # 初始延遲秒數 readinessPeriodSeconds: 10 # 檢測週期,默認值10,最小爲1 resources: {} # 容器資源設置 # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi ## Node labels and tolerations for pod assignment ### ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector ### ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature labels: {} podAnnotations: {} nodeSelector: {} tolerations: [] affinity: {} annotations: {} ## Enable persistence using Persistent Volume Claims ## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ ## persistentVolume: # 是否存儲持久化 enabled: false ## If defined, storageClassName: <storageClass> ## If set to "-", storageClassName: "", which disables dynamic provisioning ## If undefined (the default) or set to null, no storageClassName spec is ## set, choosing the default provisioner. (gp2 on AWS, azure-disk on ## Azure, standard on GKE, AWS & OpenStack) ## storageClass: "-" accessMode: ReadWriteOnce annotations: {} # helm.sh/resource-policy: keep size: 1Gi # 大小 existingClaim: {} # 使用已存在的pvc mountPaths: [] # - name: data-storage # mountPath: /config # subPath: config # 多個路徑使用同一個pvc使用subPath,用法同上面config中示例說明 # - name: data-storage # mountPath: /data # subPath: data ingress: # 是否使用nginx暴露域名或端口 enabled: false annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" path: / hosts: - chart-example.local tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local ## Add init containers. e.g. to be used to give specific permissions for data ## Add your own init container or uncomment and modify the given example. initContainers: [] ## Prometheus Exporter / Metrics ## metrics: enabled: false image: registry: docker.io repository: nginx/nginx-prometheus-exporter tag: 0.1.0 pullPolicy: IfNotPresent ## Optionally specify an array of imagePullSecrets. ## Secrets must be manually created in the namespace. ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ ## pullSecrets: [] # - myRegistrKeySecretName ## Metrics exporter pod Annotation and Labels podAnnotations: # prometheus.io/scrape: "true" # prometheus.io/port: "9113" ## Metrics exporter resource requests and limits ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ## resources: {} ## Uncomment and modify this to run a command after starting the core container. ## ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ lifecycle: {} # preStop: # exec: # command: ["/bin/bash","/pre-stop.sh"] # postStart: # exec: # command: ["/bin/bash","/post-start.sh"] ## Deployment additional volumes. deployment: additionalVolumes: [] ## init containers ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ ## Add init containers. e.g. to be used to give specific permissions for data ## Add your own init container or uncomment and modify the given example. initContainers: {} # - name: fmp-volume-permission # image: busybox # imagePullPolicy: IfNotPresent # command: ['chown','-R', '200', '/extra-data'] # volumeMounts: # - name: extra-data # mountPath: /extra-data ## Additional containers to be added to the core pod. additionalContainers: {} # - name: my-sidecar # image: nginx:latest # - name: lemonldap-ng-controller # image: lemonldapng/lemonldap-ng-controller:0.2.0 # args: # - /lemonldap-ng-controller # - --alsologtostderr # - --configmap=$(POD_NAMESPACE)/lemonldap-ng-configuration # env: # - name: POD_NAME # valueFrom: # fieldRef: # fieldPath: metadata.name # - name: POD_NAMESPACE # valueFrom: # fieldRef: # fieldPath: metadata.namespace # volumeMounts: # - name: copy-portal-skins # mountPath: /srv/var/lib/lemonldap-ng/portal/skins
README.md
和templates/NOTES.txt
根據 values.yaml
中的默認設置相應修改README.md
,內容使用markdown語法,這裏不做詳細說明。templates/NOTES.txt
是部署chart後輸出的幫助文檔,裏面支持go template語法。模板裏已經寫成了很是通用。必要狀況下,適當按應用需求來修改,這樣會顯得部署後提示很是友好和人性化。
templates
下yaml簡要說明templates
目錄下爲kubernetes資源yaml文件模板,以資源名命名文件名,複雜些的能夠加上資源功能或者模塊名等。
templates/secret.yaml
{{- if .Values.secret.enabled }} # if用法。語法代碼注意造成一致縮進習慣,便於閱讀 apiVersion: v1 kind: Secret metadata: name: {{ template "example-chart.fullname" . }} # 使用輔助模板時,點號可用 $ 代替,特別是在range下 labels: app: {{ template "example-chart.name" . }} chart: {{ template "example-chart.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" {{- if .Values.labels }} {{ toYaml .Values.labels | indent 4 }} # 使用toYaml時,不縮進,indent接空格數 {{- end }} data: {{- range $key, $value := .Values.secret.data }} # range用法 {{ $key }}: {{ $value | b64enc | quote }} # secret中value注意使用base64轉換 {{- end }} {{- end }}
templates/deployment-statefulset.yaml
{{- if .Values.statefulset.enabled }} # 判斷使用deployment和statefulset資源api類型 apiVersion: apps/v1 kind: StatefulSet {{- else }} apiVersion: apps/v1 kind: Deployment {{- end }} metadata: name: {{ template "example-chart.fullname" . }} labels: app: {{ template "example-chart.name" . }} chart: {{ template "example-chart.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} {{- if .Values.labels }} # 額外的標籤 {{ toYaml .Values.labels | indent 4 }} {{- end }} {{- if .Values.annotations }} # 自定義註釋 annotations: {{ toYaml .Values.annotations | indent 4 }} {{- end }} spec: replicas: {{ .Values.replicaCount }} # 副本數 {{- if .Values.statefulset.enabled }} # statefulset須要定義serviceName serviceName: {{ template "example-chart.fullname" . }}-headless {{- end }} {{- if .Values.deploymentStrategy }} strategy: {{ toYaml .Values.deploymentStrategy | indent 4 }} {{- end }} selector: matchLabels: app: {{ template "example-chart.name" . }} release: {{ .Release.Name }} template: metadata: annotations: {{- if .Values.podAnnotations }} {{ toYaml .Values.podAnnotations | indent 8 }} {{- end }} {{- if .Values.metrics.podAnnotations }} {{ toYaml .Values.metrics.podAnnotations | indent 8 }} {{- end }} labels: app: {{ template "example-chart.name" . }} release: {{ .Release.Name }} spec: {{- include "example-chart.imagePullSecrets" . | indent 6 }} {{- if .Values.initContainers }} initContainers: {{ toYaml .Values.initContainers | indent 8 }} {{- end }} nodeSelector: {{ toYaml .Values.nodeSelector | indent 8 }} affinity: {{ toYaml .Values.affinity | indent 8 }} tolerations: {{ toYaml .Values.tolerations | indent 8 }} containers: {{- if .Values.metrics.enabled }} # metrics容器可根據需求修改 - name: metrics image: {{ template "metrics.image" . }} imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} command: [ '/usr/bin/exporter', '-nginx.scrape-uri', 'http://127.0.0.1:8080/status'] ports: - name: metrics containerPort: 9113 livenessProbe: httpGet: path: /metrics port: metrics initialDelaySeconds: 15 timeoutSeconds: 5 readinessProbe: httpGet: path: /metrics port: metrics initialDelaySeconds: 5 timeoutSeconds: 1 resources: {{ toYaml .Values.metrics.resources | indent 12 }} {{- end }} - name: {{ .Chart.Name }} image: {{ template "example-chart.image" . }} imagePullPolicy: {{ .Values.image.pullPolicy | quote }} {{- if .Values.lifecycle }} lifecycle: {{ toYaml .Values.lifecycle | indent 12 }} {{- end }} {{- if .Values.startCommand }} command: {{ toYaml .Values.startCommand |indent 12 }} {{- end }} env: {{ toYaml .Values.env | indent 12 }} resources: {{ toYaml .Values.resources | indent 12 }} ports: {{- range $key, $value := .Values.service.ports }} - name: {{ $key }} containerPort: {{ $value.port }} protocol: {{ $value.protocol }} {{- end }} {{- if .Values.healthCheck.enabled }} livenessProbe: {{- if eq .Values.healthCheck.type "http" }} httpGet: path: {{ .Values.healthCheck.httpPath }} port: {{ .Values.healthCheck.port }} {{- else }} tcpSocket: port: {{ .Values.healthCheck.port }} {{- end }} initialDelaySeconds: {{ .Values.healthCheck.livenessInitialDelaySeconds }} periodSeconds: {{ .Values.healthCheck.livenessPeriodSeconds }} readinessProbe: {{- if eq .Values.healthCheck.type "http" }} httpGet: path: {{ .Values.healthCheck.httpPath }} port: {{ .Values.healthCheck.port }} {{- else }} tcpSocket: port: {{ .Values.healthCheck.port }} {{- end }} initialDelaySeconds: {{ .Values.healthCheck.readinessInitialDelaySeconds }} periodSeconds: {{ .Values.healthCheck.readinessPeriodSeconds }} {{- end }} volumeMounts: # 容器掛載點 {{- if .Values.config.enabled }} - name: {{ template "example-chart.name" . }}-conf mountPath: {{ .Values.config.mountPath }} subPath: {{ .Values.config.subPath }} {{- end }} {{- if .Values.secret.enabled }} - name: {{ template "example-chart.name" . }}-secret mountPath: {{ .Values.secret.mountPath }} subPath: {{ .Values.secret.subPath }} readOnly: {{ .Values.secret.readOnly }} {{- end }} {{- if .Values.persistentVolume.mountPaths }} {{ toYaml .Values.persistentVolume.mountPaths | indent 12 }} {{- end }} {{- if .Values.additionalContainers }} {{ toYaml .Values.additionalContainers | indent 8 }} {{- end }} volumes: # volume名須要和上文volumeMounts中的名字一一對應 {{- if .Values.config.enabled }} - name: {{ template "example-chart.name" . }}-conf configMap: name: {{ template "example-chart.fullname" . }} {{- end }} {{- if .Values.secret.enabled }} - name: {{ template "example-chart.name" . }}-secret secret: secretName: {{ template "example-chart.fullname" . }} {{- end }} {{- if .Values.deployment.additionalVolumes }} {{ toYaml .Values.deployment.additionalVolumes | indent 8 }} {{- end }} {{- if not .Values.statefulset.enabled }} {{- if .Values.persistentVolume.enabled }} - name: data-storage persistentVolumeClaim: claimName: {{ .Values.persistentVolume.existingClaim | default (include "example-chart.fullname" .) }} {{- else }} - name: data-storage emptyDir: {} {{- end }} {{- else }} {{- if .Values.persistentVolume.enabled }} volumeClaimTemplates: - metadata: name: data-storage labels: app: {{ template "example-chart.name" . }} chart: {{ template "example-chart.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: accessModes: - {{ .Values.persistentVolume.accessMode | quote }} annotations: {{- range $key, $value := $.Values.persistentVolume.annotations }} {{ $key }}: {{ $value }} {{- end }} resources: requests: storage: {{ .Values.persistentVolume.size }} {{- if .Values.persistentVolume.storageClass }} {{- if (eq "-" .Values.persistentVolume.storageClass) }} storageClassName: "" {{- else }} storageClassName: "{{ .Values.persistentVolume.storageClass }}" {{- end }} {{- end }} {{- else }} - name: data-storage emptyDir: {} {{- end }} {{- end -}}
以上yaml中未做詳細說明,仔細看其內容都能明白大體意思。如下是對於helm chart新手的一些建議:
values.yaml
和templates
目錄中的一些設計,差很少都已經很是統一了。這樣遇到本身有類似需求,可直接使用相應的功能塊,寫出來的chart也顯得很是專業。helm
命令fetch
下來,大概讀一遍其chart內容,這樣看多了,天然就愈來愈熟悉,並且出錯時,也便於本身排查問題。參考資料:
[1] https://helm.sh/
[2] https://whmzsu.github.io/helm-doc-zh-cn/