跳到主要内容

helm 部署

helm 是什么

Helm 是 Kubernetes 中最热门的包管理工具之一,它使得打包、安装、升级和卸载 Kubernetes 应用程序变得更加容易。 它的作用类似于 Linux 下的包管理器(例如 apt-get、yum 等),可以用来管理 Kubernetes 应用程序中的组件、服务、配置以及依赖关系。

Helm 可以将复杂的 Kubernetes 应用程序打包为一个单独的 Chart(图表),简化了应用程序的部署和维护。Chart 中包含了包括容器镜像、服务部署配置、依赖关系等全部信息,使得应用程序的部署过程更加可重复、可靠和可维护。

除此之外,Helm 还提供了 Helm Repo(仓库)机制,让用户可以方便地分享自己的 Chart,也可以方便地从公共 Helm 仓库中下载找到所需的 Chart,从而进一步提高了 Kubernetes 应用程序的部署效率和开发效率。

实际场景说明

在 Kubernetes 中部署一个稍微复杂的系统,比如下面这个典型的三层架构:前端、后端和数据层。

20230506170631

如果要部署上面的这个服务,则需要写一堆的 yaml,每一层架构都至少要写 2 个 YAML 文件,写的时候还需要理解各种对象、注意各种缩进的层级关系、还要设置一堆配置参数等。这对于刚接触 Kubernetes 的人来说是一个很高的门槛,简直无法跨越。同时,对于业务交付的同学,也将是一个大灾难,因为如果缺少任何一个 YAML 文件,都会导致整个系统无法正常工作。

看到这里,你也许会想到能不能通过一种包的方式进行管理呢,类似于 Node.js 通过 npm 来管理包,Debian 系统通过 dpkg 来管理包,而 Python 通过 pip 来管理包。

那么在 Kubernetes 中, 这个答案就是 Helm。

Helm 降低了使用 Kubernetes 的门槛,你无须从头开始编写应用部署文件,甚至都不需要了解 Kubernetes 中的各个对象以及相应的 YAML 语义。直接通过 Helm 就可以在自己的 Kubernetes 中一键部署需要的应用。

Helm 中的几个概念

在 Helm 中,有三个非常核心的概念—— Chart、Config 和 Release。

Chart 可以理解成应用的安装包,通常包含了一组我们在 Kubernetes 要部署的 YAML 文件。一个 Chart 就是一个目录,我们可以将这个目录进行压缩打包,比如打包成 some-chart-version.tgz 类型的压缩文件,方便传输和存储。

每个这样的 Chart 包内都必须有一个 Chart.yaml 文件,类似这样:

apiVersion: v1
name: redis
version: 11.0.0
appVersion: 6.0.8
description: Open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.
keywords:
- redis
- keyvalue
- database
home: https://github.com/bitnami/charts/tree/master/bitnami/redis
icon: https://bitnami.com/assets/stacks/redis/img/redis-stack-220x234.png
sources:
- https://github.com/bitnami/bitnami-docker-redis
- http://redis.io/
maintainers:
- name: Bitnami
email: containers@bitnami.com
- name: desaintmartin
email: cedric@desaintmartin.fr
engine: gotpl
annotations:
category: Database

这个 Chart.yaml 主要用来描述该 Chart 的名字、版本号,以及关键字等信息。有了这个 Chart,我们就可以在 Kubernetes 集群中部署了。每一次的安装部署,我们称为一个 Release。在同一个 Kubernetes 集群中,可以有多个 Release。你可以将 Release 理解成是 Chart 包部署后的一个 Chart(应用)实例。

同时,为了能够让 Chart 实现参数可配置,即 Config,我们在每个 Chart 包内还有一个 values.yaml 文件,用来记录可配置的参数和其默认值。在每个 Release 中,我们也可以指定自己的 values.yaml 文件用来覆盖默认的配置。

此外,我们还需要统一存放这些 Chart,即 Repository(仓库)。这个概念和我们以前的 yum repo 是一样的。本质上来说,Repository 就是一个 Web 服务器,不仅保存了一系列的 Chart 软件包让用户下载安装使用,还有对应的清单文件以供查询。

Helm 安装环境

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
sudo apt-get install apt-transport-https --yes
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm

20230506172227

添加 Chart 仓库

安装好了Helm之后,可以添加一个 chart 仓库。从 Artifact Hub 中查找有效的 Helm chart 仓库。

helm repo add bitnami https://charts.bitnami.com/bitnami

添加完成,可以看到可以安装的 charts 列表:

helm search repo bitnami

20230506174928

如何创建和部署 Helm Chart

创建一个 Chart 很简单,通过 helm create 的命令就可以创建一个 Chart 模板出来:

$ helm create hello-world

20230506172637

values.yaml 里面包含了一些可配置的参数,你可以根据自己的需要进行添加,或者修改默认值等。

这个目录下面有个 charts 文件夹,主要用来放置一些子 Chart 包,也可以是 tar 包、 Chart 目录。你可以根据自己的场景,决定需不需要放置子 Chart 包。

