一、简单例子

我们创建一个Chart:

  1. # helm create hello-helm

可以看到其目录结构如下:

  1. [root@master helm]# tree hello-helm/
  2. hello-helm/
  3. ├── charts
  4. ├── Chart.yaml
  5. ├── templates
  6. ├── deployment.yaml
  7. ├── _helpers.tpl
  8. ├── ingress.yaml
  9. ├── NOTES.txt
  10. ├── service.yaml
  11. └── tests
  12. └── test-connection.yaml
  13. └── values.yaml

这是一个Nginx服务,我们修改其镜像(values.yaml):

  1. ...
  2. replicaCount: 1
  3. image:
  4. repository: nginx
  5. tag: 1.7.9
  6. pullPolicy: IfNotPresent
  7. ...

然后安装这个Helm:

  1. # helm install ./hello-helm/
  2. NAME: winning-crab
  3. LAST DEPLOYED: Wed Nov 6 14:36:45 2019
  4. NAMESPACE: default
  5. STATUS: DEPLOYED
  6. RESOURCES:
  7. ==> v1/Deployment
  8. NAME READY UP-TO-DATE AVAILABLE AGE
  9. winning-crab-hello-helm 0/1 0 0 0s
  10. ==> v1/Pod(related)
  11. NAME READY STATUS RESTARTS AGE
  12. winning-crab-hello-helm-6f59ffc587-x8lrs 0/1 Pending 0 0s
  13. ==> v1/Service
  14. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  15. winning-crab-hello-helm ClusterIP 10.68.12.232 <none> 80/TCP 0s
  16. NOTES:
  17. 1. Get the application URL by running these commands:
  18. export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=hello-helm,app.kubernetes.io/instance=winning-crab" -o jsonpath="{.items[0].metadata.name}")
  19. echo "Visit http://127.0.0.1:8080 to use your application"
  20. kubectl port-forward $POD_NAME 8080:80

这样就安装成功了,我们可以查看其Service和Pod:

  1. # kubectl get svc
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 62d
  4. winning-crab-hello-helm ClusterIP 10.68.12.232 <none> 80/TCP 7m5s
  5. # kubectl get pod
  6. NAME READY STATUS RESTARTS AGE
  7. winning-crab-hello-helm-6f59ffc587-x8lrs 1/1 Running 0 7m9s

查看release:

  1. [root@master hello-helm]# helm list
  2. NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
  3. winning-crab 1 Wed Nov 6 14:36:45 2019 DEPLOYED hello-helm-0.1.0 1.0 default

打包chart:

  1. # helm package hello-helm
  2. Successfully packaged chart and saved it to: /root/k8s/helm/hello-helm-0.1.0.tgz

然后我们就可以将打包的tgz文件分发到任意的服务器上,通过helm fetch就可以获取到该 Chart 了。

删除release:

  1. # helm list
  2. NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
  3. winning-crab 1 Wed Nov 6 14:36:45 2019 DEPLOYED hello-helm-0.1.0 1.0 default
  4. # helm delete winning-crab
  5. release "winning-crab" deleted
  6. # helm list
  7. #

二、常用操作

2.1、查找chart

命令:

  1. # helm search
  2. # helm search mysql

2.2、查看chart详情

命令:

  1. # helm inspect stable/mysql

2.3、安装chart

命令:

  1. # helm install stable/mysql

如果要自定义release名字使用如下命令:

  1. # helm install stable/mysql --name mydb

2.4、查看release状态

  1. # helm status mydb

2.5、自定义chart

