k8s包管理工具Helm V3 简单入门

1 helm相关概念

1.1 Helm 介绍

Helm就是Kubernetes的应用程序包管理器,类似于Linux系统之上的yum或apt-get等,可用于实现帮助用户查找、分享及使用Kubernetes应用程序。它的核心打包功能组件称为chart,可以帮助用户创建、安装及升级复杂应用。Helm将Kubernetes的资源(如Deployments、Services或ConfigMap等)打包到一个Charts中,制作并测试完成的各个Charts将保存到Charts仓库进行存储和分发。另外,Helm实现了可配置的发布,它支持应用配置的版本管理,简化了Kubernetes部署应用的版本控制、打包、发布、删除和更新等操作。
Helm有两个重要概念:
helm:一个命令行客户端工具,主要用于Kubernetes应用chart的创建、打包、发布和管理。
Chart:应用描述,一系列用于描述 k8s 资源相关文件的集合。
Release:基于Chart的部署实体,一个 chart 被 Helm 运行后将会生成对应的一个 release;将在k8s中创建出真实运行的资源对象。

1.2 Helm v3 变化

a.最明显的变化是 Tiller的删除
b.Release名称可以在不同命名空间重用
c.支持将 Chart 推送至 Docker 镜像仓库中
d.使用JSONSchema验证chart values
①为了更好地协调其他包管理者的措辞 Helm CLI个别更名
helm delete更名为helm uninstall
helm inspect更名为helm show
helm fetch更名为helm pull
但以上旧的命令当前仍能使用。
②移除了用于本地临时搭建 Chart Repository的 helm serve 命令。
③自动创建名称空间
在不存在的命名空间中创建发行版时,Helm 2创建了命名空间。Helm 3遵循其他Kubernetes对象的行为,如果命名空间不存在则返回错误。
④不再需要requirements.yaml, 依赖关系是直接在chart.yaml中定义。

1.3 helm架构

k8s包管理工具Helm V3 简单入门

2 Helm部署使用

2.1 Helm客户端部署

Helm客户端下载地址:https://github.com/helm/helm/releases

解压移动到/usr/bin/目录即可。

wget https://get.helm.sh/helm-vv3.2.1-linux-amd64.tar.gz
tar zxvf helm-v3.2.1-linux-amd64.tar.gz 
mv linux-amd64/helm /usr/bin/

helm               常见的命令
命令               描述
create             创建一个chart并指定名字
dependency         管理chart依赖
get                下载一个release。可用子命令:all、hooks、manifest、notes、values
history            获取release历史
install            安装一个chart
list               列出release
package            将chart目录打包到chart存档文件中
pull               从远程仓库中下载chart并解压到本地                                                    #  helm  pull  stable/mysql  --untar
repo               添加,列出,移除,更新和索引chart仓库。可用子命令:add、index、list、remove、update
rollback           从之前版本回滚
search             根据关键字搜索chart。可用子命令:hub、repo
show               查看chart详细信息。可用子命令:all、chart、readme、values
status             显示已命名版本的状态
template           本地呈现模板
uninstall          卸载一个release
upgrade            更新一个release
version            查看helm客户端版本