这个目录里面还有个 templates 文件夹,这个文件夹里面的文件是一些模板文件,Helm 会根据 values.yaml 的参数进行渲染,然后在 Kubernetes 集群中创建出来。

然后通过 helm install 命令,你就可以在 Kubernetes 集群里面部署 hello-world 这个 Chart 包:

helm install hello-world ./hello-world

安装时的报错

先确定服务是否起来了

kubectl cluster-info

20230509153103

如果没有问题再去检查配置文件

Error: INSTALLATION FAILED: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp 127.0.0.1:8080: connect: connection refused

则去设置环境变量

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

参考 https://github.com/rancher/k3s/issues/1126

如果只有 sudo 时无法读取这个环境变量

20230509160159

在 root 用户下执行

kubectl config view --raw >~/.kube/config
chmod o-r ~/.kube/config
chmod g-r ~/.kube/config

# 普通用户执行
sudo chmod o-r /etc/rancher/k3s/k3s.yaml
sudo chmod g-r /etc/rancher/k3s/k3s.yaml

如果使之不行,可以尝试使用 --kubeconfig 参数

sudo helm install my-redis-cluster \
--namespace redis \
--kubeconfig /etc/rancher/k3s/k3s.yaml \
./redis-cluster

部署一个 MySQL

先搜索一下有没有 MySQL 的 Chart 包:

helm search repo mysql

20230506175609

可以通过执行以下命令简单的了解到某个 chart 的基本信息。

helm show chart bitnami/mysql

20230506175237

# 或者 all 获取关于该 chart 的所有信息。
helm show all bitnami/mysql

然后通过 helm install 命令,就可以在 Kubernetes 集群里面部署 mysql 这个 Chart 包:

$ helm repo update              # 确定我们可以拿到最新的charts列表
$ helm install bitnami/mysql --generate-name

20230506175121

在上面的例子中,bitnami/mysql 这个chart被发布,名字是 mysql-1683366661

检查一下当前有哪些 chart 被部署了:

$ helm list

20230506175417

可以检查一下当前有哪些 pod 被部署了:

kubectl get pods -w --namespace default

20230506175955

卸载掉这个 MySQL

# 如果有命名空间要加上 --namespace <namespace_name>
$ helm uninstall mysql-1683366661
$ helm list -A

该命令会从 Kubernetes 卸载 mysql-1683366661, 它将删除和该版本相关的所有相关资源(service、deployment、 pod等等)甚至版本历史。

例:使用 Helm 部署 Harbor

# 上官网添加
# https://artifacthub.io/packages/helm/harbor/harbor
helm repo add harbor https://helm.goharbor.io
helm pull harbor/harbor

把下载的压缩包解压

# 解压
tar -zxvf harbor-1.12.0.tgz

20230508145821

然后修改 values.yaml 文件

# 通过 nodePort 提供访问
expose.type: nodePort
# 禁用了 tls
expose.tls.enabled: false
# 访问地址,因为禁用了 tls,所以这些的协议一定要改成 http,然后后面要加上 nodeport 的固定端口
externalURL: http://192.168.2.55:30002

# 禁用一些没必要的服务,以避免浪费资源
# 1、容器镜像安全扫描
trivy.enabled: false
# 2、容器镜像中可以对镜像进行加密签名用来保证镜像件来源和镜像内容防篡改
notary.enabled: false

最后进行部署

cd harbor
helm install harbor --namespace harbor --create-namespace .
sudo kubectl get pod -n harbor

20230508151840

http://localhost:30002

20230508151957

例:部署一个简单的 Web 服务

目标: 1、部署一个简单的 Web 服务 2、部署 MySQL 数据库 3、部署 Redis 缓存

# 这里直接引入官方的仓库
helm repo add bitnami https://charts.bitnami.com/bitnami

部署 Redis Cluster

Redis Cluster 是 Redis 的分布式解决方案,在 Redis 3.0 版本正式推出的,有效解决了 Redis 分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用 Cluster 架构达到负载均衡的目的。

helm search repo redis

这里我们选择 bitnami/redis-cluster 这个仓库

helm pull bitnami/redis-cluster
tar -zxvf redis-cluster-8.4.4.tgz

20230508160313

然后修改 values.yaml 文件,主要是将 storageClass 改为我们使用的持久化存储名称

# 这个节点的计算公式如下
# nodes = numberOfMasterNodes + numberOfMasterNodes * replicas
cluster.nodes: 6 # 因为主节点最少是 3,所以总数是 6,即三主三从模式
cluster.replicas: 1
# 暴露出 metrics 以便于监控
metrics.enabled: true
# 持久化存储
persistence.enabled: true
global.storageClass: local-path # 这里使用 local-path-provisioner
persistence.size: 30Mi # 注意这个单位 Mi Gi Ti

创建一个命名空间

kubectl create ns redis

接下来我们部署 redis-cluster,安装是异步的,也就是这里提示的只是成功的将 chart 发布到了 k8s 中,应用的部署还需要时间

