十二、Helm

在没使用 helm 之前,向 kubernetes 部署应用,我们要依次部署 deployment、svc 等,步骤较繁琐。况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm通过打包的方式,支持发布的版本管理和控制,很大程度上简化了 Kubernetes 应用的部署和管理。

Helm 本质就是让 K8s 的应用管理(Deployment,Service 等 ) 可配置,能动态生成。通过动态生成 K8s 资源清单文件(deployment.yamlservice.yaml)。然后调用Kubectl自动执行K8s资源部署。

Helm 是官方提供的类似于 YUM 的包管理器,是部署环境的流程封装。Helm 有两个重要的概念:chart和release:

  • chart 是创建一个应用的信息集合,包括各种 Kubernetes 对象的配置模板、参数定义、依赖关系、文档说明等。chart 是应用部署的自包含逻辑单元。可以将 chart 想象成 apt、yum 中的软件安装包。
  • release 是 chart 的运行实例,代表了一个正在运行的应用。当 chart 被安装到 Kubernetes 集群,就生成一个 release。chart 能够多次安装到同一个集群,每次安装都是一个 release。

Helm 包含两个组件:Helm 客户端和 Tiller 服务器,如下图所示:

1290695-20211009101546806-593568350

Helm 客户端负责 chart 和 release 的创建和管理以及和 Tiller 的交互。

Tiller 服务器运行在 Kubernetes 集群中,它会处理 Helm 客户端的请求,与 Kubernetes API Server 交互 。

可以前往Helm的官方网站了解更多。

1 Helm部署

越来越多的公司和团队开始使用 Helm 这个 Kubernetes 的包管理器,我们也将使用 Helm 安装 Kubernetes 的常用组件。Helm由Helm客户端命令行工具和服务端tiller组成,Helm的安装十分简单。下载helm命令行工具到master的/usr/local/bin下,这里下载的2.13.1版本:

1
2
3
4
5
6
ntpdate ntp1.aliyun.com
wget https://get.helm.sh/helm-v2.13.1-linux-amd64.tar.gz
tar -zxvf helm-v2.13.1-linux-amd64.tar.gz
cd linux-amd64/
cp helm /usr/local/bin/
chmod a+x /usr/local/bin/helm

要获取其它版本,前往github官方发布页面下载。

查看Helm和对应支持的Kubernetes版本,可以参考 Helm 版本支持策略

因为 Kubernetes API服务器开启了RBAC访问控制,所以需要创建tiller使用的service account:tiller并分配合适的角色给它。这里简单起见直接分配cluster-admin这个集群内置的 ClusterRole 给它。创建 rbac-config.yaml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1 
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding #绑定集群角色
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole #集群角色
name: cluster-admin #使用集群管理员角色名
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system

创建这个SA:

1
kubectl create -f rbac-config.yaml 

安装tiller客户端

1
helm init --service-account=tiller --skip-refresh

如下:

image-20220113101149073

tiller默认被部署在集群中的kube-system名称空间下,查看一下:

1
kubectl get pod -n kube-system -l app=helm

如果遇到ImagePullBackOff,可能是镜像下载错误,自行开启魔法,或者配置一个国内镜像,也可以从本地文件导入镜像。

查看Helm的版本:

1
helm version

如下图

image-20220113113201937

2 Helm仓库

查看官方的Helm仓库:https://artifacthub.io/

Helm 的软件仓库Repository本质上是一个 Web 服务器,该服务器保存了一系列的 Chart 软件包以供用户下载,并且提供了一个该 Repository 的 Chart 包的清单文件以供查询。Helm 可以同时管理多个不同的 Repository。

image-20220113114103607

和docker hub类似,比如搜索mysql

image-20220113114358835

按照提示安装Helm源,然后通过命令就可以安装需要的应用。

3 Helm自定义模板

除了官方仓库,还可以自定义应用模版。下面的示例创建了一个自定义的Helm模版:

创建文件夹

1
2
mkdir ./hello-world
cd ./hello-world

创建自描述文件Chart.yaml , 这个文件必须由 name 和 version 定义

1
2
3
4
cat <<'EOF' > ./Chart.yaml 
name: hello-world
version: 1.0.0
EOF