2.2 配置国内chart仓库

    微软仓库(http://mirror.azure.cn/kubernetes/charts/)这个仓库推荐,基本上官网有的chart这里都有。

    阿里云仓库(https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts )

    官方仓库(https://hub.kubeapps.com/charts/incubator)官方chart仓库,国内有点不好使。

添加存储库

helm repo add stable http://mirror.azure.cn/kubernetes/charts
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 
helm repo update

查看配置的存储库

helm repo list
helm search repo stable

删除存储库:

helm repo remove aliyun

3 Helm基本使用

3.1.1 使用chart部署一个应用

#查找chart
[root@k8s-master01 helm3]# helm search repo mysql
NAME                                            CHART VERSION   APP VERSION DESCRIPTION                                       
aliyun/mysql                                    0.3.5                       Fast, reliable, scalable, and easy to use open-...
azure/mysql                                     1.6.9           5.7.30      DEPRECATED - Fast, reliable, scalable, and easy...
azure/mysqldump                                 2.6.2           2.4.1       DEPRECATED! - A Helm chart to help backup MySQL...
azure/prometheus-mysql-exporter                 0.7.1           v0.11.0     DEPRECATED A Helm chart for prometheus mysql ex...
bitnami/mysql                                   8.8.7           8.0.26      Chart to create a Highly available MySQL cluster  
prometheus-community/prometheus-mysql-exporter  1.2.2           v0.12.1     A Helm chart for prometheus mysql exporter with...
stable/mysql                                    0.3.5                       Fast, reliable, scalable, and easy to use open-...

#查看chrt信息

[root@k8s-master01 helm3]# helm show values aliyun/mysql
## mysql image version
## ref: https://hub.docker.com/r/library/mysql/tags/
##
image: "mysql"
imageTag: "5.7.14"

## Specify password for root user
##
## Default: random 10 character string
# mysqlRootPassword: testing

#安装包
>一个 chart 包是可以多次安装到同一个集群中的,每次安装都会产生一个release, 每个release都可以独立管理和升级。
[root@k8s-master01 mysql]# helm repo add stable http://mirror.azure.cn/kubernetes/charts/
helm install db stable/mysql
WARNING: This chart is deprecated
NAME: db
LAST DEPLOYED: Wed Oct 20 21:13:10 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
db-mysql.default.svc.cluster.local

To get your root password run:

    MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default db-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)

To connect to your database:

1. Run an Ubuntu pod that you can use as a client:

    kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il

2. Install the mysql client:

    $ apt-get update && apt-get install mysql-client -y

3. Connect using the mysql cli, then provide your password:
    $ mysql -h db-mysql -p

To connect to your database directly from outside the K8s cluster:
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306

    # Execute the following command to route the connection:
    kubectl port-forward svc/db-mysql 3306

    mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}

#查看发布状态
[root@k8s-master01 mysql]# helm list
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART       APP VERSION
db      default     1           2021-10-20 21:13:10.417392635 +0800 CST deployed    mysql-1.6.9 5.7.30     

 helm status db

因为mysql需要指定使用存储才能起来 所以要用如下命令
[root@k8s-master01 mysql]#  helm install db  --set persistence.storageClass="managed-nfs-storage" stable/mysql 

[root@k8s-master01 mysql]# kubectl get pvc
NAME                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
db-mysql                            Bound    pvc-41064e58-6ea7-461a-aff3-86f3f729cd05   8Gi        RWO            managed-nfs-storage   60s

[root@k8s-master01 storageclass]# kubectl get pods
NAME                                      READY   STATUS              RESTARTS   AGE
mysql-9d7dfbc65-bpdd5                     1/1     Running             1          5m46s

卸载一个charts
[root@k8s-master01 storageclass]# helm uninstall mysql

3.1.2 安装前自定义chart配置选项

自定义chart配置选项,安装过程中有两种方法可以传递配置数据:

 --values(或-f):指定带有覆盖的YAML文件。这可以多次指定,最右边的文件优先
 --set:在命令行上指定替代。如果两者都用,--set优先级高

[root@k8s-master01 helm3]# cat config.yaml 
persistence:
  enabled: true
  storageClass: "managed-nfs-storage"
  accessMode: ReadWriteOnce
  size: 6Gi
mysqlUser: "k8s"
mysqlPassword: "123456"
mysqlDatabase: "k8s"

 helm install mysql  azure/mysql -f config.yaml
WARNING: This chart is deprecated
NAME: mysql
LAST DEPLOYED: Thu Oct 21 13:58:23 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
mysql.default.svc.cluster.local

To get your root password run:

    MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)

To connect to your database:

1. Run an Ubuntu pod that you can use as a client:

    kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il

2. Install the mysql client:

    $ apt-get update && apt-get install mysql-client -y

3. Connect using the mysql cli, then provide your password:
    $ mysql -h mysql -p

To connect to your database directly from outside the K8s cluster:
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306

    # Execute the following command to route the connection:
    kubectl port-forward svc/mysql 3306

    mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}

验证
[root@k8s-master01 helm3]# kubectl exec  -it mysql-6d755f68cb-v5qcv -- bash 

root@mysql-6d755f68cb-v5qcv:/# mysql -h mysql  -uk8s -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 5.7.30 MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| k8s                |
+--------------------+
2 rows in set (0.00 sec)

4 Helm Chart自定义模板

4.1 Charts文件组织结构

