フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【手順あり】実際にやって学ぶ「kubernetes Helm」のChartの作り方

f:id:lirlia:20200415031332p:plain

この記事ではHelmのChart(チャート)の作り方と公開方法を紹介します。

前の記事はこちら→ 【手順あり】実際に使ってみて学ぼう「kubernetes Helm」とは? - フラミナル

環境

名前 バージョン
OS CentOS Linux release 7.6.1810 (Core)
kubelet v1.18.1
kubeadm v1.18.1
docker v1.13.1
Helm v2.16.5

作業手順

前提

  • kubernetesがインストール済みである
  • Helm Clientがインストール済みである
  • Helm initが完了している

終わってない場合はこちらの記事の内容を実施してください。

【手順あり】実際に使ってみて学ぼう「kubernetes Helm」とは? - フラミナル

Helmチャートの雛形作成

まずは雛形を作ります。

[root@master helm-practice]# helm create sample-chart
Creating sample-chart

そうするとこのようなファイル群が作成されます。

[root@master helm-practice]# tree sample-chart/
sample-chart/
|-- Chart.yaml
|-- charts
|-- templates
|   |-- NOTES.txt
|   |-- _helpers.tpl
|   |-- deployment.yaml
|   |-- ingress.yaml
|   |-- service.yaml
|   |-- serviceaccount.yaml
|   `-- tests
|       `-- test-connection.yaml
`-- values.yaml
  
3 directories, 9 files

全て使う必要はないのですが代表的なものが含まれています。


Helmのパッケージはテンプレート変数ファイルで成り立っています。変数ファイルで指定された変数をテンプレートに埋め込み、それをHelmのtiller podに渡しています。

テンプレート(sample-chart/templates/service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: {{ include "sample-chart.fullname" . }}
  labels:
{{ include "sample-chart.labels" . | indent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: {{ include "sample-chart.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}

変数ファイル(sample-chart/values.yaml)

 Default values for sample-chart.
# 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: ""
  
serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name:
  
podSecurityContext: {}
  # fsGroup: 2000
  
securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000
  
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: {}

テンプレート(sample-chart/templates/service.yaml)の修正

NodePortで提供したいので変更しましょう。

apiVersion: v1
kind: Service
metadata:
  name: {{ include "sample-chart.fullname" . }}
  labels:
{{ include "sample-chart.labels" . | indent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
+     nodePort: {{ .Values.service.nodePort }}
  selector:
    app.kubernetes.io/name: {{ include "sample-chart.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}

変数ファイル(sample-chart/values.yaml)の修正

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000
  
service:
- type: ClusterIP
+ type: NodePort
  port: 80
+ nodePort: 30088
  
ingress:
  enabled: false
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths: []

Helmチャートを実行してみる

今作ったチャートを実行してみましょう。

[root@master helm-practice]# helm install --name sample-helm sample-chart 
NAME:   sample-helm
LAST DEPLOYED: Tue Apr 14 19:09:11 2020
NAMESPACE: default
STATUS: DEPLOYED
  
RESOURCES:
==> v1/Deployment
NAME                      READY  UP-TO-DATE  AVAILABLE  AGE
sample-helm-sample-chart  0/1    1           0          0s
  
==> v1/Pod(related)
NAME                                      READY  STATUS             RESTARTS  AGE
sample-helm-sample-chart-b5bc67674-m4c6c  0/1    ContainerCreating  0         1s
  
==> v1/Service
NAME                      TYPE      CLUSTER-IP      EXTERNAL-IP  PORT(S)       AGE
sample-helm-sample-chart  NodePort  10.107.170.223  <none>       80:30088/TCP  0s
  
==> v1/ServiceAccount
NAME                      SECRETS  AGE
sample-helm-sample-chart  1        0s
  
  
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services sample-helm-sample-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

起動の確認をします。

[root@master helm-practice]# kubectl get pods |grep sample
sample-helm-sample-chart-b5bc67674-m4c6c   1/1     Running   0          97s
[root@master helm-practice]# 
[root@master helm-practice]# kubectl get svc | grep sample
sample-helm-sample-chart   NodePort    10.107.170.223   <none>        80:30088/TCP   2m11s

NodePortも問題なく指定できていますね。curlを叩くとアクセスもできます。

[root@master helm-practice]# curl 0.0.0.0:30088
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
  
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
  
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

もう使わないので削除しましょう。

[root@master helm-practice]# helm delete sample-helm
release "sample-helm" deleted

作ったチャートをパッケージ化して公開しよう

チャートのパッケージ化

まずは作ったチャートをtgz形式にパッケージ化します。

[root@master helm-practice]# helm package --dependency-update --save=false ./sample-chart/
No requirements found in /home/vagrant/k8s-sample/helm-practice/sample-chart/charts.
Successfully packaged chart and saved it to: /home/vagrant/k8s-sample/helm-practice/sample-chart-0.1.0.tgz

そしてリポジトリ用のindex.yamlを生成します。

[root@master helm-practice]# helm repo index .
[root@master helm-practice]# cat index.yaml 
apiVersion: v1
entries:
  sample-chart:
  - apiVersion: v1
    appVersion: "1.0"
    created: "2020-04-14T19:24:27.135096708Z"
    description: A Helm chart for Kubernetes
    digest: 329f538550d312826a6ae2554a4e5e4da939d37baa02078d7a98c9692c458e81
    name: sample-chart
    urls:
    - sample-chart-0.1.0.tgz
    version: 0.1.0
generated: "2020-04-14T19:24:27.133923454Z"

チャートをリポジトリへ追加

続いてこれをリポジトリに追加します。

今回はローカルにWebサーバを立ち上げてそこに置いてみることにします。

[root@master helm-practice]# python -m SimpleHTTPServer 30000 &
[1] 16411

このコマンドで先ほどsample-chart-0.1.0.tgzを作ったところをルートディレクトリとするHTTPサーバが起動しました。ブラウザでアクセスするとこんな風に見えます。

f:id:lirlia:20200415042210p:plain

これをhelmのリポジトリに追加してあげましょう。myrepoという名前で登録してみます。

[root@master helm-practice]# helm repo add myrepo http://0.0.0.0:30000
127.0.0.1 - - [14/Apr/2020 19:25:04] "GET /index.yaml HTTP/1.1" 200 -
"myrepo" has been added to your repositories

無事登録ができたらhelm searchで作ったものを検索しましょう。

[root@master helm-practice]# helm search sample-chart
NAME                    CHART VERSION   APP VERSION     DESCRIPTION                
myrepo/sample-chart     0.1.0           1.0             A Helm chart for Kubernetes

作ったチャートをkubernetesに適用してみる

では、おいたHelmチャートを実際に使ってみましょう!

[root@master helm-practice]# helm install sample-chart --name sample-chart-from-myrepo
NAME:   sample-chart-from-myrepo
LAST DEPLOYED: Tue Apr 14 19:27:12 2020
NAMESPACE: default
STATUS: DEPLOYED
  
RESOURCES:
==> v1/Deployment
NAME                      READY  UP-TO-DATE  AVAILABLE  AGE
sample-chart-from-myrepo  0/1    1           0          0s
  
==> v1/Pod(related)
NAME                                       READY  STATUS             RESTARTS  AGE
sample-chart-from-myrepo-58dc894c44-zxmpd  0/1    ContainerCreating  0         0s
  
==> v1/Service
NAME                      TYPE      CLUSTER-IP     EXTERNAL-IP  PORT(S)       AGE
sample-chart-from-myrepo  NodePort  10.104.137.39  <none>       80:30088/TCP  0s
  
==> v1/ServiceAccount
NAME                      SECRETS  AGE
sample-chart-from-myrepo  1        0s
  
  
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services sample-chart-from-myrepo)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

ここまでできたら先ほど同様に動作チェックです。

[root@master helm-practice]# kubectl get pods | grep myrepo
sample-chart-from-myrepo-58dc894c44-zxmpd   1/1     Running   0          2m2s
[root@master helm-practice]#      
[root@master helm-practice]# kubectl get svc | grep myrepo
sample-chart-from-myrepo   NodePort    10.104.137.39    <none>        80:30088/TCP   2m13s
[root@master helm-practice]# 
[root@master helm-practice]# 
[root@master helm-practice]# curl 0.0.0.0:30088
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
  
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
  
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

以上で終了です、お疲れ様でした。

いかがだったでしょうか。Helmでのチャート管理と公開が意外に簡単にできたんじゃないかと思います。

参考

こちらはHelmをもう少し学んでみたい方向けの書籍です。