创建模板文件,用于生成Kubernetes资源清单(manifests)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
mkdir ./templates  #必须是这个目录名
# deployment的清单
cat <<'EOF' > ./templates/deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 1
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: ibmcom/helloworld
ports:
- containerPort: 8080
protocol: TCP
EOF

# svc的清单
cat <<'EOF' > ./templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-world
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
protocol: TCP
selector:
app: hello-world
EOF

然后,使用命令创建Release

1
helm install .

使用 helm install 命令在 Kubernetes 集群中部署的 Chart 称为 Release。

单个chart可以在同一个集群中安装多次,并能创建多个不同的版本,类似于docker镜像和容器的关系。

image-20220113125803570

查看当前helm运行列表信息,使用命令:

1
helm list

也可以通过kubectl查看:

1
2
3
kubectl get po
NAME READY STATUS RESTARTS AGE
hello-world-5b696b88b-wj6tg 1/1 Running 0 4m29s

查看Release的状态信息:

1
helm status [Release名称]

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LAST DEPLOYED: Thu Jan  6 08:24:16 2022
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
hello-world-5b696b88b-wj6tg 1/1 Running 0 <invalid>

==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world NodePort 10.97.96.155 <none> 80:31325/TCP <invalid>

==> v1beta1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world 1/1 1 1 <invalid>

看到服务的端口为31325,可以通过浏览器访问http://192.168.142.20:31325/获取到如下内容:

image-20220113131029637

使用Helm的好处是,可以通过values.yaml来进行更新:

新建配置文件values.yaml,内容为:

1
2
3
4
5
cat <<'EOF' > ./values.yaml 
image:
repository: ibmcom/helloworld
tag: 'v2'
EOF

这个文件中定义的值,在模板文件中可以通过.Values对象访问到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat <<'EOF' > ./templates/deployment.yaml  #(直接修改上面的文件)
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 1
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
ports:
- containerPort: 80
protocol: TCP
EOF

这样后续直接修改values.yaml就能直接修改镜像和tag,现在我们只需要更新配置:

1
helm upgrade [Release名称] .

就可以实现更新。

4 常用命令

可以通过helm help获取帮助,查看一些常用的命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 列出已经部署的 Release 
helm list

# 查询一个特定的 Release 的状态
helm status RELEASE_NAME

# 移除所有与这个 Release 相关的 Kubernetes 资源(还有回滚余地)
helm delete cautious-shrimp

# 更新Release
helm upgrade RELEASE名称 CHART路径

# 回滚 helm rollback RELEASE_NAME REVISION_NUMBER
helm rollback cautious-shrimp 1

# 使用 helm delete --purge RELEASE_NAME 移除所有与指定 Release 相关的 Kubernetes 资源和所有这个 Release 的记录(彻底删除,无法回滚)
helm delete --purge cautious-shrimp

# 查看删除但还保留的记录
helm list --deleted

# 使用模板动态生成K8s资源清单时,提前预览生成的结果:使用--dry-run
helm install --dry-run . # 尝试部署,但不真正执行部署
helm install . --dry-run --debug # --debug选项来打印出生成的清单文件内容

5 使用Helm部署dashboard

Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源 (如 Deployment,Job,DaemonSet 等等)。 例如,你可以对 Deployment 实现弹性伸缩、发起滚动升级、重启 Pod 或者使用向导创建新的应用。

Dashboard 同时展示了 Kubernetes 集群中的资源状态信息和所有报错信息。

ui-dashboard

你可以手动部署:

1
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml

这里介绍使用Helm部署方式:

把Chart的压缩包下载到本地使用:

1
helm fetch stable/kubernetes-dashboard --version 1.8.0  # 下载1.8.0版本

如果提示Error: no cached repo found. (try 'helm repo update'). open /root/.helm/repository/cache/stable-index.yaml: no such file or directory,尝试更新仓库

1
helm repo update

如果还是失败,更换仓库:

1
2
3
4
5
6
# 先移除原先的仓库
helm repo remove stable
# 添加新的仓库地址
helm repo add stable https://charts.helm.sh/stable/
# 更新仓库
helm repo update

下载到本地之后,解压:

1
2
tar -xzf kubernetes-dashboard-1.8.0.tgz
cd kubernetes-dashboard

image-20220113151008444

和我们自定义的Helm模版目录结构一样。

