K8s原生微服务管理工具helm-v3的使用初探实践(2)

目录:
根据微服务的发版需求进行对应用进行调试,使用chart的模版发布微服务
1、基于dubbo微服务发布一个基于生产环境用到的helm模版
模版地址:
git clone [email protected]:zhaocheng172/helm-dubbo.git
拉取请把你的公钥给我,不然拉不下来

3.6 Chart模板
Helm最核心的就是模板,即模板化的K8S manifests文件。
它本质上就是一个Go的template模板。Helm在Go template模板的基础上,还会增加很多东西。如一些自定义的元数据信息、扩展的库以及一些类似于编程形式的工作流,例如条件语句、管道等等。这些东西都会使得我们的模板变得更加丰富。

说在前面的话,其实在helm中,其实最关键的就是这个模版的渲染,我们将yaml中可能经常变动的字段,去指定一个变量,这个变量就可以通过helm的命令行,通过它的命名行去覆盖它默认的变量,这就能动态的渲染到yaml中,里面最重要的就是这个模版values,helm帮我们做的事就是集中管理yaml,能动态的渲染这些yaml,因为在写yaml时里面可能会有很多字段,在后面部署的时候可能回有其他变化,其实就是将这些变动的字段,动态的批量的去修改,之前没有helm的时候,一般都是也会设计一个通用的模版来改变里面经常变动的字段,一般就是使用sed来替换里面的值,比如替换镜像,将镜像替换一个名字就可以部署一个新的应用了,替换成功,apply一下就应用上了,当然这个镜像是你提前将代码编译好的,然后通过dockerfile制作一个自己的镜像,一般替换的镜像地址也是harbor上的镜像地址为准,这样的话,可能会写很多替换的命令,显然也不是很灵活,文件越来越多,对管理也是有一定成本,其实最好的方式有没有在一个文件中,把这些变量字段写进去,所有的yaml都可以读到这个变量,把它引用到渲染的文件中,这也是helm要做的事,这也是helm核心的功能。

1、模板
有了模板,我们怎么把我们的配置融入进去呢?用的就是这个values文件。这两部分内容其实就是chart的核心功能。
当我们去部署一个应用的时候,比如发布一个微服务,都是要做这么一个chart,这个chart可以来自于互联网上,或者别人分享给你,或者自己制作的都可以,在这个chart中最核心的就是这个模版了,我们去部署一个应用,它这个模版本身就是一个go的模版,用go去渲染的,只不过helm在go的基础之上添写了一些东西,让它更灵活,比如条件判段
接下来,部署nginx应用,熟悉模板使用,先把templates 目录下面所有文件全部删除掉,这里我们自己来创建模板文件,语法的控制,都是满足这个模版更多的需求。

比如先创建一个chart,一共4个目录,在templates里面就是我们部署一个应用所需的配置yaml,像deployment,service,ingress等,我们将一些经常变动的字段写成变量的模式,通过values去定义这些变量的值,通过helm install创建的时候,它就会进行对values进行渲染到我们的template里面了,还有一个_helpers.tpl,它会放一些deployment,service都会用到的模版,比如都会用到一些通用的字段,那么久可以把它放到_helpers.tpl命名模版里面,NOTES.txt是部署一个应用用到的一个提示,比如访问的地址,还有一个test的这个目录,比如你部署好一个应用,测试一下看看是不是部署正常。