一个Charts就是按特定格式组织的目录结构,目录名即为Charts名,目录名称本身不包含版本信息。目录结构中除了charts/和templates/是目录之外,其他的都是文件。它们的基本功用如下。
[root@k8s-master01 helm3]# helm create mychart
Creating mychart
[root@k8s-master01 helm3]# tree mychart/
mychart/
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── serviceaccount.yaml
│   ├── service.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

# Chart.yaml:用于描述这个 Chart的基本信息,包括名字、描述信息以及版本等。
# values.yaml :用于存储 templates 目录中模板文件中用到变量的值。
# Templates: 目录里面存放所有yaml模板文件。
# charts:目录里存放这个chart依赖的所有子chart。
# NOTES.txt :用于介绍Chart帮助信息, helm install 部署后展示给用户。例如:如何使用这个 Chart、列出缺省的设置等。
# _helpers.tpl:放置模板助手的地方,可以在整个 chart 中重复使用

打包推送的charts仓库
[root@k8s-master01 helm3]#  helm package mychart/
Successfully packaged chart and saved it to: /root/k8s-ceshi/helm3/mychart-0.1.0.tgz

升级、回滚和删除
发布新版本的chart时,或者当您要更改发布的配置时,可以使用该helm upgrade 命令。
# helm upgrade --set imageTag=1.17 web mychart

# helm upgrade -f values.yaml web mychart

4.2 Chart模板配置

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

4.2.1 helm chart values的引用

helm create nginx
[root@k8s-master01 nginx]# kubectl create deploy nginx --image=nginx:1.16 --dry-run=client -o yaml > deployment.yml

[root@k8s-master01 templates]# cat deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: helm-nginx
  name: helm-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helm-nginx
  template:
    metadata:
      labels:
        app: helm-nginx
    spec:
      containers:
      - image: nginx:1.16
        name: helm-nginx

 kubectl create deploy nginx --image=nginx:1.16
 [root@k8s-master01 templates]# kubectl expose deploy nginx --port=80 --target-port=80 --type=NodePort nginx --dry-run=client -o yaml > service.yaml

cat service.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: helm-nginx
  name: helm-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: helm-nginx
  type: NodePort

创建Chart后,接下来就是将其部署:
[root@k8s-master01 helm3]# helm install web  nginx -n nginx
NAME: web
LAST DEPLOYED: Fri Oct 22 17:01:52 2021
NAMESPACE: nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None

[root@k8s-master01 helm3]# helm list -n nginx
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
web     nginx       1           2021-10-22 17:01:52.681448993 +0800 CST deployed    helm-nginx-0.1.0    1.16.0     
访问验证
[root@k8s-master01 helm3]# curl 10.104.245.231 -I
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Fri, 22 Oct 2021 09:03:23 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 13 Aug 2019 10:05:00 GMT
Connection: keep-alive
ETag: "5d528b4c-264"
Accept-Ranges: bytes

然后更新nginx版本,这里我们引用value的使用
[root@k8s-master01 nginx]# vim values.yaml 

image:
  repository: nginx
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: "1.17"

[root@k8s-master01 templates]# cat deployment.yml 

      - image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        name: helm-nginx

版本升级
[root@k8s-master01 helm3]# helm upgrade web  nginx -n nginx
Release "web" has been upgraded. Happy Helming!
NAME: web
LAST DEPLOYED: Fri Oct 22 17:08:58 2021
NAMESPACE: nginx
STATUS: deployed
REVISION: 2
TEST SUITE: None

[root@k8s-master01 helm3]#  helm history web      -n nginx       #查看历史
REVISION    UPDATED                     STATUS      CHART               APP VERSION DESCRIPTION     
1           Fri Oct 22 17:01:52 2021    superseded  helm-nginx-0.1.0    1.16.0      Install complete
2           Fri Oct 22 17:08:58 2021    deployed    helm-nginx-0.1.0    1.16.0      Upgrade complete

[root@k8s-master01 helm3]# kubectl get pod,svc -n nginx
NAME                              READY   STATUS    RESTARTS   AGE
pod/helm-nginx-79b54d4bdb-qpjxd   1/1     Running   0          81s

NAME                 TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/helm-nginx   NodePort   10.104.245.231   <none>        80:31604/TCP   8m26s
[root@k8s-master01 helm3]# curl 10.104.245.231 -I 
HTTP/1.1 200 OK
Server: nginx/1.17.10
Date: Fri, 22 Oct 2021 09:10:25 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
Connection: keep-alive
ETag: "5e95c66e-264"
Accept-Ranges: bytes
如下 nginx版本已经更新到了nginx1.17