创建kubernetes-dashboard.yaml内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
image: 
repository: k8s.gcr.io/kubernetes-dashboard-amd64 # 这个镜像如果不能下载,尝试先下载到本地然后上传
tag: v1.10.1
ingress:
enabled: true
hosts:
- k8s.frognew.com
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
tls:
- secretName: frognew-com-tls-secret
hosts:
- k8s.frognew.com
rbac: clusterAdminRole: true

创建这个Release:

1
2
3
4
helm install . \
-n kubernetes-dashboard \ #指定名称
--namespace kube-system \ #指定名称空间
-f kubernetes-dashboard.yaml #指定创建的yaml文件

查看服务:

1
2
3
4
5
kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 46h
kubernetes-dashboard ClusterIP 10.98.252.152 <none> 443/TCP 97s
tiller-deploy ClusterIP 10.110.29.137 <none> 44134/TCP 6h5m

这里将TYPE修改为NodePort方式(Ingress也可以),暴露服务给外界访问:

1
kubectl edit svc kubernetes-dashboard -n kube-system

修改完成后再次查看:

1
2
3
4
5
[root@k8s-master kubernetes-dashboard]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 46h
kubernetes-dashboard NodePort 10.98.252.152 <none> 443:30332/TCP 5m17s
tiller-deploy ClusterIP 10.110.29.137 <none> 44134/TCP 6h9m

端口为30332,我们打开浏览器访问一下https://192.168.142.20:30332/

使用HTTPS,Chrome浏览器可能无法访问。

image-20220113164114295

有以下三种解决方案:

  1. 下载证书sz /etc/kubernetes/pki/ca.crt,将证书导入到浏览器:打开浏览器右上角三个点设置--安全和隐私设置--安全--管理证书点击导入证书。
  2. 在不受信任的页面空白处输入thisisunsafe绕过Chrome证书验证(仅用于学习用途,不要滥用)
  3. 使用其它浏览器(火狐等)

最后你会看到如下页面:

image-20220113165755327

可以通过指定kubeconfig文件访问,也可以通过令牌token的方式访问

查看token:

1
2
3
kubectl -n kube-system get secret | grep kubernetes-dashboard-token

kubernetes-dashboard-token-5bg6x kubernetes.io/service-account-token 3 44m

使用describe查看:

1
2
3
kubectl describe secret kubernetes-dashboard-token-5bg6x -n kube-system

token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZC10b2tlbi01Ymc2eCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjdmM2RjZWQ1LWFlYjEtNGQ0NS1iYWEzLWU4MWRjNGRkYmMwNiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprdWJlcm5ldGVzLWRhc2hib2FyZCJ9.hwmS2AvHQ5mjeIbBYbw95fVvj_IxvJgmQ0YoDjIdrlwhtpzJpaLSTjgC7PoNDOoFfb1_hPqjclcOIwSxv_fI3v4kfQRkA-BuPyMc-_waLZrw1hP_fe9bM9PxnvHSpCWyOZrrOWTum9MKY9SqfcvKUDsS2iaks-ynAJHP7occnr_gMJ8YNMtNDkNdd0Ry1pzRIEJhr-kX-81eJ2DhsjLyVFHHb2o0jkbDDOenJnNmODy5za7d7xOaguPuXCqsH2tu7MUbIoHDF78Sqg19qP4aprJYQO5t26wpA8_RArr5vf_iO64lrGgOZKIwY2uFi0v9iOklkCRY6vYeRBiBU9SIfg

复制token,使用令牌登录

image-20220113171130392

然后就可以在管理页面可视化地创建应用了。

6 Prometheus

6.1 介绍

Prometheus(普罗米修斯)是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目,拥 有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus于2016年加入云原生云计算基金会 (CNCF),成为继Kubernetes之后的第二个托管项目。github官网地址

普罗米修斯的架构图:

1583033650580-62e59385-4b44-458b-be10-53194f608cbc

  • Prometheus Server:收集指标和存储时间序列数据,并提供查询接口
  • ClientLibrary:客户端库
  • Push Gateway:短期存储指标数据。主要用于临时性的任务
  • Exporters:采集已有的第三方服务监控指标并暴露metrics
  • Alertmanager:告警
  • Web UI:简单的Web控制台,展示功能较弱一般用来调试监控函数PromSQL,一般用grafana替代展示
  • TSDB:时序数据库,用来存储监控数据。

普罗米修斯的监控内容:

1583036137103-0b86489d-ff0d-4362-9ed3-bea8cf3a8206

