目录:
根据微服务的发版需求进行对应用进行调试,使用chart的模版发布微服务
一、基于dubbo微服务发布一个基于生产环境用到的helm模版
模版地址:git clone git@gitee.com:zhaocheng172/helm-dubbo.git
拉取请把你的公钥给我,否则拉不下来css
3.6 Chart模板
Helm最核心的就是模板,即模板化的K8S manifests文件。
它本质上就是一个Go的template模板。Helm在Go template模板的基础上,还会增长不少东西。如一些自定义的元数据信息、扩展的库以及一些相似于编程形式的工做流,例如条件语句、管道等等。这些东西都会使得咱们的模板变得更加丰富。html
说在前面的话,其实在helm中,其实最关键的就是这个模版的渲染,咱们将yaml中可能常常变更的字段,去指定一个变量,这个变量就能够经过helm的命令行,经过它的命名行去覆盖它默认的变量,这就能动态的渲染到yaml中,里面最重要的就是这个模版values,helm帮咱们作的事就是集中管理yaml,能动态的渲染这些yaml,由于在写yaml时里面可能会有不少字段,在后面部署的时候可能回有其余变化,其实就是将这些变更的字段,动态的批量的去修改,以前没有helm的时候,通常都是也会设计一个通用的模版来改变里面常常变更的字段,通常就是使用sed来替换里面的值,好比替换镜像,将镜像替换一个名字就能够部署一个新的应用了,替换成功,apply一下就应用上了,固然这个镜像是你提早将代码编译好的,而后经过dockerfile制做一个本身的镜像,通常替换的镜像地址也是harbor上的镜像地址为准,这样的话,可能会写不少替换的命令,显然也不是很灵活,文件愈来愈多,对管理也是有必定成本,其实最好的方式有没有在一个文件中,把这些变量字段写进去,全部的yaml均可以读到这个变量,把它引用到渲染的文件中,这也是helm要作的事,这也是helm核心的功能。java
一、模板
有了模板,咱们怎么把咱们的配置融入进去呢?用的就是这个values文件。这两部份内容其实就是chart的核心功能。
当咱们去部署一个应用的时候,好比发布一个微服务,都是要作这么一个chart,这个chart能够来自于互联网上,或者别人分享给你,或者本身制做的均可以,在这个chart中最核心的就是这个模版了,咱们去部署一个应用,它这个模版自己就是一个go的模版,用go去渲染的,只不过helm在go的基础之上添写了一些东西,让它更灵活,好比条件判段
接下来,部署nginx应用,熟悉模板使用,先把templates 目录下面全部文件所有删除掉,这里咱们本身来建立模板文件,语法的控制,都是知足这个模版更多的需求。node
好比先建立一个chart,一共4个目录,在templates里面就是咱们部署一个应用所需的配置yaml,像deployment,service,ingress等,咱们将一些常常变更的字段写成变量的模式,经过values去定义这些变量的值,经过helm install建立的时候,它就会进行对values进行渲染到咱们的template里面了,还有一个_helpers.tpl,它会放一些deployment,service都会用到的模版,好比都会用到一些通用的字段,那么久能够把它放到_helpers.tpl命名模版里面,NOTES.txt是部署一个应用用到的一个提示,好比访问的地址,还有一个test的这个目录,好比你部署好一个应用,测试一下看看是否是部署正常。nginx
[root@k8s-master1 one_chart]# helm create one Creating one [root@k8s-master1 one_chart]# ls one [root@k8s-master1 one_chart]# cd one/ [root@k8s-master1 one]# ls charts Chart.yaml templates values.yaml [root@k8s-master1 one]# tree . . ├── charts ├── Chart.yaml ├── templates │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── ingress.yaml │ ├── NOTES.txt │ ├── serviceaccount.yaml │ ├── service.yaml │ └── tests │ └── test-connection.yaml └── values.yaml
先准备两个yaml,而后咱们进行去对一些常常变的字段,进行渲染git
[root@k8s-master1 templates]# kubectl create deployment application --image=nginx --dry-run -o yaml > deployment.yaml [root@k8s-master1 templates]# kubectl expose deployment application --port=80 --target-port=80 --dry-run -o yaml > service.yaml
而后咱们将咱们的服务先发布出去测试一下,顺便测试能不能正常访问
咱们正常是经过apply -f 去发布这样的一个服务,如今使用helm来发布试一下,其实效果是同样的,可是这样去发布的话,咱们跟apply -f 没什么效果了,而helm的核心应用的功能在于咱们可以有效的去渲染咱们的变量,使发布咱们的微服务更灵活,好比就能够经过模版进行变量的渲染修改一下镜像的地址,发布服务的名称,以及副本数,等等,来动态的传入,快速发布多套微服务,简单说就是部署一套通用的模版,来部署一些常规性的应用。docker
[root@k8s-master1 one_chart]# helm install application one/ NAME: application LAST DEPLOYED: Wed Dec 18 11:44:21 2019 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None [root@k8s-master1 templates]# kubectl get pod,svc NAME READY STATUS RESTARTS AGE pod/application-6c45f48b87-2gl95 1/1 Running 0 10s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/application ClusterIP 10.0.0.221 <none> 80/TCP 9s [root@k8s-master1 templates]# curl -I 10.0.0.221 HTTP/1.1 200 OK Server: nginx/1.17.6 Date: Wed, 18 Dec 2019 03:35:22 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 19 Nov 2019 12:50:08 GMT Connection: keep-alive ETag: "5dd3e500-264" Accept-Ranges: bytes
也就是部署一个chart,使用这个模版,可以部署一些常规性的应用,首先须要常常变更的是名字,还有副本,以及镜像名称编程
二、调试
Helm也提供了--dry-run 调试参数,帮助你验证模板正确性。在执行helm install时候带上这两个参数就能够把对应的values值和渲染的资源清单打印出来,而不会真正的去部署一个release。
好比咱们来调试上面建立的 chart 包:helm install pod-nodejs-tools --dry-run /root/one
vim
三、内置对象
{{ Release.Name}}这个属于内置变量,这个内置变量其实就是咱们install的时候进行对咱们部署应用起的名字,也就是传进来了,那么就能够直接使用这个来部署资源的名字
{{ Chart.Name}}这个值也是属于helm的一个内置变量,这个也就是咱们建立chart后模版有Chart.yaml这个yaml,其实这个就是在这里面去取的值,固然项目的名字,通常都是统一的,能够直接经过{{ Values.name}}咱们本身去定义,也就是在values.yaml这个里面去定义的
咱们编写好了变量的传输以后,也能够输出一下,看看是否是可以正常输出渲染
这里的pod-base-common其实就会使我在{{ Release.name}}去生效 --dry-run就是预执行 ,one就是个人chart的目录
像一些经常使用的release内置变量,Chart的变量能够直接在chart包中去看到api
[root@k8s-master1 one]# cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: chart: {{ .Chart.Name }} app: {{ .Chart.Name }} name: {{ .Release.Name }} spec: replicas: {{ .Values.replicas }} selector: matchLabels: app: {{ .Values.label }} template: metadata: labels: app: {{ .Values.label }} spec: containers: - image: {{ .Values.image }}:{{ .Values.imagetag }} name: {{ .Release.Name }}
四、Values自定义变量
Values对象是为Chart模板提供值,这个对象的值有4个来源:
chart 包中的 values.yaml 文件
父 chart 包的 values.yaml 文件
经过 helm install 或者 helm upgrade 的 -f或者 --values参数传入的自定义的 yaml 文件
经过 --set 参数传入的值[root@k8s-master1 one]# helm install pod-mapper-service --set replicas=1 ../one/
经过--set命令会优先将覆盖values的值,建立一个副本,而不是二个了。
chart 的 values.yaml 提供的值能够被用户提供的 values 文件覆盖,而该文件一样能够被 --set提供的参数所覆盖。
[root@k8s-master1 one]# cat values.yaml replicas: 2 image: nginx imagetag: 1.16 label: nginx [root@k8s-master1 one_chart]# helm install pod-base-common --dry-run one/ [root@k8s-master1 ~]# helm install pod-css-commons /root/one_chart/one/ NAME: pod-css-commons LAST DEPLOYED: Wed Dec 18 14:41:02 2019 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None
执行以后查看渲染后的结果使用get manifest+项目的名称,经过helm ls,就能查看到helm建立的服务
[root@k8s-master1 ~]# helm get manifest pod-css-commons [root@k8s-master1 one]# helm ls NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION pod-css-commons default 1 2019-12-18 14:41:02.800570406 +0800 CSTdeployed application-0.1.0 1.16.0
好比咱们再测试一下,好比咱们的代码更新了,经过dockerfile又构成新的镜像了,那么咱们须要去替换新的镜像,怎么作?
其实讲咱们的values下定义的名称换成新的镜像的地址就能够了,这里作演示写的是nginx1.17
而后经过helm upgrade更换了新的镜像
[root@k8s-master1 one]# helm upgrade pod-css-commons ../one/ Release "pod-css-commons" has been upgraded. Happy Helming! NAME: pod-css-commons LAST DEPLOYED: Wed Dec 18 15:00:14 2019 NAMESPACE: default STATUS: deployed REVISION: 2 TEST SUITE: None
经过get manifest能够查看到渲染后的镜像的地址,通常在微服务的发布当中为了保证项目名字的一致性,都是统一使用{{Values.name}},本身设置变量[root@k8s-master1 one]# helm get manifest pod-css-commons
好比如今有要发布一个微服务
那么咱们通常替换的通常就是服务的名字还有镜像了
直接在values中去修改为新的镜像的地址还有项目的名字就--dry-run 一下测试没问题直接发布
[root@k8s-master1 one]# cat values.yaml replicas: 2 image: nginx imagetag: 1.15 name: pod-base-user-service app: pod-base-user-service port: 80 targetPort: 80 [root@k8s-master1 one]# helm install pod-base-user-service ../one/ [root@k8s-master1 one]# kubectl get pod NAME READY STATUS RESTARTS AGE nfs-client-provisioner-6f54fc894d-dbvmk 1/1 Running 0 5d3h pod-base-ec-service-664987f9c6-5f9vl 1/1 Running 0 7m18s pod-base-ec-service-664987f9c6-mw4jb 1/1 Running 0 7m18s pod-base-user-service-6b7d9d47b8-qqcbp 1/1 Running 0 7s pod-base-user-service-6b7d9d47b8-r5f96 1/1 Running 0 8s
五、管道与函数
刚才的values,以及内置的对象其实就是将值传给模板引擎进行渲染,另外模板引擎还支持对拿到数据进行二次处理,也就是必定非要使用values的值,也能够对这个模版进行二次处理,好比我将拿到的数据,第一个字母为大写,或者我将拿到的值的字符串进行加个双引号,那么均可以对这个模版引擎进行二次处理,好比将拿到的值变成一个字符串,那么这就用到了一个函数,那么这个模版引擎支持这个函数,那么这个函数不是特别的经常使用,可是也会用到这个,好比deployment这里,好比labels这里拿到这个值并加个双引号,有的yaml的值必须加双引号才能够,其实这个实现的话也比较简单,直接加一个quote就能够
双引号
labels: app: {{ quote .Values.name }}
测试效果已经给将双引号给添加上了,其实这就是quote函数帮咱们作的一个二次处理,当咱们特定的给一些值加双引号的时候,就能够直接经过quote函数来实现
[root@k8s-master1 one]# helm install pod-tools-service --dry-run ../one/ labels: app: "pod-mapper-service"
再好比将一个特定的变量直接传入,不经过values,我定义的env这个字段,默认是没有的,经过{{ default "xxxx" .Values.env }} 传入,好比这就是一个默认值,不须要变的,就能够直接这么定义
spec: nodeSelector: team: {{ .Values.team }} env: {{ default "JAVA_OPTS" .Values.env }}
那么若是values里面有这个值,它默认就会使用values里面的值,若是没有就会使用default使用默认的值
像缩进这一块,自己yaml就是以层级关系来定义的,那么有时候咱们就会用到这种的需求来渲染咱们的层级关系
其余函数:
缩进:{{ .Values.resources | indent 12 }} 大写:{{ upper .Values.resources }} 首字母大写:{{ title .Values.resources }}
六、流程控制
流程控制是为模板提供了一种能力,知足更复杂的数据逻辑处理。
Helm模板语言提供如下流程控制语句:
if/else 条件块
with 指定范围
range 循环块
像缩进流程控制通常也都会用到,像else/if了都会作一下复杂逻辑的处理,
values下定义这个参数
test: "123"
templates/deployment.yaml下去定义这个判断,if test=123,那么就输出test:a,不然若是变量的值为其余,这里就打印test:b了,这种的应用的场景也能根据本身的实际应用场景对yaml进行定义,可是这种遇到的状况也很少。
spec: nodeSelector: team: {{ .Values.team }} env: {{ default "JAVA_OPTS" .Values.env }} {{ if eq .Values.test "123" }} test: a {{ else }} test: b {{ end }}
其实在这里输出的话,给留出空格,其实就是刚才的{{咱们定义的参数留下的}},这个直接去掉就能够了,经过-就能够删除
eq运算符判断是否相等,另外还支持ne、 lt、 gt、 and、 or等运算符。
{{- if eq .Values.test "123" }} test: a {{- else }} test: b {{- end }} containers:
条件判断就是判断条件是否为真,若是值为如下几种状况则为false:
一个布尔类型的 为flase
一个数字 零
一个 空的字符串
一个 nil(空或 null)
一个空的集合( map、 slice、 tuple、 dict、 array)
除了上面的这些状况外,其余全部条件都为 真。
好比values的值设置的就是flase,那就不为真
或者就是values的值设置的就是0,那么默认也是设置为false,那也不为真
若是为空,那么也为false,或者为集合,以上的状况都为false
那么咱们在values设置一个0,测试一下,而后这边打印的为b,说明就是假的
test: 0 test: "" [root@k8s-master1 one]# helm install pod-mapper-service --dry-run ../one/ spec: nodeSelector: team: team1 env: JAVA_OPTS test: b containers: - image: nginx:1.15 name: pod-mapper-service
如今咱们使用它们helm官方原来的values的模版来建立一个应用并且它这个支持序列化的格式化的结构,好比镜像image,可能会有他的镜像的地址标签名字,可能下面还定义多个属性,因此这种就能够定义这种结构化的一个格式,好比像仓库的地址,拉取镜像的策略
image: repository: nginx tag: 1.17 pullPolicy: IfNotPresent
[root@k8s-master1 one]# cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Values.name }} template: metadata: labels: app: {{ .Values.name }} spec: nodeSelector: team: {{ .Values.team }} containers: - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} name: {{ .Values.name }}
[root@k8s-master1 one]# cat templates/service.yaml apiVersion: v1 kind: Service metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: ports: - port: {{ .Values.port }} protocol: TCP targetPort: {{ .Values.port }} selector: app: {{ .Values.name }}
[root@k8s-master1 one]# vim values.yaml app: pod-base-jss name: pod-base-jss replicaCount: 3 image: repository: nginx tag: 1.17 pullPolicy: IfNotPresent team: team3 [root@k8s-master1 one]# helm install pod-base-jss ../one/ [root@k8s-master1 one]# helm ls NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION pod-base-jss default 1 2019-12-19 13:57:49.881954736 +0800 CST deployed application-0.1.0
如今再增长一个资源限制
作一个判断当默认为false或者true的状况下,作相关的动做,就是说资源限制用不用,若是定义的为false,那么就不使用这里面的资源,那么为ture的话,就使用,或者不设置,将限制的资源注释去掉
如今就去判断这个resource是否是为真,若是为真的话就使用resource,而后对这个pod多一个资源的限制,若是为假的话,就不作资源限制,直接判断{{ if .Values.resources }}
这里我先判断为真测试一下,它会将咱们的判断为真的加进去
[root@k8s-master1 one]# cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Values.name }} template: metadata: labels: app: {{ .Values.name }} spec: nodeSelector: team: {{ .Values.team }} containers: - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} name: {{ .Values.name }} {{- if .Values.resources }} resources: limits: cpu: {{ .Values.resources.limits.cpu }} memory: {{ .Values.resources.limits.memory}} requests: cpu: {{ .Values.resources.requests.cpu }} memory: {{ .Values.resources.requests.memory }} {{- else }} resources: {} {{- end }}
这里就会去引用咱们下面的变量,若是没这个需求就能够直接在resources: 0 ,或者""或者false均可以,而后将下面的注释就不会引用了,也就是至关于一个开关,很好的去管理咱们的应用
[root@k8s-master1 one]# cat values.yaml resources: limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi
测试结果查看
[root@k8s-master1 one]# helm upgrade pod-base-jss --dry-run ../one/ Release "pod-base-jss" has been upgraded. Happy Helming! NAME: pod-base-jss LAST DEPLOYED: Thu Dec 19 14:36:37 2019 NAMESPACE: default STATUS: pending-upgrade REVISION: 2 TEST SUITE: None HOOKS: MANIFEST: --- Source: application/templates/service.yaml apiVersion: v1 kind: Service metadata: labels: app: pod-base-jss name: pod-base-jss spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: pod-base-jss --- Source: application/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-base-jss name: pod-base-jss spec: replicas: 3 selector: matchLabels: app: pod-base-jss template: metadata: labels: app: pod-base-jss spec: nodeSelector: team: team3 containers: - image: nginx:1.17 name: pod-base-jss resources: limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi
或者还有一种方法,直接在values加入enabled,false就是关闭的意思,执行以后首先会根据enabeld去使用
resources: enabled: false limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi
那么在{{ if .Values.resource.enabled}} 去定义将values的开关为true就就会使用,为false就不会使用
[root@k8s-master1 one]# cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Values.name }} template: metadata: labels: app: {{ .Values.name }} spec: nodeSelector: team: {{ .Values.team }} containers: - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} name: {{ .Values.name }} {{- if .Values.resources.enabled }} resources: limits: cpu: {{ .Values.resources.limits.cpu }} memory: {{ .Values.resources.limits.memory}} requests: cpu: {{ .Values.resources.requests.cpu }} memory: {{ .Values.resources.requests.memory }} {{- else }} resources: {} {{- end }}
像这样的需求也不少,有的微服务不须要去建立ingress的,有的可能须要,或者有的可能不使用ingress做为集群外部的负载均衡器流入到集群内部的你的服务上,直接使用service的clusterIP再部署几台nginx负载均衡器来进行负责转发内部的服务,经过slb进行暴露出去,那么咱们去实现一下这两个需求
在values中它有这个模版enabled能够跟刚才的也同样,若是设置为false的话就不建立ingress规则,若是为true的话就建立这个规则
先对service进行定义,也就是流程控制,如今对service不进行使用
values进行设置开关为false,enabled
[root@k8s-master1 one]# cat values.yaml app: pod-base-tools name: pod-base-tools replicaCount: 3 image: repository: nginx tag: 1.17 pullPolicy: IfNotPresent serviceAccount: create: true name: service: enabled: false port: 80 targetPort: 80 ingress: enabled: false annotations: {} hosts: - host: chart-example.local paths: [] tls: [] resources: enabled: true limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi nodeSelector: team: team2
[root@k8s-master1 templates]# cat service.yaml {{- if .Values.service.enabled }} apiVersion: v1 kind: Service metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: ports: - port: {{ .Values.service.port }} protocol: TCP targetPort: {{ .Values.service.targetPort }} selector: app: {{ .Values.name }} {{ end }} [root@k8s-master1 templates]# cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Values.name }} template: metadata: labels: app: {{ .Values.name }} spec: nodeSelector: team: {{ .Values.nodeSelector.team }} containers: - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} name: {{ .Values.name }} {{- if .Values.resources.enabled }} resources: limits: cpu: {{ .Values.resources.limits.cpu }} memory: {{ .Values.resources.limits.memory}} requests: cpu: {{ .Values.resources.requests.cpu }} memory: {{ .Values.resources.requests.memory }} {{- else }} resources: {} {{- end }}
执行以后不会建立service,由于我设置的if去判断为假的话,那么就不建立service,并设置的开关为false,那么设置为true就直接能够建立service了[root@k8s-master1 templates]# helm install pod-base-tools --dry-run ../../one/
如今建立一个ingress,也设置一个开关,其实方法也是同样的
[root@k8s-master1 one]# cat values.yaml app: pod-base-user name: pod-base-user replicaCount: 3 image: repository: nginx tag: 1.17 pullPolicy: IfNotPresent serviceAccount: create: true name: service: enabled: false port: 80 targetPort: 80 ingress: enabled: true annotations: {} hosts: - host: chart-example.local paths: [] tls: [] resources: enabled: true limits: cpu: 100m memory: 128Mi requests: cpu: 100m memory: 128Mi nodeSelector: team: team2
[root@k8s-master1 templates]# cat ingress.yaml {{- if .Values.ingress.enabled }} apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: test-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: /testpath backend: serviceName: test servicePort: 80 {{ end }} [root@k8s-master1 templates]# helm install pod-base-user ../../one/ [root@k8s-master1 templates]# kubectl get ing NAME HOSTS ADDRESS PORTS AGE ingress.extensions/test-ingress * 80 39s
with
with :控制变量做用域。
{{.Release.xxx}}或者 {{.Values.xxx}}其中的 .就是表示对当前范围的引用, .Values就是告诉模板在当前范围中查找 Values对象的值。而 with语句就能够来控制变量的做用域范围,其语法和一个简单的 if语句比较相似
一个小问题就是当咱们去写变量引用的时候都会在前面加一个.这个点的意思就是从哪一个范围去找,按照.的话,就是按这个生成模版的结构去找的
再使用一下nodeSelector这个值吧,这个看实际的场景,通常呢都是会设置调度的节点进行分组,这样才保证咱们更好的去管理node节点的分布微服务的布局
这个呢也可使用以前的语法if去作判断
也能够经过这个开关的方式进行配置,或者就是with的方式,或者就是toyaml的函数方式
spec: {{- if .Values.nodeSelector.enabled }} nodeSelector: team: {{ .Values.nodeSelector.team }} {{- else }} {{- end }}
[root@k8s-master1 one]# cat values.yaml nodeSelector: enabled: true team: team2 [root@k8s-master1 templates]# cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: {{ .Values.name }} name: {{ .Values.name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Values.name }} template: metadata: labels: app: {{ .Values.name }} spec: {{- if .Values.nodeSelector.enabled }} nodeSelector: team: {{ .Values.nodeSelector.team }} {{- else }} {{- end }} containers: - image: {{ .Values.image.repository }}:{{ .Values.image.tag }} name: {{ .Values.name }} {{- if .Values.resources.enabled }} resources: limits: cpu: {{ .Values.resources.limits.cpu }} memory: {{ .Values.resources.limits.memory}} requests: cpu: {{ .Values.resources.requests.cpu }} memory: {{ .Values.resources.requests.memory }} {{- else }} resources: {} {{- end }}
或者把开关去掉,用with直接去读取咱们的参数也是能够的
[root@k8s-master1 one]# tail -4 values.yaml nodeSelector: team: team2
在deployment去定义这个字段,- with 指定.team,来读取相应的值
spec: {{- with .Values.nodeSelector }} nodeSelector: team: {{ .team }} {{- else }} {{- end }}
使用toYaml方式
spec: {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }}
with是一个循环构造。使用.Values.nodeSelector中的值:将其转换为Yaml。
toYaml以后的点是循环中.Values.nodeSelector的当前值
range
在 Helm 模板语言中,使用 range关键字来进行循环操做。
咱们在 values.yaml文件中添加上一个变量列表:
像range通常要写多个元素的时候要使用,像toyaml和with通常用于结构化的层次比较多的,比较使用env这样的适合使用range,
cat values.yaml test: - 1 - 2 - 3
循环打印该列表:
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }} data: test: | {{- range .Values.test }} {{ . }} {{- end }}
循环内部咱们使用的是一个 .,这是由于当前的做用域就在当前循环内,这个 .引用的当前读取的元素
七、变量
变量,在模板中,使用变量的场合很少,但咱们将看到如何使用它来简化代码,并更好地利用with和range。由于刚才咱们用到的with,不能在下面再去定义其余的变量了,那么怎么在with中去引用一些全值内置的变量呢,有两种方法,一个是使用helm的变量赋值进行去使用,第二种是使用$去使用
测试一下,先不添加$
spec: {{- with .Values.nodeSelector }} nodeSelector: app: {{ .Values.name }}
执行结果是这样的
[root@k8s-master1 templates]# helm install pod-base-user --dry-run ../../one/ Error: template: application/templates/deployment.yaml:19:23: executing "application/templates/deployment.yaml" at <.Values.name>: nil pointer evaluating interface {}.name
那么加上$的话这样就会正常输出
spec: nodeSelector: app: pod-base-user team: team2
也可使用另一种形式来输出
spec: {{- $releaseName := .Release.Name -}} {{- with .Values.nodeSelector }} nodeSelector: app: {{ $releaseName }}
能够看到在 with语句上面增长了一句 {{-$releaseName:=.Release.Name-}},其中 $releaseName就是后面的对象的一个引用变量,它的形式就是 $name,赋值操做使用 :=,这样 with语句块内部的 $releaseName变量仍然指向的是 .Release.Name
另外就是咱们在定义一个微服务或者java的项目的时候会设置java的堆内存大小,那么这个也是比较经常使用的选项,怎么将这个也加入进去呢,这里方法不少,可使用toYaml方式,
咱们先去values去定义一下
[root@k8s-master1 one]# tail -4 values.yaml env: - name: JAVA_OPTS value: -Xmx1024m -Xms1014m
经过刚才方法也是能够打印的
{{- with .Values.env }} env: {{- toYaml . | nindent 8 }} {{- end }}
八、命名模板
命名模板:使用define定义,template引入,在templates目录中默认下划线开头的文件为公共模板(helpers.tpl),好比这个yaml里面有一两处的都须要这不如toYaml模式,或者if else开关的模式,那么久可使用这个命名模版了
好比资源的名字都是相同的名字这个就能够定义一个命名模版,把这一块的逻辑都写在一个模版里,让这些yaml都引用这一块,而后他们引用的名字都同样,好比label这一块,标签选择器,那么控制器呢须要根据标签选择器来匹配pod,那么这一块能够写到_helper.tpl里面,这个就是实际存放公共模版的地方,定义模版呢就是使用define定义,template来引入
cat _helpers.tpl {{- define "demo.fullname" -}} {{- .Chart.Name -}}-{{ .Release.Name }} {{- end -}} cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ template "demo.fullname" . }} ...
template指令是将一个模板包含在另外一个模板中的方法。可是,template函数不能用于Go模板管道。为了解决该问题,增长include功能
cat _helpers.tpl {{- define "demo.labels" -}} app: {{ template "demo.fullname" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" {{- end -}}
cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "demo.fullname" . }} labels: {{- include "demo.labels" . | nindent 4 }} ...
上面包含一个名为 demo.labels 的模板,而后将值 . 传递给模板,最后将该模板的输出传递给 nindent 函数。
3.7 开发本身的Chart:dubbo微服务应用为例
先建立模板
helm create dubbo
修改Chart.yaml,Values.yaml,
添加经常使用的变量
git clone git@gitee.com:zhaocheng172/helm-dubbo.git