回滚到1版本
[root@k8s-master01 helm3]# helm rollback web 1 -n nginx
Rollback was a success! Happy Helming!

[root@k8s-master01 helm3]# curl 10.104.245.231 -I 
HTTP/1.1 200 OK
Server: nginx/1.16.1
已回滚到版本1

4.2.2 构建自己的chart模板

Helm最核心的就是模板,即模板化的K8S manifests文件。 使用如下命令可以看到实际的模板被渲染过后的资源文件:
# 查看manifest
# helm get manifest web

一个deployment.yaml 部署多个应用,有哪些字段需要修改: 镜像 标签 副本数 资源限制 环境变量 端口 资源名称
  • helm内置变量
内置对象 Release就是Helm的内置对象
Release.Name release 名称
Release.Time release 的时间
Release.Namespace release 的 namespace(如果清单未覆盖
Release.Service release 服务的名称
Release.Revision 此 release 的修订版本号,从1开始累加
Release.IsUpgrade 如果当前操作是升级或回滚,则将其设置为 true。
Release.IsInstall 如果当前操作是安装,则设置为 true。
  • Values Values对象是为Chart模板提供值,这个对象的值有4个来源: ● chart 包中的 values.yaml 文件 ● 父 chart 包的 values.yaml 文件 ● 通过 helm install 或者 helm upgrade 的 -f或者 --values参数传入的自定义的 yaml 文件 ● 通过 --set 参数传入的值 chart 的 values.yaml 提供的值可以被用户提供的 values 文件覆盖,而该文件同样可以被 --set提供的参数所覆盖。
  • 通过charts模板部署nginx

 cat nginx/values.yaml 
# Default values for nginx.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.17"
  name: nginx

labels:
  project: www
  app: helm-nginx

service:
  type: NodePort
  port: 80
  targetport: 80

ingress:
  enabled: false
  annotations: {}
    # kubernetes.io/ingress.class: nginx

cat nginx/templates/deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: {{ .Values.labels.app }}
  name: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Values.labels.app }}
  template:
    metadata:
      labels:
        app: {{ .Values.labels.app }}
    spec:
      containers:
      - image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        name: {{ .Values.image.name }}

cat nginx/templates/service.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: {{ .Values.labels.app }}
  name: {{ .Values.labels.app }}
spec:
  ports:
  - port: {{ .Values.service.port }}
    protocol: TCP
    targetPort: {{ .Values.targetport }}
  selector:
    app: {{ .Values.labels.app }}
  type: {{ .Values.service.type }}

$ helm install web nginx --dry-run   #测试执行,检查有无语法错误

[root@k8s-master01 helm3]# helm install web nginx -n nginx  #直接安装,即可使用
NAME: web
LAST DEPLOYED: Wed Oct 27 21:26:02 2021
NAMESPACE: nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None

$ helm  show values nginx -nginx  #查看values

[root@k8s-master01 helm3]# helm list -n nginx
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
web     nginx       1           2021-10-27 21:26:02.174975039 +0800 CST deployed    helm-nginx-0.1.0    1.17.0     

调试使用–dry-run 如上面nginx的实例deployment使用charts部署应用需要修改如下字段 镜像 标签 副本数 资源限制 环境变量 端口 资源名称

4.3 管道与函数

从.Values中读取的值变成字符串,可以使用quote函数实现.
# vi templates/deployment.yaml
app: {{ quote .Values.label.app }}
# helm install --dry-run web ../mychart/ 
        project: ms
        app: "nginx"
quote .Values.label.app 将后面的值作为参数传递给quote函数。

另外还会经常使用一个default函数,该函数允许在模板中指定默认值,以防止该值被忽略掉。
例如忘记定义,执行helm install 会因为缺少字段无法创建资源,这时就可以定义一个默认值。
# cat values.yaml

replicas: 2

# cat templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deployment

- name: {{ .Values.name | default "nginx" }}

其他函数:
缩进:{{ .Values.resources | indent 12 }}
大写:{{ upper .Values.resources }}
首字母大写:{{ title .Values.resources }}

4.4 流程控制

