Ubuntu Weekly Recipe

第470回Kubernetesのパッケージ管理ツール「Helm」

第469回ではKubernetesの環境を構築しました。今回はそのKubernetes上にソフトウェアスタックを構築する上で便利なパッケージ管理ツール「Helm」について紹介します。

Kubernetesでパッケージ管理ツールを使う理由

HelmはKubernetes用のパッケージ管理ツールです[1]⁠。パッケージそのものは「Chart」と呼ばれるYAMLファイルの集合体で、独自のパッケージリポジトリとしてKubernetes Chartsを提供しています。

UbuntuのAPTシステムでいうところのDebパッケージファイルがChartで、Kubernetes Chartsは公式パッケージリポジトリ、そのリポジトリやローカルシステムからDebパッケージファイルをダウンロード・インストールするコマンドがhelmだとイメージすれば良いでしょう。

Kubernetesにはその役割に応じてさまざまなリソースの概念が存在します。たとえばPodsはひとつないし複数のDockerコンテナを細分化不可なひとつのリソースとしてまとめたものですし、Servicesはレプリケーションされた複数のPodsが提供するサービスを抽象化するリソースです。Deploymentsはレプリケーションコントローラーとして、Podsの生死を監視し必要に応じてPodsの再起動を行います。また永続的なデータはVolumesで管理します。サービスやコンテナの実体を分離することで、サービスを維持したままPodsのアップデートやスケールを実現できるのです。

kubectlコマンドはこれら個々のリソースを区別することなく、kubectl create -f YAMLで一括して作成します。リソースごとにYAMLファイルを作成する場合もありますし、前回使用したGuestbookのall-in-oneのようにひとつのYAMLファイルにまとめることもできます。

ただし、実際にKubernetesのサンプルを使ってみるとわかるのですが、ソフトウェアスタックが提供するYAMLファイルをそのまま使えることはまれです。大抵の場合は、秘密鍵をどうするのか、ストレージはどのように準備するのか、ロードバランサーは何を使うのかなど、デプロイするサイト固有の環境に応じてYAMLファイルをカスタマイズする必要があります。

そこで出てくるのが今回紹介するHelmです。Helmでは、kubectlコマンドが使うYAMLファイルから設定可能な部分を別YAMLファイルとして分離できます。テンプレートエンジンを使って、インストール時にサイト固有の設定をkubectlコマンドに提供するYAMLファイルに反映するのです。また、Hook機能によってパッケージのライフサイクルや定義済みのイベントの途中に、別の処理を行うことも可能ですし、他のパッケージ(Chart)との依存関係も構築できます。

パッケージそのものはひとつのアーカイブファイルとして構築します。アクセス可能な箇所であればネットワーク越しにダウンロードしてインストールすることも可能ですし、git cloneしたディレクトリをインストール対象としても指定できます。またローカルパッケージリポジトリをKubernetes上に構築可能です。

いずれにせよKubernetesを使うのであれば、Helmの使い方もセットで覚えておくと、さまざまなソフトウェアスタックの作成・構築・削除が簡単になることでしょう。

Helmのインストールと初期設定

HelmそのものはGo言語で構築されたひとつのバイナリファイルとして提供されています。よってそのインストール方法は、最新のバイナリファイルをダウンロードしてbinディレクトリに展開するだけです。

$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.4.1-linux-amd64.tar.gz
$ tar xvf helm-v2.4.1-linux-amd64.tar.gz
$ cp linux-amd64/helm ~/bin/
$ which kubectl
/home/willem/bin/helm

Helmを使う前に、リポジトリなどのメタデータセットをホームディレクトリ以下に作成しhelm init⁠、Kubernetes Chartsのリポジトリデータをダウンロードしますhelm repo update⁠。