[[email protected] one_chart]# helm create one
Creating one
[[email protected] one_chart]# ls
one
[[email protected] one_chart]# cd one/
[[email protected] one]# ls
charts  Chart.yaml  templates  values.yaml
[[email protected] 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,然后我们进行去对一些经常变的字段,进行渲染

[[email protected] templates]# kubectl create deployment application --image=nginx --dry-run -o yaml > deployment.yaml
[[email protected] templates]# kubectl expose deployment application --port=80 --target-port=80 --dry-run -o yaml > service.yaml

然后我们将我们的服务先发布出去测试一下,顺便测试能不能正常访问
我们正常是通过apply -f 去发布这样的一个服务,现在使用helm来发布试一下,其实效果是一样的,但是这样去发布的话,我们跟apply -f 没什么效果了,而helm的核心应用的功能在于我们能够有效的去渲染我们的变量,使发布我们的微服务更灵活,比如就可以通过模版进行变量的渲染修改一下镜像的地址,发布服务的名称,以及副本数,等等,来动态的传入,快速发布多套微服务,简单说就是部署一套通用的模版,来部署一些常规性的应用。

[[email protected] 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
[[email protected] 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
[[email protected] 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,使用这个模版,能够部署一些常规性的应用,首先需要经常变动的是名字,还有副本,以及镜像名称

2、调试
Helm也提供了--dry-run 调试参数,帮助你验证模板正确性。在执行helm install时候带上这两个参数就可以把对应的values值和渲染的资源清单打印出来,而不会真正的去部署一个release。
比如我们来调试上面创建的 chart 包:
helm install pod-nodejs-tools --dry-run /root/one

3、内置对象
{{ 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包中去看到

[[email protected] 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 }}

4、Values自定义变量
Values对象是为Chart模板提供值,这个对象的值有4个来源:
chart 包中的 values.yaml 文件
父 chart 包的 values.yaml 文件
通过 helm install 或者 helm upgrade 的 -f或者 --values参数传入的自定义的 yaml 文件
通过 --set 参数传入的值
[[email protected] one]# helm install pod-mapper-service --set replicas=1 ../one/
通过--set命令会优先将覆盖values的值,创建一个副本,而不是二个了。
chart 的 values.yaml 提供的值可以被用户提供的 values 文件覆盖,而该文件同样可以被 --set提供的参数所覆盖。

[[email protected] one]# cat values.yaml
replicas: 2
image: nginx
imagetag: 1.16
label: nginx
[[email protected] one_chart]# helm install pod-base-common --dry-run one/
[[email protected] ~]# 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创建的服务

[[email protected] ~]# helm get manifest pod-css-commons
[[email protected] 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更换了新的镜像

[[email protected] 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}},自己设置变量
[[email protected] one]# helm get manifest pod-css-commons
比如现在有要发布一个微服务
那么我们一般替换的一般就是服务的名字还有镜像了
直接在values中去修改成新的镜像的地址还有项目的名字就--dry-run 一下测试没问题直接发布

[[email protected] 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
[[email protected] one]# helm install pod-base-user-service  ../one/
[[email protected] 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

5、管道与函数

刚才的values,以及内置的对象其实就是将值传给模板引擎进行渲染,另外模板引擎还支持对拿到数据进行二次处理,也就是一定非要使用values的值,也可以对这个模版进行二次处理,比如我将拿到的数据,第一个字母为大写,或者我将拿到的值的字符串进行加个双引号,那么都可以对这个模版引擎进行二次处理,比如将拿到的值变成一个字符串,那么这就用到了一个函数,那么这个模版引擎支持这个函数,那么这个函数不是特别的常用,但是也会用到这个,比如deployment这里,比如labels这里拿到这个值并加个双引号,有的yaml的值必须加双引号才可以,其实这个实现的话也比较简单,直接加一个quote就可以
双引号

labels:
        app: {{ quote .Values.name }}

测试效果已经给将双引号给添加上了,其实这就是quote函数帮我们做的一个二次处理,当我们特定的给一些值加双引号的时候,就可以直接通过quote函数来实现

[[email protected] 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 }}

6、流程控制

流程控制是为模板提供了一种能力,满足更复杂的数据逻辑处理。
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: ""
[[email protected] 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
[[email protected] 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 }}
[[email protected] 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 }}
[[email protected] one]# vim values.yaml
app: pod-base-jss
name: pod-base-jss
replicaCount: 3

image:
  repository: nginx
  tag: 1.17
  pullPolicy: IfNotPresent

team: team3

[[email protected] one]# helm install pod-base-jss  ../one/
[[email protected] 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 }}
这里我先判断为真测试一下,它会将我们的判断为真的加进去

[[email protected] 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都可以,然后将下面的注释就不会引用了,也就是相当于一个开关,很好的去管理我们的应用

[[email protected] one]# cat values.yaml
resources:
     limits:
       cpu: 100m
       memory: 128Mi
     requests:
       cpu: 100m
       memory: 128Mi

测试结果查看

[[email protected] 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就不会使用

[[email protected] 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

[[email protected] 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
[[email protected] 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 }}

[[email protected] 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了
[roo[email protected] templates]# helm install pod-base-tools --dry-run ../../one/

现在创建一个ingress,也设置一个开关,其实方法也是一样的

[[email protected] 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
[[email protected] 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 }}

[[email protected] templates]# helm install pod-base-user  ../../one/
[[email protected] 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 }}
[[email protected] one]# cat values.yaml
nodeSelector:
  enabled: true
  team: team2
[[email protected] 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直接去读取我们的参数也是可以的

[[email protected] 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 }}

循环内部我们使用的是一个 .,这是因为当前的作用域就在当前循环内,这个 .引用的当前读取的元素

7、变量
变量,在模板中,使用变量的场合不多,但我们将看到如何使用它来简化代码,并更好地利用with和range。因为刚才我们用到的with,不能在下面再去定义其他的变量了,那么怎么在with中去引用一些全值内置的变量呢,有两种方法,一个是使用helm的变量赋值进行去使用,第二种是使用$去使用
测试一下,先不添加$

spec:
      {{- with .Values.nodeSelector }}
      nodeSelector:
        app: {{ .Values.name }}

执行结果是这样的

[[email protected] 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去定义一下

[[email protected] one]# tail -4 values.yaml 

env:
- name: JAVA_OPTS
  value: -Xmx1024m -Xms1014m

通过刚才方法也是可以打印的

{{- with .Values.env }}
        env:
        {{- toYaml . | nindent 8 }}
        {{- end }}

8、命名模板
命名模板:使用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微服务应用为例

  1. 先创建模板

    helm create dubbo
  2. 修改Chart.yaml,Values.yaml,添加常用的变量
  3. 在templates目录下创建部署镜像所需要的yaml文件,并变量引用yaml里经常变动的字段
    这里代码已经放在我的git代码仓库中,如要使用请把你的公钥发给我
    git clone [email protected]:zhaocheng172/helm-dubbo.git

原文地址:https://blog.51cto.com/14143894/2461024

时间: 2024-11-05 18:39:50

K8s原生微服务管理工具helm-v3的使用初探实践(2)的相关文章

k8s原生微服务管理工具helm-v3的使用初探实践(1)

Helm-v3应用包管理器 3.1 为什么需要Helm?K8S上的应用对象,都是由特定的资源描述组成,包括deployment.service等.都保存各自文件中或者集中写到一个配置文件.然后kubectl apply –f 部署. 为什么使用helm?在k8s中,当我们去部署应用的时候,一般都是使用yaml文件去管理我们的应用的发布,比如像微服务,其中包括deployment,service,configmap,ingress,但是如果我们有上百个微服务的话,每次的修改涉及也都会比较多,感觉就

了解systemctl和chkconfig的服务管理工具

crontab计划任务 crontab计划任务的计时方式:对大部分时间单位都清楚的划分,具体可以划分到分钟,时间单位有分钟,小时,日(一个月内的第几天),月,周(一周的第几天,计划任务中可以是指定为每隔几周来执行某些任务) [[email protected] ~]# cat /etc/crontab SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # For details see man 4 crontabs #

中国.NET开发者峰会特别活动-基于k8s的微服务和CI/CD动手实践报名

2019.11.9 的中国.NET开发者峰会将在上海举办,到目前为止,大会的主题基本确定,这两天就会和大家会面,很多社区的同学基于对社区的信任在我们议题没有确定的情况下已经购票超过了300张,而且分享的主题都来自于社区,来自于生产实践之中的经验分享,内容之中有一点非常值得分享-基于k8s的微服务实践内容很多,但是每一个分享的时间只有30分钟,难以全面阐述k8s 这样的一个大主题,因此陈计节.陈作.刘腾飞和我又特别策划了一个11.10号的workshop活动,采用一天的时间来带领大家使用.NET

Ubuntu 和 Redhat / Fedora 服务管理命令对比表(附Fedora16新的服务管理工具systemctl )

以 apache/httpd 服务作为例子 任务 Red Hat / Fedora Ubuntu Ubuntu (with sysv-rc-conf or sysvconfig) 立即启动/停止某服务 service httpd start invoke-rc.d apache start service apache start 启动时自动加载 chkconfig httpd on update-rc.d apache defaults sysv-rc-conf apache on 启动时不加

已禁用对分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问。

已禁用对分布式事务管理器(MSDTC)的网络访问.请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问. 此错误好像只有sql server2005才有,2008数据库以后版本就没有此错误了. 与基础事务管理器的通信失败. .net 代码里 写事务代码 如: using System.Transactions; using (TransactionScope ts = new TransactionScope()) { } ts.Complete(); DTC登陆账户为

微服务管理平台nacos虚拟ip负载均衡集群模式搭建

一.Nacos简介 Nacos是用于微服务管理的平台,其核心功能是服务注册与发现.服务配置管理. Nacos作为服务注册发现组件,可以替换Spring Cloud应用中传统的服务注册于发现组件,如:Eureka.consul等,支持服务的健康检查. Nacos作为服务配置中心,可以替换Spring Cloud Config. 当然Nacos作为一个微服务管理平台,除了面向spring Cloud,还支持很多其他的微服务基础设施,如:docker.dubbo.kubernetes等.除了核心的服务

iUAP云运维平台v3.0全面支持基于K8s的微服务架构

什么是微服务架构?微服务(MicroServices)架构是当前互联网业界的一个技术热点,业内各公司也都纷纷开展微服务化体系建设.微服务架构的本质,是用一些功能比较明确.业务比较精练的服务去解决更大.更实际的问题.该架构强调的一些准则:单一职责.协议轻量.进程隔离.数据分离.独立部署.按需伸缩.什么是Kubernetes?Kubernetes是Google开源的容器集群管理系统,其提供应用部署.维护. 扩展机制等功能,利用Kubernetes能方便地管理跨机器运行容器化的应用,其主要功能:1)

如何更高效的管理原生微服务应用

阿里云分布式应用服务EDAS 最近发布了支持原生Dubbo和Spring Cloud应用功能的新版本,此功能是以非侵入方式支持的,且几乎不需要修改任何代码.在此我们体验了一下如何在EDAS上部署原生Dubbo和Spring Cloud应用. 原生Dubbo应用自从阿里重启Dubbo维护以来,其热度迅速蹿升,Github上的星标数已经达到了2.2万个之多,可谓中国开源软件界的明星产品.但是作为自家商业化输出的EDAS产品,却一直以来只能支持闭源的HSF微服务框架,对用户而言不能不说是一种遗憾.虽然

SpringBoot + Kubernetes云原生微服务实践 - (1) 介绍与案例需求

学习目标 Dev 掌握微服务架构和前后分离架构设计 掌握基于Spring Boot搭建微服务基础框架 进一步提升Java/Spring微服务开发技能 掌握Spring Boot微服务测试和相关实践 理解SaaS多租户应用的架构和设计 Ops 理解可运维架构理念和相关实践 掌握服务容器化和容器云部署相关实践 理解云时代的软件工程流程和实践 案例需求:Staffjoy工时排班(Scheduling)SaaS服务 功能 管理员Admin管理公司和排班 雇员Worker管理个人信息 非功能 SaaS +