はじめに
第1章 Helmの概要・基本構成
第2章 Kubernetesクラスター構築・Helmインストール
第3章 Helmでアプリケーションをデプロイ
第4章 Helm Chartを自作しよう
第5章 Helm Chartを発展させよう
付録A コマンドチートシート
付録B Chart用変数チートシート
付録C Chart用Sprig 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」で頒布されたものを底本としています。
本章では、Helmの概要・基本構成を紹介します。コンテナ以前のパッケージマネージャーから、コンテナ以降のパッケージマネージャーの変遷などを理解しつつ、Helmの構成や利点を深掘りします。
HelmはKubernetesの周辺エコシステムのひとつで、Helmの利用にはKubernetesクラスターとHelmClientとHelmServerのインストールが必要です。実際のインストールは、第2章「Kubernetesクラスター構築・Helmインストール」で解説します。
繰り返し述べていますが、HelmとはKubernetesのパッケージマネージャーです。Helmの概要に触れる前に、まずパッケージマネージャーの変遷について考察します。
ここでの「パッケージマネージャー」とは、OSの上でソフトウェアの導入・更新・削除などの管理や、ソフトウェア・ミドルウェア間の依存関係を管理するシステムを指します。
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
このように、「コマンドひとつで簡単インストール」というわけにはいきません。JenkinsはMaster・Slave構成を取ることもできます。当然Slave構成を取る場合はサーバーを用意し、JavaやGitなどの必要なミドルウェアを自分で設定する必要があります。
YumやAPTを利用するのはオンプレミスのサーバーやVMにソフトウェアを入れる場合のユースケースですが、ここでコンテナを利用すると導入が容易になります。
コンテナの特徴のひとつに「Build Once. Run Anywhere」という言葉があります。文字通り、一度構築してしまえばDockerが動く環境ならばどこでも実行が可能になるのです。
Jenkinsをコンテナで構築・実行する場合は、次のDockerコマンドを実行します。
$ docker run -p 8080:8080 -p 50000:50000 jenkins
YumやAPTを利用する場合より、コマンドひとつで起動できる分、非常に構築が簡単です。
単純にJenkinsサーバーを立てるだけならこれで完了です。では、続いてMaster・Slave構成を立てるケースを考えてみます。
これを実現するには
1.Jenkins Masterコンテナ(一個)
2.Jenkins Slaveコンテナ(N個)
の2種類のコンテナを起動し、連携させる必要があります。複数のコンテナを起動させるために、次の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
docker-composeコマンドで実行すると、コンテナが起動し、JenkinsのMaster・Slaveサーバーがそれぞれ立ち上がります。
正確には、初回起動はMasterコンテナのみ成功し、Slaveコンテナは起動に失敗します。JenkinsでSlave構成を取るには、Masterコンテナ側にノードの設定が必要なためです。公式Jenkinsイメージは、起動直後に手作業での初回設定作業が必要になります。初回設定作業後にはメニュー「Jenkinsの管理」から「ノードの管理」でSlaveサーバーのノードを追加しておく必要があります。
また、デフォルトでセキュリティー設定が有効なため、Slaveの実行コマンドにオプションでシークレットを渡す必要もあります。リスト1.1は分かりやすさ優先でセキュリティー設定を無効に設定した場合の例です。本書では細かい設定については触れませんが、参考になるリンクを次に掲載しますので参照してください。
$ docker-compose up
コンテナにすると非常に簡単に立ち上がり、Docker Composeを利用すれば複数コンテナの立ち上げも簡単になりました。さて、これでもう簡易化は十分でしょうか?
複数のコンテナを扱えるDocker Composeも、エンタープライズでの利用においては不十分です。そのデメリットとして、次の点が挙げられます。
・コンテナの管理を自分で行う必要がある。プロセスが止まったら再び自分で復旧しなければならない
・複数のコンテナがひとつのホストで立ち上がるため、システムリソースが競合することがある
・ひとつのホストで複数のコンテナが立ち上がるため、ポートがバインディングをしないように設計する必要がある
ではどうすれば複数のコンテナを利用しつつ、これらのデメリットを克服できるでしょうか?
そこで登場するのがKubernetesです。
「コンテナオーケストレーションツール」であるKubernetesの利用で、主に次のメリットが得られます。
・Self Healing(自己回復)
・Immutable Infrastructure(不変なサーバー基盤)
・AutoScaling(自動的な規模の調整)
・etc...
Kubernetesはエンタープライズで利用される例が増えており、コンテナオーケストレーションのデファクトスタンダードといえます。
さっそくKubernetesを利用してJenkinsを構築します。
実行する対象ファイルは7つあります。対象ファイルは次のリンクを参照してください。
・https://github.com/govargo/container/tree/master/kubernetes/jenkins
ここでは、中でももっとも重要なファイルとして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
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.6のように待機する状態になります。Podの状態を確認すると、イメージをプルしてコンテナを作成しようとしていることが分かります。
$ 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が登場しましたが、オフライン状態です。
$ 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」に変化します。