监控指标具体实现举例
Pod性能cAdvisor容器CPU,内存利用率
Node性能node-exporter节点CPU,内存利用率
K8S资源对象kube-state-metricsPod/Deployment/Service

6.2 部署Prometheus

接下来开始构建:

1
2
3
mkdir prometheus && cd prometheus
git clone https://github.com/coreos/kube-prometheus.git
cd kube-prometheus/manifests

修改grafana-service.yaml文件,使用NodePort方式访问grafana(修改原因是集群IP的方式无法暴露给外部):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vim grafana-service.yaml

apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: monitoring
spec:
type: NodePort #添加内容
ports:
- name: http
port: 3000
targetPort: http
nodePort: 30100 #添加内容
selector:
app: grafana

修改prometheus-service.yaml,改为NodePort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vim prometheus-service.yaml

apiVersion: v1
kind: Service
metadata:
labels:
prometheus: k8s
name: prometheus-k8s
namespace: monitoring
spec:
type: NodePort #添加内容
ports:
- name: web
port: 9090
targetPort: web
nodePort: 30200 #添加内容
selector:
app: prometheus
prometheus: k8s

修改alertmanager-service.yaml,改为NodePort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vim alertmanager-service.yaml 

apiVersion: v1
kind: Service
metadata:
labels:
alertmanager: main
name: alertmanager-main
namespace: monitoring
spec:
type: NodePort #添加内容
ports:
- name: web
port: 9093
targetPort: web
nodePort: 30300 #添加内容
selector:
alertmanager: main
app: alertmanager

开始部署:

1
kubectl apply -f ../manifests/

创建完成后,就可以查看监控信息了

1
2
kubectl top node
kubectl top pod

Prometheus对应的访问端口为30200,访问 http://192.168.142.20:30200

image-20220114162528364

通过访问 http://192.168.142.20:30200/target 可以看到Prometheus已经成功连接上了 k8s 的API Server

grafana的端口号是30100,浏览器访问 http://192.168.142.20:30100/ 用户名密码默认为admin/admin

image-20220114162757469

7 Horizontal Pod Autoscaling

Horizontal Pod Autoscaling(HPA)可以根据 CPU 利用率自动伸缩Replication Controller、Deployment或者Replica Set 中的 Pod 数量。

构建HPA示例:

1
2
3
kubectl run php-apache --image=gcr.io/google_containers/hpa-example --requests=cpu=200m --expose --port=80

# --requests=cpu=200m:资源限制,初始分配值

创建 HPA 控制器(CPU负载超过50%就扩容,最大扩容数为10,负载小了之后会减小节点数,最少保持1个)

1
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10

增加负载,如果CPU利用率上去了,就会自动扩容增加Pod数量进行减压,最大增加到上面设置的10个上限。

8 部署EFK日志平台

EFK指的是:

  • E:Elasticsearch

  • F:Fluentd

  • K:Kibana

添加 Google incubator 仓库

1
helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator

部署Elasticsearch

1
2
3
4
5
6
7
8
9
10
kubectl create namespace efk  #创建名称空间
helm fetch incubator/elasticsearch #提前下载好镜像
tar -xf elasticsearch-xxx.tgz && cd elasticsearch #如果服务器配置不够,可以修改values.yaml对应的集群节点和PVC设置,生产的也可以不修改

#安装运行
helm install --name els1 --namespace=efk -f values.yaml .

#启动测试
kubectl run cirror-$RANDOM --rm -it --image=cirros -- /bin/sh
curl Elasticsearch:Port/_cat/nodes

部署Fluentd

1
2
3
4
5
6
helm fetch stable/fluentd-elasticsearch 
# 解压进入修改文件
vim values.yaml
# 更改其中 Elasticsearch 访问地址
# 安装运行
helm install --name flu1 --namespace=efk -f values.yaml . 

部署Kibana

部署EFK时,E和K的版本必须一致,否则会报错。

1
2
3
helm fetch stable/kibana --version 0.14.8 
# 同样需要进入values.yaml中Elasticsearch的访问地址
helm install --name kib1 --namespace=efk -f values.yaml . --version 0.14.8

修改svc访问方式为NodePort暴露给外部访问

1
2
kubectl edit svc kib1-kibana -n efk
type: NodePort

访问测试:

image-20220114164037551