流程控制是为模板提供了一种能力,满足更复杂的数据逻辑处理。 Helm模板语言提供以下流程控制语句: if/else 条件块 with 指定范围 range 循环块

4.4.1 if

if/else块是用于在模板中有条件地包含文本块的方法,条件块的基本结构如下:
{{ if PIPELINE }}
  # Do something
{{ else if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}

例子:
cat nginx/templates/deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
    name: {{ .Values.labels.app }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Values.labels.app }}
  template:
    metadata:
      labels:
        app: {{ .Values.labels.app }}
        {{- if eq .Values.test "123" }}  ##{{- 用来消除此行执行后产生的空格
        ttt: 123
        {{- else }}
        ttt: 456
        {{- end }}

    spec:
      containers:
      - image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        name: {{ .Values.image.name }}

[root@k8s-master01 helm3]# cat nginx/values.yaml 

test: "123"
通过模板引擎来渲染一下
[root@k8s-master01 helm3]#  helm install web nginx --dry-run 

spec:
  replicas: 1
  selector:
    matchLabels:
      app: helm-nginx
  template:
    metadata:
      labels:
        app: helm-nginx
        ttt: 123

条件判断就是判断条件是否为真,如果值为以下几种情况则为false:
● 一个布尔类型的 假
● 一个数字 零
● 一个 空的字符串
● 一个 nil(空或 null)
● 一个空的集合( map、 slice、 tuple、 dict、 array)

通过判断变量的值的真假可以开启对应的参数,如下面例子
cat nginx/values.yaml 
resources: 
   limits:
     cpu: 100m
     memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

[root@k8s-master01 helm3]#  helm install web nginx --dry-run 

# Source: helm-nginx/templates/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: helm-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helm-nginx
  template:
    metadata:
      labels:
        app: helm-nginx
        ttt: 123

    spec:
      containers:
      - image: nginx:1.17
        name: nginx
        resources:
           limits:
             cpu: 100m
             memory: 128Mi

经调试,当values里注释resources: {}时,则无资源限制,当values有值时,可以引用资源限制

也可以通过增加控件开关的方式控制是否引用变量
[root@k8s-master01 helm3]# cat nginx/values.yaml 

resources:
   enabled: false 
   limits:
     cpu: 100m
     memory: 128Mi

 cat nginx/templates/deployment.yml 

    spec:
      containers:
      - image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        name: {{ .Values.image.name }}
        {{- if .Values.resources.enabled }}
        resources:
           limits:
             cpu: {{ .Values.resources.limits.cpu }}
             memory: {{ .Values.resources.limits.memory }}
        {{- else }}
        resources: {}
        {{- end }}

当我们设置resources.enabled为false时,不启用资源限制
[root@k8s-master01 helm3]#  helm install web nginx --dry-run 
# Source: helm-nginx/templates/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: helm-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helm-nginx
  template:
    metadata:
      labels:
        app: helm-nginx
        ttt: 123

    spec:
      containers:
      - image: nginx:1.17
        name: nginx
        resources: {}

通过value中增加类似  enabled: false,可以控制是否创建某些资源对象.如ingress
 {{- if .Values.ingress.enabled }}
 ingress资源对象内容
 {{- end }}

思考:
也可以通过value 设置不同的nodeSelector 的选择不同的node服务器资源.

4.4.2 with

with :控制变量作用域。 其语法和一个简单的 if语句比较类似: {{ with PIPELINE }} #restricted scope {{ end }} with语句可以允许将当前范围 .设置为特定的对象,比如我们前面一直使用的 .Values.label,我们可以使用 with来将 .范围指向 .Values.label:
[root@k8s-master01 helm3]# cat nginx/values.yaml 

nodeSelector:
  team: a
  gpu: yes

[root@k8s-master01 helm3]# cat nginx/templates/deployment.yml 

    spec:
      {{- with .Values.nodeSelector }}
      nodeSelector:
        team: {{ .team }}
        gpu: {{ .gpu }} 
      {{- end }}
      containers:

[root@k8s-master01 helm3]#  helm install web nginx --dry-run 

    spec:
      nodeSelector:
        team: a
        gpu: true
      containers:
      - image: nginx:1.17
        name: nginx
        resources: {}

另一种简单的写法
    spec:
      {{- with .Values.nodeSelector }}
      nodeSelector:
         {{- toYaml . | nindent 8 }}
      {{- end }}
      containers:
with是一个循环构造。使用.Values.nodeSelector中的值:将其转换为Yaml。
toYaml之后的点是循环中.Values.nodeSelector的当前值 

4.4.3 range

在Helm模板语言中,使用range关键字来进行循环操作。
$ vim mychart/values.yaml
test:
  - 1
  - 2
  - 3

$ vim mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}
data:
  test: |
  {{- range .Values.test }}
    {{ . }}
  {{- end }}

$ helm install web1 mychart --dry-run 
# Source: helm-nginx/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: web
data:
  test: |
    1
    2
    3
循环内部我们使用的是一个 .,这是因为当前的作用域就在当前循环内,这个 .引用的当前读取的元素。

4.4.4 变量

变量,在模板中,使用变量的场合不多,但我们将看到如何使用它来简化代码,并更好地利用with和range。
获取数组键值

$ vim mychart/values.yaml
env:
  NAME: "gateway"
  JAVA_OPTS: "-Xmx1G"
$ vim mychart/templates/deployment.yaml
        - image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        name: nginx
        env:
        {{- range $k,$v := .Values.env }}
          - name: {{ $k }}
            value: {{ $v | quote }}
        {{- end }}
$ helm install web1 mychart --dry-run  
结果如下
    env:
       - name: JAVA_OPTS
         value: "-Xmx1G"
       - name: NAME
         value: "gateway"

上面在 range循环中使用 $key和 $value两个变量来接收后面列表循环的键和值。

with中不能使用内置对象

with语句块内不能再 .Release.Name对象,否则报错。

我们可以将该对象赋值给一个变量可以来解决这个问题:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deployment
spec:
  replicas: {{ .Values.replicas }}
  template:
    metadata:
      labels:
        project: {{ .Values.label.project }}
        app: {{ quote .Values.label.app }}
      {{- with .Values.label }}
        project: {{ .project }}
        app: {{ .app }}
        release: {{ .Release.Name }}
      {{- end }}

上面会出错
      {{- $releaseName := .Release.Name -}}
      {{- with .Values.label }}
        project: {{ .project }}
        app: {{ .app }}
        release: {{ $releaseName }}
        # 或者可以使用$符号,引入全局命名空间
        release: {{ $.Release.Name }}
      {{- end }}

可以看到在 with语句上面增加了一句 {{-$releaseName:=.Release.Name-}},其中 $releaseName就是后面的对象的一个引用变量,它的形式就是 $name,赋值操作使用 :=,这样 with语句块内部的 $releaseName变量仍然指向的是 .Release.Name

命名模板
需要复用代码的地方用。
命名模板:使用define定义,template引入,在templates目录中默认下划线开头的文件为公共模板(helpers.tpl)

# 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 }}

 cat nginx/templates/service.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    {{- include "demo.labels" . | nindent 4 }}
  name: {{ .Values.labels.app }}
spec:

[root@k8s-master01 helm3]#  helm install web nginx --dry-run 

# Source: helm-nginx/templates/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: helm-nginx
    labels:
     app: helm-nginx-web
     chart: "helm-nginx-0.1.0"
     release: "web"

# Source: helm-nginx/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: helm-nginx-web
    chart: "helm-nginx-0.1.0"
    release: "web"
  name: helm-nginx

...

上面包含一个名为 demo.labels 的模板,然后将值 . 传递给模板,最后将该模板的输出传递给 nindent函数.
所以可以把每个资源都用到的内容写道模板里.

5 开发自己的chart

开发Chart大致流程: 先创建模板 helm create demo 修改Chart.yaml,Values.yaml,添加常用的变量 在templates目录下创建部署镜像所需要的yaml文件,并变量引用yaml里经常变动的字段

5.1 创建模板

helm  create demo
[root@k8s-master01 helm3]# tree demo
demo
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── serviceaccount.yaml
│   ├── service.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

5.2 修改Chart.yaml,Values.yaml


[root@k8s-master01 helm3]# cat demo/Chart.yaml apiVersion: v2 name: demo description: A Helm chart for demo type: application version: 0.1.0 appVersion: 1.16.0 cat demo/values.yaml replicas: 2 image: repository: lizhenliang/java-demo pullPolicy: IfNotPresent tag: "latest" service: type: ClusterIP port: 80 targetport: 8080 ingress: enabled: true annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: - host: demo.devopstack.cn paths: / tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi autoscaling: enabled: false minReplicas: 1 maxReplicas: 100 targetCPUUtilizationPercentage: 80 targetMemoryUtilizationPercentage: 80 nodeSelector: {}