首先通过helm inspect values命令来查看可配置选项。
如下:

  1. # helm inspect values stable/mysql
  2. ## mysql image version
  3. ## ref: https://hub.docker.com/r/library/mysql/tags/
  4. ##
  5. image: "mysql"
  6. imageTag: "5.7.14"
  7. busybox:
  8. image: "busybox"
  9. tag: "1.29.3"
  10. testFramework:
  11. image: "dduportal/bats"
  12. tag: "0.4.0"
  13. ## Specify password for root user
  14. ##
  15. ## Default: random 10 character string
  16. # mysqlRootPassword: testing
  17. ## Create a database user
  18. ##
  19. # mysqlUser:
  20. ## Default: random 10 character string
  21. # mysqlPassword:
  22. ## Allow unauthenticated access, uncomment to enable
  23. ##
  24. # mysqlAllowEmptyPassword: true
  25. ## Create a database
  26. ##
  27. # mysqlDatabase:
  28. ## Specify an imagePullPolicy (Required)
  29. ## It's recommended to change this to 'Always' if the image tag is 'latest'
  30. ## ref: http://kubernetes.io/docs/user-guide/images/#updating-images
  31. ##
  32. imagePullPolicy: IfNotPresent
  33. ## Additionnal arguments that are passed to the MySQL container.
  34. ## For example use --default-authentication-plugin=mysql_native_password if older clients need to
  35. ## connect to a MySQL 8 instance.
  36. args: []
  37. extraVolumes: |
  38. # - name: extras
  39. # emptyDir: {}
  40. extraVolumeMounts: |
  41. # - name: extras
  42. # mountPath: /usr/share/extras
  43. # readOnly: true
  44. extraInitContainers: |
  45. # - name: do-something
  46. # image: busybox
  47. # command: ['do', 'something']
  48. # Optionally specify an array of imagePullSecrets.
  49. # Secrets must be manually created in the namespace.
  50. # ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
  51. # imagePullSecrets:
  52. # - name: myRegistryKeySecretName
  53. ## Node selector
  54. ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
  55. nodeSelector: {}
  56. ## Tolerations for pod assignment
  57. ## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
  58. ##
  59. tolerations: []
  60. livenessProbe:
  61. initialDelaySeconds: 30
  62. periodSeconds: 10
  63. timeoutSeconds: 5
  64. successThreshold: 1
  65. failureThreshold: 3
  66. readinessProbe:
  67. initialDelaySeconds: 5
  68. periodSeconds: 10
  69. timeoutSeconds: 1
  70. successThreshold: 1
  71. failureThreshold: 3
  72. ## Persist data to a persistent volume
  73. persistence:
  74. enabled: true
  75. ## database data Persistent Volume Storage Class
  76. ## If defined, storageClassName: <storageClass>
  77. ## If set to "-", storageClassName: "", which disables dynamic provisioning
  78. ## If undefined (the default) or set to null, no storageClassName spec is
  79. ## set, choosing the default provisioner. (gp2 on AWS, standard on
  80. ## GKE, AWS & OpenStack)
  81. ##
  82. # storageClass: "-"
  83. accessMode: ReadWriteOnce
  84. size: 8Gi
  85. annotations: {}
  86. ## Use an alternate scheduler, e.g. "stork".
  87. ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
  88. ##
  89. # schedulerName:
  90. ## Security context
  91. securityContext:
  92. enabled: false
  93. runAsUser: 999
  94. fsGroup: 999
  95. ## Configure resource requests and limits
  96. ## ref: http://kubernetes.io/docs/user-guide/compute-resources/
  97. ##
  98. resources:
  99. requests:
  100. memory: 256Mi
  101. cpu: 100m
  102. # Custom mysql configuration files path
  103. configurationFilesPath: /etc/mysql/conf.d/
  104. # Custom mysql configuration files used to override default mysql settings
  105. configurationFiles: {}
  106. # mysql.cnf: |-
  107. # [mysqld]
  108. # skip-name-resolve
  109. # ssl-ca=/ssl/ca.pem
  110. # ssl-cert=/ssl/server-cert.pem
  111. # ssl-key=/ssl/server-key.pem
  112. # Custom mysql init SQL files used to initialize the database
  113. initializationFiles: {}
  114. # first-db.sql: |-
  115. # CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
  116. # second-db.sql: |-
  117. # CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
  118. metrics:
  119. enabled: false
  120. image: prom/mysqld-exporter
  121. imageTag: v0.10.0
  122. imagePullPolicy: IfNotPresent
  123. resources: {}
  124. annotations: {}
  125. # prometheus.io/scrape: "true"
  126. # prometheus.io/port: "9104"
  127. livenessProbe:
  128. initialDelaySeconds: 15
  129. timeoutSeconds: 5
  130. readinessProbe:
  131. initialDelaySeconds: 5
  132. timeoutSeconds: 1
  133. flags: []
  134. serviceMonitor:
  135. enabled: false
  136. additionalLabels: {}
  137. ## Configure the service
  138. ## ref: http://kubernetes.io/docs/user-guide/services/
  139. service:
  140. annotations: {}
  141. ## Specify a service type
  142. ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types
  143. type: ClusterIP
  144. port: 3306
  145. # nodePort: 32000
  146. # loadBalancerIP:
  147. ssl:
  148. enabled: false
  149. secret: mysql-ssl-certs
  150. certificates:
  151. # - name: mysql-ssl-certs
  152. # ca: |-
  153. # -----BEGIN CERTIFICATE-----
  154. # ...
  155. # -----END CERTIFICATE-----
  156. # cert: |-
  157. # -----BEGIN CERTIFICATE-----
  158. # ...
  159. # -----END CERTIFICATE-----
  160. # key: |-
  161. # -----BEGIN RSA PRIVATE KEY-----
  162. # ...
  163. # -----END RSA PRIVATE KEY-----
  164. ## Populates the 'TZ' system timezone environment variable
  165. ## ref: https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html
  166. ##
  167. ## Default: nil (mysql will use image's default timezone, normally UTC)
  168. ## Example: 'Australia/Sydney'
  169. # timezone:
  170. # Deployment Annotations
  171. deploymentAnnotations: {}
  172. # To be added to the database server pod(s)
  173. podAnnotations: {}
  174. podLabels: {}
  175. ## Set pod priorityClassName
  176. # priorityClassName: {}
  177. ## Init container resources defaults
  178. initContainer:
  179. resources:
  180. requests:
  181. memory: 10Mi
  182. cpu: 10m

