Helm简介

    xiaoxiao2022-06-30  204

     

    2018年03月13日 13:02:11 迷途的攻城狮(798570156) 阅读数:9729

     版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenleiking/article/details/79539012

    Helm简介

    这几天花了不少时间在helm的学习之上,目前还不能熟练运行,很多东西都停留在记忆层面。整理这篇文章为加深印象,也便于后续实践的过程中参考和查询——记性不好。

    1、简介

    Helm is the best way to find, share, and use software built for Kubernetes.

    Helm之于Kubernetes好比yum之于RHEL,或者apt-get之于Ubuntu。Helm使用Chart帮助我们管理应用,Chart就好像RPM一样,里面描述了应用及其依赖关系。主要概念:

    Chart:Helm管理的应用部署包,一个结构相对固定的目录或者tgz压缩文件,Chart之间可相互依赖Release:Chart部署之后的事例,每一次helm install就会生成一个新的release

    2、部署

    2.1、前提条件

    一个现有可用的Kubernetes集群。

    2.2、系统清单

    IPHostnameRoleOS192.168.119.160k8s-masterMasterCentOS 7192.168.119.161k8s-node-1NodeCentOS 7192.168.119.162k8s-node-2NodeCentOS 7192.168.119.163k8s-node-3NodeCentOS 7

    Kubernetes平台版本:1.9.2,也就是之前的文章中搭建的版本。

    2.3、软件清单

    Helm是由helm CLI和Tiller组成,是典型的C/S应用。helm运行与客户端,提供命令行界面,而Tiller应用运行在Kubernetes内部。

    [root@k8s-master charts]# helm version Client: &version.Version{SemVer:"v2.8.1", GitCommit:"6af75a8fd72e2aa18a2b278cfe5c7a1c5feca7f2", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.8.1", GitCommit:"6af75a8fd72e2aa18a2b278cfe5c7a1c5feca7f2", GitTreeState:"clean"} 123

    正常的helm环境可以看到client和server两个版本。

    客户端下载参考链接:https://github.com/kubernetes/helm/releases

    服务端镜像:gcr.io/kubernetes-helm/tiller:v2.8.1,下文附网盘链接

    2.4、部署说明

    安装helm [root@k8s-master ~]# wget https://storage.googleapis.com/kubernetes-helm/helm-v2.8.1-linux-amd64.tar.gz [root@k8s-master ~]# mkdir -p /usr/local/helm/ [root@k8s-master ~]# mv helm-v2.8.1-linux-amd64.tar.gz /usr/local/helm/ [root@k8s-master ~]# cd /usr/local/helm/ [root@k8s-master helm]# tar -zxvf helm-v2.8.1-linux-amd64.tar.gz [root@k8s-master helm]# rm -rf helm-v2.8.1-linux-amd64.tar.gz [root@k8s-master helm]# cp -s /usr/local/helm/linux-amd64/helm /usr/local/bin/ 12345678

    helm只是是一个单纯的可执行文件

    部署tiller ### 配置helm的Service account及其相关角色 ### [root@k8s-master helm]# vi helm-rbac.yml --- apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: helm name: helm-admin namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: helm-admin labels: k8s-app: helm roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: helm-admin namespace: kube-system [root@k8s-master helm]# kubectl apply -f helm-rbac.yml [root@k8s-master helm]# kubectl get sa --all-namespaces | grep helm kube-system helm-admin 1 2d 123456789101112131415161718192021222324252627282930

    注意,默认情况下只需要执行 helm init 就可以完成tiller部署,而且看上去很正常,但是无法执行 helm install 。因为helm需要访问k8s的API,而我们的集群启用了RBAC,要让helm正常工作,我们需要为其配置好相关权限。

    ### 部署tiller并为其指定sa ### [root@k8s-master helm]# helm init --service-account helm-admin ### 如果你不是第一次执行 ### [root@k8s-master helm]# helm init --service-account helm-admin --upgrade 12345 测试 ### 查看tiller-deploy服务 ### [root@k8s-master helm]# kubectl get svc --all-namespaces NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 9d kube-system kubernetes-dashboard NodePort 10.111.158.221 <none> 443:32286/TCP 9d kube-system tiller-deploy ClusterIP 10.99.8.140 <none> 44134/TCP 2d ### 查看helm version ### [root@k8s-master helm]# helm version Client: &version.Version{SemVer:"v2.8.1", GitCommit:"6af75a8fd72e2aa18a2b278cfe5c7a1c5feca7f2", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.8.1", GitCommit:"6af75a8fd72e2aa18a2b278cfe5c7a1c5feca7f2", GitTreeState:"clean"} ### 查询repo上的内容 ### [root@k8s-master helm]# helm search 123456789101112131415

    如果你的应用部署失败了,可以用 kubectl describe pod 查看一下原因,一般可能是镜像下载失败,如果是这样,文末附网盘地址。

    2.5、注意事项

    如果启用的RBAC,在 helm init 时指定sa多使用 helm -h 和 helm [command] -h

    3、Chart

    Helm管理的kubernetes资源包称之为Chart,Chart是一个结构相对固定的文件目录。一个单独的Chart可以用于部署一下简单的Kubernetes资源,如:memcached,又或者更复杂的应用,如完整的Web应用:HTTP servers, databases, caches等等。

    Helm的结构:

    3.1、Chart的结构

    [root@k8s-master mychart]# tree mychart/ mychart # Chart的名字,也就是目录的名字 ├── charts # Chart所依赖的子Chart │ ├── jenkins-0.14.0.tgz # 被“mychart”依赖的其中一个subChart │ ├── mysubchart # 被“mychart”依赖的另一个subChart │ │ ├── charts │ │ ├── Chart.yaml │ │ ├── templates │ │ │ └── configmap.yaml │ │ └── values.yaml │ └── redis-1.1.17.tgz ├── Chart.yaml # 记录关于该Chart的描述信息:比如名称、版本等等 ├── config1.toml # 其他文件:可以是任何文件 ├── config2.toml # 其他文件:可以是任何文件 ├── requirements.yaml # 记录该Chart的依赖,类似pom.xml ├── templates # 存放模版文件,模板也就是将k8s的yml文件参数化,最终还是会被helm处理成k8s的正常yml文件,然后用来部署对应的资源 │ ├── configmap.yaml # 一个ConfigMap资源模版 │ ├── _helpers.tpl # "_"开头的文件不会本部署到k8s上,可以用于定于通用信息,在其他地方应用,如loables │ └── NOTES.txt # 在执行helm instll安装此Chart之后会被输出到屏幕的一些自定义信息 └── values.yaml # 参数定义文件,这里定义的参数最终会应用到模版中 1234567891011121314151617181920

    Chart可以是目录,也可以是tgz格式的压缩包。

    charts目录和requirements.yaml文件到区别就和lib和pom.xml的区别类似,一个用于存放,一个用于描述

    3.1.1、创建一个Chart

    [root@k8s-master charts]# pwd /root/charts [root@k8s-master charts]# helm create mychart-2 [root@k8s-master charts]# ll drwxr-xr-x. 4 root root 93 3月 12 10:48 mychart-2 [root@k8s-master charts]# tree mychart-2 mychart-2 ├── charts ├── Chart.yaml ├── templates │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── ingress.yaml │ ├── NOTES.txt │ └── service.yaml └── values.yaml 2 directories, 7 files ### 为了后面的实验,我们先删除helm默认生成的文件 ### [root@k8s-master charts]# rm -rf mychart-2/templates/* 123456789101112131415161718192021222324

    helm会帮我们创建一下必要的模版文件,简单的Chart直接修改这些文件即可

    3.1.2、文件:Chart.yaml

    [root@k8s-master charts]# vi mychart-2/Chart.yaml apiVersion: v1 appVersion: "1.0" description: A Helm chart for Kubernetes name: mychart-2 version: 0.1.0 123456 apiVersion:官网文档上没有,helm create创建的的模版中有,指k8s API的版本appVersion:当前Chart包含的应用的版本,比如redis、apache等description:当前Chart的描述信息name:当前Chart的名称version:当前Chart的版本,版本规范,打包后的文件名:name-version.tgz,如:nginx-1.2.3.tgz

    这里仅列举了重要的数据项,还有很多可选项:keywords、home、maintainers等,参考。这些内容在打包分享时很有用。

    3.1.3、文件:values.yaml

    此文件主要用来存放Chart的默认值,这些值会被应用到模版中,替换掉模版中的变量,生成最终k8s的yaml部署文件,例如:

    [root@k8s-master charts]# vi mychart/values.yaml favorite: drink: coffee food: pizza [root@k8s-master charts]# vi mychart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ quote .Values.favorite.drink }} food: {{ .Values.favorite.food}} 1234567891011121314

    在这个例子中,我们有一个configmap.yaml模版,模版中点了一个ConfigMap,模版中包含了很多 {{}},这些 {{}} 中以.Values开头的会被替换成values.yaml中的值,.Release开头的会被替换成release相关的变量值,Release是内置变量中的一员。quote是一个function,当然还有很多其他的function。

    这里为什么说默认值呢,因为在执行 helm install 时,可以通过 helm install --set tags.front-end=true --set subchart2.enabled=false 这种方式来改变实际的值。

    关于template的详细内容,将在下文阐述。

    3.1.4.1、内置变量

    Release.Name: The name of the release (not the chart)Release.Time: The time the chart release was last updated. This will match the Last Released time on a Release object.Release.Namespace: The namespace the chart was released to.Release.Service: The service that conducted the release. Usually this is Tiller.Release.IsUpgrade: This is set to true if the current operation is an upgrade or rollback.Release.IsInstall: This is set to true if the current operation is an install.Release.Revision: The revision number. It begins at 1, and increments with each helm upgrade.Chart: The contents of the Chart.yaml. Thus, the chart version is obtainable as Chart.Version and the maintainers are in Chart.Maintainers.Files: A map-like object containing all non-special files in the chart. This will not give you access to templates, but will give you access to additional files that are present (unless they are excluded using .helmignore). Files can be accessed using {{index .Files "file.name"}} or using the {{.Files.Get name}} or {{.Files.GetString name}} functions. You can also access the contents of the file as []byte using {{.Files.GetBytes}}Capabilities: A map-like object that contains information about the versions of Kubernetes ({{.Capabilities.KubeVersion}}, Tiller ({{.Capabilities.TillerVersion}}, and the supported Kubernetes API versions ({{.Capabilities.APIVersions.Has "batch/v1")

    3.1.4.2、全局变量

    Helm的变量是有作用域的:父Chart可以访问子Chart的值,而子Chart不能访问父Chart的值:

    [root@k8s-master charts]# vi mychart-2/values.yaml title: "MyChart-2" mysubchart1: title: mysubchart1 mysubchart2: title: mysubchart2 [root@k8s-master charts]# vi mychart-2/charts/mysubchart1/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: title: {{ .Values.title }} [root@k8s-master charts]# vi mychart-2/charts/mysubchart2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: title: {{ .Values.title }} [root@k8s-master charts]# helm install --debug --dry-run mychart-2/ [debug] Created tunnel using local port: '37936' [debug] SERVER: "127.0.0.1:37936" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-2 NAME: cautious-hare REVISION: 1 RELEASED: Mon Mar 12 13:51:29 2018 CHART: mychart-2-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: mysubchart1: global: {} title: mysubchart1 mysubchart2: global: {} title: mysubchart2 title: MyChart-2 HOOKS: MANIFEST: --- # Source: mychart-2/charts/mysubchart1/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: cautious-hare-configmap data: title: mysubchart1 --- # Source: mychart-2/charts/mysubchart2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: cautious-hare-configmap data: title: mysubchart2 --- # Source: mychart-2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: cautious-hare-configmap data: title: MyChart-2 mysubchart1: mysubchart1 mysubchart2: mysubchart2 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778

    上例中,mychart-2/charts/mysubchart1/values.yaml和mychart-2/charts/mysubchart1/values.yaml为空白文件。mysubchart1和mysubchart2可以正常访问到mychart-2/values.yaml文件中定义的对应子Chart的内容。如果直接访问其他变量,比如:{{ .Values.mysubchart2.xxx }} 将得到一个错误。

    如果在父Chart和子Chart中同时定义了相同的值,则父Chart覆盖子Chart:

    [root@k8s-master charts]# vi mychart-2/values.yaml title: "MyChart-2" mysubchart1: title: mysubchart1 [root@k8s-master charts]# vi mychart-2/charts/mysubchart1/values.yaml title: xxxxxxx [root@k8s-master charts]# vi mychart-2/charts/mysubchart2/values.yaml title: nnnnnnnnnn [root@k8s-master charts]# helm install --debug --dry-run mychart-2/ [debug] Created tunnel using local port: '35979' [debug] SERVER: "127.0.0.1:35979" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-2 NAME: nosy-lobster REVISION: 1 RELEASED: Mon Mar 12 13:57:58 2018 CHART: mychart-2-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: mysubchart1: global: {} title: mysubchart1 mysubchart2: global: {} title: nnnnnnnnnn title: MyChart-2 HOOKS: MANIFEST: --- # Source: mychart-2/charts/mysubchart1/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nosy-lobster-configmap data: title: mysubchart1 --- # Source: mychart-2/charts/mysubchart2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nosy-lobster-configmap data: title: nnnnnnnnnn --- # Source: mychart-2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nosy-lobster-configmap data: title: MyChart-2 mysubchart1: mysubchart1 mysubchart2: nnnnnnnnnn 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465

    可以在父Chart中定义全局变量,子Chart可以通过 .Values.global.name 访问全局变量:

    [root@k8s-master charts]# vi mychart-2/values.yaml global: app: MyTestAPP title: "MyChart-2" mysubchart1: title: mysubchart1 [root@k8s-master charts]# vi mychart-2/charts/mysubchart1/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: title: {{ .Values.title }} appName: {{ .Values.global.app }} [root@k8s-master charts]# helm install --debug --dry-run mychart-2/ [debug] Created tunnel using local port: '39141' [debug] SERVER: "127.0.0.1:39141" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-2 NAME: ignorant-gerbil REVISION: 1 RELEASED: Mon Mar 12 14:03:02 2018 CHART: mychart-2-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: global: app: MyTestAPP mysubchart1: global: app: MyTestAPP title: mysubchart1 mysubchart2: global: app: MyTestAPP title: nnnnnnnnnn title: MyChart-2 HOOKS: MANIFEST: --- # Source: mychart-2/charts/mysubchart1/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: ignorant-gerbil-configmap data: title: mysubchart1 appName: MyTestAPP --- # Source: mychart-2/charts/mysubchart2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: ignorant-gerbil-configmap data: title: nnnnnnnnnn --- # Source: mychart-2/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: ignorant-gerbil-configmap data: title: MyChart-2 mysubchart1: mysubchart1 mysubchart2: nnnnnnnnnn 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576

    3.1.4、文件:requirements.yaml

    这个文件需要手动创建,requirements.yaml文件用来定义Chart的依赖,直接将这些依赖放到chart目录下也是可以的。使用文件来管理是来会更加便利。简单文件的格式如下:

    dependencies: - name: redis version: 1.1.17 repository: https://kubernetes-charts.storage.googleapis.com 1234

    文件内容表明当前Chart依赖redis-1.1.17这个Chart,这个Chart的仓库地址是https://kubernetes-charts.storage.googleapis.com,这个地址必须已经添加到你的helm中,添加命令:helm repo add ,查看命令:helm repo list 。

    然后我们执行 helm dependency update chartName 命令helm就会帮我们下载requirements.yaml文件中定义的其他Chart,这些Chart会存放在charts目录中。

    [root@k8s-master charts]# helm dependency update mychart-2/ Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "stable" chart repository Update Complete. ⎈Happy Helming!⎈ Saving 1 charts Downloading redis from repo https://kubernetes-charts.storage.googleapis.com Deleting outdated charts [root@k8s-master charts]# ll mychart-2/charts/ 总用量 8 -rw-r--r--. 1 root root 6189 3月 12 10:54 redis-1.1.17.tgz 1234567891011

    命令简写:helm dep up mychart-2/

    下面是一个复杂一点的例子:

    dependencies: - name: redis version: 1.1.17 repository: https://kubernetes-charts.storage.googleapis.com condition: redis.enabled tags: - redis - name: jenkins version: 0.14.0 repository: https://kubernetes-charts.storage.googleapis.com condition: jenkins.enabled tags: - jenkins - name: redis version: 1.1.17 repository: https://kubernetes-charts.storage.googleapis.com alias: newname tags: - redis 12345678910111213141516171819

    在这个例子中,涉及到alias、condition、tags三个关键字,我们配合下面的values.yaml文件一项一项来解释,values.yaml文件内容:

    redis: enabled: false jenkins: enabled: false tags: redis: false jenkins: true 123456789 alias:给依赖的Chart定义别名,官网上说:别名会在下载之后,以新名称存放在charts目录下,但是实时上并非如此。在我的实验过程中,上面的例子会下载三个Chart:redis、jenkins和redis,也就是redis下载了两次,但是在charts目录下只有redis和jenkins两个文件,没有newname。我在想alias目前可能只是记录在文件中,最后一个redis依然叫redis,而且将第一个redis覆盖了,所以只有两个文件。也可能是我的实验姿势不对。condition:boolean值,用来决定当前依赖是否启用,如果condition后面的值不存在,比如redis.enabled或者jenkins.enabled未定义,则忽略condition。condition可定义多个值,用 “,” 分隔。如果第一个值存在,则忽略后面的值。tags:boolean值,与condition类似,但是condition的优先级更高,如果同时定义了condition和tags,tags将被忽略。在不考虑condition时,tags中的任何一个值被定义为true,则启用该依赖 [root@k8s-master charts]# helm dep up mychart-2/ Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "stable" chart repository Update Complete. ⎈Happy Helming!⎈ Saving 3 charts Downloading redis from repo https://kubernetes-charts.storage.googleapis.com Downloading jenkins from repo https://kubernetes-charts.storage.googleapis.com Downloading redis from repo https://kubernetes-charts.storage.googleapis.com Deleting outdated charts [root@k8s-master charts]# ll mychart-2/charts/ 总用量 24 -rw-r--r--. 1 root root 12685 3月 12 11:18 jenkins-0.14.0.tgz -rw-r--r--. 1 root root 6189 3月 12 11:18 redis-1.1.17.tgz 1234567891011121314 首先可以看到确实下载了三个Chart,redis两次,但是在charts目录下只有两个tgz文件,alias和官网上的描述有出入。其次我们定义的condition和tags并未生效,按照上面的规则,不应该有任何一个Chart本下载,但是所有的依赖都被下载了。实时并非如此,接着往下看。 [root@k8s-master charts]# helm install --debug --dry-run mychart-2/ [debug] Created tunnel using local port: '43383' [debug] SERVER: "127.0.0.1:43383" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-2 NAME: reeling-puffin REVISION: 1 RELEASED: Mon Mar 12 11:24:30 2018 CHART: mychart-2-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: jenkins: enabled: false redis: enabled: false tags: jenkins: true redis: false HOOKS: MANIFEST: 123456789101112131415161718192021222324252627

    helm install 用于在k8s上部署Chart,–debug –dry-run选项用于调试,加了两个选项之后,不会在k8s上部署任何资源,仅输出helm转换之后的模版信息和相关变量

    ### 修改values.yaml文件 ### [root@k8s-master charts]# vi mychart-2/values.yaml redis: enabled: false jenkins: enabled: false tags: redis: true jenkins: true ### 再次执行install ### [root@k8s-master charts]# helm install --debug --dry-run mychart-2/ [debug] Created tunnel using local port: '45794' [debug] SERVER: "127.0.0.1:45794" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-2 NAME: sweet-hyena REVISION: 1 RELEASED: Mon Mar 12 11:29:49 2018 CHART: mychart-2-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: jenkins: enabled: false newname: global: {} image: bitnami/redis:4.0.8-r5 imagePullPolicy: IfNotPresent metrics: annotations: prometheus.io/port: "9121" prometheus.io/scrape: "true" enabled: false image: oliver006/redis_exporter imagePullPolicy: IfNotPresent imageTag: v0.11 resources: {} networkPolicy: allowExternal: true enabled: false nodeSelector: {} persistence: accessMode: ReadWriteOnce enabled: true path: /bitnami size: 8Gi subPath: "" podAnnotations: {} podLabels: {} resources: requests: cpu: 100m memory: 256Mi securityContext: enabled: true fsGroup: 1001 runAsUser: 1001 service: annotations: {} loadBalancerIP: null serviceType: ClusterIP tolerations: [] usePassword: true redis: enabled: false tags: jenkins: true redis: true HOOKS: MANIFEST: --- # Source: mychart-2/charts/newname/templates/secrets.yaml apiVersion: v1 kind: Secret metadata: name: sweet-hyena-newname labels: app: sweet-hyena-newname chart: "newname-1.1.17" release: "sweet-hyena" heritage: "Tiller" type: Opaque data: redis-password: "anVXdzdJQjJRTg==" --- # Source: mychart-2/charts/newname/templates/pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: sweet-hyena-newname labels: app: sweet-hyena-newname chart: "newname-1.1.17" release: "sweet-hyena" heritage: "Tiller" spec: accessModes: - "ReadWriteOnce" resources: requests: storage: "8Gi" --- # Source: mychart-2/charts/newname/templates/svc.yaml apiVersion: v1 kind: Service metadata: name: sweet-hyena-newname labels: app: sweet-hyena-newname chart: "newname-1.1.17" release: "sweet-hyena" heritage: "Tiller" annotations: spec: type: ClusterIP ports: - name: redis port: 6379 targetPort: redis selector: app: sweet-hyena-newname --- # Source: mychart-2/charts/newname/templates/deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sweet-hyena-newname labels: app: sweet-hyena-newname chart: "newname-1.1.17" release: "sweet-hyena" heritage: "Tiller" spec: template: metadata: labels: app: sweet-hyena-newname spec: securityContext: fsGroup: 1001 runAsUser: 1001 containers: - name: sweet-hyena-newname image: "bitnami/redis:4.0.8-r5" imagePullPolicy: "IfNotPresent" env: - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: sweet-hyena-newname key: redis-password ports: - name: redis containerPort: 6379 livenessProbe: exec: command: - redis-cli - ping initialDelaySeconds: 30 timeoutSeconds: 5 readinessProbe: exec: command: - redis-cli - ping initialDelaySeconds: 5 timeoutSeconds: 1 resources: requests: cpu: 100m memory: 256Mi volumeMounts: - name: redis-data mountPath: /bitnami subPath: volumes: - name: redis-data persistentVolumeClaim: claimName: sweet-hyena-newname 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190

    忽略输出内容的细节,注意看 COMPUTED VALUES 和 # Source:,这里只有newname的相关资源和计算值,行为正好和我们预期的一致。说明condition和tags只在install时有效,在dependency update时无效。

    还有一点,执行 helm install 之前,如果requirements.yaml中有charts中不存在的依赖,必须先执行 helm dep up 更新所有的依赖,否则会提示:

    [debug] Created tunnel using local port: '45706' [debug] SERVER: "127.0.0.1:45706" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-2 Error: found in requirements.yaml, but missing in charts/ directory: redis, jenkins, redis 12345678

    3.1.5、目录:charts

    目录charts用来存放当前Chart依赖的其他Chart,这些被依赖的Chart可以是上文requirements.yaml文件中描述的,也可以直接在charts目录下创建新的charts

    [root@k8s-master charts]# cd mychart-2/charts/ [root@k8s-master charts]# pwd /root/charts/mychart-2/charts [root@k8s-master charts]# helm create mysubchart-1 Creating mysubchart-1 [root@k8s-master charts]# helm create mysubchart-2 Creating mysubchart-2 [root@k8s-master charts]# ll drwxr-xr-x. 4 root root 93 3月 12 12:10 mysubchart-1 drwxr-xr-x. 4 root root 93 3月 12 12:10 mysubchart-2 12345678910

    每个subChart都是一个结构完整的Chart,可以是目录,也可以是tgz文件,tgz文件可以用 tar -zxvf 命令解压

    此时若部署mychart-2,也会连同mysubchart-1和mysubchart-2一同部署到k8s上

    3.1.6、目录:templates

    templates的具体内容在下文专门作为一个章节来阐述。

    3.2、Hooks

    3.2.1、Hooks介绍

    Hook允许我们干涉执行 helm install 的过程。正常情况下 helm install 的执行步骤如下:

    User runs helm install fooChart is loaded into TillerAfter some verification, Tiller renders the foo templatesTiller loads the resulting resources into KubernetesTiller returns the release name (and other data) to the clientThe client exits

    而可用的hook包括:

    pre-install: Executes after templates are rendered, but before any resources are created in Kubernetes.post-install: Executes after all resources are loaded into Kubernetespre-delete: Executes on a deletion request before any resources are deleted from Kubernetes.post-delete: Executes on a deletion request after all of the release’s resources have been deleted.pre-upgrade: Executes on an upgrade request after templates are rendered, but before any resources are loaded into Kubernetes (e.g. before a Kubernetes apply operation).post-upgrade: Executes on an upgrade after all resources have been upgraded.pre-rollback: Executes on a rollback request after templates are rendered, but before any resources have been rolled back.post-rollback: Executes on a rollback request after all resources have been modified.

    在正常的执行步骤中加入 pre-install 和 post-install 之后:

    User runs helm install fooChart is loaded into TillerAfter some verification, Tiller renders the foo templatesTiller prepares to execute the pre-install hooks (loading hook resources into Kubernetes)Tiller sorts hooks by weight (assigning a weight of 0 by default) and by name for those hooks with the same weight in ascending order.Tiller then loads the hook with the lowest weight first (negative to positive)Tiller waits until the hook is “Ready”Tiller loads the resulting resources into Kubernetes. Note that if the --wait flag is set, Tiller will wait until all resources are in a ready state and will not run the post-installhook until they are ready.Tiller executes the post-install hook (loading hook resources)Tiller waits until the hook is “Ready”Tiller returns the release name (and other data) to the clientThe client exits

    注意:hook是安装weight值的大小,由小到大排序之后,按顺序执行,如果weight值相同则按名称排序。

    Hook通常可以用来备份/回复数据之类的操作。

    3.2.2、定义一个hook

    [root@k8s-master charts]# vi mychart-2/templates/pre-install-job.yaml apiVersion: batch/v1 kind: Job metadata: name: "{{.Release.Name}}" labels: heritage: {{.Release.Service | quote }} release: {{.Release.Name | quote }} chart: "{{.Chart.Name}}-{{.Chart.Version}}" annotations: # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. "helm.sh/hook": pre-install "helm.sh/hook-weight": "-5" "helm.sh/hook-delete-policy": hook-succeeded spec: template: metadata: name: "{{.Release.Name}}" labels: heritage: {{.Release.Service | quote }} release: {{.Release.Name | quote }} chart: "{{.Chart.Name}}-{{.Chart.Version}}" spec: restartPolicy: Never containers: - name: pre-install-job image: "alpine:3.7" command: ["/bin/sleep","{{default "20" .Values.sleepyTime}}"] 1234567891011121314151617181920212223242526272829

    “helm.sh/hook”:定义一个hook,如果需要定义为多个hook,可以用逗号分隔:post-install,post-upgrade

    “helm.sh/hook-weight”:定义weight,可以是正数或者负数

    “helm.sh/hook-delete-policy”:定义hook的删除策略

    测试:可以执行 helm install mychart-2 部署此Chart,用 kubectl get cm 观察k8s上资源出现的时间

    3.3、Repo

    Helm的repository是一个HTTP服务,可以用于管理Chart:

    ### 查看已添加的repository ### [root@k8s-master charts]# helm repo list ### 使用帮助 ### [root@k8s-master charts]# helm repo -h ### Chart打包 ### [root@k8s-master charts]# helm package mychart-2/ Successfully packaged chart and saved it to: /root/charts/mychart-2-0.1.0.tgz drwxr-xr-x. 4 root root 143 3月 12 14:01 mychart-2 -rw-r--r--. 1 root root 19642 3月 12 14:33 mychart-2-0.1.0.tgz 1234567891011

    Helm提供一个serve,用于管理本地Chart:

    ### 使用帮助 ### [root@k8s-master charts]# helm serve -h ### 启动本地服务 ### [root@k8s-master charts]# helm serve --address "0.0.0.0:8879" Regenerating index. This may take a moment. Now serving you on 0.0.0.0:8879 1234567

    然后在浏览器中访问,地址:http://192.168.119.160:8879

    4、Template

    前面的内容也提到了模版,模版主要功能就是将k8s部署用的yaml文件中的会发生改变的内容参数话,将不变的内容固定到模版文件中。

    对于一个Chart,所有的模版都存放在templates目录内,在部署时,templates目录内的所有内容(处理”_”开头的内容)都会在被处理后发生到k8s。

    4.1、第一个模版

    ### 创建一个Chart ### [root@k8s-master charts]# helm create mychart-3 Creating mychart-3 ### 删除helm生成的文件,从零开始 ### [root@k8s-master charts]# rm -rf mychart-3/templates/* ### 创建第一个模版文件,一个简单的ConfigMap ### [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: mychart-configmap data: myvalue: "Hello World" ### 安装部署到k8s上 ### [root@k8s-master charts]# helm install mychart-3/ NAME: veering-owl LAST DEPLOYED: Mon Mar 12 15:09:37 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/ConfigMap NAME DATA AGE mychart-configmap 1 0s ### 查看release ### [root@k8s-master charts]# helm ls NAME REVISION UPDATED STATUS CHART NAMESPACE veering-owl 1 Mon Mar 12 15:09:37 2018 DEPLOYED mychart-3-0.1.0 default ### 查看k8s部署情况 ### [root@k8s-master charts]# kubectl get cm NAME DATA AGE mychart-configmap 1 56s [root@k8s-master charts]# kubectl describe cm mychart-configmap Name: mychart-configmap Namespace: default Labels: <none> Annotations: <none> Data ==== myvalue: ---- Hello World Events: <none> ### 删除release ### [root@k8s-master charts]# helm del veering-owl release "veering-owl" deleted [root@k8s-master charts]# kubectl get cm No resources found. [root@k8s-master charts]# helm ls [root@k8s-master charts]# helm ls -a NAME REVISION UPDATED STATUS CHART NAMESPACE veering-owl 1 Mon Mar 12 15:09:37 2018 DELETED mychart-3-0.1.0 default [root@k8s-master charts]# helm del --purge veering-owl release "veering-owl" deleted [root@k8s-master charts]# helm ls -a 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061

    Release的名称在不指定的情况下,随机产生。

    使用 helm get manifest releaseName 可以重新查看 install 时的输出。

    上面的例子中,将name硬编码到文件中可能不是一个好主意,下面的配置使我们得到一个和release name名称相仿的CM:

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" [root@k8s-master charts]# helm install mychart-3/ NAME: peddling-moose LAST DEPLOYED: Mon Mar 12 15:37:46 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/ConfigMap NAME DATA AGE peddling-moose-configmap 1 0s [root@k8s-master charts]# helm ls NAME REVISION UPDATED STATUS CHART NAMESPACE peddling-moose 1 Mon Mar 12 15:37:46 2018 DEPLOYED mychart-3-0.1.0 default [root@k8s-master charts]# kubectl get cm NAME DATA AGE peddling-moose-configmap 1 12s 1234567891011121314151617181920212223242526

    Release是helm的内置变量,上文有详细说明,或者官方文档

    在模版中,使用闭合的 {{ 和 }} 块来引用变量

    变量本身支持namespace,Release前面的 “.” 表示最高级namespace,后面的 “.” 作为分隔符

    4.2、Values.yaml文件

    关于values.yaml文件上文有简单说明过,这里做进一步说明:values.yaml文件中的内容可以通过Values对象引用,Values对象的内容包括:

    当前Chart的values.yaml文件如果当前Chart是一个子Chart,还包括父Chart的values.yaml文件执行 helm install 或者 helm update 时 -f 参数指定的yaml文件,例如:helm install -f myvals.yaml ./mychart--set 参数指定的内容,例如:helm install --set foo=bar ./mychart

    —set具有最高优先级

    4.2.1、使用values.yaml文件中的变量

    [root@k8s-master charts]# vi mychart-3/values.yaml favoriteDrink: coffee [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favoriteDrink }} ### 使用默认值 ### [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '46193' [debug] SERVER: "127.0.0.1:46193" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: odd-wallaby REVISION: 1 RELEASED: Mon Mar 12 16:06:58 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favoriteDrink: coffee HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: odd-wallaby-configmap data: myvalue: "Hello World" drink: coffee ### 使用 --set 赋值 ### [root@k8s-master charts]# helm install --debug --dry-run --set drink:=slurm mychart-3/ [debug] Created tunnel using local port: '40468' [debug] SERVER: "127.0.0.1:40468" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: volted-chinchilla REVISION: 1 RELEASED: Mon Mar 12 16:09:16 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: 'drink:': slurm COMPUTED VALUES: 'drink:': slurm favoriteDrink: coffee HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: volted-chinchilla-configmap data: myvalue: "Hello World" drink: coffee 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576

    4.2.2、使用层次结构

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink }} food: {{ .Values.favorite.food }} [root@k8s-master charts]# vi mychart-3/values.yaml favorite: drink: coffee food: pizza [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '42576' [debug] SERVER: "127.0.0.1:42576" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: whimsical-rabbit REVISION: 1 RELEASED: Mon Mar 12 16:13:41 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: whimsical-rabbit-configmap data: myvalue: "Hello World" drink: coffee food: pizza 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

    4.2.3、删除一个已经定义的值

    在下载或者安装Chart时,如果想删除掉某个已经定义在values.yaml文件中的值,可以将该值设置为 null:

    [root@k8s-master charts]# helm install mychart-3/ --set favorite.food=null NAME: mothy-hare LAST DEPLOYED: Mon Mar 12 16:32:37 2018 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/ConfigMap NAME DATA AGE mothy-hare-configmap 3 0s [root@k8s-master charts]# kubectl get cm NAME DATA AGE mothy-hare-configmap 3 5s [root@k8s-master charts]# kubectl describe cm mothy-hare-configmap Name: mothy-hare-configmap Namespace: default Labels: <none> Annotations: <none> Data ==== drink: ---- coffee food: ---- myvalue: ---- Hello World Events: <none> 123456789101112131415161718192021222324252627282930313233

    这个在使用—debug –dry-run时,对应的值会被设置为 “null”,在k8s上则被设置为空。

    4.3、模版方法和管道

    4.3.1、方法

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ quote .Values.favorite.drink }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '37662' [debug] SERVER: "127.0.0.1:37662" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: lunging-stingray REVISION: 1 RELEASED: Mon Mar 12 16:39:36 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: lunging-stingray-configmap data: myvalue: "Hello World" drink: "coffee 1234567891011121314151617181920212223242526272829303132333435363738394041

    在这个例子中,我们调用了quote方法,并为其传递了一个参数.Values.favorite.drink

    Helm有超过60个可用的方法,其中一部分上Go template language自己定义的,大部分其他的Sprig template library。

    4.3.2、管道

    和UNIX操作系统类似,管道用于连接两个命令,将前一个命令的输出传递给后一个命令输入,对于上面的例子可以修改为:

    apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | quote }} 1234567

    另一个例子:

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | repeat 5 | quote }} food: {{ .Values.favorite.food | upper | quote }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '34727' [debug] SERVER: "127.0.0.1:34727" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: looming-pig REVISION: 1 RELEASED: Mon Mar 12 16:47:24 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: looming-pig-configmap data: myvalue: "Hello World" drink: "coffeecoffeecoffeecoffeecoffee" food: "PIZZA" 12345678910111213141516171819202122232425262728293031323334353637383940414243

    4.3.3、使用Default方法

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | repeat 5 | quote }} food: {{ .Values.favorite.food | upper | quote }} game: {{ .Values.favorite.game | default "NFS" | quote }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '46170' [debug] SERVER: "127.0.0.1:46170" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: cautious-opossum REVISION: 1 RELEASED: Mon Mar 12 16:50:59 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: cautious-opossum-configmap data: myvalue: "Hello World" drink: "coffeecoffeecoffeecoffeecoffee" food: "PIZZA" game: "NFS" 123456789101112131415161718192021222324252627282930313233343536373839404142434445

    Values.yaml文件中并未定义game。

    4.4、操作符

    Helm实现了所有的操作符( eq、 ne、 lt、 gt、 and、 or等等),并且可以使用”()”进行分组

    4.4.1、流程控制语句

    Helm支持的流程控制语句包括:if/else 、with 、range,接下来分别介绍

    4.4.1.1、IF/ELSE

    结构 {{ if PIPELINE }} # Do something {{ else if OTHER PIPELINE }} # Do something else {{ else }} # Default case {{ end }} 1234567 举例 [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | repeat 5 | quote }} food: {{ .Values.favorite.food | upper | quote }} game: {{ .Values.favorite.game | default "NFS" | quote }} {{ if eq .Values.favorite.drink "coffee" }} mug: true {{ end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '36351' [debug] SERVER: "127.0.0.1:36351" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: bald-newt REVISION: 1 RELEASED: Mon Mar 12 17:11:01 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: bald-newt-configmap data: myvalue: "Hello World" drink: "coffeecoffeecoffeecoffeecoffee" food: "PIZZA" game: "NFS" mug: true 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

    可以看到正确输出了mug: true,但是格式不好看,莫名其妙多个一个空白行,这是因为helm在处理{{}}时,单纯的替换掉了{{}}块,保留了换行字符。

    说明

    PIPELINE 为一个boolean值,下面的所有内容都将被当作false处理:

    a boolean falsea numeric zeroan empty stringa nil (empty or null)an empty collection (map, slice, tuple, dict, array)

    4.4.1.2、控制空白字符

    上面的例子中,多出了一行空白行,我们可以使用 {{- 去掉左边的空白字符,或者使用 -}} 去掉右边的空白字符,也可以同时使用,去掉两遍的空白字符。注意,换行也属于空白字符,例如:

    aaa {{- xxxx }} bbb 123

    将得到:

    aaa bbb 12

    因为中间一行左边的换行符被去掉,但是右边的换行符被保留。

    在看:

    aaa {{- xxxx -}} bbb 123

    将得到:

    aaabbb 1

    因为中间一行两遍的换行符都被去掉了。

    因此,上面的例子可以修改为:

    apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | repeat 5 | quote }} food: {{ .Values.favorite.food | upper | quote }} game: {{ .Values.favorite.game | default "NFS" | quote }} {{- if eq .Values.favorite.drink "coffee" }} mug: true {{- end }} 123456789101112

    4.4.1.3、使用WITH修改作用域

    结构 {{ with PIPELINE }} # restricted scope {{ end }} 123 举例 [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" {{- with .Values.favorite }} drink: {{ .drink | repeat 5 | quote }} food: {{ .food | upper | quote }} game: {{ .game | default "NFS" | quote }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '40227' [debug] SERVER: "127.0.0.1:40227" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: maudlin-yak REVISION: 1 RELEASED: Mon Mar 12 17:28:58 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: maudlin-yak-configmap data: myvalue: "Hello World" drink: "coffeecoffeecoffeecoffeecoffee" food: "PIZZA" game: "NFS" 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 说明

    With将默认的命名空间改变为”.Values.favorite”,使with块内部可以方便的引用变量。

    注意

    With块内部不能在访问其他任何命令空间的内容,比如下面的写法将得到一个异常:

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" {{- with .Values.favorite }} drink: {{ .drink | repeat 5 | quote }} food: {{ .food | upper | quote }} game: {{ .game | default "NFS" | quote }} release: {{ .Release.Name }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '38400' [debug] SERVER: "127.0.0.1:38400" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 Error: render error in "mychart-3/templates/configmap.yaml": template: mychart-3/templates/configmap.yaml:11:22: executing "mychart-3/templates/configmap.yaml" at <.Release.Name>: can't evaluate field Name in type interface {} 1234567891011121314151617181920212223

    可以修改为:

    apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" {{- with .Values.favorite }} drink: {{ .drink | repeat 5 | quote }} food: {{ .food | upper | quote }} game: {{ .game | default "NFS" | quote }} {{- end }} release: {{ .Release.Name }} 123456789101112

    4.4.1.4、循环控制语句

    Helm使用range来实现循环。

    举例 [root@k8s-master charts]# vi mychart-3/values.yaml pizzaToppings: - mushrooms - cheese - peppers - onions [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: toppings: |- {{- range .Values.pizzaToppings }} - {{ . | title | quote }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '38008' [debug] SERVER: "127.0.0.1:38008" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: illocutionary-molly REVISION: 1 RELEASED: Mon Mar 12 17:43:35 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: illocutionary-molly-configmap data: toppings: |- - "Mushrooms" - "Cheese" - "Peppers" - "Onions" 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 说明

    Range块中,”.“表示当前值,title是一个首字母大写的function,toppings后面的”|”表示后面的内容是一个可择行的大字符串,在之后的”-“表示去掉末尾的空白字符。

    迭代元祖 sizes: |- {{- range tuple "small" "medium" "large" }} - {{ . }} {{- end }} 1234 sizes: |- - small - medium - large 1234

    4.4.2、自定义变量

    使用自定义变量可以更好的使用 with 和 range 。在上面的例子中,我们使用下面的内容会出现异常:

    {{- with .Values.favorite }} drink: {{ .drink | default "tea" | quote }} food: {{ .food | upper | quote }} release: {{ .Release.Name }} {{- end }} 12345

    因为Release.Name不再with块范围内,一种可以避免错误的办法就是在with块之外定义一个变量,然后将Release.Name的值赋给这个变量:

    [root@k8s-master charts]# vi mychart-3/values.yaml favorite: drink: coffee food: pizza [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: {{- $relname := .Release.Name -}} {{- with .Values.favorite }} drink: {{ .drink | default "tea" | quote }} food: {{ .food | upper | quote }} release: {{ $relname }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '40191' [debug] SERVER: "127.0.0.1:40191" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: moldy-labradoodle REVISION: 1 RELEASED: Mon Mar 12 17:58:56 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: favorite: drink: coffee food: pizza HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: moldy-labradoodle-configmap data: drink: "coffee" food: "PIZZA" release: moldy-labradoodle 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051

    另外一个例子:定义循环下标

    [root@k8s-master charts]# vi mychart-3/values.yaml pizzaToppings: - mushrooms - cheese - peppers - onions [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: {{- range $index, $topping := .Values.pizzaToppings }} {{ $index }}: {{ $topping }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '40932' [debug] SERVER: "127.0.0.1:40932" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: wobbly-macaw REVISION: 1 RELEASED: Mon Mar 12 18:02:04 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: wobbly-macaw-configmap data: 0: mushrooms 1: cheese 2: peppers 3: onions 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253

    同理:

    apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" {{- range $key, $val := .Values.favorite }} {{ $key }}: {{ $val | quote }} {{- end}} 123456789

    将得到:

    # Source: mychart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: eager-rabbit-configmap data: myvalue: "Hello World" drink: "coffee" food: "pizza" 123456789

    4.4.3、命名模版

    命名模版允许我们定义模版块,从而将完整的大模版拆分成数个小模版。将重复的部门抽取来定义成命名模版使我们的模版文件看起来更清晰。模版的命名规范如下:

    大多数包含kubernetes对象定义的模版文件都存放在templates目录下,install时会被部署到kubernetes上NOTES.txt 是一个例外,它并不包含kubernetes对象定义以”_“开头的文件不对被传递给kubernetes,即使它包含kubernetes对象定义。这类文件通常会被其他模版引用

    4.4.3.1、定义和引用模版

    结构 {{ define "MY_NAME" }} # body of template here {{ end }} 123 举例 [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml {{- define "my_labels" }} labels: generator: helm date: {{ now | htmlDate }} {{- end }} apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap {{- template "my_labels" }} data: {{- range $index, $topping := .Values.pizzaToppings }} {{ $index }}: {{ $topping }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '39896' [debug] SERVER: "127.0.0.1:39896" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: yucky-tuatara REVISION: 1 RELEASED: Tue Mar 13 09:26:51 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: yucky-tuatara-configmap labels: generator: helm date: 2018-03-13 data: 0: mushrooms 1: cheese 2: peppers 3: onions 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 说明  通过 define 定义模版通过 template 引用模版

    Helm建议我们将这类用来引用的模版定义到 _helpers.tpl 文件中:

    [root@k8s-master charts]# vi mychart-3/templates/_helpers.tpl {{- define "my_labels" }} labels: generator: helm date: {{ now | htmlDate }} {{- end }} [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap {{- template "my_labels" }} data: {{- range $index, $topping := .Values.pizzaToppings }} {{ $index }}: {{ $topping }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ 12345678910111213141516171819

    4.4.3.2、为模版指定命名空间

    默认情况下,命名模版不能够使用任何参数或者内建对象(如:Release、Values等),但是可以调用function,比如下面的例子:

    [root@k8s-master charts]# vi mychart-3/templates/_helpers.tpl {{/* Generate basic labels */}} {{- define "my_labels" }} labels: generator: helm date: {{ now | htmlDate }} chart: {{ .Chart.Name }} version: {{ .Chart.Version }} {{- end }} [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap {{- template "my_labels" }} data: {{- range $index, $topping := .Values.pizzaToppings }} {{ $index }}: {{ $topping }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '44449' [debug] SERVER: "127.0.0.1:44449" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: nonplussed-toucan REVISION: 1 RELEASED: Tue Mar 13 11:03:16 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nonplussed-toucan-configmap labels: generator: helm date: 2018-03-13 chart: version: data: 0: mushrooms 1: cheese 2: peppers 3: onions 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

    可以正常使用now和管道,但是 {{ .Chart.Name }} 和 {{ .Chart.Version }} 的值为空

    解决这个问题的方案就是在引用模版时,为其传递一个命名空间,将上述事例做如下改动:

    [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap {{- template "my_labels" . }} data: {{- range $index, $topping := .Values.pizzaToppings }} {{ $index }}: {{ $topping }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '35723' [debug] SERVER: "127.0.0.1:35723" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: dinky-worm REVISION: 1 RELEASED: Tue Mar 13 11:06:57 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: dinky-worm-configmap labels: generator: helm date: 2018-03-13 chart: mychart-3 version: 0.1.0 data: 0: mushrooms 1: cheese 2: peppers 3: onions 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152

    将 {{- template "my_labels" }} 修改为 {{- template "my_labels" . }} ,”.” 表示顶级命名空间,你也可以更具需要传递 .Values 或者 .Values.favorite 等任何你想要传递的范围。

    4.4.3.3、使用INCLUDE引用模版

    使用include引用模版允许我们使用管道和函数,看下面的例子:

    ### 假设有如下模版 ### [root@k8s-master charts]# vi mychart-3/templates/_helpers.tpl {{- define "mychart_app" -}} app_name: {{ .Chart.Name }} app_version: "{{ .Chart.Version }}+{{ .Release.Time.Seconds }}" {{- end -}} ### 引用 ### [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap labels: {{ template "mychart_app" .}} data: myvalue: "Hello World" ### 测试 ### [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '38909' [debug] SERVER: "127.0.0.1:38909" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: kind-giraffe REVISION: 1 RELEASED: Tue Mar 13 11:15:34 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: kind-giraffe-configmap labels: app_name: mychart-3 app_version: "0.1.0+1520910934" data: myvalue: "Hello World" [root@k8s-master charts]# 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

    输出与预期有些出入,app_version: "0.1.0+1520910934" 没有对齐,因为模版中的内容是没有左边的空白符的,而我们也不能在定义模版时添加空白字符,并且 template 不支持函数,一种解决办法是:

    ### 修改上例引用 ### [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap labels: {{ include "mychart_app" . | indent 4 }} data: myvalue: "Hello World" [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ 123456789101112

    注意:{{ include "mychart_app" . | indent 4 }} 要顶格写,左边不要有空格

    4.4.4、文件访问

    除了命名模版,helm还可以直接应用文件。Helm提供 .Files 对象来支持文件访问,并给出以下建议:

    可以在你的Chart中添加额外的文件,这些文件会被发送到kubernetes,但是要小心,一个Chart必须要小于1M,因为这是kubernetes对象大小的限制。因为某些安全因素,有些文件无法通过 .Files 访问:  templates/ 目录下的文件无法访问使用 .helmignore 排除的文件无法访问Charts do not preserve UNIX mode information, so file-level permissions will have no impact on the availability of a file when it comes to the .Files object.

    4.4.4.1、基本事例

    [root@k8s-master charts]# vi mychart-3/config1.toml message = Hello from config 1 [root@k8s-master charts]# vi mychart-3/config2.toml message = This is config 2 [root@k8s-master charts]# vi mychart-3/config3.toml message = Goodbye from config 3 [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: {{- $files := .Files }} {{- range tuple "config1.toml" "config2.toml" "config3.toml" }} {{ . }}: |- {{ $files.Get . }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '42465' [debug] SERVER: "127.0.0.1:42465" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: loopy-mastiff REVISION: 1 RELEASED: Tue Mar 13 12:14:13 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: loopy-mastiff-configmap data: config1.toml: |- message = Hello from config 1 config2.toml: |- message = This is config 2 config3.toml: |- message = Goodbye from config 3 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061

    4.4.4.2、路径匹配

    ### 修改上面的事例 ### [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: {{- $files := .Files }} {{ range $path, $bytes := .Files.Glob "**.toml" }} {{ $path }}: |- {{ $files.Get $path }} {{ end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ 1234567891011121314

    官网上的例子:

    {{ range $path := .Files.Glob "**.yaml" }} {{ $path }}: | {{ .Files.Get $path }} {{ end }} 1234

    是有问题的,此时$path为文件内容的字节码,而非路径,而且在循环内部不能使用 .Files ,当然也不排除我做实验时姿势不对的原因!

    4.4.4.3、CONFIGMAP 和 SECRETS函数

    ### 两个便利的函数 ### [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: {{ (.Files.Glob "**.toml").AsConfig | indent 2 }} {{ (.Files.Glob "**.toml").AsSecrets | indent 2 }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '40984' [debug] SERVER: "127.0.0.1:40984" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: mangy-antelope REVISION: 1 RELEASED: Tue Mar 13 12:26:12 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: mangy-antelope-configmap data: config1.toml: | message = Hello from config 1 config2.toml: | message = This is config 2 config3.toml: | message = Goodbye from config 3 config1.toml: bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK config2.toml: bWVzc2FnZSA9IFRoaXMgaXMgY29uZmlnIDIK config3.toml: bWVzc2FnZSA9IEdvb2RieWUgZnJvbSBjb25maWcgMwo= 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152

    4.4.4.4、ENCODING

    ### 有一个便利的函数 ### [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: token: |- {{ .Files.Get "config1.toml" | b64enc }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '40126' [debug] SERVER: "127.0.0.1:40126" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: mortal-warthog REVISION: 1 RELEASED: Tue Mar 13 12:28:25 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: mortal-warthog-configmap data: token: |- bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK 1234567891011121314151617181920212223242526272829303132333435363738394041424344

    4.4.4.5、逐行读取文件

    [root@k8s-master charts]# vi mychart-3/config1.toml message = Hello from config 1 message = Hello from config 2 message = Hello from config 3 message = Hello from config 4 message = Hello from config 5 message = Hello from config 6 message = Hello from config 7 message = Hello from config 8 [root@k8s-master charts]# vi mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: some-file.txt: | {{- range .Files.Lines "config1.toml" }} {{ . }} {{- end }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '43350' [debug] SERVER: "127.0.0.1:43350" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 NAME: giddy-rat REVISION: 1 RELEASED: Tue Mar 13 12:32:59 2018 CHART: mychart-3-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: pizzaToppings: - mushrooms - cheese - peppers - onions HOOKS: MANIFEST: --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: giddy-rat-configmap data: some-file.txt: | message = Hello from config 1 message = Hello from config 2 message = Hello from config 3 message = Hello from config 4 message = Hello from config 5 message = Hello from config 6 message = Hello from config 7 message = Hello from config 8 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

    4.4.5、创建NOTE.txt文件

    NOTE.txt是一个文本文件,文件内容会在 chart install 或者 chart upgrade 之后输出到屏幕上,因此我们可以给出一些提示信息:

    [root@k8s-master charts]# vi mychart-3/templates/NOTE.txt Thank you for installing {{ .Chart.Name }}. Your release is named {{ .Release.Name }}. To learn more about the release, try: $ helm status {{ .Release.Name }} $ helm get {{ .Release.Name }} [root@k8s-master charts]# helm install --debug --dry-run mychart-3/ [debug] Created tunnel using local port: '34825' [debug] SERVER: "127.0.0.1:34825" [debug] Original chart version: "" [debug] CHART PATH: /root/charts/mychart-3 Error: YAML parse error on mychart-3/templates/NOTE.txt: error converting YAML to JSON: yaml: line 4: mapping values are not allowed in this context --- # Source: mychart-3/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: whopping-wolf-configmap data: some-file.txt: | message = Hello from config 1 message = Hello from config 2 message = Hello from config 3 message = Hello from config 4 message = Hello from config 5 message = Hello from config 6 message = Hello from config 7 message = Hello from config 8 --- # Source: mychart-3/templates/NOTE.txt Thank you for installing mychart-3. Your release is named whopping-wolf. To learn more about the release, try: $ helm status whopping-wolf $ helm get whopping-wolf 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

    4.4.6、子Chart和全局变量

    关于全局变量的部分内容已经在Chart一节中介绍过,更多详细内容可参考:https://docs.helm.sh/chart_template_guide/#subcharts-and-global-values

    5、附件下载

    网盘链接:https://pan.baidu.com/s/1YUkLahajwqxH9hoPW74x9Q

    解压:tar -zxvf tiller-v2.8.1-tar.gz

    导入:docker load -i tiller-v2.8.1-tar

    6、参考资料

    https://docs.helm.sh/

    这次学习Helm的唯一参考资料就是官方文档,但是英语水平有限,很多地方理解不到位或者可能存在偏差。关于文档中给出的事例和我自己得出的结果不一致的地方,也不排除此原因导致!


    最新回复(0)