上一篇文章 Kubernetes上应用部署之三步曲 中提到了一句话 Kubernetes上一切皆资源,我们通过创建pods(deployment),service,ingress三种资源完成了 HelloDevOps应用的部署,一个简单的应用就有了三个yaml文件,但是真实实践中,应用(微服务应用)肯定不止一个,这样下来,就会有十多个,甚至几十个yaml文件,如果每次部署都用 kubectl 来对相应的资源进行增(create),删(delete),改(edit),查(get),那么这种管理方式无疑是复杂多变甚至是灾难的,在这种情况下,Kubernetes提供了Helm来让整个流程变得简单起来。

Helm 介绍

正如官网所说, Helm is the packagemanager for Kubernetes and Helm is the best way to find,share,and use software built for Kubernetes. 顾名思义,Helm 是kubernetes的包管理器,就像apt-get 与之Ubuntu和yum与之Redhat和Centos。

Helm 基本原理

image.png

Helm 是C/S模型,总共有两部分组成: Helm客户端(Helm)和服务器端(Tiller,以2.x版本为例,3.x剔除了tiller)。Helm 客户端是一个CLI,而Tiller是以deployment形式部署在Kubernetes平台的kube-system namespace下。

其中Helm接受来自于用户对于Helm Charts 所生成的Release的增(helm install)、删(helm delete)、改(helm upgrade)、查(helm ls);Tiller主要用来与Kubernetes API server进行交互(因为对于Kubernetes来说,一切请求的入口都是API server),从而实现对于Kubernetes资源的增、删、改、查,另外Tiller还可以对于已经创建好的Release进行存储与管理。

当用户需要用某一个chart来通过install方式生成一个Release的时候,Helm客户端接受这个install请求,并将请求发个Tiller服务端,Tiller服务端会将chart中的相关文件根据values.yaml中定义的值或者来自于--set后面指定的参数来进行渲染,而后将渲染好的文件发给Kubernetes API server生成相应的资源,最终完成一个Release的创建。

Helm 安装

由于Helm有客户端与服务端两部分组成,所以安装分两步走。

第一步:Helm 客户端的安装

Helm客户端有源码和二进制码两种安装方式,本文采用二进制进行安装(二进制安装比较方便,所以个人推荐用二进制进行安装)。首先在Helm 客户端Release的github页面中,找到与自己OS想匹配的版本进行下载,将下载文件进行解压并将解压之后的二进制文件helm拷贝至目标路径(比如/usr/local/bin/helm),可以用helm help命令来验证helm 客户端是否安装成功。

第二步:创建Service Account

由于在Kubernetes中,对于资源的控制权限是通过RBAC(Role-Based Access Control)来实现的, 而Tiller是在kube-system namespace下的,但是由Tiller管理的Release 是在别的namespace下面的,这种情况下需要给Tiller创建一个相应权限的Service Account,这个Service Account和cluster-admin这个ClusterRole进行绑定,这样确保Tiller能够对于整个cluster各个namespace下面的资源进行list,delete,update等操作。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

创建完service account,可以在kube-system ns下面查看service account的具体信息

$ kubectl -n kube-system get sa | grep tillertiller                              1         115d

第三步:Helm 服务端的安装

借助于上一步生成的Service Account(tiller),可以执行 helm init --service-account tiller 命令来完成 Tiller 服务端的安装。这个过程会先对helm本地环境进行有效性验证,然后会与Kubernetes cluster的kubectl进行连接,如果连接成功 ,会在kube-system namespace形势下部署一个与tiller相关的deployment。可以在 kube-system namespace下面进行查看。

$kubectl -n kube-system get deploy,pods | grep tiller
deployment.extensions/tiller-deploy   1         1         1            1      115d
pod/tiller-deploy-6f6fd74b68-tzhcv    1/1       Running
   0          2d21h

执行 helm version

