目次

はじめに

免責事項
表記関係について
底本について

第1章 Helmの概要・基本構成

1.1 具体例で考えるパッケージマネージャーの変遷
1.2 Helmの特徴・構成

第2章 Kubernetesクラスター構築・Helmインストール

2.1 Kubernetesクラスターの構築の選択肢
2.2 Google Kubernetes Engineの構築
2.3 Helmのインストール

第3章 Helmでアプリケーションをデプロイ

3.1 Helmコマンド
3.2 MySQLとPrometheus/GrafanaをHelmでインストールする

第4章 Helm Chartを自作しよう

4.1 Chart作成チュートリアル
4.2 GoアプリケーションをChart化する

第5章 Helm Chartを発展させよう

5.1 SubChartsとは
5.2 Happy Helming ChartをSubChart化する

付録A コマンドチートシート

付録B Chart用変数チートシート

付録C Chart用Sprig Functionsチートシート

C.1 String Functions
C.2 String Slice Functions
C.3 Math Functions
C.4 Integer Slice Functions
C.5 Date Functions
C.6 Encoding Functions
C.7 Lists and List Functions
C.8 Dictionaries and Dict Functions
C.9 Type Conversion Functions
C.10 File Path Functions
C.11 Flow Control Functions
C.12 Advanced Functions

はじめに

 本書を手に取っていただき、ありがとうございます。本書は、進化が早く日本語のドキュメントの少ないクラウドネイティブの世界にある便利なツールを紹介したい、という気持ちから生まれました。その中でも、強力かつ便利なパッケージマネージャーであるHelmの使い方から、実際にアプリをデプロイするまでを解説しています。

 クラウドネイティブ1とは、「モダンかつダイナミックなクラウド環境において、スケーラブルなアプリケーションの開発と実行を担う組織の力を強化するもの」と定義されています。

 クラウドネイティブなアプリケーションの開発を進める団体「Cloud Native Computing Foundation」(CNCF)2で公開されているプロジェクトは数百を超えます。本書で解説するHelm3もこのプロジェクトのひとつで、2019年04月現在、急速に成長中のプロダクトです。

 Helmは、コンテナオーケストレーションのデファクトスタンダードツールであるKubernetes4とセットで利用します。そのため、Helmでデプロイを行うためには、Kubernetesクラスタを作成する必要があります。そのため、本書の理解にはコンテナ(Docker)とコンテナオーケストレーター(Kubernetes)の知識が必要です。

 本書では、Kubernetesクラスタの構築について紹介しますが、Kubernetesのリソースの種類や使い方についてについて解説することはありません5

 しかし、Helmの便利さは強力で、Kubernetesにデプロイするためのツールの中でも、最もデファクトスタンダードに近い位置にあります。

 GitHubで公開されているテンプレートファイル群であるChart(チャート)を利用すれば、JenkinsやGitLabなどの馴染みのあるアプリケーションを簡単にデプロイできます。さらに自作したアプリケーションについても、Chartを作成することで簡単にデプロイできるのです。

 本書を通して、その魅力が一端でも伝われば幸いです。

この本の想定読者

 ・DockerやKubernetesは知っているが6、Helmを知らない

 ・DockerやKubernetesを利用しているが、Helmは使っていない

 ・Helmを利用しているが、Chartを自作した経験がないので方法を知りたい

本書の流れ

 本書は、次の流れでHelmで自作Chartを作るためのフローを経ていきます。

 1.第1章では、Helmの概念や基本構成について説明します。

 2.第2章では、Helmをインストールするための準備として、Kubernetesクラスタ(Google Kubernetes Engine)を作成し、その後Helmをインストールします。

 3.第3章では、実際にHelmを利用してOSSソフトウェアのデプロイを行います。

 4.第4章では、自作のアプリケーションを簡単にデプロイするために、Helm Chartを作成する方法を説明します。

 5.第5章では、第4章で作成したChartをさらに発展させる方法を説明します。

 また、AppendixとしてHelmコマンドチートシートとChart組み込み変数一覧、Functionチートシートを収録しています。

検証バージョン

 本書でのHelmのバージョンは、クライアント・サーバーともに2.13.0で検証しています。これと異なる環境では、説明の内容や動作の紹介などが異なる場合があります。

サンプルコード

 サンプルコード(Chart)は、次のURLからダウンロードできます。

 https://github.com/govargo/sample-charts