然后,我们可以直接在 YAML 格式的文件中来覆盖上面的任何配置,在安装的时候直接使用该配置文件即可:(config.yaml)

  1. mysqlUser: unclejoker
  2. mysqlDatabase: jokerDB
  3. service:
  4. type: NodePort

我们这里通过 config.yaml 文件定义了 mysqlUser 和 mysqlDatabase,并且把 service 的类型更改为了NodePort,然后现在我们来安装的时候直接指定该 yaml 文件:

  1. # helm install -f config.yaml stable/mysql --name mydb
  2. NAME: mydb
  3. LAST DEPLOYED: Wed Nov 6 15:27:01 2019
  4. NAMESPACE: default
  5. STATUS: DEPLOYED
  6. RESOURCES:
  7. ==> v1/ConfigMap
  8. NAME DATA AGE
  9. mydb-mysql-test 1 1s
  10. ...

可以看到release的名字是我们定义的mydb:

  1. # helm list
  2. NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
  3. mydb 1 Wed Nov 6 15:27:01 2019 DEPLOYED mysql-1.3.1 5.7.14 default

其service也变成了我们config.yaml中定义的nodeport:

  1. # kubectl get svc
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 62d
  4. mydb-mysql NodePort 10.68.108.76 <none> 3306:33158/TCP 83s
  5. [root@master helm]# kubectl get pod
  6. NAME READY STATUS RESTARTS AGE
  7. mydb-mysql-8d746574b-8b2n7 0/1 Pending 0 88s

而其中pod处于pending的状态原因如下:

  1. Events:
  2. Type Reason Age From Message
  3. ---- ------ ---- ---- -------
  4. Warning FailedScheduling 79s (x2 over 2m43s) default-scheduler pod has unbound immediate PersistentVolumeClaims (repeated 2 times)

我们可以发现两个 Pod 处于 Pending 状态的原因都是 PVC 没有被绑定上,所以这里我们可以通过 storageclass 或者手动创建一个合适的 PV 对象来解决这个问题。

2.6、升级

比如我们把上面的持久化禁用掉,改写config.yaml如下:

  1. mysqlUser: unclejoker
  2. mysqlDatabase: jokerDB
  3. service:
  4. type: NodePort
  5. persistence:
  6. enabled: false

然后执行以下命令:

  1. # helm upgrade -f config.yaml mydb stable/mysql
  2. Release "mydb" has been upgraded.

我们可以看到Pod的状态已经变了;

  1. # kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. mydb-mysql-897fcbfcd-jv96j 0/1 PodInitializing 0 28s

其日志并不是PVC的问题了:

  1. Events:
  2. Type Reason Age From Message
  3. ---- ------ ---- ---- -------
  4. Normal Scheduled 67s default-scheduler Successfully assigned default/mydb-mysql-897fcbfcd-jv96j to 172.16.1.129
  5. Normal Pulling 65s kubelet, 172.16.1.129 Pulling image "busybox:1.29.3"
  6. Normal Pulled 46s kubelet, 172.16.1.129 Successfully pulled image "busybox:1.29.3"
  7. Normal Created 46s kubelet, 172.16.1.129 Created container remove-lost-found
  8. Normal Started 46s kubelet, 172.16.1.129 Started container remove-lost-found
  9. Normal Pulling 45s kubelet, 172.16.1.129 Pulling image "mysql:5.7.14"

我们可以通过helm list查看release信息:

  1. # helm list
  2. NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
  3. mydb 2 Wed Nov 6 15:33:24 2019 DEPLOYED mysql-1.3.1 5.7.14 default

可以看到 mydb 这个 release 的REVISION已经变成2了,这是因为 release 的版本是递增的,每次安装、升级或者回滚,版本号都会加1,第一个版本号始终为1,同样我们可以使用 helm history 命令查看 release 的历史版本:

  1. # helm history mydb
  2. REVISION UPDATED STATUS CHART DESCRIPTION
  3. 1 Wed Nov 6 15:27:01 2019 SUPERSEDED mysql-1.3.1 Install complete
  4. 2 Wed Nov 6 15:33:24 2019 DEPLOYED mysql-1.3.1 Upgrade complete

2.7、回滚

命令如下:

  1. # helm rollback mydb 1

2.8、删除

命令如下:

  1. # helm delete mydb

这种删除并不会彻底删除,我们可以通过以下命令查看:

  1. # helm list --all
  2. NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
  3. mydb 2 Wed Nov 6 15:33:24 2019 DELETED mysql-1.3.1 5.7.14 default
  4. winning-crab 1 Wed Nov 6 14:36:45 2019 DELETED hello-helm-0.1.0 1.0 default

如果要彻底删除需要加上—purge参数:

  1. # helm delete mydb --purge