sudo helm install my-redis-cluster --namespace redis ./redis-cluster
# 如果想再次展示 notes 信息,可以执行
sudo helm get notes my-redis-cluster -n redis

# 执行失败记得删掉
# sudo helm uninstall my-redis-cluster --namespace redis
# K8S 删除命名空间下所有的 pod
# kubectl delete --all pods -n redis
# kubectl delete --all deploy -n redis
# kubectl delete --all sts -n redis
# kubectl delete --all pvc -n redis # pvc 被删了 pv 也会被删掉


# 安装成功后,可以通过下面的命令查看部署的状态
kubectl get pod -n redis
kubectl logs my-redis-cluster-0 -n redis
kubectl describe pod my-redis-cluster-0 -n redis

20230509175118

可以用下面这种方式取得密码(设置了才有)

export REDIS_PASSWORD=$(sudo kubectl get secret --namespace "redis" my-redis-cluster -o jsonpath="{.data.redis-password}" | base64 -d)

# 这里的 redis-headless.redis.svc.cluster.local 是 redis 的服务名,进入终端
sudo kubectl run --namespace redis my-redis-cluster-client --rm --tty -i --restart='Never' \
--env REDIS_PASSWORD=$REDIS_PASSWORD \
--image docker.io/bitnami/redis-cluster:7.0.11-debian-11-r0 -- bash

# 进入终端执行命令
redis-cli -c -h my-redis-cluster -a $REDIS_PASSWORD

进入终端可以发现可以正常访问服务了

部署 MySQL 主从库

helm search repo mysql
helm pull bitnami/mysql
tar -zxvf mysql-9.9.0.tgz
sudo kubectl create ns mysql

同样修改 values.yaml 文件

global.storageClass: "local-path"
primary.persistence.size: 100Mi
primary.service.type: "NodePort" # 因为是本地,所以使用 NodePort
secondary.persistence.size: 100Mi
secondary.service.type: "NodePort"
metrics.enabled: true
secondary.name: "slave" # 从库的名称(改不改都行吧)
secondary.replicaCount: 1 # 从库的数量
auth.rootPassword: "123456" # root 密码
image.debug: true # 打开日志
architecture: "replication" # 主从模式

注意,下面这个配置文件中的三个 3306

  1. [mysqld] 部分中的 port=3306 指定了MySQL服务器监听的端口号。默认情况下,MySQL服务器使用 3306 作为默认端口号,这意味着当客户端应用程序连接到服务器时,它们将使用该端口号进行通信。

  2. [client] 部分中的 port=3306 指定了MySQL客户端连接到服务器时要使用的端口号。这意味着客户端应用程序需要连接到MySQL服务器时,它们将使用指定的端口号 3306。

  3. [manager] 部分中的 port=3306 定义了 MySQL 管理工具连接到服务器时要使用的端口号。MySQL 管理工具(如 MySQL Workbench)可以使用该端口号与服务器建立连接以进行管理和配置操作。

[mysqld]
default_authentication_plugin=mysql_native_password
skip-name-resolve
explicit_defaults_for_timestamp
basedir=/opt/bitnami/mysql
plugin_dir=/opt/bitnami/mysql/lib/plugin
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
datadir=/bitnami/mysql/data
tmpdir=/opt/bitnami/mysql/tmp
max_allowed_packet=16M
bind-address=*
pid-file=/opt/bitnami/mysql/tmp/mysqld.pid
log-error=/opt/bitnami/mysql/logs/mysqld.log
character-set-server=UTF8
collation-server=utf8_general_ci
slow_query_log=0
slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log
long_query_time=10.0

[client]
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
default-character-set=UTF8
plugin_dir=/opt/bitnami/mysql/lib/plugin

[manager]
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
pid-file=/opt/bitnami/mysql/tmp/mysqld.pid

部署安装

sudo helm install my-mysql --namespace mysql ./mysql
# 执行失败记得删掉
# sudo helm uninstall my-mysql --namespace mysql
# K8S 删除命名空间下所有的 pod
# kubectl delete --all pods -n mysql
# kubectl delete --all deploy -n mysql
# kubectl delete --all sts -n mysql
# kubectl delete --all pvc -n mysql # pvc 被删了 pv 也会被删掉


# 如果想再次展示 notes 信息,可以执行
sudo helm get notes my-mysql -n mysql

MYSQL_ROOT_PASSWORD=$(sudo kubectl get secret --namespace mysql my-mysql -o jsonpath="{.data.mysql-root-password}" | base64 -d)
sudo kubectl run my-mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.33-debian-11-r3 --namespace mysql --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash

# 进入终端执行命令
mysql -h my-mysql.mysql.svc.cluster.local -uroot -p"$MYSQL_ROOT_PASSWORD"

# 暴露出 metrics 以便于监控
sudo kubectl port-forward --namespace mysql svc/my-mysql-metrics 9104:9104 &

20230511102134

sudo kubectl get pod -n mysql
kubectl describe pod my-mysql-0 -n mysql

创建了主从库

20230511103357

部署一个自己的 Web 服务

fdUPjjQs1zCxd6Ik