十二、k8s工程化管理Helm
十二、k8s工程化管理Helm
文章目录
- 十二、k8s工程化管理Helm
- 1、什么是Helm
- 2、Helm核心概念:
- 3、Helm主要功能:
- 4、Helm使用示例
- 4.1 在线
- 4.2 离线
- 5、Helm 安装
- 6、Helm 仓库管理
- 7、Helm Chart 管理
- 8、Helm Release 管理
- 8.1 在线安装
- 8.2 离线安装 Release
- 9、常用服务安装
- 9.1 安装 Redis 到 K8s 中
- 9.2 安装 MySQL 到 K8s 中
- 9.3 安装 MySQL 主从模式到 K8s 中
- 9.4 安装高可用 PostgreSQL 到 K8s 中
- 10、自定义 Helm Chart
- 10.1 使用场景
- 10.2 自定义 Helm Chart
- 10.3 Helm常用内置变量
- 10.4 Helm常用函数
- 10.4.1 字符串函数
- 10.4.2 类型转换函数
- 10.4.3 逻辑转换函数
- 10.5 自定义 Helm Chart
- 10.5.1 自定义单个Helm配置
- 10.5.2 自定义多个Helm配置
- 10.5.3 打包上传仓库
1、什么是Helm
Helm是K8s的包管理器,类似于Linux上的apt或yum,可以用包的形式工程化管理和部署复杂的k8S应用程序,比如一键安装zookeeper集群、一键部署整个项目等。
2、Helm核心概念:
- Helm:Helm的管理工具
- Chart:Helm的包,是一个包含K8s资源定义的安装文件包
- Release:Helm每次部署会产生一个 Release ,可以用于回滚等
- Repository:Helm Chart存储库,用于存储和分发Chart
3、Helm主要功能:
- 资源管理:Helm Chart是一组预定义的YAML文件,描述了K8s应用程序的各个组件配置与模板
- 版本控制:Helm支持版本控制,可以轻松回滚到之前的版本
- 依赖管理:Chart可以声明依赖关系,Helm可以自动解析并安装这些依赖
- 模板化:Charts可以使用Go的模板语言,动态生成资源文件
4、Helm使用示例
4.1 在线
# 添加Bitnami仓库
heml repo add bitnami https://charts.bitnami.com/bitnami# 使用Bitnami安装
heml install my-mysql bitnami/mysql --version 12.0.1# 更改MySQL镜像
heml install my-mysql bitnami/mysql --version 12.0.1 --set global.imageRegistry=xxx
OCI方式:
heml install my-release oci://registry-1.docker.io/bitnamicharts/schema-registry
4.2 离线
# 添加Bitnami仓库
heml repo add bitnami https://charts.bitnami.com/bitnami# 下载安装包:
heml pull my-mysql bitnami/mysql --version 12.0.1# 解压后安装
heml install my-mysql .
OCI方式:
heml pull oci://registry-1.docker.io/bitnamicharts/schema-registry
5、Helm 安装
官方安装文档、Helm 安装包
# 下载安装包:
[root@k8s-master01 ~]# wget https://get.helm.sh/helm-v3.16.2-linux-amd64.tar.gz# 解压
[root@k8s-master01 ~]# tar xf helm-v3.16.2-linux-amd64.tar.gz [root@k8s-master01 ~]# ls
helm-v3.16.2-linux-amd64.tar.gz linux-amd64[root@k8s-master01 ~]# cd linux-amd64/
[root@k8s-master01 linux-amd64]# ls
helm LICENSE README.md[root@k8s-master01 linux-amd64]# mv helm /usr/local/bin/
[root@k8s-master01 linux-amd64]# helm version
version.BuildInfo{Version:"v3.16.2", GitCommit:"13654a52f7c70a143b1dd51416d633e1071faffb", GitTreeState:"clean", GoVersion:"go1.22.7"}
6、Helm 仓库管理
# 添加仓库:
[root@k8s-master01 ~]# helm repo add bitnami https://charts.bitnami.com/bitnami# 添加后仓库的保存位置:
[root@k8s-master01 ~]# cat ~/.config/helm/repositories.yaml
apiVersion: ""
generated: "0001-01-01T00:00:00Z"
repositories:
- caFile: ""certFile: ""insecure_skip_tls_verify: falsekeyFile: ""name: bitnamipass_credentials_all: falsepassword: ""url: https://charts.bitnami.com/bitnamiusername: ""
# 添加阿里云仓库:
[root@k8s-master01 ~]# helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts# 添加 Rancher 仓库:
[root@k8s-master01 ~]# helm repo add rancher-mirror https://rancher-mirror.rancher.cn/server-charts/latest# 查看仓库:
[root@k8s-master01 ~]# helm repo list
NAME URL
bitnami https://charts.bitnami.com/bitnami
aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
rancher-mirror https://rancher-mirror.rancher.cn/server-charts/latest# 删除仓库:
[root@k8s-master01 ~]# helm repo remove bitnami[root@k8s-master01 ~]# helm repo list
NAME URL
aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
rancher-mirror https://rancher-mirror.rancher.cn/server-charts/latest
# 更新单个仓库:
[root@k8s-master01 ~]# helm repo update aliyun# 更新所有仓库:
# helm repo update
7、Helm Chart 管理
# 搜索 Chart:
[root@k8s-master01 ~]# helm search repo nginx
NAME CHART VERSION APP VERSION DESCRIPTION
aliyun/nginx-ingress 0.9.5 0.10.2 An nginx Ingress controller that uses ConfigMap...
aliyun/nginx-lego 0.3.1 Chart for nginx-ingress-controller and kube-lego
bitnami/nginx 21.0.1 1.29.0 NGINX Open Source is a web server that can be a...
bitnami/nginx-ingress-controller 11.6.25 1.12.3 NGINX Ingress Controller is an Ingress controll...
bitnami/nginx-intel 2.1.15 0.4.9 DEPRECATED NGINX Open Source for Intel is a lig...
aliyun/gcloud-endpoints 0.1.0 Develop, deploy, protect and monitor your APIs ...
# 搜索某个仓库:
[root@k8s-master01 ~]# helm search repo bitnami/nginx
NAME CHART VERSION APP VERSION DESCRIPTION
bitnami/nginx 21.0.1 1.29.0 NGINX Open Source is a web server that can be a...
bitnami/nginx-ingress-controller 11.6.25 1.12.3 NGINX Ingress Controller is an Ingress controll...
bitnami/nginx-intel 2.1.15 0.4.9 DEPRECATED NGINX Open Source for Intel is a lig...# 查看某个 Chart 的版本:
[root@k8s-master01 ~]# helm search repo bitnami/nginx -l
NAME CHART VERSION APP VERSION DESCRIPTION
bitnami/nginx 21.0.1 1.29.0 NGINX Open Source is a web server that can be a...
bitnami/nginx 21.0.0 1.29.0 NGINX Open Source is a web server that can be a...
bitnami/nginx 20.1.4 1.28.0 NGINX Open Source is a web server that can be a...
bitnami/nginx 20.1.3 1.28.0 NGINX Open Source is a web server that can be a...
....# CHART VERSION:helm的版本
# APP VERSION:Nginx的版本
# 下载 Chart
[root@k8s-master01 ~]# helm pull bitnami/nginx# 下载指定版本的 Chart(18.2.5往上的版本需要oci方式下载)
[root@k8s-master01 ~]# helm pull bitnami/nginx --version 18.2.5
[root@k8s-master01 ~]# ls
nginx-18.2.5.tgz# 通过 OCI 下载
[root@k8s-master01 ~]# helm pull oci://docker.kubeasy.com/bitnamicharts/nginx --version 18.2.6
8、Helm Release 管理
8.1 在线安装
# 在线安装 Chart
[root@k8s-master01 ~]# kubectl create ns helm-test[root@k8s-master01 ~]# helm install nginx oci://docker.kubeasy.com/bitnamicharts/nginx --version 18.2.6 -n helm-test# 发现是无法下载镜像
[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
nginx-5cf58fb86d-rg6gk 0/1 Init:ImagePullBackOff 0 5m24s# 发现是去docker.io下载镜像,目前国内是无法连docker.io的
[root@k8s-master01 ~]# kubectl describe po nginx-5cf58fb86d-rg6gk -n helm-test
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 2m36s default-scheduler Successfully assigned helm-test/nginx-5cf58fb86d-rg6gk to k8s-node01Normal Pulling 57s (x3 over 2m23s) kubelet Pulling image "docker.io/bitnami/nginx:1.29.0-debian-12-r0"Warning Failed 32s (x3 over 118s) kubelet Failed to pull image "docker.io/bitnami/nginx:1.29.0-debian-12-r0": failed to pull and unpack image "docker.io/bitnami/nginx:1.29.0-debian-12-r0": failed to resolve reference "docker.io/bitnami/nginx:1.29.0-debian-12-r0": failed to do request: Head "https://registry-1.docker.io/v2/bitnami/nginx/manifests/1.29.0-debian-12-r0": dial tcp 118.193.240.37:443: connect: connection refusedWarning Failed 32s (x3 over 118s) kubelet Error: ErrImagePullNormal BackOff <invalid> (x5 over 118s) kubelet Back-off pulling image "docker.io/bitnami/nginx:1.29.0-debian-12-r0"Warning Failed <invalid> (x5 over 118s) kubelet Error: ImagePullBackOff
# 安装时修改参数
[root@k8s-master01 ~]# helm upgrade --install nginx oci://docker.kubeasy.com/bitnamicharts/nginx --version 18.2.6 -n helm-test --set image.registry=docker.kubeasy.com --set image.repository=bitnami/nginx --set image.pullPolicy=IfNotPresent# 查看pod已经安装成功
[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
nginx-596569f468-6xc66 1/1 Running 0 119s# 查看 Releases 状态:
[root@k8s-master01 ~]# helm status nginx -n helm-test# 查看某个 Release 的详细信息,包括值、配置、状态
[root@k8s-master01 ~]# helm get all nginx -n helm-test
# 如果之前安装时是修改参数,后续的改动也需要带上参数,否则会丢数据
[root@k8s-master01 ~]# helm upgrade --install nginx oci://docker.kubeasy.com/bitnamicharts/nginx --version 18.2.6 -n helm-test --set image.registry=docker.kubeasy.com --set image.repository=bitnami/nginx --set image.pullPolicy=IfNotPresent --set replicaCount=2[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
nginx-596569f468-6xc66 1/1 Running 0 20m
nginx-596569f468-l62pd 1/1 Running 0 2m42s# 查看 Release 历史版本
[root@k8s-master01 ~]# helm history nginx -n helm-test
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Sat Jun 28 07:15:41 2025 superseded nginx-18.2.6 1.27.3 Install complete
2 Sat Jun 28 07:16:37 2025 superseded nginx-18.2.6 1.27.3 Upgrade complete
3 Sat Jun 28 07:34:04 2025 deployed nginx-18.2.6 1.27.3 Upgrade complete# 查看某个版本的状态
[root@k8s-master01 ~]# helm status nginx -n helm-test --revision 2# 查看某个 Release 设置的值
[root@k8s-master01 ~]# helm get values nginx -n helm-test
USER-SUPPLIED VALUES:
image:pullPolicy: IfNotPresentregistry: docker.kubeasy.comrepository: bitnami/nginx
replicaCount: 2# 回滚某个 Release
[root@k8s-master01 ~]# helm rollback nginx 2 -n helm-test[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
nginx-596569f468-6xc66 1/1 Running 0 32m[root@k8s-master01 ~]# helm get values nginx -n helm-test
USER-SUPPLIED VALUES:
image:pullPolicy: IfNotPresentregistry: docker.kubeasy.comrepository: bitnami/nginx
# 卸载
[root@k8s-master01 ~]# helm delete nginx -n helm-test
8.2 离线安装 Release
# 下载包
[root@k8s-master01 ~]# helm pull bitnami/nginx --version 18.2.4# 解压缩
[root@k8s-master01 ~]# tar xf nginx-18.2.4.tgz
[root@k8s-master01 ~]# ls
nginx nginx-18.2.4.tgz
[root@k8s-master01 ~]# cd nginx# 修改更新镜像地址
[root@k8s-master01 nginx]# ls
Chart.lock charts Chart.yaml README.md templates values.schema.json values.yaml[root@k8s-master01 nginx]# vim values.yaml
[root@k8s-master01 nginx]# sed -n "80,83p" values.yaml
image:registry: docker.kubeasy.comrepository: bitnami/nginxtag: 1.27.2-debian-12-r1# 离线安装
[root@k8s-master01 nginx]# helm install nginx . -n helm-test[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
nginx-67f54c6467-rgbqj 1/1 Running 0 98s
# 如果想根据 Chart 导出 Yaml,可以使用 template 字段:
[root@k8s-master01 nginx]# helm template nginx . -n helm-test --output-dir yaml
wrote yaml/nginx/templates/networkpolicy.yaml
wrote yaml/nginx/templates/pdb.yaml
wrote yaml/nginx/templates/serviceaccount.yaml
wrote yaml/nginx/templates/tls-secret.yaml
wrote yaml/nginx/templates/svc.yaml
wrote yaml/nginx/templates/deployment.yaml[root@k8s-master01 nginx]# ls yaml/nginx/templates/
deployment.yaml networkpolicy.yaml pdb.yaml serviceaccount.yaml svc.yaml tls-secret.yaml
9、常用服务安装
9.1 安装 Redis 到 K8s 中
# 使用 Helm 安装单节点 Redis,并设置密码:
[root@k8s-master01 ~]# helm upgrade --install redis bitnami/redis -n helm-test --set global.imageRegistry=docker.kubeasy.com --set global.redis.password=ywb123 --set architecture=standalone --set master.persistence.enabled=false --version 20.3.0# 查看 Pod 状态:
[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
redis-master-0 1/1 Running 0 45s# 查看 svc 状态:
[root@k8s-master01 ~]# kubectl get svc -n helm-test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-headless ClusterIP None <none> 6379/TCP 49s
redis-master ClusterIP 10.109.157.84 <none> 6379/TCP 49s
# 登录测试:
[root@k8s-master01 ~]# kubectl exec -ti redis-master-0 -n helm-test -- bash
I have no name!@redis-master-0:/$ redis-cli -h redis-master
redis-master:6379> auth ywb123
OK
redis-master:6379> set a 123
OK
redis-master:6379> get a
"123"
# 卸载:
[root@k8s-master01 ~]# helm delete redis -n helm-test
9.2 安装 MySQL 到 K8s 中
# 使用 Helm 安装单节点 MySQL,并设置密码,本次采用离线安装的方式,首先下载 Chart 包:
[root@k8s-master01 ~]# helm pull oci://docker.kubeasy.com/bitnamicharts/mysql --version 12.0.1# 解压缩
[root@k8s-master01 ~]# tar xf mysql-12.0.1.tgz # 修改配置
[root@k8s-master01 ~]# cd mysql
[root@k8s-master01 mysql]# ls
Chart.lock charts Chart.yaml README.md templates values.schema.json values.yaml[root@k8s-master01 mysql]# vim values.yaml
[root@k8s-master01 mysql]# sed -n "15,16p;22p;114p;117p;121p;125p;129p" values.yaml
global:imageRegistry: "docker.m.daocloud.io"defaultStorageClass: "nfs-csi" # 生产当作不建议使用NFS这种
architecture: standalone
auth:rootPassword: "ywb123" # 数据库密码createDatabase: truedatabase: "yunwei" # 可以初始创建一共库,选填# 安装
[root@k8s-master01 mysql]# helm install mysql . -n helm-test[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
mysql-0 1/1 Running 0 6m30s[root@k8s-master01 ~]# kubectl get svc -n helm-test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql ClusterIP 10.101.19.208 <none> 3306/TCP 6m55s
mysql-headless ClusterIP None <none> 3306/TCP 6m55s
# 登录测试:
[root@k8s-master01 ~]# kubectl exec -ti mysql-0 -n helm-test -- bash
Defaulted container "mysql" out of: mysql, preserve-logs-symlinks (init)
I have no name!@mysql-0:/$ mysql -uroot -hmysql -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 8.4.3 Source distributionCopyright (c) 2000, 2024, Oracle and/or its affiliates.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 |
| mysql |
| performance_schema |
| sys |
| yunwei |
+--------------------+
5 rows in set (0.00 sec)
# 卸载:
[root@k8s-master01 ~]# helm delete mysql -n helm-test
9.3 安装 MySQL 主从模式到 K8s 中
# 上述的 Chart 也支持部署主从模式的 MySQL,首先修改架构模式为复制模式:
[root@k8s-master01 mysql]# vim values.yaml
[root@k8s-master01 mysql]# sed -n "15,16p;22p;114p;117p;121p;125p;129p;140p;143p" values.yaml
global:imageRegistry: "docker.m.daocloud.io"defaultStorageClass: "nfs-csi"
architecture: replication # 修改架构模式为复制模式
auth:rootPassword: "ywb123"createDatabase: truedatabase: "yunwei"replicationUser: replicatorreplicationPassword: "ywb123" # 按需修改复制所用用户的密码# 安装
[root@k8s-master01 mysql]# helm install mysql . -n helm-test[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
mysql-primary-0 1/1 Running 0 5m51s
mysql-secondary-0 1/1 Running 0 5m51s[root@k8s-master01 ~]# kubectl get svc -n helm-test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql-primary ClusterIP 10.105.173.206 <none> 3306/TCP 55s
mysql-primary-headless ClusterIP None <none> 3306/TCP 55s
mysql-secondary ClusterIP 10.97.212.175 <none> 3306/TCP 55s
mysql-secondary-headless ClusterIP None <none> 3306/TCP 55s
# 数据同步测试:
[root@k8s-master01 ~]# kubectl exec -it mysql-primary-0 -n helm-test -- bash
Defaulted container "mysql" out of: mysql, preserve-logs-symlinks (init)# 登录主库
I have no name!@mysql-primary-0:/$ mysql -uroot -hmysql-primary-0 -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 104
Server version: 8.4.3 Source distributionCopyright (c) 2000, 2024, Oracle and/or its affiliates.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> create database dotbalo;
Query OK, 1 row affected (0.01 sec)# 登录备库查看数据是否同步
I have no name!@mysql-primary-0:/$ mysql -uroot -hmysql-secondary -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 80
Server version: 8.4.3 Source distributionCopyright (c) 2000, 2024, Oracle and/or its affiliates.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 |
+--------------------+
| dotbalo | # 数据已经同步
| information_schema |
| mysql |
| performance_schema |
| sys |
| yunwei |
+--------------------+
6 rows in set (0.01 sec)
# 卸载:
[root@k8s-master01 ~]# helm delete mysql -n helm-test
9.4 安装高可用 PostgreSQL 到 K8s 中
# 下载 PostgreSQL 安装文件:
[root@k8s-master01 ~]# helm pull oci://docker.kubeasy.com/bitnamicharts/postgresql-ha# 解压缩
[root@k8s-master01 ~]# tar xf postgresql-ha-16.0.15.tgz # 修改配置
[root@k8s-master01 ~]# cd postgresql-ha
[root@k8s-master01 postgresql-ha]# ls
Chart.lock charts Chart.yaml README.md templates values.yaml[root@k8s-master01 postgresql-ha]# vim values.yaml
[root@k8s-master01 postgresql-ha]# sed -n "27p;33,42p;46,49p;696p;700p" values.yaml imageRegistry: "docker.m.daocloud.io"defaultStorageClass: "nfs-csi"storageClass: ""postgresql:username: ""password: "ywb123"database: ""repmgrUsername: ""repmgrPassword: "ywb123"repmgrDatabase: ""existingSecret: ""pgpool: # 可以将查询分发到多个 PostgreSQL 节点,实现读写分离adminUsername: ""adminPassword: "ywb123"existingSecret: ""
witness:create: true # 用于提供额外的投票机制,防止脑裂现象,非必须# 安装 PostgreSQL:
[root@k8s-master01 postgresql-ha]# helm install pg . -n helm-test[root@k8s-master01 ~]# kubectl get po -n helm-test
NAME READY STATUS RESTARTS AGE
pg-postgresql-ha-pgpool-6dfc7b7f58-bz9qj 1/1 Running 3 (2m53s ago) 9m37s
pg-postgresql-ha-postgresql-0 1/1 Running 0 9m37s
pg-postgresql-ha-postgresql-1 1/1 Running 2 (2m57s ago) 9m37s
pg-postgresql-ha-postgresql-2 1/1 Running 0 9m37s
pg-postgresql-ha-postgresql-witness-0 1/1 Running 2 (2m59s ago) 9m37s[root@k8s-master01 ~]# kubectl get svc -n helm-test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
pg-postgresql-ha-pgpool ClusterIP 10.96.90.77 <none> 5432/TCP 30s
pg-postgresql-ha-postgresql ClusterIP 10.105.30.254 <none> 5432/TCP 30s
pg-postgresql-ha-postgresql-headless ClusterIP None <none> 5432/TCP 30s
pg-postgresql-ha-postgresql-witness ClusterIP None <none> 5432/TCP 30s
# 登录测试:
[root@k8s-master01 ~]# kubectl exec -it pg-postgresql-ha-postgresql-0 -n helm-test -- bash
I have no name!@pg-postgresql-ha-postgresql-0:/$ psql -h pg-postgresql-ha-pgpool -U postgres
Password for user postgres:
psql (17.2)
Type "help" for help.postgres=# CREATE DATABASE mydatabase;
CREATE DATABASE
mydatabase(# \c mydatabase
You are now connected to database "mydatabase" as user "postgres".
mydatabase=#
mydatabase=# CREATE TABLE employees (
mydatabase(# id SERIAL PRIMARY KEY,
mydatabase(# name VARCHAR(100),
mydatabase(# age INT,
mydatabase(# department VARCHAR(50)
mydatabase(# );
CREATE TABLE
mydatabase=# \d employeesTable "public.employees"Column | Type | Collation | Nullable | Default ------------+------------------------+-----------+----------+-------------------------------------
--id | integer | | not null | nextval('employees_id_seq'::regclass
)name | character varying(100) | | | age | integer | | | department | character varying(50) | | |
Indexes:"employees_pkey" PRIMARY KEY, btree (id)# 查看集群的状态:
I have no name!@pg-postgresql-ha-postgresql-0:/$ /opt/bitnami/scripts/postgresql-repmgr/entrypoint.sh repmgr -f /opt/bitnami/repmgr/conf/repmgr.conf cluster showID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string
------+---------------------------------------+---------+-----------+-------------------------------+----------+----------+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------1000 | pg-postgresql-ha-postgresql-0 | primary | * running | | default | 100 | 1 | user=repmgr password=ywb123 host=pg-postgresql-ha-postgresql-0.pg-postgresql-ha-postgresql-headless.helm-test.svc.cluster.local dbname=repmgr port=5432 connect_timeout=5 1001 | pg-postgresql-ha-postgresql-1 | standby | running | pg-postgresql-ha-postgresql-0 | default | 100 | 1 | user=repmgr password=ywb123 host=pg-postgresql-ha-postgresql-1.pg-postgresql-ha-postgresql-headless.helm-test.svc.cluster.local dbname=repmgr port=5432 connect_timeout=5 1002 | pg-postgresql-ha-postgresql-2 | standby | running | pg-postgresql-ha-postgresql-0 | default | 100 | 1 | user=repmgr password=ywb123 host=pg-postgresql-ha-postgresql-2.pg-postgresql-ha-postgresql-headless.helm-test.svc.cluster.local dbname=repmgr port=5432 connect_timeout=5 2000 | pg-postgresql-ha-postgresql-witness-0 | witness | * running | pg-postgresql-ha-postgresql-0 | default | 0 | n/a | user=repmgr password=ywb123 host=pg-postgresql-ha-postgresql-witness-0.pg-postgresql-ha-postgresql-witness.helm-test.svc.cluster.local dbname=repmgr port=5432 connect_timeout=5
# 卸载:
[root@k8s-master01 ~]# helm delete pg -n helm-tes
10、自定义 Helm Chart
10.1 使用场景
- 简化应用部署
- 多环境部署
- 快速迭代和回滚
- CI/CD集成
- 项目一键启动
10.2 自定义 Helm Chart
# 创建一个自定义 Chart:
[root@k8s-master01 ~]# helm create test[root@k8s-master01 ~]# tree test/
test/
├── charts # 依赖文件
├── Chart.yaml # 当前chart的基本信息
├── templates # 模板位置
│ ├── deployment.yaml
│ ├── _helpers.tpl # 自定义的模板或者函数
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt # Chart安装完毕后的提醒信息
│ ├── serviceaccount.yaml
│ ├── service.yaml
│ └── tests # 测试文件
│ └── test-connection.yaml
└── values.yaml # 配置全局变量或者一些参数3 directories, 10 files
_helpers.tp文件是Helm中一共非常重要的组成部分,通常用了定义可以被其他模板文件复用的辅助函数、片段或者变量等。
在Helm中可以将常用的代码片段和逻辑放在_helpers.tp中,用来保持模板的整洁、避免重复,并且更容易管理和维护。
NOTES.txt是一个Helm Chart的安装说明文件,在执行helm install
或helm upgrade
命令后,Helm会打印对用户有用的信息,比如使用说明。
NOTES文件同样可以使用template
语法进行生成。
10.3 Helm常用内置变量
- Release.Name:实例的名称,helm install指定的名字
- Release.Namespace:应用实例的命名空间
- Release.IsUpgrade:如果当前对实例的操作是更新或者回滚,这个变量的值就会被置为true
- Release.IsInstall:如果对当前实例的操作是安装,则这边变量被置为true
- Release.Revision:此次修订的版本号,从1开始,每次升级回滚都会增加1
- Chart:Chart.yaml文件中的内容,可以使用Chart.Version表示应用版本,Chart.Name表示Chart的名称
10.4 Helm常用函数
10.4.1 字符串函数
- trim:去除字符串两边的空格
- trimALL:从字符串中移除给定的字符
- trimPrefix:从字符串前面移除某个字符
- trimSuffix:从字符串后面移除某个字符
- lower:转成小写
- upper:转成大写
- title:首字母大写
- repeat:重复字符串
- nospace:去除所有的空格
- contains:判断是否包含某个值
- hasPrefix:判断是否以什么开头
- hasSuffix:判断是否以什么结尾
- quote:使用双引号括起来字符串
- squote:使用单引号括起来字符串
- cat:字符串使用空格拼接
- indent:以指定的长度缩进
- nindent:缩进,并添加新一行
- replace:字符串替换
- substr:截断字符串,从哪到哪
- trunc:截断字符串,从前或从后
- print:组合字符串
- println:组合字符串,但会在末尾新添加一行
- printf:格式化字符串,printf “%shas %d dogs.” .Name .NumberDogs
10.4.2 类型转换函数
- atoi:字符串转成整型
- toString:转换成字符串
- totoString:转换成字符串列表
- toYaml:将列表、切片、数组、字典等,转换成已缩进的yaml块
10.4.3 逻辑转换函数
- and:且,多个条件必须均成立
- or或,多个条件成立一共即可
- not:取反
- eq:判断是否相等
- ne:判断是否不相等
- lt:判断是否小于
- le:判断是否小于等于
- gt:判断是否大于
- ge:判断是否大于等于
- default:设置默认值
- empty:判断是否为空
10.5 自定义 Helm Chart
10.5.1 自定义单个Helm配置
# 创建自定义模板文件
[root@k8s-master01 ~]# helm create demo-ui# 修改配置
[root@k8s-master01 ~]# cd demo-ui/
[root@k8s-master01 demo-ui]# vim values.yaml
[root@k8s-master01 demo-ui]# sed -n "9,10p;14p;23p;25p;60,63p;66,70p;89,94p" values.yaml
image:repository: crpi-q1nb2n896zwtcdts.cn-beijing.personal.cr.aliyuncs.com/ywb01/demo-uitag: "v1"
serviceAccount:create: false
ingress:enabled: trueclassName: "nginx"annotations: {}hosts:- host: demo.test.compaths:- path: /pathType: ImplementationSpecific
livenessProbe:tcpSocket:port: 80
readinessProbe:tcpSocket:port: 80# 检查配置是否有误
[root@k8s-master01 demo-ui]# helm lint
==> Linting .
[INFO] Chart.yaml: icon is recommended1 chart(s) linted, 0 chart(s) failed# 临时预览配置的命令
[root@k8s-master01 demo-ui]# helm template demo-ui .# 启动
[root@k8s-master01 demo-ui]# helm install demo-ui . -n demo --create-namespace
NAME: demo-ui
LAST DEPLOYED: Sun Jun 29 00:32:18 2025
NAMESPACE: demo
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:http://demo.test.com/# pod已经正常启动
[root@k8s-master01 demo-ui]# kubectl get pod -n demo
NAME READY STATUS RESTARTS AGE
demo-ui-576766448b-gftdp 1/1 Running 0 55s# svc已经正常启动
[root@k8s-master01 demo-ui]# kubectl get svc -n demo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-ui ClusterIP 10.96.206.116 <none> 80/TCP 17m# ingress已经正常启动
[root@k8s-master01 demo-ui]# kubectl get ingress -n demo
NAME CLASS HOSTS ADDRESS PORTS AGE
demo-ui nginx demo.test.com 80 17m
# 卸载
[root@k8s-master01 demo-ui]# helm delete demo-ui -n demo
10.5.2 自定义多个Helm配置
# 创建自定义模板文件
[root@k8s-master01 ~]# helm create demo# 修改配置
[root@k8s-master01 ~]# cd demo
[root@k8s-master01 demo]# cat values.yaml
....
applications:- name: demo-uiimage: crpi-q1nb2n896zwtcdts.cn-beijing.personal.cr.aliyuncs.com/ywb01/demo-ui:v1resources: {}appPort: 80service:port: 80type: ClusterIPreplicaCount: 1 env:- name: SPRING_PROFILES_ACTIVEvalue: k8singress:enabled: trueclassName: "nginx"annotations: {}hosts:- host: demo.test.compaths:- path: /pathType: ImplementationSpecifictls: []- name: demo-receiveimage: crpi-q1nb2n896zwtcdts.cn-beijing.personal.cr.aliyuncs.com/ywb01/demo-receive:v1resources: {}appPort: 8080service:port: 8080type: ClusterIPreplicaCount: 2env:- name: SPRING_PROFILES_ACTIVEvalue: k8supgrade- name: SERVER_PORTvalue: '8080'ingress:enabled: trueclassName: "nginx"annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2hosts:- host: demo.test.compaths:- path: /receiveapi(/|$)(.*)pathType: ImplementationSpecifictls: []- name: demo-handlerimage: crpi-q1nb2n896zwtcdts.cn-beijing.personal.cr.aliyuncs.com/ywb01/demo-handler:v1resources: {}appPort: 8080service:port: 80type: ClusterIPreplicaCount: 1env:- name: SPRING_PROFILES_ACTIVEvalue: k8supgrade- name: SERVER_PORTvalue: '8080'ingress:enabled: falseclassName: "nginx"annotations: {}hosts:- host: demo.test.compaths:- path: /pathType: ImplementationSpecifictls: []....
[root@k8s-master01 demo]# cat templates/_helpers.tpl
{{/*
Expand the name of the chart.
*/}}
{{- define "demo.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "demo.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "demo.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}{{/*
Common labels
*/}}
{{- define "demo.labels" -}}
helm.sh/chart: {{ include "demo.chart" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
project: {{ .Chart.Name }}
{{- end }}{{/*
Selector labels
*/}}
{{- define "demo.selectorLabels" -}}
project: {{ .Chart.Name }}
{{- end }}{{/*
Create the name of the service account to use
*/}}
{{- define "demo.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "demo.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
[root@k8s-master01 demo]# cat templates/deployment.yaml
{{ range .Values.applications -}}
---
apiVersion: apps/v1
kind: Deployment
metadata:name: {{ .name }}labels:{{- include "demo.labels" $ | nindent 4 }}app: {{ .name }}
spec:replicas: {{ .replicaCount }}selector:matchLabels:{{- include "demo.selectorLabels" $ | nindent 6 }}app: {{ .name }}template:metadata:{{- with $.Values.podAnnotations }}annotations:{{- toYaml . | nindent 8 }}{{- end }}labels:{{- include "demo.selectorLabels" $ | nindent 8 }}app: {{ .name }}spec:{{- with $.Values.imagePullSecrets }}imagePullSecrets:{{- toYaml . | nindent 8 }}{{- end }}containers:- name: {{ .name }}image: "{{ .image }}"imagePullPolicy: {{ $.Values.image.pullPolicy }}ports:- name: httpcontainerPort: {{ .appPort }}protocol: TCPlivenessProbe:tcpSocket:port: httpreadinessProbe:tcpSocket:port: httpenv:{{- toYaml .env | nindent 12 }} resources:{{- toYaml .resources | nindent 12 }}
{{ end }}
[root@k8s-master01 demo]# cat templates/service.yaml
{{ range .Values.applications -}}
---
apiVersion: v1
kind: Service
metadata:name: {{ .name }}labels:{{- include "demo.labels" $ | nindent 4 }}
spec:type: {{ .service.type }}ports:- port: {{ .service.port }}targetPort: httpprotocol: TCPname: httpselector:{{- include "demo.selectorLabels" $ | nindent 4 }}
[root@k8s-master01 demo]# cat templates/ingress.yaml
{{ range .Values.applications -}}
---
{{- if .ingress.enabled -}}
{{ $servicePort := .service.port}}
{{ $Name := .name}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: {{ .name }}labels:{{- include "demo.labels" $ | nindent 4 }}app: {{ .name }}{{- with .ingress.annotations }}annotations:{{- toYaml . | nindent 4 }}{{- end }}
spec:{{- with .ingress.className }}ingressClassName: {{ . }}{{- end }}{{- if .ingress.tls }}tls:{{- range .ingress.tls }}- hosts:{{- range .hosts }}- {{ . | quote }}{{- end }}secretName: {{ .secretName }}{{- end }}{{- end }}rules:{{- range .ingress.hosts }}- host: {{ .host | quote }}http:paths:{{- range .paths }}- path: {{ .path }}{{- with .pathType }}pathType: {{ . }}{{- end }}backend:service:name: {{ $Name }}port:number: {{ $servicePort }}{{- end }}{{- end }}
{{- end }}
{{ end }}
# 启动
[root@k8s-master01 demo]# helm install demo . -n demo# pod已经正常启动
[root@k8s-master01 demo]# kubectl get pod -n demo
NAME READY STATUS RESTARTS AGE
demo-handler-7794946988-llq7h 1/1 Running 0 90s
demo-receive-57c6d69ccf-cv2jj 1/1 Running 0 90s
demo-ui-f5899b8fb-6s7nt 1/1 Running 0 90s# svc已经正常启动
[root@k8s-master01 demo]# kubectl get svc -n demo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-handler ClusterIP 10.97.203.224 <none> 80/TCP 94s
demo-receive ClusterIP 10.96.155.137 <none> 8080/TCP 94s
demo-ui ClusterIP 10.106.16.212 <none> 80/TCP 94s# ingress已经正常启动
[root@k8s-master01 demo]# kubectl get ingress -n demo
NAME CLASS HOSTS ADDRESS PORTS AGE
demo-receive nginx demo.test.com 80 101s
demo-ui nginx demo.test.com 80 101s
10.5.3 打包上传仓库
# 打包
[root@k8s-master01 ~]# helm package demo
[root@k8s-master01 ~]# ls
demo demo-0.1.0.tgz# 登录
[root@k8s-master01 ~]# helm registry login 192.168.200.53 -u admin -pHarbor12345 --insecure# 上传镜像
[root@k8s-master01 ~]# helm push demo-0.1.0.tgz oci://192.168.200.53/library --plain-http
此博客来源于:https://edu.51cto.com/lecturer/11062970.html