https://jimmysong.io/posts/manage-kubernetes-native-app-with-helm/
Wed Oct 25, 2017
4600 Words|Read in about 10 Min
Tags: kubernetes helm chart
完本文后您应该可以自己创建chart,并创建自己的私有chart仓库。
Helm是一个kubernetes应用的包管理工具,用来管理charts——预先配置好的安装包资源,有点类似于Ubuntu的APT和CentOS中的yum。
Helm chart是用来封装kubernetes原生应用程序的yaml文件,可以在你部署应用的时候自定义应用程序的一些metadata,便与应用程序的分发。
Helm和charts的主要作用:
本文同时归档到kubernetes-handbook。
前提要求
安装步骤
首先需要安装helm客户端
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh
创建tiller的serviceaccount
和clusterrolebinding
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
然后安装helm服务端tiller
helm init -i sz-pg-oam-docker-hub-001.tendcloud.com/library/kubernetes-helm-tiller:v2.3.1
我们使用-i
指定自己的镜像,因为官方的镜像因为某些原因无法拉取。
为应用程序设置serviceAccount
:
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
检查是否安装成功:
$ kubectl -n kube-system get pods|grep tiller
tiller-deploy-2372561459-f6p0z 1/1 Running 0 1h
$ helm version
Client: &version.Version{SemVer:"v2.3.1", GitCommit:"32562a3040bb5ca690339b9840b6f60f8ce25da4", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.3.1", GitCommit:"32562a3040bb5ca690339b9840b6f60f8ce25da4", GitTreeState:"clean"}
我们创建一个名为mychart
的chart,看一看chart的文件结构。
$ helm create mongodb
$ tree mongodb
mongodb
├── Chart.yaml #Chart本身的版本和配置信息
├── charts #依赖的chart
├── templates #配置模板目录
│ ├── NOTES.txt #helm提示信息
│ ├── _helpers.tpl #用于修改kubernetes objcet配置的模板
│ ├── deployment.yaml #kubernetes Deployment object
│ └── service.yaml #kubernetes Serivce
└── values.yaml #kubernetes object configuration
2 directories, 6 files
Templates
目录下是yaml文件的模板,遵循Go template语法。使用过Hugo的静态网站生成工具的人应该对此很熟悉。
我们查看下deployment.yaml
文件的内容。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.internalPort }}
livenessProbe:
httpGet:
path: /
port: {{ .Values.service.internalPort }}
readinessProbe:
httpGet:
path: /
port: {{ .Values.service.internalPort }}
resources:
{{ toYaml .Values.resources | indent 12 }}
这是该应用的Deployment的yaml配置文件,其中的双大括号包扩起来的部分是Go template,其中的Values是在values.yaml
文件中定义的:
# Default values for mychart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service:
name: nginx
type: ClusterIP
externalPort: 80
internalPort: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
比如在Deployment.yaml
中定义的容器镜像image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
其中的:
.Values.image.repository
就是nginx.Values.image.tag
就是stable以上两个变量值是在create chart的时候自动生成的默认值。
我们将默认的镜像地址和tag改成我们自己的镜像sz-pg-oam-docker-hub-001.tendcloud.com/library/nginx:1.9
。
当使用kubernetes部署应用的时候实际上讲templates渲染成最终的kubernetes能够识别的yaml格式。
使用helm install --dry-run --debug
命令来验证chart配置。该输出中包含了模板的变量配置与最终渲染的yaml文件。
$ helm install --dry-run --debug mychart
Created tunnel using local port: '58406'
SERVER: "localhost:58406"
CHART PATH: /Users/jimmy/Workspace/github/bitnami/charts/incubator/mean/charts/mychart
NAME: filled-seahorse
REVISION: 1
RELEASED: Tue Oct 24 18:57:13 2017
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
image:
pullPolicy: IfNotPresent
repository: sz-pg-oam-docker-hub-001.tendcloud.com/library/nginx
tag: 1.9
replicaCount: 1
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
service:
externalPort: 80
internalPort: 80
name: nginx
type: ClusterIP
HOOKS:
MANIFEST:
---
# Source: mychart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: filled-seahorse-mychart
labels:
chart: "mychart-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: filled-seahorse-mychart
---
# Source: mychart/templates/deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: filled-seahorse-mychart
labels:
chart: "mychart-0.1.0"
spec:
replicas: 1
template:
metadata:
labels:
app: filled-seahorse-mychart
spec:
containers:
- name: mychart
image: "sz-pg-oam-docker-hub-001.tendcloud.com/library/nginx:1.9"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
readinessProbe:
httpGet:
path: /
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
我们可以看到Deployment和Service的名字前半截由两个随机的单词组成,最后才是我们在values.yaml
中配置的值。
在mychart
目录下执行下面的命令将nginx部署到kubernetes集群上。
helm install .
NAME: eating-hound
LAST DEPLOYED: Wed Oct 25 14:58:15 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
eating-hound-mychart 10.254.135.68 80/TCP 0s
==> extensions/v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
eating-hound-mychart 1 1 1 0 0s
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app=eating-hound-mychart" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
现在nginx已经部署到kubernetes集群上,本地执行提示中的命令在本地主机上访问到nginx实例。
export POD_NAME=$(kubectl get pods --namespace default -l "app=eating-hound-mychart" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
在本地访问http://127.0.0.1:8080
即可访问到nginx。
查看部署的relaese
$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
eating-hound 1 Wed Oct 25 14:58:15 2017 DEPLOYED mychart-0.1.0 default
删除部署的release
$ helm delete eating-hound
release "eating-hound" deleted
我们可以修改Chart.yaml
中的helm chart配置信息,然后使用下列命令将chart打包成一个压缩文件。
helm package .
打包出mychart-0.1.0.tgz
文件。
我们可以在requirement.yaml
中定义应用所依赖的chart,例如定义对mariadb
的依赖:
dependencies:
- name: mariadb
version: 0.6.0
repository: https://kubernetes-charts.storage.googleapis.com
使用helm lint .
命令可以检查依赖和模板配置是否正确。
我们在前面安装chart可以通过HTTP server的方式提供。
$ helm serve
Regenerating index. This may take a moment.
Now serving you on 127.0.0.1:8879
访问http://localhost:8879
可以看到刚刚安装的chart。
点击链接即可以下载chart的压缩包。
下面列举一些常见问题,和在解决这些问题时候的注意事项。
所有使用helm部署的应用中如果没有特别指定chart的名字都会生成一个随机的Release name
,例如romping-frog
、sexy-newton
等,跟启动docker容器时候容器名字的命名规则相同,而真正的资源对象的名字是在YAML文件中定义的名字,我们成为App name
,两者连接起来才是资源对象的实际名字:Release name
-App name
。
而使用helm chart部署的包含依赖关系的应用,都会使用同一套Release name
,在配置YAML文件的时候一定要注意在做服务发现时需要配置的服务地址,如果使用环境变量的话,需要像下面这样配置。
env:
- name: SERVICE_NAME
value: "{{ .Release.Name }}-{{ .Values.image.env.SERVICE_NAME }}"
这是使用了Go template的语法。至于{{ .Values.image.env.SERVICE_NAME }}
的值是从values.yaml
文件中获取的,所以需要在values.yaml
中增加如下配置:
image:
env:
SERVICE_NAME: k8s-app-monitor-test
在本地当前chart配置的目录下启动helm server,我们不指定任何参数,直接使用默认端口启动。
helm serve
将该repo加入到repo list中。
helm repo add local http://localhost:8879
在浏览器中访问http://localhost:8879可以看到所有本地的chart。
然后下载依赖到本地。
helm dependency update
这样所有的chart都会下载到本地的charts
目录下。
为了方便helm命令的使用,helm提供了自动补全功能,如果使用zsh请执行:
source <(helm completion zsh)
如果使用bash请执行:
source <(helm completion bash)
MEAN是用来构建网站和web应用的免费开源的JavaScript软件栈,该软件栈包括MongoDB、Express.js、Angular和Node.js。
下载charts
$ git clone https://github.com/bitnami/charts.git
$ cd charts/incubator/mean
$ helm dep list
NAME VERSION REPOSITORY STATUS
mongodb 0.4.x https://kubernetes-charts.storage.googleapis.com/ missing
缺少mongodb的依赖,需要更新一下chart。
注:https://kubernetes-charts.storage.googleapis.com/
是Google维护的chart库,访问该地址可以看到所有的chart列表。
$ helm dep update
Hang tight while we grab the latest from your chart repositories...
...Unable to get an update from the "local" chart repository (http://127.0.0.1:8879/charts):
Get http://127.0.0.1:8879/charts/index.yaml: dial tcp 127.0.0.1:8879: getsockopt: connection refused
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading mongodb from repo https://kubernetes-charts.storage.googleapis.com/
所有的image都在 values.yaml
文件中配置。
下载缺失的chart。
$ helm dep build
Hang tight while we grab the latest from your chart repositories...
...Unable to get an update from the "local" chart repository (http://127.0.0.1:8879/charts):
Get http://127.0.0.1:8879/charts/index.yaml: dial tcp 127.0.0.1:8879: getsockopt: connection refused
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading mongodb from repo https://kubernetes-charts.storage.googleapis.com/
修改mongodb chart配置
将刚才下载的charts/mongodb-0.4.17.tgz
给解压后,修改其中的配置:
persistence
下的enabled
设置为false执行helm install --dry-run --debug .
确定模板无误。
将修改后的mongodb chart打包,在mongodb的目录下执行:
helm package .
现在再访问前面启动的helm server http://localhost:8879
将可以在页面上看到mongodb-0.4.17这个chart。
我们对官方chart配置做了如下修改后推送到了自己的chart仓库:
requirements.yaml
和requirements.lock
文件中的repository
为http://localhost:8879
values.yaml
中的storageClass
设置为null
values.yaml
中的Image
都改为私有镜像repositroy
都设置为http://localhost:8879
注:因为我们没有使用PVC所以将所有的关于持久化存储的配置都设置为false了。
部署MEAN
在mean
目录下执行:
helm install .
NAME: orbiting-platypus
LAST DEPLOYED: Wed Oct 25 16:21:48 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Secret
NAME TYPE DATA AGE
orbiting-platypus-mongodb Opaque 2 2s
==> v1/ConfigMap
NAME DATA AGE
orbiting-platypus-mean 1 2s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
orbiting-platypus-mongodb 10.254.144.208 27017/TCP 2s
orbiting-platypus-mean 10.254.165.23 80/TCP 2s
==> extensions/v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
orbiting-platypus-mean 1 1 1 0 2s
orbiting-platypus-mongodb 1 1 1 0 2s
NOTES:
Get the URL of your Node app by running:
export POD_NAME=$(kubectl get pods --namespace default -l "app=orbiting-platypus-mean" -o jsonpath="{.items[0].metadata.name}")
echo http://127.0.0.1:8080/
kubectl port-forward $POD_NAME 8080:80
这样MEAN软件栈就部署到你的kuberentes集群里面了(默认是在default namespace下)。
验证检查
为了验证MEAN是否安装成功过,可以使用kubectl get pods
查看pod是否启动完成,会先启动mongodb的pod,然后启动MEAN中的4步init。
访问Web UI
在Ingress中增加如下配置:
- host: mean.jimmysong.io
http:
paths:
- backend:
serviceName: orbiting-platypus-mean
servicePort: 80
path: /
然后在页面中更新ingress:
kubectl repalce -f ingress.yaml
关于Ingress配置请参考:边缘节点配置
然后在本地的/etc/hosts
文件中增加一条配置:
172.20.0.119 mean.jimmysong.io
注:172.20.0.119即边缘节点的VIP。
因为该页面需要加载google的angularjs、还有两个css在国内无法访问,可以使用curl测试:
curl mean.jimmysong.io
将会返回HTML内容:
Node/Angular Todo App
访问 http://mean.jimmysong.io 可以看到如下界面,我在其中添加几条todo:
注:Todo中的文字来自What does the fox say?
测试完成后可以使用下面的命令将mean chart推送的本地chart仓库中。
在mean目录下执行:
helm package .
再次刷新http://localhost:8879
将可以看到如下三个chart:
Wed Oct 25, 2017
4600 Words|Read in about 10 Min
Tags: kubernetes helm chart