免責事項

 本書に記載された内容は、情報の提供のみを目的としています。したがって、本書を用いた開発、製作、運用は、必ずご自身の責任と判断によって行ってください。これらの情報による開発、製作、運用の結果について、著者はいかなる責任も負いません。

表記関係について

 本書に記載されている会社名、製品名などは、一般に各社の登録商標または商標、商品名です。会社名、製品名については、本文中では©、®、™マークなどは表示していません。

底本について

 本書籍は、技術系同人誌即売会「技術書典6」で頒布されたものを底本としています。



第1章 Helmの概要・基本構成

 本章では、Helmの概要・基本構成を紹介します。コンテナ以前のパッケージマネージャーから、コンテナ以降のパッケージマネージャーの変遷などを理解しつつ、Helmの構成や利点を深掘りします。

 HelmはKubernetesの周辺エコシステムのひとつで、Helmの利用にはKubernetesクラスターとHelmClientとHelmServerのインストールが必要です。実際のインストールは、第2章「Kubernetesクラスター構築・Helmインストール」で解説します。

1.1 具体例で考えるパッケージマネージャーの変遷

 繰り返し述べていますが、HelmとはKubernetesのパッケージマネージャーです。Helmの概要に触れる前に、まずパッケージマネージャーの変遷について考察します。

 ここでの「パッケージマネージャー」とは、OSの上でソフトウェアの導入・更新・削除などの管理や、ソフトウェア・ミドルウェア間の依存関係を管理するシステムを指します。

1.1.1 オンプレミス・VMのパッケージ管理

 Linuxにおけるパッケージマネージャーには、Red Hat Linux系の「Yum」やDebian系の「APT」があります。またNode.jsでのパッケージマネージャーである「npm」も有名です。

 たとえばRed Hat Linux系サーバーに、WebサーバーのApacheをインストールする場合は、次のコマンドを実行します。

$ yum install -y httpd

 またDebian系のサーバーに同じくApacheをインストールする場合は、次のコマンドを実行します。

$ aptitude -y install apache2

 パッケージマネージャーを利用すれば、ライブラリの依存関係を気にすることなく、ソフトウェアを容易に導入できます。

 しかし、ビルドサーバーのJenkinsをCentOS7のサーバーにインストールする場合を考えてみます。CentOS7のサーバーにJenkinsをインストールするには、次のコマンドを実行する必要があります。

# JDKのインストール

$ yum -y install java-1.8.0-openjdk

# リポジトリーの設定

$ curl -o /etc/yum.repos.d/jenkins.repo \

https://pkg.jenkins.io/redhat-stable/jenkins.repo

$ rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key

# jenkinsのインストール

$ yum -y install jenkins

# サービスの有効化

$ systemctl enable jenkins

# サービスの開始

$ systemctl start jenkins


図1.1: CentOS7上にJenkinsを構築する例

 このように、「コマンドひとつで簡単インストール」というわけにはいきません。JenkinsはMaster・Slave構成を取ることもできます。当然Slave構成を取る場合はサーバーを用意し、JavaやGitなどの必要なミドルウェアを自分で設定する必要があります。

1.1.2 コンテナの利用

 YumやAPTを利用するのはオンプレミスのサーバーやVMにソフトウェアを入れる場合のユースケースですが、ここでコンテナを利用すると導入が容易になります。

 コンテナの特徴のひとつに「Build Once. Run Anywhere」という言葉があります。文字通り、一度構築してしまえばDockerが動く環境ならばどこでも実行が可能になるのです。

 Jenkinsをコンテナで構築・実行する場合は、次のDockerコマンドを実行します。

$ docker run -p 8080:8080 -p 50000:50000 jenkins


図1.2: DockerでJenkinsを構築する例

 YumやAPTを利用する場合より、コマンドひとつで起動できる分、非常に構築が簡単です。

1.1.3 複数のコンテナの連携

 単純にJenkinsサーバーを立てるだけならこれで完了です。では、続いてMaster・Slave構成を立てるケースを考えてみます。

 これを実現するには

 1.Jenkins Masterコンテナ(一個)

 2.Jenkins Slaveコンテナ(N個)

 の2種類のコンテナを起動し、連携させる必要があります。複数のコンテナを起動させるために、次のdocker-compose.ymlを起動します。

リスト1.1: docker-compose.yml

