在Kubernetes中部署容器云的应用也是一项有挑战性的工做,Helm就是为了简化在Kubernetes中安装部署容器云应用的一个客户端工具。经过helm可以帮助开发者定义、安装和升级Kubernetes中的容器云应用,同时,也能够经过helm进行容器云应用的分享。在Kubeapps Hub中提供了包括Redis、MySQL和Jenkins等常见的应用,经过helm可使用一条命令就可以将其部署安装在本身的Kubernetes集群中。node
Helm是一个用于kubernetes的包管理器。每一个包称为一个Chart,一个Chart是一个目录(通常状况下会将目录进行打包压缩,造成name-version.tgz格式的单一文件,方便传输和存储)。咱们能够将Helm看做Kubernetes下的apt-get/yum。mysql
对于应用发布者而言,能够经过Helm打包应用,管理应用依赖关系,管理应用版本并发布应用到软件仓库。linux
Helm组件及相关术语nginx
1)Helm Helm是一个命令行下的客户端工具。主要用于Kubernetes应用程序Chart的建立、打包、发布及建立和管理 本地和远程的Chart仓库。 2)Tiller Tiller是Helm的服务端,部署在Kubernetes集群中,Tiller用于接收Helm的请求,并根据Chart生成Kubernete s的部署文件,而后提交给Kubernetes建立应用,Tiller还提供和了Release的升级、删除、回滚等一系列功能。 3)Chart Chart是一个Helm的程序包,包含了运行一个Kubernetes应用程序所需的镜像、依赖关系和资源定义等。 4)Repoistory Repoistory是Helm的软件仓库,Repository本质上是一个Web服务器,该服务器保存了一系列的Chart软件包 以供用户下载,而且提供了该Repository的Chart包的清单文件便于查询。Helm能够同时管理多个不一样的Repository。 5)Release Release是应用程序运行Chart以后,获得的一个实例。
elm架构
helm的总体架构以下图所示,Helm架构由Helm客户端、Tiller服务器端和Chart仓库所组成;Tiller部署在Kubernetes中,Helm客户端从Chart仓库中获取Chart安装包,并将其安装部署到Kubernetes集群中。web
Chart install过程: 1)Helm从指定的目录或者tgz文件中解析出Chart结构信息; 2)Helm将指定的Chart结构和Values信息经过gRPC传递给Tiller; 3)Tiller根据Chart和Values生成一个Release; 4)Tiller将Release发送给Kubernetes用于生成Release; --- Chart update过程: 1)Helm从指定的目录或者tgz文件中解析出Chart结构信息; 2)Helm将要更新的Release的名称和Chart结构、Values信息传递给Tiller; 3)Tiller生成Release并更新指定名称的Release的history; 4)Tiller将Release发送给Kubernetes用于更新Release; --- Chart Rollback过程: 1)Helm将要回滚的Release的名称传递给Tiller; 2)Tiller根据Release的名称查找history; 3)Tiller从history中获取上一个Release; 4)Tiller将上一个Release发送给Kubernetes用于替换当前的Release;
1)安装Helm客户端sql
[root@master ~]# wget https://get.helm.sh/helm-v2.14.3-linux-amd64.tar.gz //从Github上下载Helm软件包 [root@master ~]# tar zxf helm-v2.14.3-linux-amd64.tar.gz [root@master ~]# mv linux-amd64/helm /usr/local/bin/ [root@master ~]# chmod +x /usr/local/bin/helm //获取这个软件包只是为了获取这个helm文件 [root@master ~]# echo 'source <(helm completion bash)' >> /etc/profile [root@master ~]# source /etc/profile //设置helm命令能够自动补全而且写入环境变量文件中
2)安装Tiller server(须要建立受权用户)docker
[root@master ~]# vim tiller-rbac.yaml //编写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 [root@master ~]# kubectl apply -f tiller-rbac.yaml [root@master ~]# helm init --service-account=tiller //Tiller server的环境初始化 //helm的服务端就是Tiller //指定刚才建立的受权用户初始化helm [root@master ~]# kubectl get pod -n kube-system | grep tiller //查看tiller的pod名称 tiller-deploy-8557598fbc-mlr6c 0/1 ContainerCreating 0 6s //编辑pod的yaml文件,将其使用的镜像改成国内阿里云的,默认是Google的镜像,下载不下来 //修改spec字段的image指定的镜像,以下: [root@master ~]# kubectl edit pod -n kube-system tiller-deploy-8557598fbc-mlr6c //修改spec字段的image指定的镜像,以下: image: gcr.io/kubernetes-helm/tiller:v2.14.3 //修改后以下: image: registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.14.3 //修改后,保存退出便可,它会去自动下载新镜像(若是没有自动下载,就想办法吧,好比说在tiller容器所在的节点手动下载下来镜像,而后重启该节点的kubelet,或重启该容器) [root@master ~]# kubectl get pod -n kube-system | grep tiller //必须保证tiller的Pod正常运行 tiller-deploy-8557598fbc-mlr6c 1/1 Running 0 5m16s
注:避免出错附加一张图片以下:数据库
3)配置Helm仓库apache
[root@master ~]# helm repo list //查看仓库的详细信息 NAME URL stable https://kubernetes-charts.storage.googleapis.com //默认是Google,在国外,速度特别慢 local http://127.0.0.1:8879/charts [root@master ~]# helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts //更改成国内阿里云的地址 [root@master ~]# helm repo list //再次查看仓库的详细信息,能够发现地址已经换成了阿里云的仓库地址 NAME URL stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts local http://127.0.0.1:8879/charts [root@master ~]# helm repo update //更新一下helm仓库 [root@master ~]# helm version //查看helm版本信息 Client: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"} //必须保证能够查看出来client和server,才可正常使用helm
注:就此Helm就已经表示部署成功,能够正常使用!vim
建立Storage Class
1)部署nfs
[root@master ~]# yum -y install nfs-utils rpcbind [root@master ~]# mkdir /nfsdata [root@master ~]# echo "/nfsdata *(rw,no_root_squash,sync)" > /etc/exports [root@master ~]# systemctl start nfs-server && systemctl start rpcbind [root@master ~]# showmount -e Export list for master: /nfsdata *
2)建立rbac受权
[root@master ~]# vim rbac-rolebind.yaml //编辑yaml文件 apiVersion: v1 //建立一个用于认证的服务帐号 kind: ServiceAccount metadata: name: nfs-provisioner --- apiVersion: rbac.authorization.k8s.io/v1 //建立群集规则 kind: ClusterRole metadata: name: nfs-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["watch", "create", "update", "patch"] - apiGroups: [""] resources: ["services", "endpoints"] verbs: ["get","create","list", "watch","update"] - apiGroups: ["extensions"] resources: ["podsecuritypolicies"] resourceNames: ["nfs-provisioner"] verbs: ["use"] --- kind: ClusterRoleBinding //将服务认证用户与群集规则进行绑定 apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-provisioner subjects: - kind: ServiceAccount name: nfs-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-provisioner-runner apiGroup: rbac.authorization.k8s.io [root@master ~]# kubectl apply -f rbac-rolebind.yaml //执行yaml文件
3)建立nfs-deployment.资源
[root@master ~]# vim nfs-deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nfs-client-provisioner spec: replicas: 1 //指定副本数量为1 strategy: type: Recreate //指定策略类型为重置 template: metadata: labels: app: nfs-client-provisioner spec: serviceAccount: nfs-provisioner //指定rbac yaml文件中建立的认证用户帐号 containers: - name: nfs-client-provisioner image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner //使用的镜像 volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes //指定容器内挂载的目录 env: - name: PROVISIONER_NAME //容器内的变量用于指定提供存储的名称 value: bjq-test - name: NFS_SERVER //容器内的变量用于指定nfs服务的IP地址 value: 192.168.45.129 - name: NFS_PATH //容器内的变量指定nfs服务器对应的目录 value: /nfsdata volumes: //指定挂载到容器内的nfs的路径及IP - name: nfs-client-root nfs: server: 192.168.45.129 path: /nfsdata //编辑完成保存退出便可 [root@master ~]# kubectl apply -f nfs-deployment.yaml //执行yaml文件 [root@master ~]# kubectl get pod | grep nfs //确认pod是否正常运行 nfs-client-provisioner-8844fb875-prjhq 1/1 Running 0 14s
4)建立Storage Class
[root@master ~]# vim storage-class.yaml //编辑yaml文件 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: stateful-nfs provisioner: bjq-test //这个要和nfs-client-provisioner的env环境变量中的PROVISIONER_NAME的value值对应。 reclaimPolicy: Retain //指定回收策略为Retain(手动释放) [root@master ~]# kubectl apply -f storage-class.yaml //执行yaml文件 [root@master ~]# kubectl get sc //确认Storage Class建立成功 NAME PROVISIONER AGE stateful-nfs bjq-test 8s
5)helm部署mysql
[root@master ~]# helm fetch stable/mysql //将mysql的软件包下载到本地 [root@master ~]# tar zxf mysql-0.3.5.tgz [root@master ~]# vim mysql/values.yaml +55 storageClass: "stateful-nfs" //去除注释,并指定刚才建立的Storage Class名称 [root@master ~]# vim mysql/values.yaml +79 type: NodePort //默认是ClusterIP,可更改成NodePort [root@master ~]# helm install stable/mysql -f mysql/values.yaml --set mysqlRootPassword=123.com -n test-mysql //若是修改了values.yaml文件的数据,建立时应该指定values.yaml文件 //安装mysql,并设置mysql的root密码为123.com,-n表示指定名称 root@master ~]# helm list //查看已安装的软件包 NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE test-mysql 1 Tue Sep 1 13:26:01 2020 DEPLOYED mysql-0.3.5 default
避免出错附加一张图片:
[root@master ~]# kubectl get svc | grep test-mysql //确认service类型 test-mysql-mysql NodePort 10.98.129.4 <none> 3306:30083/TCP 4m56s [root@master ~]# kubectl get pv,pvc //查看PV、PVC是否绑定成功 NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/pvc-4ebb3a43-b192-4e2d-884a-2b75308f63dd 8Gi RWO Delete Bound default/test-mysql-mysql stateful-nfs 5m5s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/test-mysql-mysql Bound pvc-4ebb3a43-b192-4e2d-884a-2b75308f63dd 8Gi RWO stateful-nfs 5m5s [root@master ~]# kubectl exec -it test-mysql-mysql-dfb9b6944-q7tcd -- mysql -u root -p123.com //登陆到刚才建立的mysql数据库中 mysql>
6)使用helm对mysql进行升级操做
[root@master ~]# kubectl describe pod test-mysql-mysql-dfb9b6944-q7tcd //查看pod的详细信息如下能够看出,该pod所用镜像为mysql:5.7.14 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 8m57s (x2 over 8m57s) default-scheduler pod has unbound immediate PersistentVolumeClaims (repeated 2 times) Normal Scheduled 8m56s default-scheduler Successfully assigned default/test-mysql-mysql-dfb9b6944-q7tcd to node02 Normal Pulling 8m55s kubelet, node02 Pulling image "busybox:1.25.0" Normal Pulled 8m46s kubelet, node02 Successfully pulled image "busybox:1.25.0" Normal Created 8m46s kubelet, node02 Created container remove-lost-found Normal Started 8m46s kubelet, node02 Started container remove-lost-found Normal Pulling 8m46s kubelet, node02 Pulling image "mysql:5.7.14" Normal Pulled 8m24s kubelet, node02 Successfully pulled image "mysql:5.7.14" Normal Created 8m24s kubelet, node02 Created container test-mysql-mysql Normal Started 8m24s kubelet, node02 Started container test-mysql-mysql [root@master ~]# kubectl get pod | grep test-mysql //注意升级以后,pod名称会发生变化 test-mysql-mysql-54c7bfdd77-8jlpj 1/1 Running 0 2m54s [root@master ~]# kubectl describe pod test-mysql-mysql-54c7bfdd77-8jlpj //再次查看pod详细信息,能够看出,镜像升级为mysql:5.7.15 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 4m1s default-scheduler Successfully assigned default/test-mysql-mysql-54c7bfdd77-8jlpj to node01 Normal Pulling 4m1s kubelet, node01 Pulling image "busybox:1.25.0" Normal Pulled 3m50s kubelet, node01 Successfully pulled image "busybox:1.25.0" Normal Created 3m50s kubelet, node01 Created container remove-lost-found Normal Started 3m50s kubelet, node01 Started container remove-lost-found Normal Pulling 3m50s kubelet, node01 Pulling image "mysql:5.7.15" Normal Pulled 3m25s kubelet, node01 Successfully pulled image "mysql:5.7.15" Normal Created 3m25s kubelet, node01 Created container test-mysql-mysql Normal Started 3m25s kubelet, node01 Started container test-mysql-mysql
7)使用helm对mysql进行回滚操做
[root@master ~]# helm list //再次查看实例,能够发现“REVISION”字段为2,而初次建立实例时,该列为1,只要对该实例进行升级回滚一次,数值便会加1 NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE test-mysql 2 Tue Sep 1 13:37:45 2020 DEPLOYED mysql-0.3.5 default [root@master ~]# helm history test-mysql //查看该实例的历史版本 REVISION UPDATED STATUS CHART DESCRIPTION 1 Tue Sep 1 13:26:01 2020 SUPERSEDED mysql-0.3.5 Install complete 2 Tue Sep 1 13:37:45 2020 DEPLOYED mysql-0.3.5 Upgrade complete [root@master ~]# helm rollback test-mysql 1 //将该实例回滚到版本1 [root@master ~]# helm list //再次查看,能够看到“REVISION”的值变成了3 NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE test-mysql 3 Tue Sep 1 13:55:57 2020 DEPLOYED mysql-0.3.5 default [root@master ~]# kubectl get pod | grep test-mysql //确认pod是正常状态 test-mysql-mysql-dfb9b6944-fd6l9 1/1 Running 0 67s [root@master ~]# kubectl describe pod test-mysql-mysql-dfb9b6944-fd6l9 //查看pod的详细信息,能够看出,该pod使用的镜像已经回滚到mysql:5.7.14版本 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m4s default-scheduler Successfully assigned default/test-mysql-mysql-dfb9b6944-fd6l9 to node02 Normal Pulled 2m3s kubelet, node02 Container image "busybox:1.25.0" already present on machine Normal Created 2m3s kubelet, node02 Created container remove-lost-found Normal Started 2m3s kubelet, node02 Started container remove-lost-found Normal Pulled 2m1s kubelet, node02 Container image "mysql:5.7.14" already present on machine Normal Created 2m1s kubelet, node02 Created container test-mysql-mysql Normal Started 2m1s kubelet, node02 Started container test-mysql-mysql
1)node01节点运行web容器做为私有仓库
[root@node01 ~]# mkdir -p /var/www/charts //建立目录,用于存放charts包 [root@node01 ~]# docker run -d -p 8080:80 -v /var/www:/usr/local/apache2/htdocs httpd
2)master节点上,建立chart包并打包
[root@master ~]# helm create testchart //建立chart包(生成的是目录),名称为testchart [root@master ~]# helm package testchart //将刚才生成的目录进行打包,会在当前目录下生成名为testchart-0.1.0.tgz的包
3)master节点生成仓库的index文件
[root@master ~]# mkdir myrepo [root@master ~]# mv testchart-0.1.0.tgz myrepo/ //建立用于存放chart包的目录,并将chart包移动到该目录 [root@master ~]# helm repo index myrepo/ --url http://192.168.45.141:8080/charts //url路径表示运行web容器的节点IP+端口,也就是指定的是node01节点 [root@master ~]# ls myrepo/ index.yaml testchart-0.1.0.tgz //确认已经生成index.yaml文件 [root@master ~]# scp myrepo/* node01:/var/www/charts //将生成的index.yaml文件及charts包复制到web容器所在节点映射的本地目录
4)将新repo仓库添加到helm
[root@master ~]# helm repo add newrepo http://192.168.45.141:8080/charts //url是web容器所在的节点的IP+端口+存放chart包的目录,并指定仓库的名称为newrepo [root@master ~]# helm repo list NAME URL stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts local http://127.0.0.1:8879/charts newrepo http://192.168.45.141:8080/charts //stable是刚建立helm添加的阿里云的仓库 //local是本地的缓存 //newrepo是刚刚添加的仓库名称(确认该仓库已经存在)
注:配置至此,已经能够正常供内网环境使用这个charts包的私有仓库了,下面是一些验证。
5)搜索可用的chart包并部署
[root@master ~]# helm search testchart NAME CHART VERSION APP VERSION DESCRIPTION local/testchart 0.1.0 1.0 A Helm chart for Kubernetes newrepo/testchart 0.1.0 1.0 A Helm chart for Kubernetes //local是本地的缓存,不用理会,能够查看到newrepo提供的testchart包 [root@master ~]# helm install newrepo/testchart -n test-nginx //既然能够搜索到就表示可使用chart包建立实例 [root@master ~]# kubectl get pod | grep test-nginx //确认pod运行成功 test-nginx-testchart-64d8585997-jxtv7 1/1 Running 0 33s [root@master ~]# kubectl describe pod test-nginx-testchart-64d8585997-jxtv7 //查看这个pod的详细信息,并确认pod所使用的镜像 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m28s default-scheduler Successfully assigned default/test-nginx-testchart-64d8585997-jxtv7 to node01 Normal Pulling 2m28s kubelet, node01 Pulling image "nginx:stable" Normal Pulled 2m10s kubelet, node01 Successfully pulled image "nginx:stable" Normal Created 2m10s kubelet, node01 Created container testchart Normal Started 2m9s kubelet, node01 Started container testchart
6)更新chart包中所运行服务的镜像
其实就是一个服务版本升级的操做,大概思路以下:修改解压后的charts包目录下的values.yaml文件为所需的值(values.yaml文件包含的是这个服务的值,能够在里面指定镜像及标签、数据持久化的类型等等),修改完成后,再使用下面的命令进行升级操做。
[root@master ~]# helm upgrade -f testchart/values.yaml test-nginx newrepo/testchart //my-nginx是以前实例的名称,能够经过“helm list”查看实例名称 //newrepo/testchart :为自定义仓库中的chart包 [root@master ~]# kubectl describe pod test-nginx-testchart-6d6984ddd9-gn9sw //确认pod所使用的镜像已经更新
注:若是使用命令的方式直接进行升级,命令执行完成不会报错,可是镜像并不会更新,推荐使用更改values.yaml的方式进行升级!
7)再次向newrepo仓库上传chart包
[root@master ~]# helm create mychart [root@master ~]# helm package mychart/ [root@master ~]# mv mychart-0.1.0.tgz myrepo/ [root@master ~]# helm repo index myrepo/ --url http://192.168.45.141:8080/charts //当有新的chart包时,需更新index.yaml文件 [root@master ~]# scp myrepo/* node01:/var/www/charts [root@master ~]# helm repo update //若是须要使用则需更新一下本地的仓库 [root@master ~]# helm search mychart NAME CHART VERSION APP VERSION DESCRIPTION local/mychart 0.1.0 1.0 A Helm chart for Kubernetes newrepo/mychart 0.1.0 1.0 A Helm chart for Kubernetes //确保新添加的chart包能够被搜索到
[root@master ~]# helm version //查看helm版本信息 [root@master ~]# helm list /查看当前安装的Chart包 [root@master ~]# helm search mysql //查看与mysql相关的chart包 [root@master ~]# helm fetch stable/mysql //将mysql软件包下载到本地 [root@master ~]# helm inspect stable/mysql //查看该软件包的详细信息 [root@master ~]# helm install stable/mysql -n mysql //安装指定的mysql软件包,并命名为mysql [root@master ~]# helm status mysql //查看mysql的状态信息 [root@master ~]# helm delete --purge mysql //删除mysql,并将本地的缓存也进行删除 [root@master ~]# helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts //添加阿里云的repo源 [root@master ~]# helm repo update //更新repo仓库资源 [root@master ~]# helm create helm_charts //建立一个chart,名称为helm_charts [root@master ~]# cd helm_charts/ && helm lint //测试charts语法 [root@master ~]# helm package helm_charts //打包charts [root@master helm_charts]# helm template helm_charts-0.1.0.tgz //查看该软件包生成的yaml文件