什么是Helm
在没使用 helm 之前,向kubernetes 部署应用,我们要依次部署 deployment、svc等,步骤较繁琐。况且随着项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm通过打包的方式,支持发布的版本管理和控制,很大程度上简化了kubernetes应用的部署和管理
Helm 本质上就是让 k8s 的应用管理(Deployment,SVC等)可配置,能动态生成。通过动态生成k8s资源清单文件(deployment.yaml,service.yaml)。然后调用 kuberctl 自动执行k8s资源部署
Helm 是官方提供的类似与 YUM 的包管理器,是部署环境的流程封装。Helm 有两个重要的概念: chart 和 release
- chart 是创建一个应用的信息集合,包括各种kubernetes对象的配置模板、参数定义、依赖关系、文档说明等。chart是应用部署的自包含逻辑单元。可以将chart想象成apt、yum中的软件安装包
- release 是chart的运行实例,代表了一个正在运行的应用。当chart被安装到kubernetes集群,就生成一个release。chart能够多次安装到同一个集群,每次安装都是一个release
Helm是包管理工具,这里的包就是指的 chart。Helm 能够:
- 从零创建新 chart
- 与存储chart的仓库交互,拉取、保存和更新chart
- 在kubernetes 集群中安装和卸载 release
- 更新、回滚和测试release
Helm架构
Helm 包含两个组件:Helm客户端和Tiller服务器,如下图:
Helm 客户端是终端用户使用的命令行工具,用户可以:
- 在本地开发chart
- 管理chart仓库
- 与 Tiller 服务器交互
- 在远程 kubernetes 集群上安装 chart
- 查看 release 信息
- 升级或卸载已有的release
Tiller 服务器运行在 kubernetes 集群中,它会处理 Helm 客户端的请求,与 kubernetes API Server交互。Tiller 服务器负责:
- 监听来自 Helm 客户端的请求
- 通过chart 构建 release
- 在 kubernetes 中安装 chart,并跟踪 release 的状态
- 通过 API Server升级或卸载已有的release
安装 Helm
本节我们将依次安装Helm 客户端和 Tiller 服务器
Helm 客户端
越来越多的公司和团队开始使用Helm这个Kubernetes的包管理器,我们也将使用Helm安装kubernetes的常用组件。helm由客户端命令行工具和服务端tiller组成,Helm的安装十分简单。下载helm命令行工具到master 节点即k8s-master 的/usr/local/bin/下,这里下载的2.13.1版本:
ntpdate ntp1.aliyun.com
wget https://storage.googleapis.com/kubernetes-helm/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
为了安装服务端tiller,还需要在这台机器上配置好kubectl 工具和kubeconfig文件,确保kubectl工具可以在这台机器上访问apiserver且正常使用。这里的k8s-master节点是已经配置好了kubectl这个工具
因为kubernetes APIServer 开启了RBAC访问控制,所以需要创建tiller 使用的service account: tiller并分配合适的角色给它。详细内容可以查看helm文档中的Role-based Access Control。这里简单起见直接分配cluster-admin这个集群内置的ClusterRole给它。创建 rbac-config.yaml文件:
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
kubectl create -f rbac-config.yaml
helm init --service-account tiller --skip-refresh
tiller 默认被部署在k8s集群中的kube-system 这个namespace下
[root@k8s-master helm]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 14d
tiller-deploy ClusterIP 10.102.235.237 44134/TCP 81s
[root@k8s-master helm]# kubectl get deployment -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 14d
tiller-deploy 1/1 1 1 55s
[root@k8s-master helm]# kubectl get rs -n kube-system
NAME DESIRED CURRENT READY AGE
coredns-5c98db65d4 2 2 2 14d
tiller-deploy-58565b5464 1 1 1 112s
[root@k8s-master helm]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5c98db65d4-pxl78 1/1 Running 0 14d
coredns-5c98db65d4-vdtsr 1/1 Running 0 14d
etcd-k8s-master 1/1 Running 0 14d
kube-apiserver-k8s-master 1/1 Running 0 14d
kube-controller-manager-k8s-master 1/1 Running 0 14d
kube-flannel-ds-amd64-852cl 1/1 Running 0 14d
kube-flannel-ds-amd64-p5h64 1/1 Running 0 14d
kube-flannel-ds-amd64-rglvq 1/1 Running 0 12d
kube-proxy-6sp4j 1/1 Running 0 14d
kube-proxy-hbnkf 1/1 Running 0 12d
kube-proxy-ttjcn 1/1 Running 0 14d
kube-scheduler-k8s-master 1/1 Running 0 14d
tiller-deploy-58565b5464-8vrfb 1/1 Running 0 65s
[root@k8s-master helm]# helm version
Client: &version.Version{SemVer:"v2.13.1", GitCommit:"618447cbf203d147601b4b9bd7f8c37a5d39fbb4", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.13.1", GitCommit:"618447cbf203d147601b4b9bd7f8c37a5d39fbb4", GitTreeState:"clean"}
Helm 自定义模板
# 创建文件夹
$ mkdir ./hello-world
$ cd ./hello-world
# 创建自描述文件 Chart.yaml ,这个文件必须有 name 和 version 定义
$ cat << 'EOF' >./Chart.yaml
name: hello-world
version: 1.0.0
EOF
# 创建模板文件,用于生成kubernetes 资源清单 (manifests)
$ mkdir ./templates
$ 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: harbor.bwingame8.com/library/myapp:v1
ports:
- containerPort: 80
protocol: TCP
EOF
$ cat << 'EOF' > ./templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-world
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: hello-world
EOF
# 使用命令 helm install RELATIVE_PATH_TO_CHART 创建一次Release
$ helm install .
# 列出已经部署的 Release
$ helm ls
# 查询一个特定的 Release 的状态
$ helm status RELEASE_NAME
# 移除所有与这个 Release 相关的 kubernetes 资源
$ helm delete cautious-shrimp
# 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 ls --deleted
# 配置体现在配置文件 values.yaml
$ cat << 'EOF' > ./values.yaml
image:
repository: harbor.bwingame8.com/library/myapp
tag: 'v3'
EOF
# 这个文件中定义的值,在模板文件中可以通过 .Values对象访问到
$ 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.images.repository }}:{{ .Values.image.tag }}
ports:
- containerPort: 80
protocol: TCP
EOF
# 在 values.yaml 中的值可以被部署 release 时用到的参数 --values YAML_FILE_PATH 或 --set key1=value1, key2=value2 覆盖掉
$ helm install --set image.tag='latest' .
# 升级版本
helm upgrade -f values.yaml test .
Debug
# 使用模板动态生成 k8s 资源清单,非常需要能提前预览生成的结果
# 使用 --dry-run --debug 选项来打印出生成的清单文件内容,而不执行部署
helm install . --dry-run --debug --set image.tag=latest