$ helm version
Client: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b146b", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.11.0", GitCommit:"2e55dbe1fdb5fdb96b75ff144a339489417b146b", GitTreeState:"clean"}

至此,helm 客户端和服务端都安装完成。下面我们就可以用helm来部署上篇文章中的应用了,部署之前先要讲几个与Helm相关的概念。

Helm的一些基本概念

Chart

部署一个应用所需要的一个包,这个包是由能够描述kubernetes 相关资源(deploy, service, ingress 等等)的一系列文件组成 ,通过这些文件,可以在kubernetes上创建相关资源

Release

由Helm Chart所创建生成的一个实例(一般情况下就是部署了一个微服务应用)

Repoistory

存放Helm charts的仓库,和Docker Registry Repository一样,用来存放helm chart包。比如Jfrog Artifactory。

Helm 部署应用

首先,我们用 helm create devops命令创建一个名为devops的chart,查看一下包含的文件有哪些

$ tree devops
devops/
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── ingress.yaml
│   └── service.yaml
└── values.yaml

先简单的介绍一下上面出现的一些文件的作用

Chart.yaml

此文件主要用来描述此chart的信息,包括版本号,维护者的信息等。

charts

这是个目录,里面主要存放此chart所依赖的一些chart包。

templates

这是一个目录,里面包含chart的重点内容,可以看到有 deployment.yaml,ingress.yaml,service.yaml,这三个文件(chart创建出来之后,默认只有这三种资源的定义文件,但是这并不代表只能有这三个文件,如果部署应用的过程中用到了secret,configmap等相关资源,也可以写在这个目录下,这也是就看出来了,文件越来越多的时候 helm 的方便快捷就能体现出来了)描述的就是与pod(deployment),ingress,service 等kubernetes资源相关的信息。

_helpers.tpl

这是个模版文件,用来定义用于一些模版语言。

value.yaml

这是最后也是要着重要介绍的一个文件。在介绍这个文件之前,我们先看一下,service.yaml文件中的内容有什么,这样能帮我们更好的理解 values.yaml 文件。

