简介
Helm is the best way to find,share,and use software built for Kubernetes.
Helm号称 构建k8s运行的软件 最好的一种途径和方式,实际上Helm是一个软件管理服务,通过Helm Charts的方式帮助我们定义,安装和升级 即使很复杂的 k8s 应用和软件。
有点类似于 Ubuntu 中使用的apt、Centos中使用的yum 或者Python中的 pip 。
Helm是经过CNCF认证的软件服务,目前由Helm社区进行维护。
Cloud Native Computing Foundation,云原生计算基金会(以下简称CNCF)是一个开源软件基金会,它致力于云原生(Cloud Native)技术的普及和可持续发展
相关概念
Helm Charts
资源和软件的定义文件,Charts文件里 需要 声明式的 指定 我们需要哪些软件,版本 以及需要发布的内容,它描述了一组相关的 k8s 集群资源。
Helm release
使用 helm install 命令在 Kubernetes 集群中部署的 Chart 称为 Release
Helm 包含两个组件,分别是 helm 客户端 和 Tiller 服务器:
Helm 客户端(helm命令行工具)
helm 是一个命令行工具,用于本地开发及管理chart,chart仓库管理等
Helm的服务端–Tiller
Tiller 是 Helm 的服务端。Tiller 负责接收 Helm 的请求,与 k8s 的 apiserver 交互,根据chart 来生成一个 release 并管理 release
Helm Repoistory
Helm charts 的仓库,Helm 客户端通过 HTTP 协议来访问存储库中 chart 的索引文件和压缩包
Helm体系里也有可以查询公开的Charts的模板的地方,例如:Helm Hub,比如我们需要安装一个Jupyter,那么我们不需要完全重头自己写一个Chart,可以先查看 公开库里有没有已经写好的,别人公开的模板来微调使用。
适用场景
1、需要把使用的软件更透明化,大家通过定义的Charts文件就能了解软件的情况,而不是一个人黑箱操作安装后 其他人并不清楚其中定义和关键
2、期望 比较高的可移植性,如果我们有一份软件应用在k8s集群1中运行,现在需要把这些应用 移植到k8s集群2中,那我们只需要 再运行一次 Charts文件即可,而不需要 复杂的一步步的细节操作安装配置。
3、需要使用的软件应用多而且零散,期望统一管理:比如你安装一个 WordPress 博客,用到了一些 Kubernetes (下面全部简称k8s)的一些资源对象,包括 Deployment 用于部署应用、Service 提供服务发现、Secret 配置 WordPress 的用户名和密码,可能还需要 pv 和 pvc 来提供持久化服务。并且 WordPress 数据是存储在mariadb里面的,所以需要 mariadb 启动就绪后才能启动 WordPress。这些 k8s 资源过于分散,不方便进行管理,直接通过 kubectl 来管理一个应用,你会发现这十分蛋疼。
原理
下面两张图描述了 Helm 的几个关键组件 Helm(客户端)、Tiller(服务器)、Repository(Chart 软件仓库)、Chart(软件包)之间的关系以及它们之间如何通信
创建release
helm 客户端从指定的目录或本地tar文件或远程repo仓库解析出chart的结构信息
helm 客户端指定的 chart 结构和 values 信息通过 gRPC 传递给 Tiller
Tiller 服务端根据 chart 和 values 生成一个 release
Tiller 将install release请求直接传递给 kube-apiserver
删除release
helm 客户端从指定的目录或本地tar文件或远程repo仓库解析出chart的结构信息
helm 客户端指定的 chart 结构和 values 信息通过 gRPC 传递给 Tiller
Tiller 服务端根据 chart 和 values 生成一个 release
Tiller 将delete release请求直接传递给 kube-apiserver
更新release
helm 客户端将需要更新的 chart 的 release 名称 chart 结构和 value 信息传给 Tiller
Tiller 将收到的信息生成新的 release,并同时更新这个 release 的 history
Tiller 将新的 release 传递给 kube-apiserver 进行更新
Chart的基本结构
上文已经说过 Chart是 资源和软件的定义文件,Charts文件里 需要 声明式的 指定 我们需要哪些软件,版本 以及需要发布的内容,它描述了一组相关的 k8s 集群资源。
简单的chart结构如下:
$ helm create hello-helm
Creating hello-helm
$ tree hello-helm
hello-helm
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── ingress.yaml
│ ├── NOTES.txt
│ └── service.yaml
└── values.yaml
2 directories, 7 files
charts
存放子Chart (Subchart) 的定义,Subchart 指的是当前 Chart 依赖的 Chart , 在 requirements.yaml 中定义
Chart.yaml
包含 Chart 信息的 YAML 文件, 包括 Chart 的版本、名称等,在 DCE Helm 插件中还包含 Chart 的 团队授权 信息 和 是否公开 的信息
README.md
可选:Chart 的介绍信息等(该文件对于一个大型 Chart 来说十分重要)
Requirements.yaml 可选:列举当前 Chart 的需要依赖的 Chart
templates
该目录下存放 Chart 所有的 K8s 资源定义模板,通常不同的资源放在不同的文件中
在templates目录中有可以看到deployment.yaml、ingress.yaml、service.yaml文件这些为定义Kubernetes deployment、ingress、service对象的模板文件
_helpers.tpl
模板助手文件,通常这个文件存放可重用的模板片段,该文件中定义的值 可以在 Chart 其它资源定义模板中使用
NOTES.txt
可选:一段简短使用说明的文本文件,用于安装 Release 后提示用户使用
values.yaml
当前 Chart 的默认配置的值
复杂的chart结构则会定义多个依赖的服务如下:
[root@k8s-master mychart]# tree mychart/
mychart # Chart的名字,也就是目录的名字
├── charts # Chart所依赖的子Chart
│ ├── jenkins-0.14.0.tgz # 被“mychart”依赖的其中一个subChart
│ ├── mysubchart # 被“mychart”依赖的另一个subChart
│ │ ├── charts
│ │ ├── Chart.yaml
│ │ ├── templates
│ │ │ └── configmap.yaml
│ │ └── values.yaml
│ └── redis-1.1.17.tgz
├── Chart.yaml # 记录关于该Chart的描述信息:比如名称、版本等等
├── config1.toml # 其他文件:可以是任何文件
├── config2.toml # 其他文件:可以是任何文件
├── requirements.yaml # 记录该Chart的依赖,类似pom.xml
├── templates # 存放模版文件,模板也就是将k8s的yml文件参数化,最终还是会被helm处理成k8s的正常yml文件,然后用来部署对应的资源
│ ├── configmap.yaml # 一个ConfigMap资源模版
│ ├── _helpers.tpl # "_"开头的文件不会本部署到k8s上,可以用于定于通用信息,在其他地方应用,如loables
│ └── NOTES.txt # 在执行helm instll安装此Chart之后会被输出到屏幕的一些自定义信息
└── values.yaml # 参数定义文件,这里定义的参数最终会应用到模版中
Charts可以是目录,也可以是tgz格式的压缩包。
Charts目录和requirements.yaml文件到区别就和lib和pom.xml的区别类似,一个用于存放,一个用于描述
安装客户端Helm
二进制包手动安装
或者在第三方仓库中查找 https://storage.googleapis.com/kubernetes-helm
github的release中查找 https://github.com/kubernetes/helm/releases
$ 下载 Helm 二进制文件
$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.3-linux-amd64.tar.gz
$ 解压缩
$ tar -zxvf helm-v2.14.3-linux-amd64.tar.gz
$ 复制 helm 二进制 到bin目录下
$cp linux-amd64/helm /usr/local/bin/
注意选择合适的平台版本,否则可能遇到/usr/local/bin/helm: cannot execute binary file的问题
比如 mac系统需要使用的链接是 https://get.helm.sh/helm-v2.14.3-darwin-amd64.tar.gz
相关平台的链接可以参考 官网
使用官方提供的脚本一键安装—推荐
默认是获取master分支的代码进行安装,所以该脚本安装的是最新版本的helm,如果需要指定版本,建议使用二进制手动安装
$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh
注:因为该地址需要科学上网,可以直接复制文末的附录get_helm.sh的内容 自己新建一个脚本使用命令
vi get_helm.sh
输入附录的内容
保存退出
安装成功输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ vi get_helm.sh
zhangxiaofans-MacBook-Pro:helm joe$
zhangxiaofans-MacBook-Pro:helm joe$
zhangxiaofans-MacBook-Pro:helm joe$
zhangxiaofans-MacBook-Pro:helm joe$
zhangxiaofans-MacBook-Pro:helm joe$ chmod 700 get_helm.sh
zhangxiaofans-MacBook-Pro:helm joe$ ./get_helm.sh
Helm v2.16.9 is available. Changing from version v2.11.0.
Downloading https://get.helm.sh/helm-v2.16.9-darwin-amd64.tar.gz
Preparing to install helm and tiller into /usr/local/bin
Password:
helm installed into /usr/local/bin/helm
tiller installed into /usr/local/bin/tiller
Run 'helm init' to configure helm.
zhangxiaofans-MacBook-Pro:helm joe$
其他方式安装
Homebrew 用户使用 brew install kubernetes-helm.
Chocolatey 用户使用 choco install kubernetes-helm.
Scoop 用户使用 scoop install helm.
GoFish 用户使用 gofish install helm.
Snap 用户使用 sudo snap install helm --classic.
更多安装方式可参考官网安装教程
安装服务端Tiller
Tiller 是以 Deployment 方式部署在 Kubernetes 集群中的,只需使用以下指令便可简单的完成安装。
安装好 helm 客户端后,就可以通过以下命令将 Tiller 安装在 kubernetes 集群中:
helm init
直接使用这个命令进行初始化时默认使用 https://kubernetes-charts.storage.googleapis.com 作为缺省的 stable repository 的地址,但由于国内有一张无形的墙的存在,googleapis.com 是不能访问的。可以使用阿里云的源来配置:
helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.9 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
版本需要与自己的对应
Helm 服务端正常安装完成后,Tiller默认被部署在kubernetes集群的kube-system命名空间下:
使用命令 查看 tiller 的安装运行情况
kubectl get pod -n kube-system -l app=helm
输出如下
zhangxiaofans-MacBook-Pro:helm joe$ kubectl get pod -n kube-system -l app=helm
NAME READY STATUS RESTARTS AGE
tiller-deploy-688bbd554f-86dwq 1/1 Running 0 1d
可能遇到的问题–socat not found-Error: cannot connect to Tiller
具体报错如下:
E0125 14:03:19.093131 56246 portforward.go:331] an error occurred forwarding 55943 -> 44134: error forwarding port 44134 to pod d01941068c9dfea1c9e46127578994d1cf8bc34c971ff109dc6faa4c05043a6e, uid : unable to do port forwarding: socat not found.
2020/07/25 14:03:19 (0xc420476278) (0xc4203ae1e0) Stream removed, broadcasting: 3
2020/07/25 14:03:19 (0xc4203ae150) (3) Writing data frame
2020/07/25 14:03:19 (0xc420476250) (0xc4200c3900) Create stream
2020/07/25 14:03:19 (0xc420476250) (0xc4200c3900) Stream added, broadcasting: 5
Error: cannot connect to Tiller
原因 是缺少socat组件
解决方法:
在k8s的每一个节点上都需要安装socat
参考命令
sudo yum install -y socat
权限调整
这一步非常重要,不然后面在使用 Helm 的过程中可能出现Error: no available release name found的错误信息。
由于 kubernetes 从1.6 版本开始加入了 RBAC 授权。当前的 Tiller 没有定义用于授权的 ServiceAccount, 访问 API Server 时会被拒绝,需要给 Tiller 加入授权。
创建 Kubernetes 的服务帐号和绑定角色
使用命令
$ kubectl create serviceaccount --namespace kube-system tiller
和
$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
输出如下:
$ kubectl create serviceaccount --namespace kube-system tiller
serviceaccount "tiller" created
$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
clusterrolebinding.rbac.authorization.k8s.io "tiller-cluster-rule" created
给 Tiller 的 deployments 添加刚才创建的 ServiceAccount
使用命令:
$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
输出如下:
# 给 Tiller 的 deployments 添加刚才创建的 ServiceAccount
$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
deployment.extensions "tiller-deploy" patched
查看 Tiller deployments 资源是否绑定 ServiceAccount
使用命令
$ kubectl get deploy -n kube-system tiller-deploy -o yaml | grep serviceAccount
输出如下:
$ kubectl get deploy -n kube-system tiller-deploy -o yaml | grep serviceAccount
serviceAccount: tiller
serviceAccountName: tiller
检查是否安装成功
使用命令:
$ helm version
输出如下:
$ helm version
Client: &version.Version{SemVer:"v2.16.9", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.16.9", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
安装成功后,即可使用 helm install xxx 来安装 helm 应用。
卸载服务端Tiller
如果你需要在 Kubernetes 中卸载已部署的 Tiller,可使用以下命令完成卸载。
kubectl delete deployment tiller-deploy --namespace kube-system
删除 Tiller 的 deployment
或者使用 helm reset 来删除
$ helm reset 或
$helm reset --force
使用—安装部署单服务nginx为例
使用helm提供的仓库repository中查找到的服务
最简单的方法就是 直接在 helm提供的仓库repository中查找相关的服务,使用install命令进行安装
使用命令
helm search nginx
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm search nginx
NAME CHART VERSION APP VERSION DESCRIPTION
stable/nginx-ingress 0.29.2 0.20.0 An nginx Ingress controller that uses ConfigMap to store ...
stable/nginx-ldapauth-proxy 0.1.2 1.13.5 nginx proxy with ldapauth
stable/nginx-lego 0.3.1 Chart for nginx-ingress-controller and kube-lego
stable/gcloud-endpoints 0.1.2 1 DEPRECATED Develop, deploy, protect and monitor your APIs...
zhangxiaofans-MacBook-Pro:helm joe$
使用命令 可以查看每个资源的详情和使用方式
helm inspect stable/nginx-ingress
安装命令如下:
$ helm install --name my-nginx-release stable/nginx-ingress
成功运行安装输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm install --name my-nginx-release stable/nginx-ingress
NAME: my-nginx-release
LAST DEPLOYED: Thu Jul 23 16:48:46 2020
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ClusterRole
NAME AGE
my-nginx-release-nginx-ingress 2s
==> v1/ClusterRoleBinding
NAME AGE
my-nginx-release-nginx-ingress 2s
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
my-nginx-release-nginx-ingress-controller 0/1 1 0 2s
my-nginx-release-nginx-ingress-default-backend 0/1 1 0 2s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
my-nginx-release-nginx-ingress-controller-fb795487f-zxjwk 0/1 ContainerCreating 0 2s
my-nginx-release-nginx-ingress-default-backend-dc456984b-xb6gt 0/1 ContainerCreating 0 2s
==> v1/Role
NAME AGE
my-nginx-release-nginx-ingress 2s
==> v1/RoleBinding
NAME AGE
my-nginx-release-nginx-ingress 2s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-release-nginx-ingress-controller LoadBalancer 10.30.23.234 <pending> 80:32569/TCP,443:30927/TCP 2s
my-nginx-release-nginx-ingress-default-backend ClusterIP 10.30.25.32 <none> 80/TCP 2s
==> v1/ServiceAccount
NAME SECRETS AGE
my-nginx-release-nginx-ingress 1 2s
my-nginx-release-nginx-ingress-backend 1 2s
NOTES:
The nginx-ingress controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace default get services -o wide -w my-nginx-release-nginx-ingress-controller'
An example Ingress that makes use of the controller:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
zhangxiaofans-MacBook-Pro:helm joe$
可以使用命令查看nginx服务的pod是否正常安装
kubectl get pods |grep nginx
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ kubectl get pods |grep nginx
my-nginx-release-nginx-ingress-controller-fb795487f-zxjwk 1/1 running 0 29m
my-nginx-release-nginx-ingress-default-backend-dc456984b-xb6gt 1/1 running 0 29m
如果不是running的状态则需要排查异常,可以参考 k8s服务发布错误排查
可能遇到的问题–ImagePullBackOff
详细报错如下:
Failed to pull image "us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1": rpc error: code = Unknown desc = Error response from daemon: Get https://us.gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
Warning Failed 5m (x118 over 35m) kubelet, ip-10-30-46-220.cn-northwest-1.compute.internal Error: ImagePullBackOff
Normal BackOff 21s (x139 over 35m) kubelet, ip-10-30-46-220.cn-northwest-1.compute.internal Back-off pulling image "us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1"
这是因为直接使用的资源库中的编排使用的镜像有可能是us的镜像,k8s集群不具备上网能力的话就会获取镜像失败。
解决方式,找到对应的deployment,修改镜像地址。
使用命令如下:
kubectl get deployment |grep nginx
找到对应的pod
使用命令
kubectl edit deployment my-nginx-release-nginx-ingress-controller
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ kubectl get deployment |grep nginx
my-nginx-release-nginx-ingress-controller 1 1 1 0 27s
my-nginx-release-nginx-ingress-default-backend 1 1 1 0 27s
zhangxiaofans-MacBook-Pro:helm joe$ kubectl edit deployment my-nginx-release-nginx-ingress-controller
替换为国内的镜像,比如阿里云的 registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.26.1
或者
quay.azk8s.cn/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
成功修改输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ KUBE_EDITOR="vim" kubectl edit deployment my-nginx-release-nginx-ingress-controller --validate=false
deployment.extensions "my-nginx-release-nginx-ingress-controller" edited
修改成功后 会自动新起pod。
pod状态running成功后可以使用 命令查看 nginx服务的状态以及访问方式
kubectl --namespace default get services -o wide -w my-nginx-release-nginx-ingress-controller
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ kubectl --namespace default get services -o wide -w my-nginx-release-nginx-ingress-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
my-nginx-release-nginx-ingress-controller LoadBalancer 10.30.23.234 123.cn-northwest-1.elb.amazonaws.com.cn 80:32569/TCP,443:30927/TCP 4m app.kubernetes.io/component=controller,app=nginx-ingress,release=my-nginx-release
zhangxiaofans-MacBook-Pro:helm joe$
使用EXTERNAL-IP对应的值 123.cn-northwest-1.elb.amazonaws.com.cn 即可访问 安装好的nginx服务。
可能遇到的问题—invalid object doesn’t have additional properties
原因是使用kubectl edit deployment 编辑后的格式不符合要求,如果改动不大的话可以忽略schema的检查,增加参数
–validate=false
使用命令
kubectl edit deployment my-nginx-release-nginx-ingress-controller --validate=false
可能遇到的问题—error: there was a problem with the editor “vi”
原因是kubectl 默认使用系统的vi进行编辑,但是有些格式处理不了,所以需要使用vim进行处理,使用参数
KUBE_EDITOR="vim"
使用命令
KUBE_EDITOR="vim" kubectl edit deployment my-nginx-release-nginx-ingress-controller --validate=false
自定义的安装方式
上面演示的是 使用第三方别人做好的资源来进行 安装,但有时候我们需要一些定制化的配置,或者是把我们先有的项目修改成helm的方式进行安装,那么就需要了解 怎么 进行 自定义安装。
我们先把上一步安装的nginx删除掉
使用命令:
helm delete my-nginx-release
这里my-nginx-release 与创建时候的 --name对应
成功删除输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm delete my-nginx-release
release "my-nginx-release" deleted
使用命令创建一个空的chart示例模板
helm create nginx-helm
这里的nginx-helm是我们自己想要的命名,随意起,创建出来的chart模板是一样的。
运行成功后 输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm create nginx-helm
Creating nginx-helm
创建成功后会在当前目录生成一个同名目录nginx-helm
使用tree命令查看目录结构如下:
zhangxiaofans-MacBook-Pro:helm joe$ tree nginx-helm
nginx-helm
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
3 directories, 8 files
如果我们查看deployment.yaml以及ingress.yaml和service.yaml等文件 会发现很多带有两个花括号的变量名。
例如:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
说明 这个chart模板比较灵活,实际起作用和需要调整的值都在values.yaml这个文件中。
查看values.yaml的内容
cat nginx-helm/values.yaml
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ cat nginx-helm/values.yaml
# Default values for nginx-helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
port: 80
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
zhangxiaofans-MacBook-Pro:helm joe$
可以发现 使用create命令创建的模板,默认的示例服务 就是nginx。
我们只需要调整一些 参数即可。
因为ClusterIP方式,外网无法访问到这个service,我们可以考虑使用NodePort方式或者LoadBalancer 以及ingress。
我们这里使用LoadBalancer 方式将
service:
type: ClusterIP
port: 80
修改为
service:
type: LoadBalancer
port: 80
如果要修改镜像的版本 可以把 stable修改为指定版本
如下:
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
修改为:
image:
repository: nginx
tag: 1.7.9
pullPolicy: IfNotPresent
修改完后使用命令
helm install ./nginx-helm
安装输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm install ./nginx-helm/
NAME: plundering-wasp
LAST DEPLOYED: Fri Jul 24 17:02:13 2020
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
plundering-wasp-nginx-helm 0/1 1 0 2s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
plundering-wasp-nginx-helm-699b5f8dc7-qrgvr 0/1 ContainerCreating 0 2s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
plundering-wasp-nginx-helm LoadBalancer 10.30.8.157 <pending> 80:30873/TCP 2s
NOTES:
1. Get the application URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace default svc -w plundering-wasp-nginx-helm'
export SERVICE_IP=$(kubectl get svc --namespace default plundering-wasp-nginx-helm -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:80
zhangxiaofans-MacBook-Pro:helm joe$
使用命令
查看外网可以访问的地址
kubectl get --namespace default svc -w plundering-wasp-nginx-helm -o wide
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ kubectl get --namespace default svc -w plundering-wasp-nginx-helm -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
plundering-wasp-nginx-helm LoadBalancer 10.30.8.157 123.cn-northwest-1.elb.amazonaws.com.cn 80:30873/TCP 10m app.kubernetes.io/instance=plundering-wasp,app.kubernetes.io/name=nginx-helm
使用EXTERNAL-IP对应的值 123.cn-northwest-1.elb.amazonaws.com.cn 即可访问
使用–安装部署多服务–Wordpress为例
Wordpress 为例,包括 MySQL、PHP 和 Apache。
由于测试环境没有可用的 PersistentVolume(持久卷,简称 PV),暂时将其关闭。
使用安装命令
helm install --name wordpress-test --set "persistence.enabled=false,mariadb.persistence.enabled=false,serviceType=NodePort" stable/wordpress
安装成功输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm install --name wordpress-test --set "persistence.enabled=false,mariadb.persistence.enabled=false,serviceType=NodePort" stable/wordpress
NAME: wordpress-test
LAST DEPLOYED: Mon Jul 27 11:53:04 2020
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
wordpress-test-mariadb 1 2s
wordpress-test-mariadb-tests 1 2s
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
wordpress-test 0/1 1 0 2s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
wordpress-test-747d457759-rjfnz 0/1 ContainerCreating 0 2s
wordpress-test-mariadb-0 0/1 Pending 0 2s
==> v1/Secret
NAME TYPE DATA AGE
wordpress-test Opaque 1 2s
wordpress-test-mariadb Opaque 2 2s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress-test LoadBalancer 10.30.22.146 <pending> 80:31769/TCP,443:32180/TCP 2s
wordpress-test-mariadb ClusterIP 10.30.9.210 <none> 3306/TCP 2s
==> v1/StatefulSet
NAME READY AGE
wordpress-test-mariadb 0/1 2s
NOTES:
This Helm chart is deprecated
Given the `stable` deprecation timeline (https://github.com/helm/charts#deprecation-timeline), the Bitnami maintained Helm chart is now located at bitnami/charts (https://github.com/bitnami/charts/).
The Bitnami repository is already included in the Hubs and we will continue providing the same cadence of updates, support, etc that we've been keeping here these years. Installation instructions are very similar, just adding the _bitnami_ repo and using it during the installation (`bitnami/<chart>` instead of `stable/<chart>`)
bash
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm install my-release bitnami/<chart> # Helm 3
$ helm install --name my-release bitnami/<chart> # Helm 2
To update an exisiting _stable_ deployment with a chart hosted in the bitnami repository you can execute
bash
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm upgrade my-release bitnami/<chart>
Issues and PRs related to the chart itself will be redirected to `bitnami/charts` GitHub repository. In the same way, we'll be happy to answer questions related to this migration process in this issue (https://github.com/helm/charts/issues/20969) created as a common place for discussion.
** Please be patient while the chart is being deployed **
To access your WordPress site from outside the cluster follow the steps below:
1. Get the WordPress URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
Watch the status with: 'kubectl get svc --namespace default -w wordpress-test'
export SERVICE_IP=$(kubectl get svc --namespace default wordpress-test --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
echo "WordPress URL: http://$SERVICE_IP/"
echo "WordPress Admin URL: http://$SERVICE_IP/admin"
2. Open a browser and access WordPress using the obtained URL.
3. Login with the following credentials below to see your blog:
echo Username: user
echo Password: $(kubectl get secret --namespace default wordpress-test -o jsonpath="{.data.wordpress-password}" | base64 --decode)
部署完成后,我们可以通过上面的提示信息生成相应的访问地址和用户名、密码等相关信息。
使用命令
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services wordpress-test)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/admin
echo Username: user
echo Password: $(kubectl get secret --namespace default wordpress-test -o jsonpath="{.data.wordpress-password}" | base64 --decode)
输出如下:
# 生成 Wordpress 管理后台地址
$ export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services wordpress-test)
$ export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
$ echo http://$NODE_IP:$NODE_PORT/admin
http://192.168.100.211:8433/admin
# 生成 Wordpress 管理帐号和密码
$ echo Username: user
Username: user
$ echo Password: $(kubectl get secret --namespace default wordpress-test -o jsonpath="{.data.wordpress-password}" | base64 --decode)
Password: QfLE7uD5fd
或者使用命令查看 访问链接:
kubectl get --namespace default svc -w wordpress-test -o wide
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ kubectl get --namespace default svc -w wordpress-test -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
wordpress-test LoadBalancer 10.30.22.146 123.cn-northwest-1.elb.amazonaws.com.cn 80:31769/TCP,443:32180/TCP 2h app.kubernetes.io/instance=wordpress-test,app.kubernetes.io/name=wordpress
则使用 123.cn-northwest-1.elb.amazonaws.com.cn 即可访问,访问如下:
在首页找到login的按钮 ,使用上面打印的账号密码登录后,登录如下:
常用命令
helm search 在仓库中查找chart
helm fetch stable/redis 下载chart到本地
helm inspect stable/mongodb 可查看该chart的介绍信息
helm install stable/mongodb 可直接下载该chart并安装该chart
helm upgrade releaseName . 版本升级,可以通过 --version 参数指定需要升级的版本号,如果没有指定版本号,则缺省使用最新版本
helm rollback releaseName 1 回滚到版本1
helm list 查看已经发布的release
helm package hello-helm 打包chart,然后我们就可以将打包的tgz文件分发到任意的服务器上,通过helm fetch就可以获取到该 Chart 了
helm delete hello-helm 删除release
kubectl get pods -l app=hello-helm 查看发布的资源
helm get wordpress-test 查看发布的release
helm get --revision 1 wordpress-test 查看指定版本的release
helm install local/mychart --name mike-test --namespace mynamespace 部署到指定命名空间
Helm 命令自动补全
为了方便 helm 命令的使用,Helm 提供了自动补全功能,不过需要设置一下 命令自动补全
如果系统使用的是BASH 请执行:
$ source <(helm completion bash)
如果系统使用的是ZSH 请执行:
$ source <(helm completion zsh)
使用第三方Chart存储库
随着 Helm 越来越普及,除了使用预置官方存储库,三方仓库也越来越多了(前提是网络是可达的)。你可以使用如下命令格式添加三方 Chart 存储库。
$ helm repo add 存储库名 存储库URL
$ helm repo update
一些三方存储库资源:
# Prometheus Operator
https://github.com/coreos/prometheus-operator/tree/master/helm
# Bitnami Library for Kubernetes
https://github.com/bitnami/charts
# Openstack-Helm
https://github.com/att-comdev/openstack-helm
https://github.com/sapcc/openstack-helm
# Tick-Charts
https://github.com/jackzampolin/tick-charts
打包分享
使用命令可以打包chart
helm package .
得到一个压缩文件,例如 mychart-0.1.0.tgz文件
压缩包方式分享
使用mychart-0.1.0.tgz文件 进行交互,发给同事后,同事把压缩包解压,然后 使用命令进行安装
helm install mychart
自建repository方式分享
压缩包分享的方式比较繁琐,而且不能复用,每个同事需要都得重新交互一次,而且版本更新也很麻烦,最好得方式就是 公司层面有一个公共得仓库repository,我们只要上传后 同事都能看到。
首先查看目前使用的仓库
使用命令:
helm repo list
输出如下:
zhangxiaofans-MacBook-Pro:helm joe$ helm repo list
NAME URL
stable https://kubernetes-charts.storage.googleapis.com
local http://127.0.0.1:8879/charts
zhangxiaofans-MacBook-Pro:helm joe$
注:新版本中执行 helm init 命令后默认会配置一个名为 local 的本地仓库。
我们可以在本地启动一个 Repository Server,并将其加入到 Helm Repo 列表中。Helm Repository 必须以 Web 服务的方式提供,这里我们就使用 helm serve 命令启动一个 Repository Server,该 Server 缺省使用 $HOME/.helm/repository/local 目录作为 Chart 存储,并在 8879 端口上提供服务。
$ helm serve &
Now serving you on 127.0.0.1:8879
默认情况下该服务只监听 127.0.0.1,如果你要绑定到其它网络接口,可使用以下命令:
比如公司层面 公用一台服务器作为仓库,把需要更新和上传包放到这台服务的 $HOME/.helm/repository/local 目录
$ helm serve --address 192.168.30.211:8879 &
如果你想使用指定目录来做为 Helm Repository 的存储目录,可以加上 --repo-path 参数:
$ helm serve --address 192.168.30.211:8879 --repo-path /data/helm/repository/ --url http://192.168.30.211:8879/charts/
通过 helm repo index 命令将 Chart 的 Metadata 记录更新在 index.yaml 文件中:
# 更新 Helm Repository 的索引文件
$ cd /home/k8s/.helm/repository/local
$ helm repo index --url=http://192.168.30.211:8879 .
完成启动本地 Helm Repository Server 后,就可以将本地 Repository 加入 Helm 的 Repo 列表。
使用命令
$ helm repo add local 192.168.30.211:8879
"local" has been added to your repositories
现在再次查找 mychart 包,就可以搜索到了。
$ helm repo update
$ helm search mychart
NAME CHART VERSION APP VERSION DESCRIPTION
local/mychart 0.1.0 1.0 A Helm chart for Kubernetes
再有其他同事想要 使用这个chart,只要添加这个repositories即可。
其他问题
1、如何让 Helm 连接到指定 Kubernetes 集群?
Helm 默认使用和 kubectl 命令相同的配置访问 Kubernetes 集群,其配置默认在 ~/.kube/config 中。
2、如何在部署时指定命名空间?
helm install 默认情况下是部署在 default 这个命名空间的。如果想部署到指定的命令空间,可以加上 --namespace 参数,比如:
$ helm install local/mychart --name mike-test --namespace mynamespace
参考链接
https://blog.csdn.net/bbwangj/article/details/81087911
https://www.jianshu.com/p/4bd853a8068b
https://blog.csdn.net/chenleiking/article/details/79539012
详细的chart模板和参数参考 https://blog.csdn.net/chenleiking/article/details/79539012
附录–get_helm.sh
#!/usr/bin/env bash
# Copyright The Helm Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The install script is based off of the MIT-licensed script from glide,
# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
PROJECT_NAME="helm"
TILLER_NAME="tiller"
: ${USE_SUDO:="true"}
: ${HELM_INSTALL_DIR:="/usr/local/bin"}
# initArch discovers the architecture for this system.
initArch() {
ARCH=$(uname -m)
case $ARCH in
armv5*) ARCH="armv5";;
armv6*) ARCH="armv6";;
armv7*) ARCH="arm";;
aarch64) ARCH="arm64";;
x86) ARCH="386";;
x86_64) ARCH="amd64";;
i686) ARCH="386";;
i386) ARCH="386";;
esac
}
# initOS discovers the operating system for this system.
initOS() {
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
case "$OS" in
# Minimalist GNU for Windows
mingw*) OS='windows';;
esac
}
# runs the given command as root (detects if we are root already)
runAsRoot() {
local CMD="$*"
if [ $EUID -ne 0 -a $USE_SUDO = "true" ]; then
CMD="sudo $CMD"
fi
$CMD
}
# verifySupported checks that the os/arch combination is supported for
# binary builds.
verifySupported() {
local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nwindows-386\nwindows-amd64"
if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
echo "No prebuilt binary for ${OS}-${ARCH}."
echo "To build from source, go to https://github.com/helm/helm"
exit 1
fi
if ! type "curl" > /dev/null && ! type "wget" > /dev/null; then
echo "Either curl or wget is required"
exit 1
fi
}
# checkDesiredVersion checks if the desired version is available.
checkDesiredVersion() {
if [ "x$DESIRED_VERSION" == "x" ]; then
# Get tag from release URL
local release_url="https://github.com/helm/helm/releases"
if type "curl" > /dev/null; then
TAG=$(curl -Ls $release_url | grep 'href="/helm/helm/releases/tag/v2.[0-9]*.[0-9]*\"' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}')
elif type "wget" > /dev/null; then
TAG=$(wget $release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v2.[0-9]*.[0-9]*\"' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}')
fi
else
TAG=$DESIRED_VERSION
fi
}
# checkHelmInstalledVersion checks which version of helm is installed and
# if it needs to be changed.
checkHelmInstalledVersion() {
if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then
local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version -c | grep '^Client' | cut -d'"' -f2)
if [[ "$version" == "$TAG" ]]; then
echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
return 0
else
echo "Helm ${TAG} is available. Changing from version ${version}."
return 1
fi
else
return 1
fi
}
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
CHECKSUM_URL="$DOWNLOAD_URL.sha256"
HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
echo "Downloading $DOWNLOAD_URL"
if type "curl" > /dev/null; then
curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
elif type "wget" > /dev/null; then
wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
fi
if type "curl" > /dev/null; then
curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
elif type "wget" > /dev/null; then
wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
fi
}
# installFile verifies the SHA256 for the file, then unpacks and
# installs it.
installFile() {
HELM_TMP="$HELM_TMP_ROOT/$PROJECT_NAME"
local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
local expected_sum=$(cat ${HELM_SUM_FILE})
if [ "$sum" != "$expected_sum" ]; then
echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
exit 1
fi
mkdir -p "$HELM_TMP"
tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/$PROJECT_NAME"
TILLER_TMP_BIN="$HELM_TMP/$OS-$ARCH/$TILLER_NAME"
echo "Preparing to install $PROJECT_NAME and $TILLER_NAME into ${HELM_INSTALL_DIR}"
runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR"
echo "$PROJECT_NAME installed into $HELM_INSTALL_DIR/$PROJECT_NAME"
if [ -x "$TILLER_TMP_BIN" ]; then
runAsRoot cp "$TILLER_TMP_BIN" "$HELM_INSTALL_DIR"
echo "$TILLER_NAME installed into $HELM_INSTALL_DIR/$TILLER_NAME"
else
echo "info: $TILLER_NAME binary was not found in this release; skipping $TILLER_NAME installation"
fi
}
# fail_trap is executed if an error occurs.
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
if [[ -n "$INPUT_ARGUMENTS" ]]; then
echo "Failed to install $PROJECT_NAME with the arguments provided: $INPUT_ARGUMENTS"
help
else
echo "Failed to install $PROJECT_NAME"
fi
echo -e "\tFor support, go to https://github.com/helm/helm."
fi
cleanup
exit $result
}
# testVersion tests the installed client to make sure it is working.
testVersion() {
set +e
HELM="$(command -v $PROJECT_NAME)"
if [ "$?" = "1" ]; then
echo "$PROJECT_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
exit 1
fi
set -e
echo "Run '$PROJECT_NAME init' to configure $PROJECT_NAME."
}
# help provides possible cli installation arguments
help () {
echo "Accepted cli arguments are:"
echo -e "\t[--help|-h ] ->> prints this help"
echo -e "\t[--version|-v <desired_version>]"
echo -e "\te.g. --version v2.4.0 or -v latest"
echo -e "\t[--no-sudo] ->> install without sudo"
}
# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
cleanup() {
if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
rm -rf "$HELM_TMP_ROOT"
fi
}
# Execution
#Stop execution on any error
trap "fail_trap" EXIT
set -e
# Parsing input arguments (if any)
export INPUT_ARGUMENTS="${@}"
set -u
while [[ $# -gt 0 ]]; do
case $1 in
'--version'|-v)
shift
if [[ $# -ne 0 ]]; then
export DESIRED_VERSION="${1}"
else
echo -e "Please provide the desired version. e.g. --version v2.4.0 or -v latest"
exit 0
fi
;;
'--no-sudo')
USE_SUDO="false"
;;
'--help'|-h)
help
exit 0
;;
*) exit 1
;;
esac
shift
done
set +u
initArch
initOS
verifySupported
checkDesiredVersion
if ! checkHelmInstalledVersion; then
downloadFile
installFile
fi
testVersion
cleanup