はじめに
kubernetes上で利用するパッケージ管理ツールにHelmがあります。HelmではChartというパッケージ単位でkubernetesのマニフェストを管理し、大量のマニフェストファイルの管理を手助けします。
Helm ver.2まではクライアントサイドのhelm
とサーバーサイドのTiller
という2つのコンポーネントで構成されていましたが、ver.3からTiller
が削除されるという大きな変更が行われました。
今回は新しく発表されたver.3のHelmを簡単に動かしてみます。
Helmとは
Helmはkubernetesマニフェストファイルを管理するパッケージ管理ツールです。kubernetesではマニフェストと呼ばれるファイルを利用してリソースをデプロイすることが多いですが、リソースが増えるにつれて管理する対象のマニフェストファイルも増加し、次第にそれらを管理するのが難しくなります。いわゆる「YAMLの壁」と呼ばれるような状態が生まれてしまいます。YAMLの壁を解決するため様々なパッケージ管理ツールが開発されたが、Helmもそのひとつと言ってよいと思います。
HelmではChartと呼ばれるパッケージ単位でマニフェストファイルを管理します。アプリケーションごとにchartを分けて管理することで、関連する複数のマニフェストファイルを管理し、管理しやすくすることができます。
またChartはリポジトリに格納・公開することで、複数ユーザーで利用できるようにしたり、バージョン管理をすることもできます。リポジトリの場所としてはクラウドストレージやgithub、ローカル環境など様々な環境を利用できます。
※参考リンク:
ver.3からの変更点
ver.3からいくつか大きな変更が行われたHelmについて、まずはHelm公式ページのFAQから変更点を紹介します。
FAQより(和訳+意訳)
Helm Documentation - Frequently Asked Questions
- Tillerの削除
- Helmはver.2までは
Tiller
を利用していました。Tiller
は複数の共有クラスター上で動作させるうえで重要な役割を担っていました。しかしKubernetes ver.1.6からでRBACがデフォルトで有効になってから、Tiller
を本番環境で管理するのが難しくなりました。(Helmを利用する環境には)膨大な数のセキュリティポリシーが存在したため、初めてのユーザーもセキュリティコントロールなしでHelm/Kubernetesを操作できるよう、寛容なセキュリティ設定にしていました。その結果、ユーザーに不要に強い権限を与えることになり、マルチテナントクラスターにTillerをインストールする際には、DevOps、SREは追加オペレーションが必要になっていました。 - コミュニティ内で意見を集め、調査をした結果、Helm ver.3からは、Tillerを完全に削除することにしました。Tillerを除いたことで、Helmのセキュリティモデルはシンプルになり、Helmの権限は
kubeconfig
ファイルで評価されます。クラスター管理者はユーザー権限を操作することができ、リリースの情報はクラスター内に記録され、Helmのその他の機能はそのまま維持しました。
- Helmはver.2までは
- upgrade時に3つのステータスを参照する
- Release NameはNamespaceにスコープされる
- tillerの削除に伴い、Releaseに関する情報は、同じNamespaceに保存される。これによりHelm ver.3では、同じ名前のreleaseを2つの異なるNamespaceできるようになりました。
- Secretリソースがデフォルトの保存ドライバになる
- JSON schemaによるバリデーションチェックの追加
- Chart作成時の
requirement.yaml
requirements.lock
はChart.yaml
Chart.lock
にそれぞれ移管 helm serve
の削除- Library Chartのサポート
- Library chartとは、他のchartに共有されますがそれ自身はreleaseに関する生成物を作成しないものです。Library chartは
Chart.yaml
で依存関係を記載することで、他のchartと同様にインストールして利用されます。
- Library chartとは、他のchartに共有されますがそれ自身はreleaseに関する生成物を作成しないものです。Library chartは
- CLIの名前が一部変更されました。なお古いコマンドも、現在はエイリアスとして利用することができます。
helm delete
->helm uninstall
helm inspect
->helm show
helm fetch
->helm pull
Helm ver.3のインストール(ver.2の削除)
ここから実際にHelm ver.3をダウンロードし、利用してみます。まず利用している環境からver.2のHelmを利用するための設定を削除し、その後Helm ver.3のバイナリファイルをダウンロードします。
# Helm ver.3を利用するためのリソースを削除 # Helm ver.2が存在しない場合は不要な手順 [root@kube-master01 ~]# kubectl delete deployment tiller-deploy -n kube-system deployment.extensions "tiller-deploy" deleted [root@kube-master01 ~]# kubectl delete service tiller-deploy -n kube-system service "tiller-deploy" deleted [root@kube-master01 ~]# helm version Client: &version.Version{SemVer:"v2.14.3", GitCommit:"0e7f3b6637f7af8fcfddb3d2941fcc7cbebb0085", GitTreeState:"clean"} Error: could not find tiller # Helm ver.3バイナリのダウンロード [root@kube-master01 ~]# wget https://get.helm.sh/helm-v3.0.0-beta.3-linux-amd64.tar.gz --2019-09-29 00:05:29-- https://get.helm.sh/helm-v3.0.0-beta.3-linux-amd64.tar.gz Resolving get.helm.sh (get.helm.sh)... 152.199.39.106, 2606:2800:247:b40:171d:1a2f:2077:f6b Connecting to get.helm.sh (get.helm.sh)|152.199.39.106|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 13097374 (12M) [application/x-tar] Saving to: ‘helm-v3.0.0-beta.3-linux-amd64.tar.gz’ 100%[==============================================================================>] 13,097,374 20.1MB/s in 0.6s 2019-09-29 00:05:30 (20.1 MB/s) - ‘helm-v3.0.0-beta.3-linux-amd64.tar.gz’ saved [13097374/13097374] [root@kube-master01 ~]# tar xzvf helm-v3.0.0-beta.3-linux-amd64.tar.gz linux-amd64/ linux-amd64/LICENSE linux-amd64/helm linux-amd64/README.md [root@kube-master01 ~]# cd linux-amd64/ [root@kube-master01 linux-amd64]# mv helm /usr/local/bin/ mv: overwrite ‘/usr/local/bin/helm’? y [root@kube-master01 linux-amd64]# helm version version.BuildInfo{Version:"v3.0.0-beta.3", GitCommit:"5cb923eecbe80d1ad76399aee234717c11931d9a", GitTreeState:"clean", GoVersion:"go1.12.9"} [root@kube-master01 linux-amd64]#
以上のようにHelm ver.3をインストールしました。これまではhelm version
コマンドでtillerの有無に関するエラーが表示されましたが、ver.3からは表示されなくなっています。
リポジトリの追加・インストール
次にchartを利用するためにリポジトリを追加し、インストールします。Helm ver.3からはデフォルトでリポジトリが追加されないため、公開されているリポジトリ等を利用するには、まずhelm repo add
コマンドで追加する必要があります。
Helm Hub - Discover & launch great Kubernetes-ready apps
# helm search [repo|hub]で検索する # helm search repoは登録済みリポジトリに含まれるchartを検索する [root@kube-master01 ~]# helm search repo wordpress Error: no repositories configured # helm search hubは公開されているHelm Hubに含まれるchartを検索する [root@kube-master01 ~]# helm search hub wordpress URL CHART VERSION APP VERSION DESCRIPTION https://hub.helm.sh/charts/presslabs/wordpress-... v0.5.1 v0.5.1 Presslabs WordPress Operator Helm Chart https://hub.helm.sh/charts/presslabs/wordpress-... v0.5.1 v0.5.1 A Helm chart for deploying a WordPress site on ... https://hub.helm.sh/charts/bitnami/wordpress 7.3.8 5.2.3 Web publishing platform for building blogs and ... https://hub.helm.sh/charts/stable/wordpress 7.3.8 5.2.3 Web publishing platform for building blogs and ... [root@kube-master01 ~]#
Helm ver.2では、helm init
で初期化した時点でリポジトリが追加されたため、すぐにchartをインストールできましたが、ver.3ではエラーが表示されます。
# デフォルトでは何のリポジトリも登録されていない [root@kube-master01 ~]# helm repo list Error: no repositories to show [root@kube-master01 ~]#
そのため、まずhelm repo add
コマンドによりリポジトリを追加します。今回はHelm公式のstableリポジトリを追加します。
# helm repo add [NAME] [URL] [root@kube-master01 ~]# helm repo add stable https://kubernetes-charts.storage.googleapis.com "stable" has been added to your repositories [root@kube-master01 ~]# helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com [root@kube-master01 ~]# helm search repo wordpress NAME CHART VERSION APP VERSION DESCRIPTION stable/wordpress 7.3.8 5.2.3 Web publishing platform for building blogs and ... [root@kube-master01 ~]#
以上のように追加すると、helm search repo
で検索結果が表示されるようになります。次にstableリポジトリを指定してWordpressをインストールします。
# 追加したリポジトリからwordpressをインストール [root@kube-master01 ~]# helm install wordpress stable/wordpress NAME: wordpress LAST DEPLOYED: 2019-10-02 14:18:09.936459344 +0000 UTC m=+2.651313567 NAMESPACE: default STATUS: deployed NOTES: 1. Get the WordPress URL: NOTE: It may take a few minutes for the LoadBalancer IP to be available. Watch the status with: 'kubectl get svc --namespace default -w wordpress' export SERVICE_IP=$(kubectl get svc --namespace default wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}") echo "WordPress URL: http://$SERVICE_IP/" echo "WordPress Admin URL: http://$SERVICE_IP/admin" 2. Login with the following credentials to see your blog echo Username: user echo Password: $(kubectl get secret --namespace default wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode) [root@kube-master01 ~]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART wordpress default 1 2019-10-02 14:18:09.936459344 +0000 UTC deployed wordpress-7.3.8 [root@kube-master01 ~]#
インストールが完了し、helm list
でwordpressが表示されるようになりました。ちなみにデプロイされたリソースは以下の通りです。
[root@kube-master01 ~]# kubectl get all NAME READY STATUS RESTARTS AGE pod/wordpress-7f7fb54955-7kknb 0/1 Pending 0 3m39s pod/wordpress-mariadb-0 0/1 Pending 0 3m39s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 60d service/wordpress LoadBalancer 10.99.246.205 192.168.1.240 80:32589/TCP,443:31718/TCP 3m39s service/wordpress-mariadb ClusterIP 10.102.73.2 <none> 3306/TCP 3m39s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/wordpress 0/1 1 0 3m39s NAME DESIRED CURRENT READY AGE replicaset.apps/wordpress-7f7fb54955 1 1 0 3m39s NAME READY AGE statefulset.apps/wordpress-mariadb 0/1 3m39s [root@kube-master01 ~]#
chartの生成・インストール
次にchartを自前で用意し、それをデプロイします。chartの雛形を生成するにはhelm create
コマンドを利用します。ver.2の時と比べ、ディレクトリ構成は多少変化しています。
# chartの生成 [root@kube-master01 ~]# helm create mychart Creating mychart [root@kube-master01 ~] # 生成されたchartのファイル構成を確認 [root@kube-master01 ~]# ls -l mychart/ total 8 -rw-r--r-- 1 root root 905 Sep 29 00:29 Chart.yaml drwxr-xr-x 2 root root 106 Sep 29 00:29 templates -rw-r--r-- 1 root root 1060 Sep 29 00:29 values.yaml [root@kube-master01 ~]# ls -l mychart/templates/ total 20 -rw-r--r-- 1 root root 1329 Sep 29 00:29 deployment.yaml -rw-r--r-- 1 root root 1415 Sep 29 00:29 _helpers.tpl -rw-r--r-- 1 root root 896 Sep 29 00:29 ingress.yaml -rw-r--r-- 1 root root 1292 Sep 29 00:29 NOTES.txt -rw-r--r-- 1 root root 409 Sep 29 00:29 service.yaml
生成された各ファイルは、それぞれ以下のように利用されます。
ファイル名 | 内容 |
---|---|
Chart.yaml | chart地震に関する定義を記載。バージョン情報など |
values.yaml | templates/配下の各ファイルに入れる変数を指定 |
templates/deployment.yaml | Deployment マニフェストを定義 |
templates/_helpers.tpl | template/配下で呼び出されるヘルパー関数。各ファイル内でtemplate の後ろに記載する |
templates/ingress.yaml | Ingress マニフェストを定義 |
templates/NOTES.txt | インストール完了後に表示するメッセージを定義 |
templates/service.yaml | service マニフェストを定義 |
各ファイルの内容は以下の通りです。
Chart.yaml
apiVersion: v2 name: mychart description: A Helm chart for Kubernetes # A chart can be either an 'application' or a 'library' chart. # # Application charts are a collection of templates that can be packaged into versioned archives # to be deployed. # # Library charts provide useful utilities or functions for the chart developer. They're included as # a dependency of application charts to inject those utilities and functions into the rendering # pipeline. Library charts do not define any templates and therefore cannot be deployed. type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. version: 0.1.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. appVersion: 1.16.0
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 pullPolicy: IfNotPresent nameOverride: "" fullnameOverride: "" 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: {}
templates/deployment.yaml
apiVersion: apps/v1beta2 kind: Deployment metadata: name: {{ template "mychart.fullname" . }} labels: {{ include "mychart.labels" . | indent 4 }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app.kubernetes.io/name: {{ include "mychart.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} template: metadata: labels: app.kubernetes.io/name: {{ include "mychart.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {{ toYaml .Values.resources | indent 12 }} {{- with .Values.nodeSelector }} nodeSelector: {{ toYaml . | indent 8 }} {{- end }} {{- with .Values.affinity }} affinity: {{ toYaml . | indent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{ toYaml . | indent 8 }} {{- end }}
templates/_helpers.tpl
{{/* vim: set filetype=mustache: */}} {{/* Expand the name of the chart. */}} {{- define "mychart.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} {{/* Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} {{- define "mychart.fullname" -}} {{- if .Values.fullnameOverride -}} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} {{- else -}} {{- $name := default .Chart.Name .Values.nameOverride -}} {{- if contains $name .Release.Name -}} {{- .Release.Name | trunc 63 | trimSuffix "-" -}} {{- else -}} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}} {{- end -}} {{- end -}} {{/* Create chart name and version as used by the chart label. */}} {{- define "mychart.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} {{/* Common labels */}} {{- define "mychart.labels" -}} app.kubernetes.io/name: {{ include "mychart.name" . }} helm.sh/chart: {{ include "mychart.chart" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}}
{{- if .Values.ingress.enabled -}} {{- $fullName := include "mychart.fullname" . -}} {{- $svcPort := .Values.service.port -}} apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: {{ $fullName }} labels: {{ include "mychart.labels" . | indent 4 }} {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 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: {{ .host | quote }} http: paths: {{- range .paths }} - path: {{ . }} backend: serviceName: {{ $fullName }} servicePort: {{ $svcPort }} {{- end }} {{- end }} {{- end }}
templates/NOTES.txt
1. Get the application URL by running these commands: {{- if .Values.ingress.enabled }} {{- range $host := .Values.ingress.hosts }} {{- range .paths }} http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} {{- end }} {{- end }} {{- else if contains "NodePort" .Values.service.type }} export NODE_PORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "mychart.fullname" . }}) export NODE_IP=$(kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT {{- else if contains "LoadBalancer" .Values.service.type }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. You can watch the status of by running 'kubectl get svc -w {{ template "mychart.fullname" . }}' export SERVICE_IP=$(kubectl get svc {{ template "mychart.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} export POD_NAME=$(kubectl get pods -l "app={{ template "mychart.name" . }},release={{ .Release.Name }}" -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 {{- end }}
templates/service.yaml
apiVersion: v1 kind: Service metadata: name: {{ template "mychart.fullname" . }} labels: {{ include "mychart.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 "mychart.name" . }} app.kubernetes.io/instance: {{ .Release.Name }}
生成したばかりのchartをインストールしてみます。
[root@kube-master01 ~]# helm install mychart ./mychart NAME: mychart LAST DEPLOYED: 2019-09-29 01:52:47.183933096 +0000 UTC m=+0.186553085 NAMESPACE: default STATUS: deployed NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods -l "app=mychart,release=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 # インストール後確認 [root@kube-master01 ~]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART mychart default 1 2019-09-29 01:52:47.183933096 +0000 UTC deployed mychart-0.1.0
またインストールしたchartの状態を詳細にみる場合はhelm show [chart名]
で確認できます。
helm show mychart
apiVersion: v2 appVersion: 1.16.0 description: A Helm chart for Kubernetes name: mychart type: application version: 0.1.0 --- affinity: {} fullnameOverride: "" image: pullPolicy: IfNotPresent repository: nginx ingress: annotations: {} enabled: false hosts: - host: chart-example.local paths: [] tls: [] nameOverride: "" nodeSelector: {} replicaCount: 1 resources: {} service: port: 80 type: ClusterIP tolerations: [] ---
最後にchartを削除します。
# mychartを削除する [root@kube-master01 ~]# helm uninstall mychart release "mychart" uninstalled [root@kube-master01 ~]# helm ls NAME NAMESPACE REVISION UPDATED STATUS CHART [root@kube-master01 ~]#
Local Repositoryにchartを保存する
次にローカルな環境にリポジトリを構築し、作成したchartを保存します。今回はテスト用のため、Chartmuseumの環境をHelmで構築し、先ほど作ったmychart
を格納します。そして、helm
コマンドで新しいリポジトリ上に格納されたことが確認できるまでを行います。
# chartを検索 [root@kube-master01 ~]# helm search repo chartmuseum NAME CHART VERSION APP VERSION DESCRIPTION stable/chartmuseum 2.3.2 0.8.2 Host your own Helm Chart Repository # インストール [root@kube-master01 ~]# helm install chartmuseum stable/chartmuseum NAME: chartmuseum LAST DEPLOYED: 2019-10-14 02:39:22.522212778 +0000 UTC m=+2.554448418 NAMESPACE: default STATUS: deployed NOTES: ** Please be patient while the chart is being deployed ** Get the ChartMuseum URL by running: export POD_NAME=$(kubectl get pods --namespace default -l "app=chartmuseum" -l "release=chartmuseum" -o jsonpath="{.items[0].metadata.name}") echo http://127.0.0.1:8080/ kubectl port-forward $POD_NAME 8080:8080 --namespace default [root@kube-master01 ~]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART chartmuseum default 1 2019-10-14 02:39:22.522212778 +0000 UTC deployed chartmuseum-2.3.2 [root@kube-master01 ~]#
次にインストール時に表示されたコマンドを実行し、chartmuseum
リポジトリにアクセスできるようにします。
# Podのデプロイされた場所を確認 [root@kube-master01 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES chartmuseum-chartmuseum-76d6cbc86c-qnm4w 1/1 Running 0 3m35s 192.168.132.53 kube-worker01 <none> <none> # port-forward [root@kube-master01 ~]# kubectl port-forward chartmuseum-chartmuseum-76d6cbc86c-qnm4w 8080:8080 --namespace default Forwarding from 127.0.0.1:8080 -> 8080 # 別コンソールを開き、curlコマンドで確認 [root@kube-master01 ~]# curl http://localhost:8080/ <!DOCTYPE html> <html> <head> <title>Welcome to ChartMuseum!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to ChartMuseum!</h1> <p>If you see this page, the ChartMuseum web server is successfully installed and working.</p> <p>For online documentation and support please refer to the <a href="https://github.com/helm/chartmuseum">GitHub project</a>.<br/> <p><em>Thank you for using ChartMuseum.</em></p> </body> </html> [root@kube-master01 ~]#
chartmuseum
リポジトリにアクセスできるようになったので、mychart
chartを配置する準備をします。chartをリポジトリに配置するのに必要なファイルはchart.tgz
index.yaml
の2つです。前者はhelm package
コマンドによりchartディレクトリをパッケージングして生成します。
# chartをパッケージング [root@kube-master01 ~]# ls -l total 16 -rw-r--r-- 1 3434 3434 11373 Sep 5 20:57 LICENSE drwxr-xr-x 3 root root 79 Sep 29 00:29 mychart -rw-r--r-- 1 3434 3434 3309 Sep 5 20:57 README.md [root@kube-master01 ~]# helm package mychart Successfully packaged chart and saved it to: /root/mychart-0.1.0.tgz [root@kube-master01 ~]# ls -l total 20 -rw-r--r-- 1 3434 3434 11373 Sep 5 20:57 LICENSE drwxr-xr-x 3 root root 79 Sep 29 00:29 mychart -rw-r--r-- 1 root root 2334 Oct 14 02:47 mychart-0.1.0.tgz -rw-r--r-- 1 3434 3434 3309 Sep 5 20:57 README.md [root@kube-master01 ~]#
index.yaml
を生成するにはhelm repo index
コマンドを利用します。
# index.yamlを生成 [root@kube-master01 ~]# helm repo index ./ --url http://localhost:8080/ [root@kube-master01 ~]# ls -l total 24 -rw-r--r-- 1 root root 404 Oct 14 02:48 index.yaml -rw-r--r-- 1 3434 3434 11373 Sep 5 20:57 LICENSE drwxr-xr-x 3 root root 79 Sep 29 00:29 mychart -rw-r--r-- 1 root root 2334 Oct 14 02:47 mychart-0.1.0.tgz -rw-r--r-- 1 3434 3434 3309 Sep 5 20:57 README.md
index.yaml
は以下のような内容です。
apiVersion: v1 entries: mychart: - apiVersion: v2 appVersion: 1.16.0 created: "2019-10-14T02:48:03.616046491Z" description: A Helm chart for Kubernetes digest: ff17768e71be78e0316234183180ff6eddf502466442f62c6b2c69bcb63c894b name: mychart type: application urls: - http://localhost:8080/mychart-0.1.0.tgz version: 0.1.0 generated: "2019-10-14T02:48:03.615067755Z"
ここまでで準備ができましたので、chartmuseum
リポジトリをhelm repo add
コマンドで新しく登録します。
# 新しいリポジトリを追加する [root@kube-master01 ~]# helm repo add chartmuseum http://localhost:8080 "chartmuseum" has been added to your repositories [root@kube-master01 ~]# helm repo list NAME URL stable https://kubernetes-charts.storage.googleapis.com chartmuseum http://localhost:8080 [root@kube-master01 ~]#
この時点では何のchartも格納されていないので、検索しても何も表示されません。
[root@kube-master01 ~]# helm search repo chartmuseum/ No results found [root@kube-master01 ~]#
先ほど生成したmychart-0.1.0.tgz
index.yaml
を、リポジトリ格納先に移動します。今回はchartmuseum
Podが格納先となりますので、まずはPodの中身を確認し、保存先を調べます。
[root@kube-master01 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE chartmuseum-chartmuseum-76d6cbc86c-qnm4w 1/1 Running 0 16m [root@kube-master01 ~]# kubectl get pods -o yaml (中略) spec: containers: - args: - --port=8080 - --storage-local-rootdir=/storage ★ここに保存する (中略) [root@kube-master01 ~]#
kubectl get pods -o yaml
の全出力結果は以下になります。
kubectl get pods -o yaml
apiVersion: v1 items: - apiVersion: v1 kind: Pod metadata: annotations: cni.projectcalico.org/podIP: 192.168.132.53/32 creationTimestamp: "2019-10-14T02:39:22Z" generateName: chartmuseum-chartmuseum-76d6cbc86c- labels: app: chartmuseum pod-template-hash: 76d6cbc86c release: chartmuseum name: chartmuseum-chartmuseum-76d6cbc86c-qnm4w namespace: default ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet name: chartmuseum-chartmuseum-76d6cbc86c uid: 7f09895a-4329-48b7-b7c2-40ba50107cae resourceVersion: "1728741" selfLink: /api/v1/namespaces/default/pods/chartmuseum-chartmuseum-76d6cbc86c-qnm4w uid: b7610a39-1791-499b-a3b3-5fdf60642b5a spec: containers: - args: - --port=8080 - --storage-local-rootdir=/storage ★ここに保存する env: - name: CHART_POST_FORM_FIELD_NAME value: chart - name: DISABLE_API value: "true" - name: DISABLE_METRICS value: "true" - name: LOG_JSON value: "true" - name: PROV_POST_FORM_FIELD_NAME value: prov - name: STORAGE value: local image: chartmuseum/chartmuseum:v0.8.2 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 httpGet: path: /health port: http scheme: HTTP initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: chartmuseum ports: - containerPort: 8080 name: http protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /health port: http scheme: HTTP initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /storage name: storage-volume - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-pvvhs readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: kube-worker01 priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: fsGroup: 1000 serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - emptyDir: {} name: storage-volume - name: default-token-pvvhs secret: defaultMode: 420 secretName: default-token-pvvhs status: conditions: - lastProbeTime: null lastTransitionTime: "2019-10-14T02:39:22Z" status: "True" type: Initialized - lastProbeTime: null lastTransitionTime: "2019-10-14T02:39:39Z" status: "True" type: Ready - lastProbeTime: null lastTransitionTime: "2019-10-14T02:39:39Z" status: "True" type: ContainersReady - lastProbeTime: null lastTransitionTime: "2019-10-14T02:39:22Z" status: "True" type: PodScheduled containerStatuses: - containerID: docker://358cac7e3d72c70ce700c96cc072aa1a3a9ac00fccefcb2b49e4cb79ec887617 image: chartmuseum/chartmuseum:v0.8.2 imageID: docker-pullable://chartmuseum/chartmuseum@sha256:beecf590c7467eaa2edbf3c977d627cbab8e1aff833318b481a4fe1513342f6e lastState: {} name: chartmuseum ready: true restartCount: 0 state: running: startedAt: "2019-10-14T02:39:30Z" hostIP: 172.16.33.20 phase: Running podIP: 192.168.132.53 qosClass: BestEffort startTime: "2019-10-14T02:39:22Z" kind: List metadata: resourceVersion: "" selfLink: "" [root@kube-master01 ~]#
格納先がわかったのでファイルを移動します。今回はkubectl cp
コマンドを利用し、ローカルのファイルをコンテナ内にコピーします。
# kubectl cp [root@kube-master01 ~]# kubectl cp index.yaml chartmuseum-chartmuseum-76d6cbc86c-qnm4w:/storage/ [root@kube-master01 ~]# kubectl cp mychart-0.1.0.tgz chartmuseum-chartmuseum-76d6cbc86c-qnm4w:/storage/ # コピー結果の確認 [root@kube-master01 ~]# kubectl exec -it chartmuseum-chartmuseum-76d6cbc86c-qnm4w -- ls -l /storage/ total 8 -rw-r--r-- 1 chartmus chartmus 404 Oct 14 02:48 index.yaml -rw-r--r-- 1 chartmus chartmus 2334 Oct 14 02:47 mychart-0.1.0.tgz [root@kube-master01 ~]#
これでファイルを配置できました。ただこのままhelm search
コマンドを利用しても何も表示されないので、helm repo update
コマンドでリポジトリを更新する必要があります。
# ファイルの移動直後は検索しても表示されない [root@kube-master01 ~]# helm search repo chartmuseum/ No results found [root@kube-master01 ~]# # リポジトリをアップデート [root@kube-master01 ~]# helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "chartmuseum" chart repository ...Successfully got an update from the "stable" chart repository Update Complete. ⎈ Happy Helming!⎈ [root@kube-master01 ~]# # アップデート後の確認 [root@kube-master01 ~]# helm search repo chartmuseum/ NAME CHART VERSION APP VERSION DESCRIPTION chartmuseum/mychart 0.1.0 1.16.0 A Helm chart for Kubernetes [root@kube-master01 ~]#
以上の通りchartmuseum/mychart
が確認できるようになりました。ここまでくればhelm install
コマンドでchartをインストールすることができるようになります。
# chartmuseumリポジトリからインストール [root@kube-master01 ~]# helm install mychart2 chartmuseum/mychart NAME: mychart2 LAST DEPLOYED: 2019-10-14 10:23:25.577755362 +0000 UTC m=+0.101634524 NAMESPACE: default STATUS: deployed NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods -l "app=mychart,release=mychart2" -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 # インストール後確認 [root@kube-master01 ~]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART chartmuseum default 1 2019-10-14 02:39:22.522212778 +0000 UTC deployed chartmuseum-2.3.2 mychart2 default 1 2019-10-14 10:23:25.577755362 +0000 UTC deployed mychart-0.1.0 [root@kube-master01 ~]#
最後に
今回はHelm ver.3を操作してみました。tiller
が削除されたり一部コマンドが変更されたりと、ver.2からの変更点がいくつかありますが、簡単に操作する分にはそこまで抵抗は感じませんでした。現時点ではまだベータ版しか利用できないため、本番環境で利用することは推奨できませんが、セキュリティ的に向上したことを考えれば、本番環境ではver.3へと推移する可能性が高いと思われます。そのため今のうちに使い方を見ておいたほうが良いかもしれません。
またLibrary Chart
など、Helm ver.3からの新機能については今回触れなかったので、また別の機会で紹介したいと思います。
参考リンク
Helm Documentation - Frequently Asked Questions
Helm Documentation - Migrating Helm v2 to v3
Helm Hub - Discover & launch great Kubernetes-ready apps
How to create a public Helm Repo using Azure Storage (and it works with Helm3 beta3)