5.3 修改_helpers.tpl(通用模板)

 cat demo/templates/_helpers.tpl 
{{/*
资源名称
*/}}
{{- define "demo.fullname" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
公共标签选择器
*/}}
{{- define "demo.labels" -}}
app: {{ template "demo.fullname" . }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}
{{- end }}

{{/*
标签选择器
*/}}
{{- define "demo.selectorLabels" -}}
app: {{ template "demo.fullname" . }}
release: {{ .Release.Name }}
{{- end }}

5.4 生成deployment.yaml,service.yaml, ingress等文件

 cat demo/templates/deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "demo.fullname" . }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
{{- end }}
  selector:
    matchLabels:
      {{- include "demo.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "demo.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          {{- if .Values.resources }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          {{- else }}
          resources: {}
          {{- end }}

cat demo/templates/ingress.yaml 
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "demo.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- $paths := .Values.ingress.paths -}}
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          - path: {{ .paths }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: {{ $svcPort }}
    {{- end }}
  {{- end }}

 cat demo/templates/service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: {{ include "demo.fullname" . }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: {{ .Values.service.targetport }}
      protocol: TCP
      name: http
  selector:
    {{- include "demo.selectorLabels" . | nindent 4 }}

5.5 NOTES.txt 提示信息

cat demo/templates/NOTES.txt 
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}

  http{{ if $.Values.ingress.tls }}s{{ end }}://{{- range .Values.ingress.hosts }}{{ .host }}{{.paths}}{{end}} 
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "demo.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "demo.fullname" . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "demo.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "demo.fullname" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
{{- end }}

5.6 演示我们的chart

#试运行chart
helm  install web1 demo --dry-run
NAME: web1
LAST DEPLOYED: Sun Nov 14 17:32:01 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: demo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo
  labels:
    app: demo
    release: web1
    chart: demo
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: demo
    release: web1
---
# Source: demo/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  labels:
    app: demo
    release: web1
    chart: demo
spec:
  replicas: 
  selector:
    matchLabels:
      app: demo
      release: web1
  template:
    metadata:
      labels:
        app: demo
        release: web1
    spec:
      containers:
        - name: demo
          image: "lizhenliang/java-demo:latest"
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              cpu: 200m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 128Mi
---
# Source: demo/templates/ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: demo
  labels:
    app: demo
    release: web1
    chart: demo
spec:
  rules:
    - host: "demo.devopstack.cn"
      http:
        paths:
          - path: /
            backend:
              serviceName: demo
              servicePort: 80

NOTES:
1. Get the application URL by running these commands:

  http://demo.devopstack.cn/

安装chart 
helm  install web1 demo -n nginx
NAME: web1
LAST DEPLOYED: Sun Nov 14 17:32:46 2021
NAMESPACE: nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:

  http://demo.devopstack.cn/

#验证我们的chart

[root@k8s-master01 helm3]# helm  list -n nginx
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART       APP VERSION
web1    nginx       1           2021-11-14 17:32:46.567894938 +0800 CST deployed    demo-0.1.0  1.16.0     
[root@k8s-master01 helm3]# kubectl get pods -n nginx
NAME                    READY   STATUS    RESTARTS   AGE
demo-6bc44cbc7b-q592l   1/1     Running   0          36s
[root@k8s-master01 helm3]# kubectl get pods -n nginx -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
demo-6bc44cbc7b-q592l   1/1     Running   0          41s   10.244.4.40   k8s-node04   <none>           <none>
[root@k8s-master01 helm3]# kubectl get ingress -n nginx 
NAME   CLASS    HOSTS                ADDRESS   PORTS   AGE
demo   <none>   demo.devopstack.cn             80      2m15s
[root@k8s-master01 helm3]# kubectl get svc -n nginx 
NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
demo   ClusterIP   10.100.151.147   <none>        80/TCP    2m30s

访问浏览器验证demo java运行情况

k8s包管理工具Helm V3 简单入门

6 使用Harbor作为Chart仓库

6.1 启用Harbor的Chart仓库服务

./install.sh --with-chartmuseum
启用后,默认创建的项目就带有helm charts功能了。
k8s包管理工具Helm V3 简单入门

6.2 安装push插件

https://github.com/chartmuseum/helm-push
$ helm plugin install https://github.com/chartmuseum/helm-push
或者
wget https://github.com/chartmuseum/helm-push/releases/download/v0.10.1/helm-push_0.10.1_linux_amd64.tar.gz
tar zxvf helm-push_0.10.1_linux_amd64.tar.gz
$ mkdir -p /root/.local/share/helm/plugins/helm-push
$ chmod +x bin/*
$ mv bin plugin.yaml /root/.local/share/helm/plugins/helm-push
[root@k8s-master01 ~]# helm plugin list
NAME    VERSION DESCRIPTION                      
cm-push 0.10.1  Push chart package to ChartMuseum

6.3 添加repo

helm repo add --ca-file harbor.devopstack.cn.cert --cert-file harbor.devopstack.cn.crt --key-file harbor.devopstack.cn.key    --username admin --password Harbor12345 myrepo  https://192.168.10.20:443/chartrepo/chart/

helm repo list #查询已添加 仓库地址
[root@k8s-master01 ~]# helm repo list
NAME                    URL                                                   
stable                  http://mirror.azure.cn/kubernetes/charts/                        
myrepo                  https://192.168.10.20:443/chartrepo/chart/           

helm repo update #跟新本地仓库缓存

备注
需要你创一个项目 eg: mychart 不然添加不进去
仓库地址格式为: http(s)//{harbor 域名或iP:端口(如果默认443 或80 可不加)}/chartrepo/{mychart}
确认你启动仓库harbor 配置的是https 还是 http 如果是http 上面的命令可以执行成功,如果是https 还需带上 ca 证书,启动harbor 用的服务器证书和密钥 如下

6.4 配置好harbor到k8s集群insecure-registry

如果想用私有chart仓库像开源的chart仓库一样,就需要把harbor的公钥私钥放到docker下

$ vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"],
  "insecure-registries": ["harbor.devopstack.cn"]
}
$ cd /etc/docker/ && mkdir cert.d/hub.devopstack.cn -pv
# 将 hubor私有仓库的私钥拷贝到/etc/docker/cert.d/hub.devopstack.cn/ 下即可
$ systemctl restart docker

6.4 推送与安装Chart

推送到harbor仓库
  helm cm-push ./demo myrepo --ca-file ~/harbor.devopstack.cn.cert --cert-file ~/harbor.devopstack.cn.crt --key-file ~/harbor.devopstack.cn.key  --username admin --password Harbor12345  
Pushing demo-0.1.0.tgz to myrepo...
Done.
如图查看已经推送到harbor仓库了

k8s包管理工具Helm V3 简单入门
查找chart 
[root@k8s-master01 helm3]# helm search  repo myrepo/demo
NAME        CHART VERSION   APP VERSION DESCRIPTION          
myrepo/demo 0.1.0           1.16.0      A Helm chart for demo

下载demo包
[root@k8s-master01 ~]# helm pull myrepo/demo
[root@k8s-master01 ~]# ls |grep demo
demo-0.1.0.tgz
如果没配置 harbor到k8s集群insecure-registry
helm pull myrepo/demo   --ca-file ~/harbor.devopstack.cn.cert --cert-file ~/harbor.devopstack.cn.crt --key-file ~/harbor.devopstack.cn.key  --username admin --password Harbor12345  

部署demo
[root@k8s-master01 ~]# helm  install myrepo/demo --generate-name  -n nginx 
NAME: demo-1636977766
LAST DEPLOYED: Mon Nov 15 20:02:46 2021
NAMESPACE: nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:

  http://demo.devopstack.cn/
如果没配置 harbor到k8s集群insecure-registry
helm  install myrepo/demo --generate-name  -n nginx  --ca-file ~/harbor.devopstack.cn.cert --cert-file ~/harbor.devopstack.cn.crt --key-file ~/harbor.devopstack.cn.key  --username admin --password Harbor12345  

[root@k8s-master01 ~]# helm list -n nginx
NAME            NAMESPACE   REVISION    UPDATED                                 STATUS      CHART       APP VERSION
demo-1636977766 nginx       1           2021-11-15 20:02:46.508425704 +0800 CST deployed    demo-0.1.0  1.16.0     

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin
avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: