Kubernetes的包管理工具Helm的安装和使用
源码版本:https://github.com/helm/helm/tags
官网安装:https://helm.sh/docs/intro/install/
1.二进制文件安装
[root@master ~]# wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.0-linux-amd64.tar.gz [root@master ~]# tar -zxvf helm-v2.14.0-linux-amd64.tar.gz linux-amd64/ linux-amd64/tiller linux-amd64/README.md linux-amd64/LICENSE linux-amd64/helm [root@master ~]# ls anaconda-ks.cfg helm-v2.14.0-linux-amd64.tar.gz linux-amd64 token.txt [root@master ~]# ls linux-amd64/ helm LICENSE README.md tiller [root@master ~]# mv linux-amd64/helm /usr/bin [root@master ~]# helm --help
2.脚本安装
[root@master ~]# curl -LO https://git.io/get_helm.sh [root@master ~]# chmod 700 get_helm.sh [root@master ~]# ./get_helm.sh //[root@master ~]# curl -L https://git.io/get_helm.sh | bash $ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 $ chmod 700 get_helm.sh $ ./get_helm.sh
2.1初始化
[root@master istio-1.1.5]# helm init [root@master istio-1.1.5]# helm version Client: &version.Version{SemVer:"v2.14.0", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"} Error: could not find a ready tiller pod //gcr.io/kubernetes-helm/tiller:v2.11.0镜像被墙,无法下载 [root@master ~]# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-fb8b8dccf-7dt66 1/1 Running 5 14d coredns-fb8b8dccf-7rt9b 1/1 Running 5 14d etcd-master 1/1 Running 3 14d kube-apiserver-master 1/1 Running 3 14d kube-controller-manager-master 1/1 Running 3 14d kube-flannel-ds-amd64-dpdws 1/1 Running 13 14d kube-flannel-ds-amd64-k8xnf 1/1 Running 118 14d kube-flannel-ds-amd64-kmc5h 1/1 Running 1 13d kube-proxy-qjtsd 1/1 Running 3 14d kube-proxy-t6lpf 1/1 Running 3 14d kube-proxy-t77xh 1/1 Running 1 13d kube-scheduler-master 1/1 Running 3 14d tiller-deploy-765dcb8745-2vswr 0/1 ImagePullBackOff 0 18m
2.2解决办法1.helm reset
[root@master ~]# kubectl delete pod tiller-deploy-765dcb8745-2vswr -n kube-system pod "tiller-deploy-765dcb8745-2vswr" deleted [root@master istio-1.1.5]# docker search tiller:v2.14.0 NAME DESCRIPTION STARS OFFICIAL AUTOMATED hekai/gcr.io_kubernetes-helm_tiller_v2.14.0 FROM gcr.io/kubernetes-helm/tiller:v2.14.0 0 //[root@master ~]# helm init --service-account tiller --tiller-image hekai/gcr.io_kubernetes-helm_tiller_v2.14.0 --skip-refresh //[root@master ~]# helm init -i hekai/gcr.io_kubernetes-helm_tiller_v2.14.0 //更新tiller,使用docker上镜像 [root@master ~]# helm init --upgrade -i hekai/gcr.io_kubernetes-helm_tiller_v2.14.0 [root@master istio-1.1.5]# helm version Client: &version.Version{SemVer:"v2.14.0", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"} Server: &version.Version{SemVer:"v2.14.0", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"}
tiller默认被部署在k8s集群中的kube-system这个namespace下
[root@master istio-1.1.5]# kubectl get pod -n kube-system -l app=helm NAME READY STATUS RESTARTS AGE tiller-deploy-58f5d95b9c-vrbbg 1/1 Running 0 24h
3.给予helm的rbac管理权限
帮助:https://github.com/helm/helm/blob/master/docs/rbac.md
[root@master helm]# vim rbac-config.yaml 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
[root@master helm]]# kubectl create -f rbac-config.yaml serviceaccount "tiller" created clusterrolebinding "tiller" created [root@master helm]]# helm init --service-account tiller --history-max 200 [root@master ~]# helm init --upgrade -i hekai/gcr.io_kubernetes-helm_tiller_v2.14.0
[root@master helm]]# kubectl get sa -n kube-system
4.使用helm
//更新镜像仓库 [root@master helm]# helm repo update //查看帮助 [root@master helm]# helm --help //官方仓库,stable是稳定版,incubator预发版 https://hub.helm.sh/ https://hub.kubeapps.com //查看使用哪些仓库 [root@master helm]# helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com local http://127.0.0.1:8879/charts 常用命令,release管理: //搜索镜像 [root@master helm]# helm search redis
[root@master helm]# helm install --name redis stable/redis //安装时要事先准备好pv,下载安装的都在$HOME/.helm/cache/archive/目录下,把.tgz的文件解压然后tree redis查看 [root@master ~]# cd .helm/cache/archive/
[root@master archive]# ls
redis-8.0.5.tgz
[root@master archive]# tar -xzvf redis-8.0.5.tgz
[root@master archive]# ls
redis redis-8.0.5.tgz
[root@master archive]# cd redis/
[root@master redis]# ls
Chart.yaml ci README.md templates values-production.yaml values.yaml
//修改values.yaml,再根据values.yaml安装 [root@master helm]# helm install --name redis -f values.yaml stable/redis [root@master helm]# helm status redis //此命令有用,用于安装完后需要做哪些操作都有步骤 [root@master helm]# helm history redis //可以用于回滚 [root@master helm]# helm list
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE redis 1 Sat Jun 1 10:09:52 2019 DEPLOYED redis-8.0.5 5.0.5 default
[root@master helm]# helm delete --help [root@master helm]# helm delete --dry-run [root@master helm]# helm delete jenkins [root@master helm]# helm upgrade/rollback //结合history用于回滚 [root@master helm]# helm upgrade nginx-ingress stable/nginx-ingress --namespace ingress-nginx --install -f values.yaml
常用命令,chart管理: [root@master helm]# helm create //下载镜像 [root@master helm]# helm fetch [root@master helm]# helm get [root@master helm]# helm inspect stable/redis //打包本地 [root@master helm]# helm package ./
[root@master archive]# tree redis redis ├── Chart.yaml ├── ci │ ├── default-values.yaml │ ├── dev-values.yaml │ ├── production-sentinel-values.yaml │ ├── production-values.yaml │ ├── redisgraph-module-values.yaml │ └── redis-lib-values.yaml ├── README.md ├── templates │ ├── configmap.yaml │ ├── headless-svc.yaml │ ├── health-configmap.yaml │ ├── _helpers.tpl │ ├── metrics-deployment.yaml │ ├── metrics-prometheus.yaml │ ├── metrics-svc.yaml │ ├── networkpolicy.yaml │ ├── NOTES.txt │ ├── redis-master-statefulset.yaml │ ├── redis-master-svc.yaml │ ├── redis-rolebinding.yaml │ ├── redis-role.yaml │ ├── redis-serviceaccount.yaml │ ├── redis-slave-statefulset.yaml │ ├── redis-slave-svc.yaml │ ├── redis-with-sentinel-svc.yaml │ └── secret.yaml ├── values-production.yaml └── values.yaml 2 directories, 29 files
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//模板语法 [root@master archive]# cat redis/templates/redis-master-statefulset.yaml apiVersion: apps/v1beta2 kind: StatefulSet metadata: name: {{ template "redis.fullname" . }}-master labels: app: {{ template "redis.name" . }} chart: {{ template "redis.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" spec: selector: matchLabels: release: "{{ .Release.Name }}" role: master app: {{ template "redis.name" . }} serviceName: {{ template "redis.fullname" . }}-headless template: metadata: labels: release: "{{ .Release.Name }}" chart: {{ template "redis.chart" . }} role: master app: {{ template "redis.name" . }} {{- if .Values.master.podLabels }} {{ toYaml .Values.master.podLabels | indent 8 }} {{- end }} annotations: checksum/health: {{ include (print $.Template.BasePath "/health-configmap.yaml") . | sha256sum }} checksum/configmap: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} {{- if .Values.master.podAnnotations }} {{ toYaml .Values.master.podAnnotations | indent 8 }} {{- end }} spec: {{- include "redis.imagePullSecrets" . | indent 6 }} {{- if .Values.securityContext.enabled }} securityContext: fsGroup: {{ .Values.securityContext.fsGroup }} {{- end }} serviceAccountName: "{{ template "redis.serviceAccountName" . }}" {{- if .Values.master.priorityClassName }} priorityClassName: "{{ .Values.master.priorityClassName }}" {{- end }} {{- with .Values.master.affinity }} affinity: {{ tpl (toYaml .) $ | indent 8 }} {{- end }} {{- if .Values.master.nodeSelector }} nodeSelector: {{ toYaml .Values.master.nodeSelector | indent 8 }} {{- end }} {{- if .Values.master.tolerations }} tolerations: {{ toYaml .Values.master.tolerations | indent 8 }} {{- end }} {{- if .Values.master.schedulerName }} schedulerName: "{{ .Values.master.schedulerName }}" {{- end }} containers: - name: {{ template "redis.fullname" . }} image: "{{ template "redis.image" . }}" imagePullPolicy: {{ .Values.image.pullPolicy | quote }} {{- if .Values.securityContext.enabled }} securityContext: runAsUser: {{ .Values.securityContext.runAsUser }} {{- end }} command: - /bin/bash - -c - | if [[ -n $REDIS_PASSWORD_FILE ]]; then password_aux=`cat ${REDIS_PASSWORD_FILE}` export REDIS_PASSWORD=$password_aux fi if [[ ! -f /opt/bitnami/redis/etc/master.conf ]];then cp /opt/bitnami/redis/mounted-etc/master.conf /opt/bitnami/redis/etc/master.conf fi if [[ ! -f /opt/bitnami/redis/etc/redis.conf ]];then cp /opt/bitnami/redis/mounted-etc/redis.conf /opt/bitnami/redis/etc/redis.conf fi ARGS=("--port" "${REDIS_PORT}") {{- if .Values.usePassword }} ARGS+=("--requirepass" "${REDIS_PASSWORD}") {{- else }} ARGS+=("--protected-mode" "no") {{- end }} ARGS+=("--include" "/opt/bitnami/redis/etc/redis.conf") ARGS+=("--include" "/opt/bitnami/redis/etc/master.conf") {{- if .Values.master.command }} {{ .Values.master.command }} ${ARGS[@]} {{- else }} redis-server "${ARGS[@]}" {{- end }} env: - name: REDIS_REPLICATION_MODE value: master {{- if .Values.usePassword }} {{- if .Values.usePasswordFile }} - name: REDIS_PASSWORD_FILE value: "/opt/bitnami/redis/secrets/redis-password" {{- else }} - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: {{ template "redis.secretName" . }} key: redis-password {{- end }} {{- else }} - name: ALLOW_EMPTY_PASSWORD value: "yes" {{- end }} - name: REDIS_PORT value: {{ .Values.redisPort | quote }} ports: - name: redis containerPort: {{ .Values.redisPort }} {{- if .Values.master.livenessProbe.enabled }} livenessProbe: initialDelaySeconds: {{ .Values.master.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.master.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.master.livenessProbe.timeoutSeconds }} successThreshold: {{ .Values.master.livenessProbe.successThreshold }} failureThreshold: {{ .Values.master.livenessProbe.failureThreshold }} exec: command: - sh - -c - /health/ping_local.sh {{ .Values.master.livenessProbe.timeoutSeconds }} {{- end }} {{- if .Values.master.readinessProbe.enabled}} readinessProbe: initialDelaySeconds: {{ .Values.master.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.master.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.master.readinessProbe.timeoutSeconds }} successThreshold: {{ .Values.master.readinessProbe.successThreshold }} failureThreshold: {{ .Values.master.readinessProbe.failureThreshold }} exec: command: - sh - -c - /health/ping_local.sh {{ .Values.master.livenessProbe.timeoutSeconds }} {{- end }} resources: {{ toYaml .Values.master.resources | indent 10 }} volumeMounts: - name: health mountPath: /health {{- if .Values.usePasswordFile }} - name: redis-password mountPath: /opt/bitnami/redis/secrets/ {{- end }} - name: redis-data mountPath: {{ .Values.master.persistence.path }} subPath: {{ .Values.master.persistence.subPath }} - name: config mountPath: /opt/bitnami/redis/mounted-etc - name: redis-tmp-conf mountPath: /opt/bitnami/redis/etc/ {{- if and .Values.cluster.enabled .Values.sentinel.enabled }} - name: sentinel image: "{{ template "sentinel.image" . }}" imagePullPolicy: {{ .Values.sentinel.image.pullPolicy | quote }} {{- if .Values.securityContext.enabled }} securityContext: runAsUser: {{ .Values.securityContext.runAsUser }} {{- end }} command: - /bin/bash - -c - | if [[ -n $REDIS_PASSWORD_FILE ]]; then password_aux=`cat ${REDIS_PASSWORD_FILE}` export REDIS_PASSWORD=$password_aux fi if [[ ! -f /opt/bitnami/redis-sentinel/etc/sentinel.conf ]];then cp /opt/bitnami/redis-sentinel/mounted-etc/sentinel.conf /opt/bitnami/redis-sentinel/etc/sentinel.conf {{- if .Values.usePassword }} printf "\nsentinel auth-pass {{ .Values.sentinel.masterSet }} $REDIS_PASSWORD" >> /opt/bitnami/redis-sentinel/etc/sentinel.conf {{- end }} fi echo "Getting information about current running sentinels" # Get information from existing sentinels existing_sentinels=$(timeout -s 9 {{ .Values.sentinel.initialCheckTimeout }} redis-cli --raw -h {{ template "redis.fullname" . }} -a $REDIS_PASSWORD -p {{ .Values.sentinel.service.sentinelPort }} SENTINEL sentinels {{ .Values.sentinel.masterSet }}) echo "$existing_sentinels" | awk -f /health/parse_sentinels.awk | tee -a /opt/bitnami/redis-sentinel/etc/sentinel.conf redis-server /opt/bitnami/redis-sentinel/etc/sentinel.conf --sentinel env: {{- if .Values.usePassword }} {{- if .Values.usePasswordFile }} - name: REDIS_PASSWORD_FILE value: "/opt/bitnami/redis/secrets/redis-password" {{- else }} - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: {{ template "redis.secretName" . }} key: redis-password {{- end }} {{- else }} - name: ALLOW_EMPTY_PASSWORD value: "yes" {{- end }} - name: REDIS_SENTINEL_PORT value: {{ .Values.sentinel.port | quote }} ports: - name: redis-sentinel containerPort: {{ .Values.sentinel.port }} {{- if .Values.sentinel.livenessProbe.enabled }} livenessProbe: initialDelaySeconds: {{ .Values.sentinel.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.sentinel.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.sentinel.livenessProbe.timeoutSeconds }} successThreshold: {{ .Values.sentinel.livenessProbe.successThreshold }} failureThreshold: {{ .Values.sentinel.livenessProbe.failureThreshold }} exec: command: - sh - -c - /health/ping_sentinel.sh {{ .Values.sentinel.livenessProbe.timeoutSeconds }} {{- end }} {{- if .Values.sentinel.readinessProbe.enabled}} readinessProbe: initialDelaySeconds: {{ .Values.sentinel.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.sentinel.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.sentinel.readinessProbe.timeoutSeconds }} successThreshold: {{ .Values.sentinel.readinessProbe.successThreshold }} failureThreshold: {{ .Values.sentinel.readinessProbe.failureThreshold }} exec: command: - sh - -c - /health/ping_sentinel.sh {{ .Values.sentinel.livenessProbe.timeoutSeconds }} {{- end }} resources: {{ toYaml .Values.sentinel.resources | indent 10 }} volumeMounts: - name: health mountPath: /health {{- if .Values.usePasswordFile }} - name: redis-password mountPath: /opt/bitnami/redis/secrets/ {{- end }} - name: redis-data mountPath: {{ .Values.master.persistence.path }} subPath: {{ .Values.master.persistence.subPath }} - name: config mountPath: /opt/bitnami/redis-sentinel/mounted-etc - name: sentinel-tmp-conf mountPath: /opt/bitnami/redis-sentinel/etc/ {{- end }} {{- $needsVolumePermissions := and .Values.volumePermissions.enabled (and ( and .Values.master.persistence.enabled (not .Values.persistence.existingClaim) ) .Values.securityContext.enabled) }} {{- if or $needsVolumePermissions .Values.sysctlImage.enabled }} initContainers: {{- if $needsVolumePermissions }} - name: volume-permissions image: "{{ template "redis.volumePermissions.image" . }}" imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} command: ["/bin/chown", "-R", "{{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }}", "{{ .Values.master.persistence.path }}"] securityContext: runAsUser: 0 resources: {{ toYaml .Values.volumePermissions.resources | indent 10 }} volumeMounts: - name: redis-data mountPath: {{ .Values.master.persistence.path }} subPath: {{ .Values.master.persistence.subPath }} {{- end }} {{- if .Values.sysctlImage.enabled }} - name: init-sysctl image: {{ template "redis.sysctl.image" . }} imagePullPolicy: {{ default "" .Values.sysctlImage.pullPolicy | quote }} resources: {{ toYaml .Values.sysctlImage.resources | indent 10 }} {{- if .Values.sysctlImage.mountHostSys }} volumeMounts: - name: host-sys mountPath: /host-sys {{- end }} command: {{ toYaml .Values.sysctlImage.command | indent 10 }} securityContext: privileged: true runAsUser: 0 {{- end }} {{- end }} volumes: - name: health configMap: name: {{ template "redis.fullname" . }}-health defaultMode: 0755 {{- if .Values.usePasswordFile }} - name: redis-password secret: secretName: {{ template "redis.secretName" . }} {{- end }} - name: config configMap: name: {{ template "redis.fullname" . }} {{- if not .Values.master.persistence.enabled }} - name: "redis-data" emptyDir: {} {{- else }} {{- if .Values.persistence.existingClaim }} - name: "redis-data" persistentVolumeClaim: claimName: {{ .Values.persistence.existingClaim }} {{- end }} {{- end }} {{- if .Values.sysctlImage.mountHostSys }} - name: host-sys hostPath: path: /sys {{- end }} - name: redis-tmp-conf emptyDir: {} {{- if and .Values.cluster.enabled .Values.sentinel.enabled }} - name: sentinel-tmp-conf emptyDir: {} {{- end }} {{- if and .Values.master.persistence.enabled (not .Values.persistence.existingClaim) }} volumeClaimTemplates: - metadata: name: redis-data labels: app: "{{ template "redis.name" . }}" component: "master" release: {{ .Release.Name | quote }} heritage: {{ .Release.Service | quote }} spec: accessModes: {{- range .Values.master.persistence.accessModes }} - {{ . | quote }} {{- end }} resources: requests: storage: {{ .Values.master.persistence.size | quote }} {{- if .Values.master.persistence.storageClass }} {{- if (eq "-" .Values.master.persistence.storageClass) }} storageClassName: "" {{- else }} storageClassName: {{ .Values.master.persistence.storageClass | quote }} {{- end }} {{- end }} {{- end }} updateStrategy: type: {{ .Values.master.statefulset.updateStrategy }} {{- if .Values.master.statefulset.rollingUpdatePartition }} {{- if (eq "Recreate" .Values.master.statefulset.updateStrategy) }} rollingUpdate: null {{- else }} rollingUpdate: partition: {{ .Values.master.statefulset.rollingUpdatePartition }} {{- end }} {{- end }}
用法:
https://helm.sh/docs/
https://www.kubernetes.org.cn/3435.html