$ cat service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "devops.fullname" . }}
  labels:
    app: {{ .Release.Name }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
      app: {{ .Release.Name }}

可以看到上面有很多用 "{{}}"括起来的内容,这是Helm Chart中定义的变量。Helm Chart的书写用到了Go Template Language。 Package Template主要实现了一些数据驱动模块,这些数据模块可以用来生成一些文本输出。而对于Template 最直观的理解可以这么理解

image.png

这些括弧里面的内容可以理解为 "形参",而"实参"的值就是来自于 values.yaml 文件,其实如果逐个打开chart目录下的其他文件,比如 deployment.yaml, ingress.yaml打开之后都会看到与 service.yaml相似的情况。所以 values.yaml文件的重要性就体现出来了,部署出来的deployment,ingress ,service是什么样的,完全取决于在 values.yaml文件中是怎么样定义的。

而且helm chart的另外一个便利之处就是,一个chart可以部署多个Release,而这多个Release又可以对应多个不同的环境,比如dev环境,svt环境,prod环境,这种变化需要的仅仅是一个 values.yaml 文件,比如将dev环境相关的信息,写在一个 values-dev.yaml的文件中,那么创建出来的Release所对应的环境就是dev环境,svt和prod都可以用同样的方式创建出来。 这些用"{{}}"括起来的变量中,有几个全局的变量,需要关注一下:

.Chart.Name

表示chart的name,比如上面用helm create devops创建了devops 这个chart,则.Chart.Name的值就是devops。

.Release.Name

表示由chart创建的Release的name,比如用上述的devops chart通过install命令生成了一个hello-devops的Release,则.Release.Name的值就是hello-devops。

.Release.Namespace

由chart创建的Release所在的namespace,比如用上述的devops chart在devops namespace下面创建的hello-devops Release,则 .Release.Namespace的值就是devops。 我们将上一篇文章中deployment,yaml,service.yaml,ingress.yaml文件中的"实参"内容写入到 values.yaml 文件中

$ cat values.yaml
replicaCount: 1

env:
  running_env: dev
  name: devops
  client: helm
  server: tiller
  version: v1

image:
  repository: dllhb/go_test
  tag: v1.3
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
  path: /
  hosts:
    - devops.test.com
  tls:
    - secretName: devops-tls
      hosts:
        - devops.test.com

resources:
   limits:
    cpu: 100m
    memory: 128Mi
   requests:
    cpu: 100m
    memory: 128Mi

deployment.yaml 文件的内容如下

$ cat templates/deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: {{ .Release.Name }}
  labels:
    app: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
        version: non-canary
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 9999
              protocol: TCP
          env:
             {{- include  "devops.env" . | nindent 12}}

service.yaml 文件内容如下

$ cat templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "devops.fullname" . }}
  labels:
    app: {{ .Release.Name }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
      app: {{ .Release.Name }}

ingress.yaml 文件内容如下

$ cat templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "devops.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.ingress.annotations }}
  annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . | quote }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
    - host: {{ . | quote }}
      http:
        paths:
          - path: {{ $ingressPath }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: http
  {{- end }}
{{- end }}

下面就可以进入到devops目录下用 helm install 来进行应用安装,

$ helm install . --name devops --namespace devops -f values.yaml
NAME:   devops
LAST DEPLOYED: Sun Aug  4 16:21:03 2019
NAMESPACE: devops
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME    AGE
devops  4s

==> v1beta2/Deployment
devops  4s

==> v1beta1/Ingress
devops  4s

==> v1/Pod(related)

NAME                     READY  STATUS   RESTARTS  AGE
devops-5f499c48b4-rzldr  1/1    Running  0         4s


NOTES:
1. Get the application URL by running these commands:
  https://devops.test.com/

查看pod,service,ingress资源

$ kubectl -n devops get pods,svc,ing
NAME                                READY     STATUS    RESTARTS   AGE
pod/hello-devops-78dd67d9cc-jpx2z   1/1       Running   0          2d22h

NAME                       TYPE        CLUSTER-IP      EXTERNAL-IP  
PORT(S)    AGE
service/hello-devops-svc   ClusterIP   172.21.246.13   <none>        8888/TCP   14d

NAME                                      
 HOSTS                                                                  
                           ADDRESS   
   PORTS     AGE
ingress.extensions/hello-devops-ingress   devops.test.com   10.208.70.22   80, 443   14d

然后就可以用 https://devops.test.com 来访问应用程序了

$ curl -k -s https://devops.test.com
Hello DevOps, pod name is hello-devops-78dd67d9cc-jpx2z

此外,可以用 helm ls 查看已经部署了的Release

$ helm ls | grep devops
devops         1           Thu Jun  6 10:13:02 2019    DEPLOYED    devops-0.1.0                1.0                                        devops

如果要删除已经安装了的Release,可以执行 helmdeletedevops--purge

$ helm delete devops --purgerelease "devops" deleted

来源:DevSecOps SIG
作者:小马哥
声明:文章获得作者授权在IDCF社区公众号(devopshub)转发。优质内容共享给思否平台的技术同伴,如原作者有其他考虑请联系小编删除,致谢。

7月每周四晚8点,【冬哥有话说】研发效能工具专场,公众号留言“研发效能”可获取地址

  • 7月8日,前微软-周文洋《微软DevOps工具链的 "爱恨情仇"(Azure DevOps)》
  • 7月15日,阿里云-陈逊《复杂型研发协作模式下的效能提升实践》
  • 7月22日,极狐(GitLab)-张扬《基础设施即代码的⾃动化测试探索》
  • 7月29日,字节跳动-胡贤彬《自动化测试,如何做到「攻防兼备」?》

用户bPcN1SC
149 声望55 粉丝