version: "3"
  services:
    master:
      container_name: jenkins-master
      image: jenkins
      ports:
        - 8080:8080
        - 50000:50000
      volumes:
        - ./jenkins_home:/var/jenkins_home

    slave:
      container_name: jenkins-slave
      image: jenkinsci/slave
      command: java -jar /usr/share/jenkins/slave.jar \
               -jnlpUrl http://master:8080/computer/agent/slave-agent.jnlp
      links:
       - master
図1.3: DockerComposeでMaster・Slaveを構築する例

 docker-composeコマンドで実行すると、コンテナが起動し、JenkinsのMaster・Slaveサーバーがそれぞれ立ち上がります。

 正確には、初回起動はMasterコンテナのみ成功し、Slaveコンテナは起動に失敗します。JenkinsでSlave構成を取るには、Masterコンテナ側にノードの設定が必要なためです。公式Jenkinsイメージは、起動直後に手作業での初回設定作業が必要になります。初回設定作業後にはメニュー「Jenkinsの管理」から「ノードの管理」でSlaveサーバーのノードを追加しておく必要があります。

 また、デフォルトでセキュリティー設定が有効なため、Slaveの実行コマンドにオプションでシークレットを渡す必要もあります。リスト1.1は分かりやすさ優先でセキュリティー設定を無効に設定した場合の例です。本書では細かい設定については触れませんが、参考になるリンクを次に掲載しますので参照してください。

https://hub.docker.com/r/jenkins/slave/

https://qiita.com/i_whammy_/items/84b71c56d70817803472


$ docker-compose up

 コンテナにすると非常に簡単に立ち上がり、Docker Composeを利用すれば複数コンテナの立ち上げも簡単になりました。さて、これでもう簡易化は十分でしょうか?


 複数のコンテナを扱えるDocker Composeも、エンタープライズでの利用においては不十分です。そのデメリットとして、次の点が挙げられます。

 ・コンテナの管理を自分で行う必要がある。プロセスが止まったら再び自分で復旧しなければならない

 ・複数のコンテナがひとつのホストで立ち上がるため、システムリソースが競合することがある

 ・ひとつのホストで複数のコンテナが立ち上がるため、ポートがバインディングをしないように設計する必要がある

 ではどうすれば複数のコンテナを利用しつつ、これらのデメリットを克服できるでしょうか?

1.1.4 コンテナオーケストレーションの利用

 そこで登場するのがKubernetesです。

 「コンテナオーケストレーションツール」であるKubernetesの利用で、主に次のメリットが得られます。

 ・Self Healing(自己回復)

 ・Immutable Infrastructure(不変なサーバー基盤)

 ・AutoScaling(自動的な規模の調整)

 ・etc...

 Kubernetesはエンタープライズで利用される例が増えており、コンテナオーケストレーションのデファクトスタンダードといえます。

 さっそくKubernetesを利用してJenkinsを構築します。

 実行する対象ファイルは7つあります。対象ファイルは次のリンクを参照してください。

 ・https://github.com/govargo/container/tree/master/kubernetes/jenkins

 ここでは、中でももっとも重要なファイルとしてdeployment.ymlを抜粋します。

リスト1.2: deployment.yml

apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: jenkins
    labels:
      app: jenkins
  spec:
    replicas: 1
    strategy:
      type: RollingUpdate
    selector:
      matchLabels:
        app: "jenkins"
    template:
      metadata:
        labels:
          app: jenkins
      spec:
        securityContext:
          runAsUser: 0
        serviceAccountName: jenkins
        initContainers:
          - name: "copy-default-config"
            image: "jenkins/jenkins:lts"
            imagePullPolicy: "Always"
            command: [ "sh", "/var/jenkins_config/apply_config.sh" ]
            volumeMounts:
              - mountPath: /var/jenkins_home
                name: jenkins-home
              - mountPath: /var/jenkins_config
                name: jenkins-config
              - mountPath: /var/jenkins_plugins
                name: plugin-dir
              - mountPath: /usr/share/jenkins/ref/secrets/
                name: secrets-dir
        containers:
          - name: jenkins
            image: "jenkins/jenkins:lts"
            imagePullPolicy: "Always"
            args: [ "--argumentsRealm.passwd.$(ADMIN_USER)=$(ADMIN_PASSWORD)",
                    "--argumentsRealm.roles.$(ADMIN_USER)=admin"]
            env:
              - name: ADMIN_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: jenkins
                    key: jenkins-admin-password
              - name: ADMIN_USER
                valueFrom:
                  secretKeyRef:
                    name: jenkins
                    key: jenkins-admin-user
            ports:
              - containerPort: 8080
                name: http
              - containerPort: 50000
                name: slavelistener
            livenessProbe:
              httpGet:
                path: "/login"
                port: http
              initialDelaySeconds: 90
              timeoutSeconds: 5
              failureThreshold: 12
            readinessProbe:
              httpGet:
                path: "/login"
                port: http
              initialDelaySeconds: 60
            volumeMounts:
              - mountPath: /var/jenkins_home
                name: jenkins-home
                readOnly: false
              - mountPath: /var/jenkins_config
                name: jenkins-config
                readOnly: true
              - mountPath: /usr/share/jenkins/ref/plugins/
                name: plugin-dir
                readOnly: false
              - mountPath: /usr/share/jenkins/ref/secrets/
                name: secrets-dir
                readOnly: false
        volumes:
        - name: jenkins-config
          configMap:
            name: jenkins
        - name: plugin-dir
          emptyDir: {}
        - name: secrets-dir
          emptyDir: {}
        - name: jenkins-home
          emptyDir: {}

 kubectlでYAMLファイルを適用すると、記述に対応したコンテナや設定ファイルとサービスディスカバリ1が生成されます。Kubernetesでは、「Pod」が実行される最も小さな単位になります。Podはひとつ以上のコンテナの集合を指します。

# ファイルをダウンロード

$ git clone https://github.com/govargo/container.git

$ cd container/kubernetes

# Jenkinsコンテナを起動

$ kubectl apply -f ./jenkins


図1.4: KubernetesでMaster・Slaveを構築する例

 Podの起動は、次のコマンドで確認できます。

$ kubectl get pods

NAME READY STATUS RESTARTS AGE

jenkins-b88f6b99d-gwfx8 0/1 Running 0 1m

 Podが起動し、STATUSが「Running」かつREADYが「1/1」になると、Jenkinsが起動しています。「jenkins-b88f6b99d-gwfx8」というPodには、JenkinsのMasterコンテナのみが含まれています。これはJenkinsのSlaveコンテナは含まれていない、という意味ではありません。JenkinsのKubernetes Pluginでは、PodTemplate2というかたちでJenkinsのSlaveが設定ファイルに定義されています3。起動したJenkinsでジョブを作成してジョブを実行すると、このためのJenkins SlaveサーバーのPodが起動します。

 例として、図1.5のシェルを実行するジョブを設定して実行することで、Slaveサーバーが立ち上がるまでを確認してみます。

図1.5: シェルを実行するジョブを定義

 メニュー「ビルドを実行」を選択すると、実行可能なノードが作成されるまで、ジョブが図1.6のように待機する状態になります。Podの状態を確認すると、イメージをプルしてコンテナを作成しようとしていることが分かります。

図1.6: ノード作成を待機中

$ kubectl get pods --watch

NAME READY STATUS RESTARTS AGE

jenkins-b88f6b99d-gwfx8 1/1 Running 0 6m

default-xvqf6 0/1 Pending 0 0s

default-xvqf6 0/1 ContainerCreating 0 0s

 Jenkins Slaveサーバーが立ち上がると、JNLPというプロトコルでMasterサーバーに接続しようとします。図1.7でSlaveが登場しましたが、オフライン状態です。

図1.7: ノード接続中

$ kubectl get pods --watch

NAME READY STATUS RESTARTS AGE

jenkins-b88f6b99d-gwfx8 1/1 Running 0 6m

default-xvqf6 0/1 Pending 0 0s

default-xvqf6 0/1 ContainerCreating 0 0s

default-xvqf6 0/1 Running 0 0s

 Slaveサーバーの接続が完了して準備が完了すると、定義したジョブが実行されます。図1.8の実行が完了すると、PodのSTATUSも「Running」から「Completed」に変化します。

1. 簡単にいうとPodにアクセスするための仕組みです。参照: https://kubernetes.io/docs/concepts/services-networking/service/

2. Kubernetes-plugin PodTemplate https://github.com/jenkinsci/kubernetes-plugin

3. サンプルコードはこちら https://github.com/govargo/container/blob/master/kubernetes/jenkins/config.yml#L30

試し読みはここまでです。
この続きは、製品版でお楽しみください。