$ helm init
Creating /home/willem/.helm
Creating /home/willem/.helm/repository
Creating /home/willem/.helm/repository/cache
Creating /home/willem/.helm/repository/local
Creating /home/willem/.helm/plugins
Creating /home/willem/.helm/starters
Creating /home/willem/.helm/repository/repositories.yaml
$HELM_HOME has been configured at /home/willem/.helm.

Tiller (the helm server side component) has been installed into your Kubernetes Cluster.
Happy Helming!

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈

この時点でのリポジトリのパッケージリストは、~/.helm/repository/cache/stable-index.yamlです。

helm initによってローカルリポジトリサーバーにインスタンス(Tiller)が自動的にKubernetes上に構築されます[2]⁠。

$ kubectl --namespace=kube-system get pods
NAME                             READY     STATUS    RESTARTS   AGE
kube-dns-806549836-nmn71         3/3       Running   0          8d
tiller-deploy-1491950541-h3g40   1/1       Running   0          8m

$ kubectl --namespace=kube-system get services
NAME            CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
kube-dns        10.152.183.10    <none>        53/UDP,53/TCP   8d
tiller-deploy   10.152.183.252   <none>        44134/TCP       8m

Jenkinsパッケージのインストール

実際の使用例として、公式リポジトリにあるJenkins Chartをインストールしてみましょう。

まずリポジトリの検索はhelm searchを、パッケージ情報の表示はhelm inspectを使います。

$ helm search jenkins
NAME            VERSION DESCRIPTION
stable/jenkins  0.6.2   Open source continuous integration server. It s...

$ helm inspect stable/jenkins
description: Open source continuous integration server. It supports multiple SCM tools
  including CVS, Subversion and Git. It can execute Apache Ant and Apache Maven-based
  projects as well as arbitrary scripts.
home: https://jenkins.io/
icon: https://wiki.jenkins-ci.org/download/attachments/2916393/logo.png
maintainers:
- email: lachlan@deis.com
  name: Lachlan Evenson
- email: viglesias@google.com
  name: Vic Iglesias
name: jenkins
sources:
- https://github.com/jenkinsci/jenkins
- https://github.com/jenkinsci/docker-jnlp-slave
version: 0.6.2

(以下略)

helm inspectはパッケージのメタデータに加えて、パッケージインストール時に変更できる設定値一覧も表示します。もしくはhelm inspect values Chart名で設定値のみを表示できます。この設定値はサイト固有のデプロイ時に変更できる値であり、その一部は変更が必要な値でもあります。インストールする前に一読する癖をつけておきましょう。

設定値は--setオプションで個別に指定したり、--valuesオプションで設定値を記述したYAMLファイルを指定できます。たとえばKubernetes外部へのアクセス手段を設定するServiceTypeとしてClusterIPを使用し、永続的なストレージを用意しない(Jenkins Podが終了や再起動するとデータが失われる)場合、次のようにインストールします ※3⁠。

$ helm install --name chtholly --set Master.ServiceType=ClusterIP,Persistence.Enabled=false stable/jenkins
NAME:   chtholly
LAST DEPLOYED: Fri May  5 07:09:16 2017
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Secret
NAME              TYPE    DATA  AGE
chtholly-jenkins  Opaque  2     2s

==> v1/ConfigMap
NAME                    DATA  AGE
chtholly-jenkins-tests  1     2s
chtholly-jenkins        3     2s

==> v1/Service
NAME              CLUSTER-IP      EXTERNAL-IP  PORT(S)             AGE
chtholly-jenkins  10.152.183.160  <none>       8080/TCP,50000/TCP  2s

==> v1beta1/Deployment
NAME              DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
chtholly-jenkins  1        1        1           0          2s


NOTES:
1. Get your 'admin' user password by running:
  printf $(kubectl get secret --namespace default chtholly-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
2. Get the Jenkins URL to visit by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace default -l "component=chtholly-jenkins-master" -o jsonpath="{.items[0].metadata.name}")
  echo http://127.0.0.1:8080
  kubectl port-forward $POD_NAME 8080:8080

3. Login with the password from step 1 and the username: admin

For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine
#################################################################################
######   WARNING: Persistence is disabled!!! You will lose your data when   #####
######            the Jenkins pod is terminated.                            #####
#################################################################################

インストール後の作業も表示してくれる親切設計です。これはChartのNOTES.txtをテンプレートによって書き換えた上で表示しています。

ちなみにHelmではインストールしたパッケージのインスタンスを「リリース(Release⁠⁠」と呼びます。--name chthollyはインストール後のリリースの名前(ReleaseName)を指定しています。APTとは異なり、あるパッケージをインストールしたらそのリリースはパッケージ名とは異なる固有の名前を持ちます。これにより、同じパッケージを別名・別設定で何度でもインストールできるのです。

--nameオプションを指定しない場合は、いくつかの単語のランダムな組み合わせで名前がつけられます。覚えるのが大変であるため、普段から--nameオプションをつけるようにしたほうが良いでしょう。

インストール済みのパッケージはhelm listコマンドで確認できます。

$ helm list
NAME           REVISION        UPDATED                         STATUS          CHART           NAMESPACE
chtholly       1               Fri May  5 07:09:16 2017        DEPLOYED        jenkins-0.6.2   default

またkubectlコマンドを使えば、Jenkinsのサービスが立ち上がっていることがわかります。

$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
default-http-backend-x6f4f          1/1       Running   0          8d
nginx-ingress-controller-100lz      1/1       Running   0          8d
nginx-ingress-controller-8prr9      1/1       Running   0          8d
nginx-ingress-controller-vcmz7      1/1       Running   0          8d
chtholly-jenkins-1794764249-2jlc7   1/1       Running   0          4m

$ kubectl get services
NAME                   CLUSTER-IP       EXTERNAL-IP   PORT(S)              AGE
default-http-backend   10.152.183.176   <none>        80/TCP               8d
kubernetes             10.152.183.1     <none>        443/TCP              8d
chtholly-jenkins       10.152.183.160   <none>        8080/TCP,50000/TCP   4m

Jenkinsは外部へのウェブインターフェースとして8080番ポートを、MasterとSlave間の通信用に50000番ポートを使用しています。インストール時のメッセージではkubectl port-forwardで設定する方法がアナウンスされていますが、これはローカルでしか使えません。よってNginx Ingress Controllerで外部からのアクセスを許可するために、8080番ポートだけをルーティングしましょう。そこで次のような内容で、jenkins-ingress.yamlファイルを作成します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: jenkins-ingress
spec:
  rules:
  - host: jenkins.example.org
    http:
      paths:
      - path: /
        backend:
          serviceName: chtholly-jenkins
          servicePort: 8080

これをkubectlコマンドに渡します。

$ kubectl create -f jenkins-ingress.yaml
$ kubectl get ingress
NAME               HOSTS                 ADDRESS            PORTS     AGE
jenkinsk-ingress   jenkins.example.org   10.183.107.11...   8080      11s

あとはjenkins.example.orgにアクセスするだけです。インストール時のメッセージにあるように、管理者のアカウント名は「admin」で、パスワードについては次のコマンドで取得できます。

$ printf $(kubectl get secret --namespace default chtholly-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
DLdjk0Uv3W

無事にフロントページにアクセスできれば、インストール完了です。

パッケージの削除

Helmでインストールしたパッケージを削除するには、helm deleteコマンドにリリースの名前を渡すだけです。リリース名(ReleaseName)であってパッケージ名ではありません。

$ helm delete chtholly

なおパッケージを削除したとしてもリリース名は予約されたままとなります。もし同じ名前で再インストールしたい場合は、--purgeオプションを付けて削除してください。

$ helm delete --purge=true chtholly

削除したけれども名前は残っているリリースも含むすべてのリリースの一覧はhelm list --allで確認できます。その他の使い方は、Helmのコマンドリファレンスが参考になるでしょう。

おすすめ記事

記事・ニュース一覧